Skip to main content
RunBook Academy

Git, CI/CD & GitOpsCVII · Production Infrastructure Delivery ArchitectureIdentity

The identity flow — from engineer to commit to production

Advanced⏱ ~26 mingitaws-cli

What you'll learn

  • Trace the chain of identity from engineer SSH key to namespace ServiceAccount
  • Distinguish an identity establishment point from an identity delegation point
  • Apply OIDC federation to remove long-lived cloud credentials from the CI plane
  • Recognise the failure modes when identity is shared across components

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

Identity in the reference architecture is not a single thing. It is a chain of delegations, each link signed by the link before it. The engineer holds an SSH key; the key authenticates to the forge; the forge records the engineer as the PR author; the PR triggers a workflow whose identity is an OIDC token; the token federates to a cloud role; the role delegates to a Kubernetes ServiceAccount via IRSA; the ServiceAccount’s RBAC defines what the pod can do in the namespace. A break in any link is a shared credential waiting to leak.

The chain

flowchart LR
    A["SSH key\n(engineer)"] -->|"B1"| B["GitHub user identity"]
    B -->|"branch protection"| C["PR approval"]
    C -->|"OIDC token"| D["CI workflow identity"]
    D -->|"OIDC federation"| E["Cloud deploy role\n(IRSA)"]
    E -->|"trust binding"| F["ServiceAccount\n(namespace)"]
    F -->|"RBAC"| G["Pod actions"]

Each arrow is a delegation, not a copy. The engineer’s SSH key is never stored in the cluster; the cluster holds a ServiceAccount token whose identity traces back to the workflow that traces back to the PR that traces back to the engineer.

Establishing vs delegating

The chain has one establishment point and five delegation points:

  • Establishment: SSH key. Engineer generates the key; public half is registered on the forge. Private half never leaves the laptop.
  • Delegation 1: forge user. Forge assigns a user identity bound to the SSH key.
  • Delegation 2: PR approval. Approver’s forge-user identity is recorded on the PR.
  • Delegation 3: OIDC token. Forge issues an OIDC token whose sub is the workflow path.
  • Delegation 4: cloud role. Cloud’s OIDC trust policy maps the token’s sub to an IAM role.
  • Delegation 5: ServiceAccount. IRSA binds the IAM role to the ServiceAccount via an annotation.

Copying the SSH key onto a runner loses the establishment. Sharing an IAM role across workflows loses delegation 4.

How OIDC federation works

The CI provider issues an OIDC token per workflow run. The iss claim is the provider; the sub claim is the workflow path. The cloud’s trust policy asserts iss and constrains sub to a specific repo, branch, or workflow file.

ROLE_ARN=arn:aws:iam::123456789012:role/deploy-prod
SERVICE_ACCOUNT=argo-deploy
AWS_REGION=us-east-1
aws sts assume-role-with-web-identity \
  --role-arn "$ROLE_ARN" \
  --role-session-name "$SERVICE_ACCOUNT" \
  --web-identity-token "$ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
  --duration-seconds 900 \
  --region "$AWS_REGION"

Output is a set of temporary credentials valid for fifteen minutes. The workflow uses them to push the image, run the plan, and apply the change; the credentials are discarded when the workflow ends. No long-lived secret exists for an attacker to steal.

Why delegation matters

A chain of delegations is auditable from either end. Given a pod, the auditor follows the ServiceAccount’s IRSA annotation to the IAM role; the role’s trust policy names the OIDC issuer and the allowed sub; the sub is the workflow path; the workflow path is in a repository; the repository has a commit history. Given the engineer, the auditor walks forward: SSH key, forge user, PRs, workflow runs, OIDC tokens, cloud calls, cluster events.

A shared credential breaks this walk. With a long-lived IAM key in the runner, the auditor can walk from the engineer to the PR but cannot distinguish which workflow invoked the key.

Production discipline

  1. Establish identity at the laptop; delegate thereafter. The SSH key never leaves the laptop.
  2. Constrain OIDC trust policies by sub. A trust policy without a sub constraint is a shared credential.
  3. Bind IAM roles to specific ServiceAccounts. A role bound to many SAs is a role whose actions cannot be attributed.

Cross-course references

  • This course, Part XLIV (Authn) - the SSH and token options that feed B1.
  • This course, Part XLVII (Signing) - the keys whose trust roots anchor the chain.
  • Kubernetes for Production Sysadmins - Parts XII-XV cover ServiceAccount and IRSA mechanics.

Quiz

Knowledge check · 4 questions

  1. Q1. A team has migrated its CI to GitHub Actions OIDC and removed the long-lived AWS access key from the runner. An auditor asks which workflow performed a particular deploy. Where is the answer?

  2. Q2. OIDC federation between the CI provider and the cloud provider eliminates long-lived cloud credentials from the runner.

  3. Q3. Name the five links of the identity chain from engineer to pod, and identify the link where shared credentials most often collapse the chain.

  4. Q4. Diagnose the identity-chain break and recommend the fix.

    A team uses GitHub Actions to deploy to three EKS clusters. The cluster's GitOps controller authenticates to AWS using IRSA, with the IAM role bound to a single ServiceAccount named `argo-deploy`. The trust policy on the IAM role asserts only `iss` (the GitHub Actions issuer) without a `sub` constraint. An attacker compromises a workflow in an unrelated repository under the same GitHub organisation and uses the trust policy's lack of constraint to assume the deploy role.

Passing score: 75%. Answers are checked in this browser.