Bird
Raised Fist0
Terraformcloud~10 mins

OIDC authentication for CI/CD in Terraform - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Process Flow - OIDC authentication for CI/CD
CI/CD Pipeline starts
Request OIDC Token
OIDC Provider validates request
Token issued with claims
Terraform uses token to authenticate
Access cloud resources securely
Pipeline continues with permissions
The CI/CD pipeline requests an OIDC token, which the provider validates and issues. Terraform uses this token to authenticate securely to cloud resources during the pipeline.
Execution Sample
Terraform
provider "aws" {
  region = "us-east-1"
}

resource "aws_iam_role" "ci_role" {
  assume_role_policy = jsonencode({
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Principal": {"Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E"},
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E:sub": "system:serviceaccount:ci-cd:terraform"
        }
      }
    }]
  })
}
Terraform config defines an AWS provider with OIDC and an IAM role that trusts the OIDC provider for CI/CD authentication.
Process Table
StepActionInput/ConditionResultNotes
1CI/CD pipeline startsTrigger pipelinePipeline begins executionPipeline triggered by code push
2Request OIDC tokenPipeline requests tokenOIDC provider receives requestToken request includes service account info
3Validate token requestCheck service account and conditionsToken issued with claimsClaims include subject and audience
4Terraform uses tokenToken passed to AWS providerAuthentication succeedsTerraform can assume IAM role
5Access AWS resourcesUse assumed role permissionsResources created/modifiedTerraform applies infrastructure changes
6Pipeline completesAll steps successfulPipeline ends successfullyInfrastructure deployed securely
💡 Pipeline ends after successful authentication and resource deployment
Status Tracker
VariableStartAfter Step 2After Step 3After Step 4Final
OIDC TokenNoneRequestedIssued with claimsUsed by TerraformExpired after pipeline
IAM RoleDefined in TerraformNo changeNo changeAssumed by TerraformIn use during pipeline
Pipeline StateIdleRunningRunningRunningCompleted
Key Moments - 3 Insights
Why does Terraform need the OIDC token during the pipeline?
Terraform uses the OIDC token to prove its identity to AWS and assume the IAM role securely, as shown in execution_table step 4.
What ensures that only the CI/CD pipeline can assume the IAM role?
The IAM role's trust policy restricts assume role action to tokens with specific claims matching the CI/CD service account, as seen in the terraform code and execution_table step 3.
What happens if the OIDC token is invalid or missing?
Terraform authentication fails, and the pipeline cannot access AWS resources, stopping deployment before step 5.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, at which step is the OIDC token issued?
AStep 2
BStep 3
CStep 4
DStep 5
💡 Hint
Check the 'Result' column for token issuance in execution_table row with Step 3.
According to variable_tracker, what is the state of the IAM Role after Step 4?
AAssumed by Terraform
BDefined in Terraform
CExpired
DDeleted
💡 Hint
Look at the 'IAM Role' row under 'After Step 4' in variable_tracker.
If the pipeline state was 'Idle' at start, when does it become 'Completed'?
AAfter Step 2
BAfter Step 4
CAfter Step 6
DNever
💡 Hint
Check the 'Pipeline State' row in variable_tracker for the 'Final' column.
Concept Snapshot
OIDC authentication for CI/CD:
- CI/CD pipeline requests OIDC token from provider
- Provider validates and issues token with claims
- Terraform uses token to assume IAM role securely
- IAM role trust policy restricts access to specific service accounts
- Enables secure, short-lived credentials for cloud access
- Avoids storing long-term secrets in pipelines
Full Transcript
This visual execution shows how OIDC authentication works in a CI/CD pipeline using Terraform. The pipeline starts and requests an OIDC token from the provider. The provider validates the request and issues a token with claims identifying the pipeline's service account. Terraform uses this token to authenticate to AWS by assuming an IAM role with a trust policy that allows only this token. This process enables secure access to cloud resources without long-term secrets. The pipeline completes after Terraform applies infrastructure changes using the assumed role.

Practice

(1/5)
1. What is the main benefit of using OIDC authentication in CI/CD pipelines with Terraform?
easy
A. It disables all access restrictions for faster builds.
B. It automatically deploys code without any manual approval.
C. It replaces Terraform with a different infrastructure tool.
D. It allows secure authentication without storing passwords in the pipeline.

Solution

  1. Step 1: Understand OIDC purpose in CI/CD

    OIDC provides a secure way for pipelines to prove identity without passwords.
  2. Step 2: Connect to Terraform usage

    Terraform can create roles that trust OIDC tokens, avoiding password storage.
  3. Final Answer:

    It allows secure authentication without storing passwords in the pipeline. -> Option D
  4. Quick Check:

    OIDC = passwordless secure authentication [OK]
Hint: OIDC means no passwords needed in CI/CD [OK]
Common Mistakes:
  • Thinking OIDC automates deployment without approval
  • Confusing OIDC with replacing Terraform
  • Assuming OIDC disables access controls
2. Which Terraform resource block correctly defines an IAM role trusting GitHub Actions OIDC provider?
easy
A. resource "aws_iam_role" "github_oidc_role" { assume_role_policy = jsonencode({ Version = "2012-10-17", Statement = [{ Effect = "Allow", Principal = { Federated = "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" }, Action = "sts:AssumeRoleWithWebIdentity" }] }) }
B. resource "aws_iam_role" "github_oidc_role" { assume_role_policy = jsonencode({ Version = "2012-10-17", Statement = [{ Effect = "Allow", Principal = { Service = "github.com" }, Action = "sts:AssumeRole" }] }) }
C. resource "aws_iam_role" "github_oidc_role" { assume_role_policy = jsonencode({ Version = "2012-10-17", Statement = [{ Effect = "Allow", Principal = { AWS = "arn:aws:iam::123456789012:root" }, Action = "sts:AssumeRoleWithWebIdentity" }] }) }
D. resource "aws_iam_role" "github_oidc_role" { assume_role_policy = jsonencode({ Version = "2012-10-17", Statement = [{ Effect = "Allow", Principal = { Federated = "arn:aws:iam::123456789012:oidc-provider/github.com" }, Action = "sts:AssumeRoleWithWebIdentity" }] }) }

