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
Step 1: Understand OIDC purpose in CI/CD
OIDC provides a secure way for pipelines to prove identity without passwords.
Step 2: Connect to Terraform usage
Terraform can create roles that trust OIDC tokens, avoiding password storage.
Final Answer:
It allows secure authentication without storing passwords in the pipeline. -> Option D
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
Step 1: Identify correct OIDC provider ARN format
The OIDC provider ARN for GitHub Actions uses 'token.actions.githubusercontent.com'.
Step 2: Check assume_role_policy structure
The policy must allow 'sts:AssumeRoleWithWebIdentity' with Principal as Federated and correct ARN.
Final Answer:
The resource block with Federated principal using 'token.actions.githubusercontent.com' and 'sts:AssumeRoleWithWebIdentity' action. -> Option A
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
Step 1: Check the OIDC provider ARN
The ARN 'arn:aws:iam::123456789012:oidc-provider/github.com' is incorrect for GitHub Actions.
Step 2: Identify correct ARN for GitHub Actions
The correct ARN uses 'token.actions.githubusercontent.com' as the OIDC provider host.
Final Answer:
The OIDC provider ARN is incorrect; it should be 'token.actions.githubusercontent.com'. -> Option C
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
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'.
Step 2: Choose correct operator
'StringEquals' ensures exact match, so only 'release' branch is allowed.
Final Answer:
The condition block with StringEquals matching 'repo:myorg/myrepo:ref:refs/heads/release'. -> Option A
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