Skip to content
CAMPUX Cloud Bootcamp Phase Four · Class Thirty-Nine
Phase Four — Operate, Secure & AI
4 drills · 2 situations · Part IX of IX
Class Thirty-Nine · Pipelines
Class Thirty-Nine · Part IX

The most powerful credential in the building

The machine that can deploy to production holds more power than almost any human in the org; securing it — so it proves who it is instead of carrying a password anyone could steal — is the highest-return work a cloud engineer does, and it is where this whole track's case file finally rests.

Phase Four · Operate, Secure, AI · Class 39 · Part I · 17 min · Assumes Class 39 Part B, Class 8, Class 9 and Class 23

After this you can restrict a GitHub OIDC trust and its Azure role scope, and keep credentials out of workflow logs.

New to this? Read Class 39 Part B, Class 8, Class 9 and Class 23 first. Already done them, or know the material? Carry on.

§1

The pipeline outranks almost everyone in the org

Make an honest list of who could push a change to production tonight, and the machine you spent this track building sits near the top of it — above most of the people, and awake at hours none of them are. A pipeline that can deploy to production can, by definition, replace what customers see, read whatever the deploy touches, and do it in seconds, unsupervised, from a trigger anyone with commit rights can pull. That is not a flaw to be patched out; it is the job you gave it. But it means the permission set the workflow can request is the most valuable thing in the building, and an attacker who reaches it does not need to breach your firewall, your VPN, or a single production server — they need only your pipeline, because your pipeline already has the keys and permission to use them.

So the last thing this bootcamp teaches you to secure is the thing you built to be powerful. Everything in the eight parts before this made the pipeline more capable — it runs unattended, it holds credentials, it reaches production. This part asks the question that capability forces: what happens the day someone who is not you gets to press the button? The answer is not a product you buy. It is a handful of decisions — how the pipeline proves who it is, how narrowly it is allowed to act, what it holds and what it must never hold — and each one is worth more, in prevented incident, than any feature you shipped to get here.

The best secret is the one that does not exist.

§2

OIDC: how a workflow proves its identity to Azure

GitHub Actions can request a short-lived identity token when a job has id-token: write. Azure trusts that token only when an Entra federated credential matches the expected repository, branch, tag, or GitHub environment. The azure/login action exchanges the token for Azure access. Configure the Entra app or managed identity and federated credential in Azure, then give the workflow the client, tenant, and subscription identifiers it needs.

Federated credential
An Entra trust rule that accepts a token only when its GitHub issuer and subject match configured values. Azure RBAC separately controls what the resulting identity can do.

A client secret is a reusable password. If stored in a repository or workflow setting, it can be copied or leaked and must be rotated. OIDC replaces that reusable credential with a short-lived token tied to a specific workflow identity.

OIDC does not make the workflow harmless. A compromised action or unsafe pull-request workflow may still be able to misuse any permissions it receives. Keep id-token: write on the deploy job only, restrict the federated subject, protect the production environment, and scope Azure RBAC to the smallest practical resource.

Verify on Microsoft Learn

Use the Azure Login action documentation for GitHub OIDC setup:
github.com/Azure/login — OpenID Connect

§3

Least privilege — a narrow door, and a lock on who may open it

Removing the long-lived secret answers how the workflow proves itself. It says nothing about how much that identity may do after authentication; Azure RBAC is a separate control. An identity with Contributor on the whole subscription is a keyless car that can still drive anywhere. A compromised action, unsafe pull-request workflow, or mistaken YAML change could use every permission granted to that identity. OIDC removes a reusable password; it does not make a powerful identity harmless.

The fix is the same lesson Class Eight taught about RBAC, applied here without flinching. Scope the Azure role assignment to the smallest practical resource, such as the warehouse resource group, and use separate identities when staging and production need different access. Also narrow GitHub permissions: set contents: read by default and grant id-token: write only to the job that logs in to Azure. Configure the Entra federated subject to match the intended repository and protected environment. These controls answer different questions: GitHub decides which workflow may request a token, Entra decides whether to trust that token, and Azure RBAC decides what the identity may change.

Fig. 1 · The pipeline authenticates, then acts — and both are held narrow
A GitHub Actions job requests an OIDC token; Entra trusts a matching federated credential, and Azure RBAC grants only the selected resource-group access. pipeline runreferences by name Entra app identityno stored secret Entra ID resource groupRBAC scope federated token exchange, per run no stored secret · one resource group · a protected environment for production
Two independent controls, drawn together. The token exchange (red loop) removes the stored secret; the resource-group scope (lower right) removes the blast radius. Neither substitutes for the other — a perfectly federated identity scoped to the whole subscription still hands too much power to any pipeline that references it.
Checkpoint · read the trust and the scope

