DevOps Peach

Security (DevSecOps) · IaC security and policy as code · Lesson 4 of 4

Least-privilege IAM for pipelines

IaC pipelines often hold very broad rights, which makes them big targets; split a read-only plan role from the apply role, use OIDC instead of keys, restrict by branch and environment, and audit every change.

Practice interactively →

The pipeline is a silent admin

To let terraform apply create VPCs, databases and IAM roles, the pipeline needs near-admin rights. If someone takes it over (a malicious PR running in a job with credentials, a compromised action, an access key leaked in a log), they control the account. So pipeline permissions need as much care as human ones, or more.

Splitting plan and apply

Role Used for Rights
tf-plan Every pull request Read-only (ReadOnlyAccess or narrower) plus state read and locking
tf-apply Merges to main, through an approved environment Write on exactly the services the module manages
flowchart LR
  PR["Pull request<br/>(even from unknown branches)"] -- "OIDC: ref=pull_request" --> P["role tf-plan<br/>read-only"]
  M["Merge to main"] --> E["production environment<br/>requires a reviewer"]
  E -- "OIDC: environment:production" --> A["role tf-apply"]

Unreviewed code only ever runs with read rights, so it cannot change infrastructure.

OIDC and a tight trust policy

{
  "Effect": "Allow",
  "Principal": { "Federated": "arn:aws:iam::111122223333:oidc-provider/token.actions.githubusercontent.com" },
  "Action": "sts:AssumeRoleWithWebIdentity",
  "Condition": {
    "StringEquals": {
      "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
      "token.actions.githubusercontent.com:sub": "repo:example-org/infra:environment:production"
    }
  }
}

On Azure the equivalent is a federated credential on an app registration or managed identity, with the subject limited to the repo and environment.

Narrowing rights step by step

  1. Start with broad rights in a sandbox account and enable CloudTrail.
  2. Use IAM Access Analyzer to generate a policy from the APIs actually called.
  3. Add a permissions boundary so the pipeline role cannot create roles more powerful than itself.
  4. At organisation level, SCPs (AWS) or Azure Policy block what nobody may do, such as disabling CloudTrail or using unexpected regions.

Other practices

Traps: one admin access key shared by every pipeline; a plan role with write rights; a trust policy allowing all of repo:example-org/*; forgetting that iam:PassRole or iam:CreatePolicyVersion can escalate to admin.

Practice interactively →