Skip to main content

Create App Registrations with Federated Credentials for GitHub Actions

This page describes how to self-service the creation of Azure App Registrations with federated credentials, enabling GitHub Actions workflows to access Azure resources without storing long-lived credentials as secrets.

Overview

Federated credentials allow your GitHub Actions workflows to authenticate to Azure using OpenID Connect (OIDC) without needing to maintain long-lived credentials. This is a more secure approach than storing service principal secrets or connection strings in GitHub.

Prerequisites

  1. You need write access to the azure-github-federation-config repository
  2. Familiarity with YAML syntax
  3. Understanding of your GitHub repository path (<org>/<repo>)
  4. Knowledge of which Azure scopes (subscriptions/resource groups/resources) your GitHub Actions need to access
  5. Knowledge of which Azure role you need (e.g., Reader, Contributor)

Key Concepts

Federated Credentials vs. Long-lived Secrets

  • Traditional approach: Store Azure credentials in GitHub secrets, risk of exposure if compromised
  • Federated credentials: GitHub Actions receive a short-lived token that is only valid for specific repository contexts, significantly reducing security risk

Subject Identifiers

A “subject” defines which GitHub repository contexts can use the App Registration. Each subject maps to a specific combination of repository and trigger condition.

Common subject formats: - repo:<org>/<repo>:ref:refs/heads/<branch> - Workflow running on a specific branch - repo:<org>/<repo>:pull_request - Workflow running on a pull request - repo:<org>/<repo>:ref:refs/tags/<tag> - Workflow running on a specific tag - repo:<org>/<repo>:environment:<environment> - Workflow running in a specific GitHub environment

The 20 Federated Credentials Limit

Azure has a hard limit of 20 federated credentials per App Registration. Each subject line counts as one credential. If you need more than 20 subjects, create multiple App Registrations (e.g., naming them with a numeric suffix like -1, -2, etc.).

Role-Based Access Control (RBAC)

Roles define what permissions the GitHub Actions workflow has. Common roles include: - Reader - Read-only access to resources - Contributor - Full management access - Custom roles - Organization-specific roles for fine-grained control

Scopes

Scopes define where the role is assigned. You can assign roles at multiple levels: - Management Group: /providers/Microsoft.Management/managementGroups/<group-name> - Subscription: /subscriptions/<subscription-id> - Resource Group: /subscriptions/<subscription-id>/resourceGroups/<resource-group-name> - Specific Resource: /subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/<resource-type>/<resource-name>

Getting Started: Adding a New App Registration

Step 1: Gather Required Information

Before editing the configuration, collect: 1. App Registration Name - A descriptive name for your app (e.g., “My Repository Deployment”) 2. GitHub Subjects - The repository contexts that will use this app: - Your repository name (<org>/<repo>) - The branches/tags/environments that will trigger deployments 3. Required Permissions: - Which Azure roles you need - Which Azure scopes (subscriptions, resource groups, resources) 4. Optional Owners - User IDs of additional owners (if different from the default deployment service account)

Step 2: Clone the Repository

git clone https://github.com/hmcts/azure-github-federation-config.git
cd azure-github-federation-config

Step 3: Edit the Configuration File

Open app-registrations.yaml in your text editor and add your App Registration configuration.

Simple Example: Read-only access to a subscription

- name: My Repository Reader
  subjects:
    - 'repo:hmcts/my-repository:ref:refs/heads/main'
    - 'repo:hmcts/my-repository:pull_request'
  permissions:
    - role_definition_name: Reader
      scopes:
        - /subscriptions/12345678-1234-1234-1234-123456789012

Complex Example: Multi-environment deployment

- name: My Repository Deployer
  subjects:
    - 'repo:hmcts/my-repository:ref:refs/heads/main'
    - 'repo:hmcts/my-repository:ref:refs/heads/develop'
    - 'repo:hmcts/my-repository:pull_request'
    - 'repo:hmcts/my-repository:environment:production'
  permissions:
    - role_definition_name: Reader
      scopes:
        - /subscriptions/12345678-1234-1234-1234-123456789012
    - role_definition_name: Contributor
      scopes:
        - /subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/my-rg

Example with Multiple Subjects at the Limit

- name: My Repository GitHub Actions-1
  subjects:
    - 'repo:hmcts/my-repository:ref:refs/heads/main'
    - 'repo:hmcts/my-repository:ref:refs/heads/develop'
    - 'repo:hmcts/my-repository:ref:refs/heads/staging'
    - 'repo:hmcts/my-repository:pull_request'
    - 'repo:hmcts/my-repository:environment:production'
    - 'repo:hmcts/another-repository:ref:refs/heads/main'
    - 'repo:hmcts/another-repository:pull_request'
    - 'repo:hmcts/third-repository:ref:refs/heads/main'
    # ... up to 20 total subjects
  permissions:
    - role_definition_name: Contributor
      scopes:
        - /subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/shared-rg

Step 4: Validate Your Configuration

Check the following before committing:

  1. YAML Syntax - Ensure proper indentation (2 spaces, not tabs)
  2. Subject Count - Count the lines under subjects: - must be ≤ 20
  3. Scopes Format - Verify subscription IDs and resource group names are correct
  4. Role Names - Ensure role names match available Azure roles in your organization

Step 5: Commit and Push

git add app-registrations.yaml
git commit -m "Add App Registration for my-repository"
git push origin main

Step 6: Create a Pull Request

Navigate to the repository on GitHub and create a pull request. The infrastructure team will review your configuration for: - Correct syntax and format - Appropriate permissions (following principle of least privilege) - Valid Azure scopes - Compliance with organizational policies