Solution

  1. Step 1: Identify correct OIDC provider ARN format

    The OIDC provider ARN for GitHub Actions uses 'token.actions.githubusercontent.com'.
  2. Step 2: Check assume_role_policy structure

    The policy must allow 'sts:AssumeRoleWithWebIdentity' with Principal as Federated and correct ARN.
  3. Final Answer:

    The resource block with Federated principal using 'token.actions.githubusercontent.com' and 'sts:AssumeRoleWithWebIdentity' action. -> Option A
  4. Quick Check:

    Correct OIDC ARN + sts:AssumeRoleWithWebIdentity = resource "aws_iam_role" "github_oidc_role" { assume_role_policy = jsonencode({ Version = "2012-10-17", Statement = [{ Effect = "Allow", Principal = { Federated = "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" }, Action = "sts:AssumeRoleWithWebIdentity" }] }) } [OK]
Hint: OIDC provider ARN uses token.actions.githubusercontent.com [OK]
Common Mistakes:
  • Using Service principal instead of Federated
  • Wrong OIDC provider ARN format
  • Using sts:AssumeRole instead of sts:AssumeRoleWithWebIdentity
3. Given this Terraform snippet for an IAM role trust policy, what is the effect of the condition block?
condition = {
  StringEquals = {
    "token.actions.githubusercontent.com:sub" = "repo:myorg/myrepo:ref:refs/heads/main"
  }
}
medium
A. Allows any GitHub repo to assume the role.
B. Restricts role assumption to the main branch of myorg/myrepo only.
C. Blocks all role assumptions from GitHub Actions.
D. Allows only forks of myorg/myrepo to assume the role.

Solution

  1. Step 1: Understand the condition key

    The condition uses 'token.actions.githubusercontent.com:sub' to specify the GitHub repo and branch.
  2. Step 2: Interpret the value

    The value 'repo:myorg/myrepo:ref:refs/heads/main' restricts access to the main branch of that repo only.
  3. Final Answer:

    Restricts role assumption to the main branch of myorg/myrepo only. -> Option B
  4. Quick Check:

    Condition limits to specific repo and branch = Restricts role assumption to the main branch of myorg/myrepo only. [OK]
Hint: Condition with repo and ref limits branch access [OK]
Common Mistakes:
  • Ignoring the branch restriction in condition
  • Assuming condition allows all repos
  • Confusing forks with original repo access
4. You wrote this Terraform assume_role_policy but your CI/CD pipeline fails to authenticate:
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/github.com" },
    "Action": "sts:AssumeRoleWithWebIdentity"
  }]
}
What is the most likely error?
medium
A. The Principal should use 'Service' instead of 'Federated'.
B. The Action should be 'sts:AssumeRole' instead of 'sts:AssumeRoleWithWebIdentity'.
C. The OIDC provider ARN is incorrect; it should be 'token.actions.githubusercontent.com'.
D. The Version date is invalid and must be updated.

Solution

  1. Step 1: Check the OIDC provider ARN

    The ARN 'arn:aws:iam::123456789012:oidc-provider/github.com' is incorrect for GitHub Actions.
  2. Step 2: Identify correct ARN for GitHub Actions

    The correct ARN uses 'token.actions.githubusercontent.com' as the OIDC provider host.
  3. Final Answer:

    The OIDC provider ARN is incorrect; it should be 'token.actions.githubusercontent.com'. -> Option C
  4. Quick Check:

    Wrong OIDC ARN causes auth failure = The OIDC provider ARN is incorrect; it should be 'token.actions.githubusercontent.com'. [OK]
Hint: Check OIDC ARN spelling carefully for GitHub Actions [OK]
Common Mistakes:
  • Using 'sts:AssumeRole' instead of 'sts:AssumeRoleWithWebIdentity'
  • Confusing Federated with Service principal
  • Ignoring ARN format for OIDC provider
5. You want to create a Terraform IAM role for GitHub Actions that only allows workflows from the 'release' branch of 'myorg/myrepo' to assume it. Which condition block correctly enforces this restriction?
hard
A. { "StringEquals": { "token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:ref:refs/heads/release" } }
B. { "StringLike": { "token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:ref:refs/heads/*" } }
C. { "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" } }
D. { "StringNotEquals": { "token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:ref:refs/heads/main" } }

Solution

  1. Step 1: Understand the condition key and value

    To restrict to the 'release' branch, the condition must match 'repo:myorg/myrepo:ref:refs/heads/release'.
  2. Step 2: Choose correct operator

    'StringEquals' ensures exact match, so only 'release' branch is allowed.
  3. Final Answer:

    The condition block with StringEquals matching 'repo:myorg/myrepo:ref:refs/heads/release'. -> Option A
  4. Quick Check:

    Exact branch match uses StringEquals with correct ref [OK]
Hint: Use StringEquals with exact repo and branch ref [OK]
Common Mistakes:
  • Using StringLike with wildcard allowing all branches
  • Checking audience (aud) instead of subject (sub)
  • Using StringNotEquals which excludes main but allows others