freundcloud

GitHub Actions

Automate your Azure infrastructure deployments using Bicep and GitHub Actions. This guide covers modern DevOps/SRE best practices, secure authentication, and real-world workflow examples.


Why Use GitHub Actions with Bicep?

  • CI/CD Automation: Trigger deployments on code changes, PRs, or schedules
  • Security: Use OIDC for passwordless authentication
  • Multi-Environment: Deploy to dev, test, and prod with parameter files
  • Observability: Integrate deployment status and logs into PRs

Prerequisites

  • Azure subscription
  • GitHub repository
  • Bicep files in your repo (e.g., bicep/main.bicep)
  • Service principal or OIDC setup for authentication

Initial Setup

1. Create a Resource Group

az group create -n exampleRG -l westus

2. Configure Authentication

Option A: Service Principal (legacy, less secure)

az ad sp create-for-rbac --name "GitHubActionsSP" --role contributor \
  --scopes /subscriptions/{subscription-id}/resourceGroups/exampleRG \
  --sdk-auth

Store the output as the AZURE_CREDENTIALS secret in GitHub.

  • Use federated credentials for passwordless, short-lived tokens. See Microsoft Docs for setup.

Example: Basic Bicep Deployment Workflow

name: Deploy Bicep Template
on:
  push:
    branches: [ main ]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Azure Login
      uses: azure/login@v1
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}
    - name: Deploy Bicep
      uses: azure/arm-deploy@v1
      with:
        subscriptionId: ${{ secrets.AZURE_SUBSCRIPTION }}
        resourceGroupName: ${{ secrets.AZURE_RG }}
        template: ./bicep/main.bicep
        parameters: ./bicep/parameters/dev.parameters.json

Example: Multi-Environment Deployment

name: Multi-Env Bicep Deploy
on:
  push:
    branches: [ develop, main ]
jobs:
  deploy-dev:
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest
    environment: development
    steps:
      - uses: actions/checkout@v3
      - uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}
      - name: Deploy to Dev
        uses: azure/arm-deploy@v1
        with:
          subscriptionId: ${{ secrets.AZURE_SUBSCRIPTION }}
          resourceGroupName: ${{ secrets.DEV_RESOURCE_GROUP }}
          template: ./bicep/main.bicep
          parameters: ./bicep/parameters/dev.parameters.json
  deploy-prod:
    if: github.ref == 'refs/heads/main'
    needs: deploy-dev
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v3
      - uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}
      - name: Deploy to Prod
        uses: azure/arm-deploy@v1
        with:
          subscriptionId: ${{ secrets.AZURE_SUBSCRIPTION }}
          resourceGroupName: ${{ secrets.PROD_RESOURCE_GROUP }}
          template: ./bicep/main.bicep
          parameters: ./bicep/parameters/prod.parameters.json

Example: Preview Changes with What-If

- name: Preview Changes (What-If)
  uses: azure/arm-deploy@v1
  with:
    subscriptionId: ${{ secrets.AZURE_SUBSCRIPTION }}
    resourceGroupName: ${{ secrets.AZURE_RG }}
    template: ./bicep/main.bicep
    parameters: ./bicep/parameters.json
    deploymentMode: Validate
    additionalArguments: --what-if

Security Best Practices

  • Use OIDC for authentication (no secrets in repo)
  • Assign least-privilege roles to service principals
  • Mark sensitive parameters with @secure() in Bicep
  • Store secrets in GitHub Secrets, not in code

Monitoring & Troubleshooting

  • Add deployment status comments to PRs using actions/github-script
  • Upload deployment logs as artifacts for traceability
  • Use az deployment group show to fetch outputs after deployment

Bicep & Azure Jokes

Bicep Joke: Why did the pipeline use Bicep? To flex on ARM templates!

Azure Joke: Why did the engineer love Azure deployments? Because they always had a resourceful day!


References