Once approved and merged, the terraform pipeline will automatically create your App Registration, service principal, federated credentials, and role assignments.

Using Your App Registration in GitHub Actions

Once your App Registration is created and deployed, use it in your GitHub Actions workflow with the official Azure Login action:

Example GitHub Actions Workflow

name: Deploy to Azure

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

permissions:
  id-token: write  # Required for OIDC token generation

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Azure Login
        uses: Azure/login@v1
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          allow-no-subscriptions: true
            OR
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Deploy Application
        run: |
          # Your deployment commands here
          az deployment group create \
            --resource-group my-rg \
            --template-file template.bicep

Storing Application Details in GitHub Secrets

After your App Registration is created, you’ll need to store three values as GitHub repository secrets:

  1. AZURE_CLIENT_ID - The Application ID of the App Registration (found in Azure portal under App registrations)
  2. AZURE_TENANT_ID - Your Azure Tenant ID
  3. allow-no-subscription: true - Simply allows a workflow to authenticate to Azure without picking a subscription, this is helps when making multiple environment deployments OR
  4. AZURE_SUBSCRIPTION_ID - Supply the ID of the subscription to limit the access to only that subscription

To add these secrets: 1. Go to your GitHub repository 2. Settings → Secrets and variables → Actions 3. Click “New repository secret” 4. Add each secret with its corresponding value

Modifying an Existing App Registration

Adding More Subjects

If you need to add more repository contexts to an existing App Registration:

  1. Edit app-registrations.yaml
  2. Add new subject lines under the subjects: section
  3. Important: Ensure the total number of subjects does not exceed 20
  4. Commit and push changes

Changing Permissions

To modify the roles or scopes:

  1. Edit the permissions: section in app-registrations.yaml
  2. Add or remove roles and scopes as needed
  3. Ensure changes follow the principle of least privilege
  4. Commit and push changes

When to Create a New App Registration

If your existing App Registration: - Already has 20 subjects and you need to add more - Has overly broad permissions that should be separated - Serves a different purpose or team

Then create a new App Registration following the “Adding a New App Registration” steps above. Use a naming convention like -1, -2, etc. for related registrations.

Troubleshooting

“Authentication failed in Azure Login action”

Cause: The GitHub Actions workflow doesn’t have the id-token: write permission

Solution: Add permissions: { id-token: write } to your workflow

“Insufficient permissions to perform action”

Cause: The role assigned to your App Registration doesn’t have the required permissions

Solution: 1. Verify the role name is correct in app-registrations.yaml 2. Check that the scope includes the resource you’re trying to access 3. Submit a PR to add the required role/scope

“Subject not found in App Registration”

Cause: The subject in your GitHub Actions workflow context doesn’t match any configured subject

Solution: 1. Verify the subject format matches one of your configured subjects 2. Check branch names, environment names, etc. are correct 3. Add the missing subject to app-registrations.yaml

“Cannot add more subjects - limit reached”

Cause: The App Registration already has 20 federated credentials

Solution: Create a new App Registration and update your workflow to use it instead

Common Use Cases

CI/CD Pipeline to Deploy to Development

- name: Dev Deployment App
  subjects:
    - 'repo:hmcts/my-app:ref:refs/heads/develop'
    - 'repo:hmcts/my-app:pull_request'
  permissions:
    - role_definition_name: Contributor
      scopes:
        - /subscriptions/dev-sub-id/resourceGroups/dev-rg

Multi-Environment Deployments

- name: Multi-Env Deployer
  subjects:
    - 'repo:hmcts/my-app:environment:development'
    - 'repo:hmcts/my-app:environment:staging'
    - 'repo:hmcts/my-app:environment:production'
  permissions:
    - role_definition_name: Contributor
      scopes:
        - /subscriptions/dev-sub-id/resourceGroups/dev-rg
        - /subscriptions/staging-sub-id/resourceGroups/staging-rg
        - /subscriptions/prod-sub-id/resourceGroups/prod-rg

Monitoring/Reporting Across Multiple Subscriptions

- name: Monitoring Reporter
  subjects:
    - 'repo:hmcts/monitoring-dashboard:ref:refs/heads/main'
  permissions:
    - role_definition_name: Reader
      scopes:
        - /providers/Microsoft.Management/managementGroups/Organization-Root

Best Practices

  1. Principle of Least Privilege: Only grant the minimum permissions needed

    • Use Reader instead of Contributor if you only need to read resources
    • Assign scopes to specific resource groups, not entire subscriptions
  2. Use Specific Subjects: Be precise with subject patterns

    • Don’t use broad patterns that could match unintended contexts
    • Separate production and non-production with different App Registrations
  3. Naming Convention: Use clear, descriptive names

    • Include the repository or service name
    • Indicate the purpose (e.g., “Deployer”, “Reader”, “Auditor”)
    • For multiple related registrations, use numeric suffixes (-1, -2, etc.)
  4. Documentation: Add comments to complex configurations

    • Document why specific permissions are needed
    • Note any special requirements or constraints
  5. Regular Reviews: Periodically review your App Registrations

    • Remove unused subjects and permissions
    • Update documentation if requirements change

Getting Help

If you encounter issues: 1. Check the Troubleshooting section above 2. Review your configuration against the examples 3. Contact the platform team in Slack (#cloud-native-platform) 4. Open an issue in the azure-github-federation-config repository

This page was last reviewed on 23 January 2026. It needs to be reviewed again on 23 July 2026 by the page owner platops-build-notices .
This page was set to be reviewed before 23 July 2026 by the page owner platops-build-notices. This might mean the content is out of date.