Bird
Raised Fist0
Terraformcloud~30 mins

OIDC authentication for CI/CD in Terraform - Mini Project: Build & Apply

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
OIDC Authentication for CI/CD with Terraform
📖 Scenario: You are setting up a secure connection between your CI/CD pipeline and your cloud provider using OpenID Connect (OIDC). This allows your pipeline to authenticate without storing long-lived credentials.
🎯 Goal: Build a Terraform configuration that creates an IAM role with an OIDC trust relationship for your CI/CD pipeline.
📋 What You'll Learn
Create a Terraform variable for the OIDC provider URL
Create a Terraform variable for the CI/CD workflow audience
Define an IAM role resource with an assume role policy that trusts the OIDC provider
Output the IAM role ARN
💡 Why This Matters
🌍 Real World
Many organizations use OIDC to securely connect their CI/CD pipelines to cloud providers without storing long-term credentials.
💼 Career
Understanding how to configure OIDC trust relationships in Terraform is a key skill for DevOps engineers managing secure cloud deployments.
Progress0 / 4 steps
1
Define OIDC Provider URL Variable
Create a Terraform variable called oidc_provider_url with the default value https://token.actions.githubusercontent.com.
Terraform
Hint

Use variable "oidc_provider_url" { default = "https://token.actions.githubusercontent.com" }

2
Define CI/CD Audience Variable
Create a Terraform variable called ci_cd_audience with the default value sts.amazonaws.com.
Terraform
Hint

Define a variable named ci_cd_audience with default sts.amazonaws.com.

3
Create IAM Role with OIDC Trust
Create an aws_iam_role resource called ci_cd_role with an assume_role_policy that allows the OIDC provider URL from var.oidc_provider_url to assume the role. The policy must include the var.ci_cd_audience as the audience condition.
Terraform
Hint

Use jsonencode to create the assume role policy with the OIDC provider and audience.

4
Output the IAM Role ARN
Create an output called ci_cd_role_arn that outputs the ARN of the aws_iam_role.ci_cd_role resource.
Terraform
Hint

Use output "ci_cd_role_arn" { value = aws_iam_role.ci_cd_role.arn } to show the role ARN.

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