Who can sign in, and what can they change?

Federated credential subject:  repo:campux/warehouse:environment:production
Role assignment:               Contributor  on  /subscriptions/…/resourceGroups/rg-warehouse-prod
  1. Which workflow runs can sign in as this identity?

  2. What can they change once signed in?

  3. A pull request from a fork runs the same workflow file. Can it sign in?

Check your answers

1: only jobs in campux/warehouse that target the production environment. 2: anything in that one resource group, nothing outside it. 3: no; its token names a different repository or no production environment, so the subject does not match. If you can answer these three for every pipeline identity you own, you are ready for §4.

Play

Play it through

Four minutes, two things to narrow. Watch a merged pull request reach the whole subscription through a Azure role nobody scoped down, then drag that scope onto the one resource group it deploys — and give staging a door of its own. It plays on its own and stops when it needs your hands.

Do it for real. The lab for this class is on its own page: GitHub OIDC deployment identity with least privilege. Workload identity federation with no secret, scoped to one resource group, and the authorization failure that proves it cannot reach a second. About thirty minutes.

§4

Secrets, and the supply chain the pipeline pulls from

Some applications still need passwords or API keys. Store those in GitHub secrets at the narrowest available scope or retrieve them from Azure Key Vault after OIDC login. Never put a secret in YAML or print it in logs. Forked pull requests should not receive deployment credentials. Protect dependencies too: review third-party actions, pin them to reviewed full commit SHAs where practical, and grant the workflow token only the permissions each job needs.

The other exposure is everything your pipeline pulls in to run. A pipeline is a supply chain: it executes actions, and those actions execute code you did not write. Pin task versions rather than floating on @latest, so a task cannot change under you between runs; treat a third-party Marketplace action with the same caution Class Twenty-Two taught for third-party Actions, because installing one grants it the run's context and whatever your identity can reach. Put production behind protected resources — environments, GitHub OIDC trust rules, and GitHub secrets carry approvals and checks that a pull-request build from a fork cannot satisfy — and use repository rulesets and protected environments to require the security checks before deployment. Reusable workflows help centralise logic but do not force every caller to use them.

Table 1 — Five controls, what each protects, and the failure if you skip it
ControlWhat it protectsThe failure if you skip it
Workload identity federationThe pipeline's identity to AzureA stored secret expires on a Sunday and breaks every pipeline; or is stolen and reused off-platform
Resource-group RBAC scopeThe blast radius once insideOne compromised pipeline acts across the entire subscription instead of one resource group
Federated subject and environment rulesWhich GitHub run may request production accessA loosely matched trust subject accepts tokens from unintended refs or environments
Key Vault access at run timeApplication secretsA broad identity or printed value exposes credentials beyond the job that needs them
Pinned actions & required checksThird-party code and merge requirementsAn unreviewed action runs with more token access than it needs, or an untested change merges
Case File · Campux Retail

Where warehouse-deploy-identity finally dies

One broad Azure role, many workflows, and a trust rule that needed review

Basecamp's deployment used a shared long-lived credential with broader Azure access than the warehouse needed. Replace it with a federated identity whose Entra subject matches the intended GitHub repository and protected environment. Scope Azure RBAC to the warehouse resource group, require review before the production environment can run, verify the deployment, then revoke the old credential after confirming it is no longer used.

The workflow now requests a short-lived token only from the intended GitHub context, Entra trusts only the configured federated subject, and Azure grants the identity only the resource-group permissions required to deploy. GitHub environment protection adds a human review before production. The old client secret is revoked after the deployment has been verified. Federation removes the recurring client-secret rotation task; the team still reviews RBAC, trust subjects, and workflow permissions as the repository changes.

On the job

The audit nobody asked for, that everybody remembers

You · Cloud Engineer · week one on an inherited estate

Start by listing which workflows can request production tokens, which federated subjects Entra trusts, and what Azure roles those identities hold. Remove obsolete long-lived credentials only after checking their usage and verifying replacement deployments. A small, documented trust and permission review gives the team concrete evidence that workflow access matches the work each job performs.

§5

What the pipeline says about you

