Azure Deployment Using GitHub Actions Reusable Workflows From Central Repo With OIDC
OpenID Connect ( OIDC ) allows your GitHub actions workflows to exchange short-lived tokens from cloud providers. This method is quite secure compared to traditional secrets and keys. This is becoming the preferred way of deploying to the cloud from a CI/CD system.
Platform/DevOps teams want to have more secure and granular controls on deployments. They want to enforce consistent deployments across your repository, organization, or enterprise. Using reusable workflows with OIDC provides them this control and trusted way of allowing application teams to deploy using GitHub actions.
In this blog, I will showcase how GitHub actions reusable workflows can be used from a central repository using OIDC to do azure deployments. There are multiple ways to achieve this however I will focus on only one of the ways.
Target State
- We would like to have a central repository containing our deployment reusable workflow. This workflow should contain the OIDC login mechanism and deployment-specific steps.
- Azure should have OIDC trust only with the reusable workflow in this central repository.
- Application teams should be able to call these deployment steps within their workflow and not worry about managing any OIDC trust.
- Application teams cannot use any other reusable deployment workflow.
Execution
1.) Create Central Repository
- Let's start by creating a repo that will act as the central repository and will contain deployment reusable workflows. For this example, I will name it “central-oidc-workflow”.
- Add actions workflow file containing download artifacts step, azure login, and deploy step.
- In the above workflow file, we are expecting the azure web app name and path to be passed from the calling workflow. We require web app name to download the artifacts in the first step and once we have logged to azure in the second step, we use the name and artifacts path to deploy.
- Azure login step requires the client id, tenant id, and subscription id of the service principal with which we will build the OIDC trust.
2.) Create OIDC Trust
- On Azure, we need to configure OIDC settings on the service principal that we plan to use for deployments. We will configure this service principal to build the OIDC trust with only above created reusable workflow in the central oidc repository.
Goto to azure active directory > app registration > your_service_principal_name > certificates & secrets > federated credentials > add credentials
You will be presented with a form to add OIDC related information.
a. In Federated credential scenario , choose > Other issuer
b. For Issuer we use : https://token.actions.githubusercontent.com
c. Subject identifier is the main section here where we need to fill in customize information. Use “job_workflow_ref:<reusableWorkflowPath>” as subject identifier. By default, Github JWT token doesn't have job_worflow_ref as token claim. We need to configure custom token claims on GitHub side. We will do this in next step.
Syntax for “job_workflow_ref:<reusableWorkflowPath>”
job_workflow_ref:ORG_NAME/REPO_NAME/.github/workflows/WORKFLOW_FILE@ref
d. Save the settings on service principal. Make sure this service principal has proper roles and permission on azure resources for deployment.
3.) Create An Application Repository
- Now that we have OIDC trust established with our central reusable workflow repo, let’s go and create a node application repo and add simple node js code.
- Below is the actions workflow file that builds the app, uploads the artifact so that they can be downloaded before deployment, and calls the reusable workflow in the last section
4.) Configuring And Customizing GitHub Token Claims
- For the security hardening of our deployments, we should customize the standard claims to suit our access conditions. We want deployments only from our central reusable workflow. If it’s called from another reusable workflow repository, the job should fail.
- On our Azure service principal we provided a specific condition in the subject identifier :
job_workflow_ref:ORG_NAME/REPO_NAME/.github/workflows/WORKFLOW_FILE@ref
- To configure the matching condition on GitHub, you can use the REST API to require that the
sub
claim must always include job_workflow_ref
5.) Customize Subject Claim On GitHub Organization
- As both our repositories ( central reusable workflow repo and application repo ) are in the same organization, we only need to apply this configuration to our single organization.
- To apply this configuration, submit a request to the API endpoint and include the required configuration in the request body
{
"include_claim_keys": [
"job_workflow_ref"
]
}
- Using Curl
Now our GitHub Org is ready to support the custom claims for reusable workflows with job_workflow_ref as one of the claims in the token.
Note: When the organization template is applied, it will not affect any existing repositories that already use OIDC. For existing repositories, as well as any new repositories that are created after the template has been applied, the repository owner will need to opt-in to receive this configuration.
6. Set Opt-In Flag For Customization Subject Claim For Repository
- For repositories, the custom subject calm is not part of the default settings. In order to use the subject custom claim that we configured on the org level in the previous step, We need to change the use_default flag to false.
- The opt-in flag needs to be set on the calling workflow repo.
- Set the opt-in flag on the application repo.
- This gives you more granular control on repositories that can use these custom claims and deploy using the central reusable workflow.
7. Test The Deployment
- Finally, all the configuration and customization are completed, and time to run the action from the application repository. Before you do that, please make sure that the calling workflow has adequate permission to call the reusable workflow in the central repository.
- The deployment was successful for me and hope it worked for you as well :).
8. Calling Reusable Workflow From Another Repo
- Our Deployment was successful when the workflow in the application repository calls the reusable workflow from the central oidc reusable workflow repository.
- One of the target state conditions that we mentioned at the beginning of this blog was
Application teams cannot use any other reusable deployment workflow.
- Let’s test this out to make sure that the OIDC trust that we established only provides access to the central repository workflow.
- Create a new repository and copy-paste the workflow from the central repository into this new repo. In the application repository, update the action workflow file to call reusable workflow from this new repository instead of the trusted central oidc repository.
- So the last section in the updated workflow file will look like this
- Run the action again and see your deployment fail with the following error message:
call-azure-login-workflow / azure-deploy
: AADSTS70021: No matching federated identity record found for presented assertion. Assertion Issuer: ‘https://token.actions.githubusercontent.com'. Assertion Subject: ‘job_workflow_ref:tjsingh-org/random-workflows/.github/workflows/azure-node-deploy.yml@refs/heads/main’. Assertion Audience: ‘api://AzureADTokenExchange’. https://docs.microsoft.com/en-us/azure/active-directory/develop/workload-identity-federation
Summary
- Using GitHub actions reusable workflows functionality with OIDC configuration is a secure way of making deployments to your cloud landscape. Rather than copying and pasting deployment jobs from one workflow to another, you can create a reusable workflow that performs the deployment steps and place it in a central repository.
- If you would like to read more about security hardening your deployments, using OIDC with reusable workflows, or how to set up different custom claims on GitHub, please go through the below-mentioned links for GitHub docs
- Security hardening your deployments
- Using OpenID Connect with reusable workflows
- Customizing the token claims
About Me
My Name is Tajinder Singh, most of my friends and colleagues call me TJ. Currently, I am working at GitHub as a Solutions Engineer based in the beautiful city of Zurich, Switzerland. If you have any feedback regarding this blog or GitHub actions, you can reach out to me via LinkedIn or the comments section
Linkedin Profile: https://www.linkedin.com/in/tajinder-singh-74740115b/
Note: Opinions are my own and not the views of my employer