| permalink | /labs/lab-07 |
|---|---|
| title | Lab 07 - GitHub Actions Pipelines and Cost Gates |
| description | Build automated scanning pipelines and PR cost gates with GitHub Actions. |
| Duration | 45 minutes |
| Level | Advanced |
| Prerequisites | Lab 02, Lab 03, Lab 04, Lab 05, Lab 06 |
Tip
Using Azure DevOps? See Lab 07-ADO — ADO YAML Pipelines and Cost Gates for the ADO variant of this lab.
By the end of this lab, you will be able to:
- Build a GitHub Actions workflow with matrix strategy for multi-app scanning
- Configure OIDC authentication for Azure using workload identity federation
- Implement a PR cost gate workflow using Infracost
- Set up cross-repo SARIF upload via the GitHub Code Scanning API
- Trigger, monitor, and debug workflow runs
You will walk through the centralised scanning workflow that runs all 4 tools across all 5 demo apps.
-
Open
.github/workflows/finops-scan.ymland review the overall architecture:finops-scan.yml ├── psrule-scan (matrix: 5 apps) → SARIF artifacts ├── checkov-scan (matrix: 5 apps) → SARIF artifacts ├── custodian-scan (matrix: 5 apps) → SARIF artifacts └── cross-repo-upload (matrix: 5 apps) └── Downloads all SARIF → uploads to each demo app's Security tab -
Review the workflow triggers:
on: schedule: - cron: '0 6 * * 1' # Weekly Monday 06:00 UTC workflow_dispatch:
The workflow runs on a weekly schedule and can be triggered manually.
-
Review the permissions block:
permissions: contents: read security-events: write id-token: write
contents: read— checks out repository codesecurity-events: write— uploads SARIF to Code Scanningid-token: write— requests OIDC tokens for Azure authentication
-
Review the matrix strategy used by each scan job:
strategy: matrix: app: ['001', '002', '003', '004', '005']
This creates 5 parallel jobs — one for each demo app. Each job checks out the corresponding demo app repo and runs the scanner against it.
-
Review the
psrule-scanjob steps:- Checkout scanner repo — gets the PSRule configuration and SARIF converters
- Checkout target app — clones the demo app repo into
target-app/ - Run PSRule — uses the
microsoft/ps-rule@v2.9.0action with theAzure.GA_2024_12baseline - Upload artifact — saves the SARIF file as a build artifact for the cross-repo upload job
-
Review the
custodian-scanjob. Unlike PSRule and Checkov, Cloud Custodian:- Authenticates to Azure using OIDC (
azure/login@v2) - Runs against live resources instead of IaC files
- Uses
continue-on-error: trueto prevent scan failures from blocking the pipeline - Converts JSON output to SARIF using
custodian-to-sarif.py
- Authenticates to Azure using OIDC (
-
Review the
cross-repo-uploadjob (covered in Lab 06, Exercise 6.5). Note how it depends on all three scan jobs and runs even if the custodian scan fails.
Tip
The matrix strategy multiplies the number of jobs: 3 scanners × 5 apps = 15 scan jobs + 5 upload jobs = 20 total jobs. GitHub Actions runs matrix jobs in parallel, so the entire scan completes in the time of the slowest individual job.
You will configure Azure OIDC federation so GitHub Actions can authenticate without storing secrets.
-
Run the OIDC setup script:
./scripts/setup-oidc.ps1
-
The script performs 5 steps:
- App registration — creates or retrieves an Azure AD app named
finops-scanner-github-actions - Federated credentials — creates OIDC credentials for each repo and branch combination
- Service principal — creates or retrieves the service principal for the app
- Role assignment — grants
Readerrole on the subscription - Summary — displays the Client ID, Tenant ID, and Subscription ID to configure as GitHub secrets
- App registration — creates or retrieves an Azure AD app named
-
Review the federated credential subject format:
repo:devopsabcs-engineering/finops-scan-demo-app:ref:refs/heads/main repo:devopsabcs-engineering/finops-demo-app-001:environment:productionEach credential maps a specific GitHub repository + branch (or environment) to the Azure AD app. This is the OIDC subject claim that Azure validates when issuing tokens.
-
After the script completes, add the following secrets to your GitHub repository settings:
AZURE_CLIENT_ID— the app registration's client IDAZURE_TENANT_ID— your Azure AD tenant IDAZURE_SUBSCRIPTION_ID— the target subscription ID
Important
OIDC federation eliminates the need for client secrets or certificates. The GitHub Actions runner requests a short-lived token from GitHub's OIDC provider, and Azure validates it against the federated credential configuration. No long-lived credentials are stored in GitHub Secrets.
You will trigger the scanning workflow manually and monitor its execution.
-
Trigger the workflow using the GitHub CLI:
gh workflow run finops-scan.yml
-
Monitor the workflow run:
gh run watch
This opens an interactive view showing all matrix jobs and their progress.
-
Alternatively, open the repository on GitHub, click Actions, and select the FinOps Scan workflow to watch the run in the browser.
-
The workflow creates 20 jobs in total:
- 5 PSRule scan jobs (one per app)
- 5 Checkov scan jobs (one per app)
- 5 Cloud Custodian scan jobs (one per app)
- 5 cross-repo upload jobs (one per app)
-
Wait for the run to complete. PSRule and Checkov jobs typically finish in 1–2 minutes. Cloud Custodian jobs may take longer because they query live Azure resources.
Note
If Cloud Custodian jobs fail with authentication errors, verify that your OIDC credentials are configured correctly (Exercise 7.2) and that the AZURE_CLIENT_ID, AZURE_TENANT_ID, and AZURE_SUBSCRIPTION_ID secrets are set in the repository settings.
You will inspect the artifacts, SARIF uploads, and Security tab after the workflow completes.
-
List the workflow artifacts:
gh run view --log
-
Download the SARIF artifacts for a specific app:
gh run download -n sarif-psrule-001 gh run download -n sarif-checkov-001 gh run download -n sarif-custodian-001
-
Open the downloaded SARIF files and verify they contain findings.
-
Navigate to each demo app's repository on GitHub and check the Security tab. The cross-repo upload job should have populated Code Scanning alerts from all three scanners.
-
Compare the findings across tools:
- PSRule — tags, naming, region, and Azure best practice violations
- Checkov — security, encryption, and CIS benchmark violations
- Cloud Custodian — runtime resource state (orphans, oversized, idle)
You will create a pull request that changes infrastructure costs and observe the Infracost cost gate in action.
-
Create a new branch:
git checkout -b test/cost-gate-demo
-
Open any demo app's
infra/main.bicepand change a SKU to something more expensive. For example, upgrade app 001's App Service Plan:sku: { name: 'P3v3', tier: 'PremiumV3' }
-
Commit and push the change:
git add . git commit -m "test: upgrade SKU to trigger cost gate" git push -u origin test/cost-gate-demo
-
Create a pull request:
gh pr create --title "test: upgrade SKU to trigger cost gate" --body "Testing Infracost cost gate workflow"
-
Wait for the
FinOps Cost Gateworkflow to run. It:- Generates a cost baseline from the
mainbranch - Runs
infracost diffagainst your PR changes - Posts a cost summary comment on the PR showing the monthly cost impact
- Uploads a SARIF file with cost findings
- Generates a cost baseline from the
-
Review the Infracost comment on the PR. It shows a table with resource-level cost changes and the total monthly impact.
-
Close the PR without merging (this was a test):
gh pr close --delete-branch
Tip
The cost gate workflow uses the --behavior update flag for the Infracost comment. This means each push to the PR branch updates the existing comment rather than creating a new one, keeping the PR conversation clean.
You will trigger the deploy-all and teardown-all workflows to understand the full lifecycle.
-
Trigger the deploy-all workflow:
gh workflow run deploy-all.yml
-
Monitor the deployment:
gh run watch
The deploy-all workflow deploys all 5 demo apps sequentially. Each app deploys its Bicep template to a dedicated resource group (
rg-finops-demo-001throughrg-finops-demo-005). -
After deployment completes, verify the resources in the Azure Portal or via the CLI:
az group list --query "[?starts_with(name, 'rg-finops-demo')].[name, location]" -o table -
Trigger the teardown-all workflow:
gh workflow run teardown-all.yml
-
The teardown workflow requires environment approval. Navigate to the GitHub Actions page and approve the
productionenvironment deployment when prompted. -
After approval, the workflow deletes all 5 resource groups and their contents.
Important
The teardown workflow uses a production environment with required reviewers as a safety gate. This prevents accidental deletion. In production FinOps workflows, always use environment protection rules for destructive operations.
Before completing the workshop, verify:
-
finops-scan.ymlworkflow ran successfully with matrix jobs - SARIF artifacts uploaded to all 5 demo app repos' Security tabs
- Cost gate workflow posted an Infracost comment on a pull request
- Can explain the OIDC federated credential subject claim format
You have completed all 8 labs in the FinOps Cost Governance Scanner Workshop. Here is a summary of what you learned:
| Lab | What You Learned |
|---|---|
| Lab 00 | Set up the development environment with all 4 scanner tools |
| Lab 01 | Identified the 5 demo app FinOps violations and the 7 required governance tags |
| Lab 02 | Ran PSRule against Bicep templates for Azure best practice analysis |
| Lab 03 | Ran Checkov for security and CIS benchmark scanning |
| Lab 04 | Ran Cloud Custodian against live Azure resources for runtime violation detection |
| Lab 05 | Used Infracost to estimate costs and compare infrastructure changes |
| Lab 06 | Understood the SARIF format and uploaded results to the GitHub Security tab |
| Lab 07 | Built automated pipelines with matrix strategy, OIDC auth, and PR cost gates |
You now have the skills to implement a complete FinOps scanning platform that:
- Scans IaC templates before deployment (PSRule, Checkov, Infracost)
- Scans live resources after deployment (Cloud Custodian)
- Produces unified SARIF output for all tools
- Integrates with GitHub Security tab for centralised alert management
- Blocks expensive changes with PR cost gates
- Runs automatically on a schedule and on-demand via GitHub Actions