This is the last teaching page of the bootcamp, and it ends where the first one started: on the line between what the provider secures and what you do. Azure will keep the token service running, rotate its own keys, and honour the RBAC you assign. It will not decide for you whether the identity is federated or secret-bearing, whether it is scoped to a resource group or a subscription, whether a password is in your YAML, or whether a stranger's Marketplace action runs with your production access. Those are the half of the model the provider will never take — and, this one last time, the half you are paid to hold.

An interviewer can inspect the workflow: permissions are limited to the job that needs them, the Entra trust subject is specific, Azure RBAC is scoped narrowly, production requires the configured environment protections, and third-party actions are reviewed and pinned appropriately. Those choices make the system easier to audit and reduce the damage a compromised run could cause.

Class 39i

Examination

Four drills, then two situations. The situations have no marking scheme — write your answer before you reveal the reasoning, or the exercise is worthless. Nothing is stored.

Drill 01Recall
Why is a GitHub Actions workflow that uses OIDC federation safer than one that uses an Entra app registration that stores a client secret?
Marked

B — the safety is the absence of the secret, not a better place to keep one. Federation holds only a trust; each run mints a short-lived token, exchanges it with Entra, and gets minutes of access, so nothing durable exists to be stolen or to lapse. C is the trap that feels responsible — encrypting a stored secret still leaves a standing credential that expires on a Sunday and can be reused if exfiltrated; the whole point of federation is that there is no such object. D describes a real and important control, but a different one: scope is about how much the identity may do (§3), not how it proves itself, and federation does not set scope for you. Microsoft states it plainly — workload identity federation "eliminates the need for secrets and secret management."

Drill 02Recall
A GitHub Actions workflow uses OIDC, but its Entra identity has Contributor on the whole subscription. What is the remaining risk?
Marked

B — authentication and blast radius are two separate controls, and only one has been fixed. Removing the secret means no durable credential can be stolen; it does nothing to limit what the credential may do once presented. An identity with subscription-wide access is a keyless car that can still drive anywhere — a compromised task, a malicious fork build, or a fat-fingered YAML change now reaches every resource group at once. A is the dangerous half-truth this drill exists to break: "no secret" is necessary, not sufficient. C invents a token-lifetime failure that GitHub Actions handles internally, and D fabricates a link between scope and masking. Limit the Azure role to the resource group it deploys, give each environment its own — the door stays narrow even after the lock is gone.

Drill 03Select three
Which three of these actually reduce the pipeline's attack surface, as this part defines it?
Marked

Narrow scope, secrets in the vault, pinned actions with per-pipeline authorization. Each shrinks what a compromised run can reach or reveal — the blast radius, the secret at rest, and the code the pipeline pulls in. The two rejects are the two most common self-inflicted wounds. Putting a secret in the YAML "because logs are masked" confuses two different exposures: masking hides a value in the run output, but the YAML itself is in the repo, readable by everyone who can clone it and permanent even after you delete the line — the secret was public the moment you committed it. And granting the identity to all pipelines to save a moment's friction is exactly how a malicious fork build or a forgotten test pipeline inherits production access; matching the federated subject and protecting production keeps the door narrow.

Drill 04Spot the error
An engineer writes the migration plan for Basecamp's warehouse-deploy-identity identity. One step defeats the entire point of the migration. Which?
# plan: retire the shared warehouse-deploy-identity identity
1.  Split warehouse-deploy-identity into a separate federated credential or identity for each environment when the access needs differ,
    each scoped to a single resource group.
2.  For each new identity, generate a strong client
    secret and store it in the identity; add a calendar
    reminder to rotate every secret once a year.
3.  Authorise each pipeline to its own identity
    individually; stop granting access to all pipelines.
4.  Retrieve the application secret from Azure Key Vault
    after OIDC login; never print it in the workflow.
Marked

Line two — and the tell is that it works hard to do the wrong thing. Generating a strong secret and diligently rotating it yearly feels like security theatre done well, but it rebuilds exactly the object the whole migration exists to delete: a stored, long-lived credential that will still expire on a bad morning and can still be exfiltrated and replayed. A yearly rotation only narrows the window; federation removes the window, because there is no secret — the Entra federated credential defines the trust and mints a short-lived token per run. The correct line two is "convert each identity to workload identity federation; there is no secret to store." The other steps are right: separate narrowly scoped identities are preferable when environments need different access (A is wrong), minimum required job and Azure permissions are the point, not friction (C), and the Key Vault value should be retrieved after OIDC login and never printed (D is sound). Rotating a secret you should not have is motion mistaken for progress.

