π Goodbye Static AWS Keys, Hello GitLab OIDC
Be honest β have you ever stored AWS keys in GitLab CI/CD variables and then thought:
- "What if someone leaks these keys?"
- "How do I rotate them across projects?"
Yeahβ¦ weβve all been there.
Luckily, AWS + GitLab have a much better way: OIDC authentication.
With OIDC, your GitLab jobs can request short-lived AWS credentials on the fly. No static keys. No rotation pain. More security. π
πΊ The Big Picture
Hereβs the 30-second flow of what happens when a GitLab pipeline hits AWS using OIDC:
π Why OIDC Rocks
- Short-lived creds (expire ~1h, customizable TTL).
- Scoped (repo + branch conditions).
- No stored secrets.
- Works with any GitLab repo.
β Step 0 β Prerequisites
- AWS account (IAM admin).
- GitLab.com repo (works with self-hosted if OIDC enabled).
- GitLab version 15.7+ (needed for
id_tokens:
). - AWS CLI v2 in your runner/job.
- (Optional) Terraform for IaC.
π Step 1 β Add OIDC Identity Provider in AWS
π In IAM β Identity providers β Add:
- Type:
OpenID Connect
- URL:
https://gitlab.com
(or self-hosted URL) - Audience:
https://gitlab.com
Terraform snippet:
resource "aws_iam_openid_connect_provider" "gitlab" {
url = "https://gitlab.com"
client_id_list = ["https://gitlab.com"]
thumbprint_list = ["9e99a48a9960b14926bb7f3b02e22da2b0ab7280"] # GitLab CA
}
π‘ Step 2 β Create IAM Role + Trust Policy
Trust only the repo + branch you want. Example:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/gitlab.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"gitlab.com:aud": "https://gitlab.com",
"gitlab.com:sub": "project_path:mygroup/myrepo:ref_type:branch:ref:main"
}
}
}
]
}
βοΈ Step 3 β Ask for a Token in GitLab CI Job
In .gitlab-ci.yml
:
deploy:
image: amazon/aws-cli:2.15.0
id_tokens:
OIDC_TOKEN:
aud: https://gitlab.com
script:
- aws sts assume-role-with-web-identity \
--role-arn "arn:aws:iam::<ACCOUNT_ID>:role/gitlab-oidc-role" \
--role-session-name "gl-$CI_PROJECT_ID-$CI_PIPELINE_ID" \
--web-identity-token "$OIDC_TOKEN" \
--duration-seconds 3600 > creds.json
- export AWS_ACCESS_KEY_ID=$(jq -r .Credentials.AccessKeyId creds.json)
- export AWS_SECRET_ACCESS_KEY=$(jq -r .Credentials.SecretAccessKey creds.json)
- export AWS_SESSION_TOKEN=$(jq -r .Credentials.SessionToken creds.json)
- aws sts get-caller-identity
π Step 4 β Safer: Token File Method
Instead of exporting keys, use AWS SDK auto-assume:
deploy:
image: amazon/aws-cli:2.15.0
id_tokens:
OIDC_TOKEN:
aud: https://gitlab.com
script:
- echo "$OIDC_TOKEN" > /tmp/web_identity_token
- export AWS_ROLE_ARN="arn:aws:iam::<ACCOUNT_ID>:role/gitlab-oidc-role"
- export AWS_WEB_IDENTITY_TOKEN_FILE="/tmp/web_identity_token"
- export AWS_ROLE_SESSION_NAME="gl-$CI_PROJECT_ID"
- aws sts get-caller-identity
- aws s3 ls s3://my-bucket
π§ͺ Step 5 β Test & Tighten
- Run pipeline β check
aws sts get-caller-identity
. -
Lock trust policy:
- Allow only
tags
orrelease/*
. - Use
StringLike
for wildcards.
- Allow only
Attach least-privilege IAM policies.
π Troubleshooting
-
AccessDenied β condition mismatch (
aud
orsub
). - Verification key error β wrong issuer URL.
-
Empty OIDC token β forgot
id_tokens:
block.
π Best Practices
- Prefer token-file method.
- Scope trust (repo + ref).
- Separate roles per env (dev/prod).
- Audit with CloudTrail.
π Wrapping Up
You just kicked static AWS keys out of your GitLab pipelines.
β
Short-lived creds.
β
Branch/repo scoped trust.
β
No secret storage.
Now your team can deploy to AWS with confidence. π
Top comments (0)