
Our CI/CD Journey: From Frustration to Contribution
In our quest to implement CI/CD operations for our Booker project, we aimed to integrate GitHub Actions with Azure Key Vault. It wasn’t a walk in the park. The official documentation lacked a comprehensive, end-to-end use case, leaving us piecing together information from various sources.
Recognizing this gap, I decided to give back to the community, contributing with a pull request to the Azure documentation to help others navigate this integration more smoothly. You can check out this contribution here: Azure Dev Docs PR #1434.In the process, we also discovered several insightful blogs that guided us:
- Set up CI/CD With Azure and GitHub Under 10 Minutes
- Continuous Integration and Continuous Deployment (CI/CD) in Azure with GitHub Actions
- How to build a CI/CD pipeline with GitHub Actions in four simple steps
These resources were invaluable in bridging the documentation gaps and providing practical insights.
Stop Stuffing Secrets in Your GitHub Mattress – Azure Key Vault is Here!
Let’s get real: keeping sensitive stuff (API keys, passwords, detailed info about your newest office crush) in your code is like hiding your house keys under the welcome mat; someone eventually looks there, and it’s never good news. GitHub Actions workflows littered with credentials? It’s practically begging for trouble.
Azure Key Vault is your digital Fort Knox. Integrating it with GitHub Actions is like hiring a tiny, overly paranoid robot assistant who hands over secrets strictly on a need-to-know basis. Here’s why you should care:
- Security: Secrets stay locked up tight, not sprinkled like candy in your code.
- Zero Fuss: Automation fetches your secrets neatly, eliminating errors and downtime during manual secret rotation
- Compliance Heaven: Audit trails and granular access controls make security auditors smile.
How GitHub Actions Gets Its Hands on Your Secrets
You’ve got two paths:
1. OpenID Connect (OIDC): Password-Free Magic
- What It Is: Think of it as your workflow flashing a temporary VIP pass. GitHub Actions authenticates with Azure without long-lived passwords.
- Why It’s Awesome: No permanent credentials. Less risk, more security. No password rotations.
- Catch: Short-lived (around 1 hour), particular permissions are needed, so there are no wildcard shortcuts; you can use them only with explicitly pointed branches and exclusively for GitHub Actions.
2. Service Principal & Client Secret: The Old-School Method
- What It Is: A dedicated Azure identity with a password stored securely in GitHub Secrets.
- Why It’s Meh: It works, sure, but you’re stuck regularly rotating passwords. It’s the digital equivalent of frequently replacing your doormat- annoying, risky, and may deter your guest from stepping in.
Plugging Security Holes
- Least Privilege or Bust: Grant only the bare minimum access required. Your bot shouldn’t get keys to the entire house when it just needs the cookie jar.
- Tighten OIDC Scope: Be hyper-specific about which workflows or branches get access.
- Network Firewall Rules: Don’t leave the Key Vault wide open. Limit access to GitHub Actions’ known IP addresses.
- Mask Your Secrets: When fetching secrets, use echo “::add-mask::$SECRET_VALUE” to avoid shouting them to the logs.
- GitHub Environment Protection: Force manual approval for workflows touching sensitive environments like production. Think club bouncer, but nerdier.
- Audit Properly: Check Azure Key Vault logs. You’ll know exactly who’s been digging around in there.
Implementation ( OIDC )
Step 1: Configure Federated Identity
- Sign in to Azure:
az login - Set your subscription:
az account set --subscription <SUBSCRIPTION_ID> - Create a Service Principal:
Ensure you have the necessary permissions in Azure AD.
Replace with the desired Application (client) ID for your new or existing Service Principal.
Note: The original command assumes an existing Azure AD Application registration. If creating a new one, useaz ad app createfirst.az ad sp create --id - Create a Federated Credential:
This links the Service Principal to your GitHub repository branch.
Adjust ref:refs/heads/main if using a different branch or tag.az ad app federated-credential create --id --parameters '{
"name": "github-oidc",
"issuer": "https://token.actions.githubusercontent.com",
"subject": "repo:/:ref:refs/heads/main",
"audiences": ["api://AzureADTokenExchange"]
}' - Grant Key Vault Access:
Assign permissions for the Service Principal to access secrets in your KeyVault.
The ‘get’ and ‘list’ permissions are typically sufficient.az keyvault set-policy --name --spn --secret-permissions get list
Step 2. Workflow
name: Securely Access Azure Key Vault Secret
on:
push:
branches: [ main ] # Define specific branches/triggers
# Required permissions for OIDC authentication
permissions:
id-token: write # Allows workflow to request OIDC token
contents: read # Standard permission for checkout
jobs:
retrieve-secret:
runs-on: ubuntu-latest
# Optionally specify environment for protection rules:
# environment: production
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to Azure
uses: azure/login@v1
with:
# Credentials stored as GitHub Actions Secrets
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
# Omit 'client-secret' for OIDC authentication
# Include for Service Principal:
# client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
- name: Retrieve Secret from Azure Key Vault
id: keyvault_secret
uses: azure/CLI@v1
with:
inlineScript: |
# Replace <SECRET_NAME> with the target secret
SECRET_VALUE=$(az keyvault secret show --name <SECRET_NAME> --vault-name
${{ secrets.KEYVAULT_NAME }} --query value -o tsv)
echo "Masking retrieved secret..."
# Mask secret value in logs
echo "::add-mask::$SECRET_VALUE"
# Export secret for subsequent steps
echo "SECRET_VALUE=$SECRET_VALUE" >> $GITHUB_ENV
- name: Utilize Retrieved Secret
run: |
echo "Secret retrieved. Proceeding with secured operation."
# Example usage:
# ./configure_application --api-key "${{ env.SECRET_VALUE }}"
Just don’t forget…
to set your secrets (AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID, and KEYVAULT_NAME) in Settings > Secrets and Variables > Actions.