Situation 01Write before you reveal
A colleague, unblocking a stuck release, proposes: "Just give the shared warehouse-deploy-identity identity Owner on the subscription and grant it to all pipelines — then nothing is ever blocked again." It would genuinely fix today's friction. What do you say?
The proposal buys convenience with blast radius. Concede the real problem it solves, then price what it actually costs — and offer the version that solves the friction without widening the door.
Reasoning

A strong answer concedes before it argues. The friction is real and worth naming out loud: waiting on authorization and narrow scope does slow a release, and a colleague fighting a stuck deploy at the wrong hour deserves agreement that the pain is legitimate. Refuse the framing and you lose the room; concede it and you earn the right to redirect.

Then price what the shortcut actually buys. Owner-on-the-subscription, granted to all pipelines, turns the most powerful credential in the building into a master key that every pipeline in the org — including a malicious pull-request build from a fork and every forgotten test pipeline — now holds. The day one of those is compromised, the incident is not "a release was slow," it is "an attacker had Owner on the whole subscription through our CI." You are trading a recurring five-minute wait for a standing, subscription-wide breach path. That is not a trade a team that trusts you with production would make, and saying so plainly is the job.

Close with the version that solves the friction the right way. The stuck release is almost never fixed by more power; it is fixed by the correct narrow one. Give the workflow a narrowly matched federated credential, scope Azure RBAC to the needed resource group, and protect production with environment reviewers. It unblocks today's release and shrinks the door instead of widening it — and it gives you the sentence that ends the debate: we don't fix a slow deploy by making a breach bigger.

Situation 02Write before you reveal
Final interview. "Walk me through the GitHub Actions workflow you built. How does a change get from a pull request to a safe Azure deployment?" You have ninety seconds. What do you say?
Use evidence from your own run: trigger, checked artifact, approval where configured, OIDC trust and Azure role scope. Say which steps you have actually completed.
Reasoning

Start with the change. “A pull request runs the checks. The build creates an artifact, and the release uses the artifact that passed rather than rebuilding it.” Name a failure you observed and the job it prevented.

Explain the two identity checks. “GitHub requests an OIDC token. Entra checks its issuer, audience and repository or environment subject against the federated credential. The Azure identity’s role assignment then limits deployment operations and scope.” Environment approval and workflow review protect who can request that access.

Finish with evidence and recovery. Describe the run and deployment you actually made, the validation signal and rollback plan. If you completed only the artifact rehearsal, say so; a green training workflow is not evidence of a production deployment.

Close by showing the reviewable evidence: "I can show the workflow, the run history, its required checks, and the Azure permissions it uses." That reframes the perceived gap into the rarest thing on the market — and it is true, which is why it survives the follow-up. The reviewer can verify those choices in the workflow and its run records.

Examination record · first attempt
0/4
Class 39i · Complete
Retain this much

Five things worth carrying out of this class

  1. The pipeline is the most powerful credential in the building: it can deploy to production, unattended, in seconds. An attacker who reaches it needs nothing else. Securing it is the highest-return security work a cloud engineer does.
  2. GitHub Actions requests an OIDC token; an Entra federated credential decides whether to trust the repository and ref; Azure RBAC then limits what the identity can do. OIDC avoids storing an Azure client secret.
  3. Removing the secret is not the same as narrowing the door. Scope the identity's Azure RBAC to a resource group, not the subscription; give each environment its own identity; limit token requests to the intended GitHub repository and environment. Identity and blast radius are two separate controls.
  4. Do not put secrets in YAML or logs. Retrieve application secrets from Key Vault after OIDC login, pin reviewed third-party actions where practical, and require the checks that matter through repository rules and protected environments. Reusable workflows share logic but do not enforce it alone.
  5. The best Azure login secret is the one the workflow does not need. Federation removes the reusable client secret; least privilege, specific trust subjects, and protected environments still require ongoing review.
Notes
  1. Microsoft's guidance is current as of this writing: workload identity federation is the recommended authentication for supported GitHub Actions deployments to Azure, and Azure and GitHub document setup steps for OIDC federation; this workflow uses the azure/login action. Class Twenty-Three introduces the token exchange; this lesson applies it to a complete deploy workflow. Verify setup steps in the current Azure and GitHub documentation. ↩
  2. Treat "the logs are masked, so it's fine" as the single most dangerous sentence in this class, and treat any specific claim about what masking catches — including this page's — with suspicion. Masking is best-effort string replacement on emitted log lines; it does not cover values you transform, write to files, or exfiltrate deliberately, and the exact boundaries shift between agent and task versions. The safe rule does not depend on the details: keep the secret in the vault and never emit it, and you never have to know precisely where masking stops. ↩