Azure resources and setup
The pipeline targets an existing Python 3.11 Linux Consumption Function App and an existing Azure Static Web App. It deploys application code; it does not provision the resource group, storage, or email service.
Resource checklist
| Resource | Used for | Setup notes |
|---|---|---|
| Resource group | Organizes the existing app resources | Matches AZURE_RESOURCE_GROUP |
| Function App, runtime v4 / Python 3.11 | Hourly processing | Match the CI Python minor version and runtime locks |
| Function host storage | Runtime and timer coordination | Configured through AzureWebJobsStorage |
| Results storage account | Public JSON and private season state | Configured through RESULTS_STORAGE_CONNECTION_STRING |
| Azure Communication Services Email | Winner and recap delivery | Configure a verified sender and connect it to ACS |
| Azure Static Web App | Browser UI in public/ | No linked API or frontend build is required |
| Microsoft Entra application | GitLab deployment identity | Uses workload identity federation for Function deployment |
These are the repository’s deployment assumptions, not an inventory retrieved from a live Azure subscription. Verify the existing resource names and hosting plan in Azure before using the settings below.
1. Prepare storage and email
- Configure the Function’s host storage through its Azure runtime setup.
- Enable static website hosting on the results account to create
$web, or ensure the intended$webcontainer exists. The app expects it to exist. - Allow anonymous blob reads for the published results at the Blob endpoint if using the current direct browser URL. Public access to the Storage website endpoint alone does not establish public Blob endpoint access.
- Keep
pool-stateprivate. The Function creates it if absent; its credentials need container creation and blob read/write permissions. - Configure Blob service CORS for each browser origin that reads the feed.
- Set up the verified ACS email sender and populate the application settings in the configuration reference.
Storage’s *.web.core.windows.net website endpoint and
*.blob.core.windows.net/$web/... Blob endpoint behave differently. The website
endpoint does not support Storage CORS; the application uses the Blob endpoint
for cross-origin JSON. See Azure Storage website behavior
and the public website guide.
2. Configure GitLab identity for the Function
sequenceDiagram
participant Job as GitLab deployment job
participant Entra as Microsoft Entra ID
participant Azure as Azure Resource Manager
Job->>Job: Request job OIDC token
Job->>Entra: Exchange token using client and tenant IDs
Entra->>Entra: Validate issuer, subject, and audience
Entra-->>Job: Short-lived Azure credentials
Job->>Azure: Configure remote build and deploy ZIP-
Create an Entra app registration and its service principal.
-
Add a federated credential with the following exact values for your project:
Field Value Issuer https://gitlab.comfor this repositorySubject project_path:bclingan-development/cloud/azure-ravens-pool:ref_type:branch:mainAudience api://AzureADTokenExchangeUpdate the subject if the project path or default branch changes. A self-managed GitLab issuer must expose discovery and signing keys to Azure.
-
Grant the service principal Website Contributor scoped to the existing Function App, as used by this deployment design. Check authorization failures against the actual scope; the job does not need to create a resource group.
-
Protect the default branch and configure the five
AZURE_*identity/resource variables listed in configuration.
GitLab generates AZURE_OIDC_TOKEN for the job. Do not store that token or create
a client secret to replace it. GitLab’s Azure OIDC guide
describes the federation flow.
3. Deploy the Function
The deploy:function job:
- Packages
function_app.py,host.json,requirements.txt, and.py,.html,.txt, and.cssfiles beneathapp/into/tmp/function.zip. - Logs in with the federated identity and selects the subscription.
- Removes
WEBSITE_RUN_FROM_PACKAGEand enablesSCM_DO_BUILD_DURING_DEPLOYMENT=trueandENABLE_ORYX_BUILD=true. - Submits the ZIP with
--build-remote trueand a 600-second command timeout.
Azure installs the fully pinned requirements.txt using the Function’s configured
Python version. Changes to app settings can restart the Function. The pipeline
leaves storage credentials and email settings managed in Azure.
See Python build options for the remote-build model. This ZIP and these settings are specific to the current hosting approach; do not carry them unchanged to another hosting plan.
For a manual code deployment from the repository root, after configuring and verifying the destination:
func azure functionapp publish <function-app-name>The application exposes only the hourly timer. Use Function invocation logs and
published data to verify it; do not assume /api/ping exists.
4. Deploy the public website
The deploy:production job installs the locked Static Web Apps CLI and deploys
public/ to the production environment with SWA_DEPLOYMENT_TOKEN.
| SWA build setting | Value |
|---|---|
| App location | /public |
| API location | Empty |
| Output location | Empty |
| Frontend build command | None |
The CLI receives Node runtime metadata even though this is a static-only site. No Function source is linked to this deployment. The feed URL and CORS settings are covered in public website.
Custom domains are configured on the Static Web App. Use the DNS record and validation steps shown by Azure, then add the custom domain’s origin to Blob CORS as well. See Static Web Apps custom domains.
Hosting lifecycle
Microsoft lists Linux Consumption retirement as September 30, 2028. Plan a move to Flex Consumption before retirement and revisit packaging, identity, build settings, and operational checks as part of that work. See Azure Functions hosting guidance.