OpenID Connect
We recommend using OpenId Connect (OIDC) to configure GitHub Actions to authenticate with your Azure environment.
Since OIDC doesn’t require storing any persistent credentials, there is no risk of accidentally exposing a persistent secret that could be used elsewhere to imitate your GitHub Action. This also means that there is no need to manually rotate your secret if it expires.
- Use a separate OIDC connection to authenticate with different environments. If for example your repository is able to deploy to a production environment in CD, and a development environment in CI, there should be no possibility of a developer accidentally making changes to production from a CD run.
- Follow the Principle of least privilege by configuring Azure Role-based access control (RBAC) such that your GitHub Actions have minimal access to your environment.
This script assumes that you have the GitHub CLI (
gh
) and Azure CLI (az
) utilities installed locally and logged in before running.
Run the following commands in a bash shell to configure OIDC for your GitHub repository:
Create an environment through the GitHub UI.
Configure the following bash variables:
# The name of the GitHub environment environment="replaceme" # Your Azure Tenant ID tenantId="replaceme" # Your Azure Subscription ID subId="replaceme" # The name of the GitHub repository owner (organization or username) repoOwner="replaceme" # The name of the GitHub repository repoName="replaceme" # The name of the resource group you will be deploying to rgName="replaceme" # The location of the resource group you will be deploying to rgLocation="replaceme"
Create the resource group:
az account set -n "$subId" az group create \ --location "$rgLocation" \ --name "$rgName"
Create the AAD application for your GitHub Action to authenticate as:
appCreate=$(az ad app create --display-name $rgName) appId=$(echo $appCreate | jq -r '.appId') appOid=$(echo $appCreate | jq -r '.id') spCreate=$(az ad sp create --id $appId) spId=$(echo $spCreate | jq -r '.id') az role assignment create --role owner --assignee-object-id $spId --assignee-principal-type ServicePrincipal --scope /subscriptions/$subId/resourceGroups/$rgName
Configure OIDC:
repoSubject="repo:$repoOwner/$repoName:environment:$environment" az ad app federated-credential create --id $appOid --parameters '{"name":"'$repoName'_'$environment'","issuer":"https://token.actions.githubusercontent.com","subject":"'$repoSubject'","description":"GitHub OIDC Connection","audiences":["api://AzureADTokenExchange"]}'
Configure your GitHub Environment Variables:
gh variable set --repo "$repoOwner/$repoName" --env "$environment" AZURE_CLIENT_ID --body $appId gh variable set --repo "$repoOwner/$repoName" --env "$environment" AZURE_SUBSCRIPTION_ID --body $subId gh variable set --repo "$repoOwner/$repoName" --env "$environment" AZURE_TENANT_ID --body $tenantId gh variable set --repo "$repoOwner/$repoName" --env "$environment" AZURE_RESOURCE_GROUP --body $rgName
NOTE: We recommend using GitHub Environment Variables instead of Secrets, because there is no risk of unauthorized access if they are public, and it can make debugging simpler. Although there is no security risk, if you would like to avoid your Azure
tenantId
orsubscriptionId
being logged, then we recommend instead using Secrets.
The full script is available in the starter repo here.
For each job that needs access to Azure, you will need the following configuration in your Workflow yaml.
Configure the environment you want to access (replace
<your_environment>
with the name of your GitHub environment):environment: name: <your_environment>
Configure job permissions:
permissions: contents: read id-token: write
Add a step to log in to Azure, using the
azure/login@v1
action:- name: AzCLI login uses: azure/login@v1 with: client-id: ${{ vars.AZURE_CLIENT_ID }} tenant-id: ${{ vars.AZURE_TENANT_ID }} subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}