publish / solution
A platform conversation, not a one-click deployment

A practical path onto Azure.

Use your platform team's landing zone, approved services, and identity patterns. This example explains the boundaries; it does not provision cloud resources or grant permissions.

Choose the simplest approved host

App Service

A common starting point for managed web applications and APIs. Review built-in authentication, HTTPS-only, networking, runtime support, and diagnostics.

Container Apps

A managed option for containerized applications. Review ingress, revisions, image provenance, managed identity, scaling limits, and environment networking.

Static frontend + API

Static hosting can serve a UI, but private keys and authorization belong on a server-side API. Review identity and data boundaries across both components.

Keep the identities separate

  1. Human identity: Entra ID authenticates users. Your backend still enforces roles and record-level access.
  2. Deployment identity: A tightly scoped application/service principal trusts a GitHub OIDC subject for one repository and production environment.
  3. Runtime identity: The hosted app uses its own Managed Identity for storage, databases, and Key Vault. Do not reuse the deployer's permissions.

OIDC pattern: no client secret

Ask the platform team to configure federation using the effective issuer, audience, and subject claims of the exact protected deployment job. On GitHub.com the issuer is https://token.actions.githubusercontent.com; Azure Login's usual audience is api://AzureADTokenExchange. Custom audiences, subject templates, and other GitHub hosts can differ. Restrict the cloud role to the specific deployment scope.

For GitHub Cloud repositories created after July 15, 2026, or renamed/transferred after that date, the default subject includes immutable owner and repository IDs. A production-environment example is repo:YOUR-ORG@OWNER-ID/YOUR-REPO@REPO-ID:environment:production. Older repositories may retain repo:YOUR-ORG/YOUR-REPO:environment:production unless opted in. Immutable defaults are not available on GitHub Enterprise Server. Do not copy either example blindly: verify the actual claims and active customization, match case and environment name, and never log or paste the raw JWT.

Source: GitHub OIDC reference: immutable subject claims and Configuring OIDC in Azure.

name: Deploy reviewed application
on:
  workflow_dispatch:
permissions:
  contents: read
jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    permissions:
      contents: read
      id-token: write
    steps:
      # Pin both actions to reviewed full commit SHAs before use.
      - uses: actions/checkout@REVIEWED_FULL_COMMIT_SHA
        with:
          persist-credentials: false
      - uses: azure/login@REVIEWED_FULL_COMMIT_SHA
        with:
          client-id: ${{ vars.AZURE_CLIENT_ID }}
          tenant-id: ${{ vars.AZURE_TENANT_ID }}
          subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}
      # Add your reviewed build/test, artifact verification, and
      # service-specific deployment commands here.

Client, tenant, and subscription IDs are identifiers, not a client secret. Apply your organization's disclosure policy. Never add creds containing a service principal password. The placeholders above intentionally prevent this from being a deployable workflow.

Before the first production deployment

  1. Review infrastructure as code, service regions, and data classification with the platform/data owners.
  2. Configure runtime Managed Identity, narrow role assignments, vault access, and configuration without production .env files.
  3. Verify HTTPS, network access, safe logs, backups/restore, and actual alert delivery.
  4. Exercise the protected deployment and rollback in staging. Record evidence in the generated issues.
  5. Ask governance to review the validation report and evidence. Only then follow the organization's release process.

Authoritative references