This guide documents the required GitHub Variables for the AWS Static Website Infrastructure CI/CD pipeline using Direct OIDC authentication.
For complete deployment setup including GitHub configuration, see the Bootstrap Scripts README.
- Current Architecture
- Required GitHub Secrets
- Required GitHub Variables
- AWS OIDC Configuration
- Security Best Practices
Direct OIDC Authentication Pattern (Operational):
GitHub Actions Workflow
↓ (OIDC token)
↓
┌────┴────┐
│ OIDC │ Created in each environment account
│Provider │ token.actions.githubusercontent.com
└────┬────┘
↓ (AssumeRoleWithWebIdentity)
↓
┌────────┴─────────┐
│ Environment │ Direct role assumption
│ Deployment Role │ Repository-scoped trust policy
└──────────────────┘
• GitHubActions-Static-site-dev
• GitHubActions-Static-site-staging
• GitHubActions-Static-site-prod
Each environment has its own OIDC provider and deployment role
No cross-account role assumptions required
Authentication Flow:
- GitHub Actions obtains OIDC token from GitHub
- Directly assumes environment-specific deployment role via
AssumeRoleWithWebIdentity - Deploys infrastructure with environment-scoped permissions
- No intermediate roles or cross-account trust relationships required
Direct OIDC Advantage: With Direct OIDC authentication, no AWS secrets are required in the GitHub repository. Authentication uses OIDC tokens automatically generated by GitHub Actions, which are exchanged for temporary AWS credentials.
Security Benefits:
- No long-lived credentials stored in GitHub
- Zero credential rotation required
- Automatic token expiration (15 minutes)
- Repository-scoped trust policies in AWS
Optional Secrets: You may choose to store application-specific secrets (API keys, database passwords, etc.) as GitHub secrets, but AWS authentication itself requires no stored credentials.
| Variable Name | Description | Example Value | Required |
|---|---|---|---|
AWS_DEFAULT_REGION |
AWS region for deployment (see config.sh) | us-east-2 |
Yes |
OPENTOFU_VERSION |
OpenTofu version to use | 1.6.1 |
Yes |
AWS_ACCOUNT_ID_DEV |
Development account ID | 123456789012 |
Yes |
AWS_ACCOUNT_ID_STAGING |
Staging account ID | 123456789012 |
Yes |
AWS_ACCOUNT_ID_PROD |
Production account ID | 123456789012 |
Yes |
AWS_ACCOUNT_ID_MANAGEMENT |
Management account ID | 123456789012 |
Yes |
DEFAULT_ENVIRONMENT |
Default deployment environment | dev |
Yes |
MONTHLY_BUDGET_LIMIT |
Budget alert threshold | 40 |
Yes |
REPLICA_REGION |
Cross-region replication target | us-west-2 |
Yes |
ALERT_EMAIL_ADDRESSES |
Budget alert email addresses | ["celtikill@celtikill.io"] |
Yes |
Region Configuration: The AWS_DEFAULT_REGION value is defined in
scripts/bootstrap/config.shand automatically configured during bootstrap. See Bootstrap README for details.
The bootstrap script (scripts/bootstrap/configure-github.sh) automatically sets all required variables. For manual configuration:
# Set required variables (use values from scripts/bootstrap/config.sh)
gh variable set AWS_DEFAULT_REGION --body "us-east-2"
gh variable set OPENTOFU_VERSION --body "1.6.1"
# Set account IDs from scripts/bootstrap/accounts.json
gh variable set AWS_ACCOUNT_ID_DEV --body "YOUR_DEV_ACCOUNT_ID"
gh variable set AWS_ACCOUNT_ID_STAGING --body "YOUR_STAGING_ACCOUNT_ID"
gh variable set AWS_ACCOUNT_ID_PROD --body "YOUR_PROD_ACCOUNT_ID"
gh variable set AWS_ACCOUNT_ID_MANAGEMENT --body "YOUR_MGMT_ACCOUNT_ID"
# List all variables to verify
gh variable listThe OIDC infrastructure is deployed by the bootstrap scripts and includes:
- OIDC Provider: Created in each environment account (dev, staging, prod)
- URL:
token.actions.githubusercontent.com - Thumbprint: GitHub's OIDC endpoint certificate
- URL:
- Deployment Roles: Direct OIDC roles in each environment
GitHubActions-Static-site-devGitHubActions-Static-site-stagingGitHubActions-Static-site-prod
- Trust Relationships: Repository-scoped OIDC trust policies
Deployment Role Trust Policy (Direct OIDC):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:celtikill/static-site:*"
}
}
}
]
}Key Features:
- Direct Trust: GitHub OIDC provider directly trusted by environment role
- Repository Scoped: Only workflows from
celtikill/static-sitecan assume the role - No Cross-Account: Each environment authenticates independently
- Automatic Tokens: GitHub generates short-lived OIDC tokens (15 minutes)
-
Zero Stored Credentials
- No GitHub secrets required for AWS authentication
- Zero credential rotation burden
- No risk of credential leakage from repository
-
Direct Trust Model
- No intermediate roles or cross-account trust chains
- Each environment authenticates independently
- Simplified security boundary (GitHub → Environment)
-
Least Privilege Access
- Environment-specific deployment roles
- Account-level isolation
- Repository-scoped trust policies
- Time-limited sessions (15-minute OIDC tokens, 1-hour role sessions)
-
Complete Audit Trail
- All role assumptions logged in CloudTrail
- Environment-specific access patterns
- OIDC token claims captured in AWS logs
-
Repository Protection:
# Protect main branch gh api repos/:owner/:repo/branches/main/protection \ --method PUT \ --field required_status_checks.strict=true \ --field required_status_checks.contexts[]="build"
-
Environment-Based Access:
- Dev: Automatic deployment on feature branches
- Staging: Manual approval required
- Prod: Code owner approval required
-
Workflow Monitoring:
# View recent workflow runs gh run list --limit 10 # Check specific workflow logs gh run view <run-id> --log
-
AWS CloudTrail Monitoring:
# Monitor OIDC role assumptions in dev environment aws logs filter-log-events \ --log-group-name CloudTrail/dev \ --filter-pattern "GitHubActions-Static-site-dev" # View OIDC token claims aws logs filter-log-events \ --log-group-name CloudTrail/dev \ --filter-pattern "AssumeRoleWithWebIdentity"
-
Environment-Specific Auditing:
# Check who assumed roles in production aws cloudtrail lookup-events \ --region us-east-2 \ --lookup-attributes AttributeKey=ResourceName,AttributeValue=GitHubActions-Static-site-prod \ --max-results 10
Symptom: Error: Not authorized to perform sts:AssumeRoleWithWebIdentity
Diagnosis:
# Verify OIDC provider exists in target account
aws iam list-open-id-connect-providers
# Check deployment role trust policy
aws iam get-role --role-name GitHubActions-Static-site-dev \
--query 'Role.AssumeRolePolicyDocument'
# Verify repository name matches exactly in trust policyCommon Causes:
- OIDC provider not created in target account
- Repository name mismatch in trust policy condition
- Role name typo in workflow configuration
- Account ID mismatch
Solution:
# Re-run bootstrap to ensure OIDC infrastructure is deployed
cd scripts/bootstrap
./bootstrap-foundation.sh
# Verify role exists and has correct trust policy
aws iam get-role --role-name GitHubActions-Static-site-devSymptom: Workflow fails with "Role not found" or "Access denied"
Solution:
# Verify GitHub variables match accounts.json
cat scripts/bootstrap/accounts.json
# Check GitHub variables
gh variable list
# Update if needed
gh variable set AWS_ACCOUNT_ID_DEV --body "$(jq -r .dev scripts/bootstrap/accounts.json)"Symptom: Error: Token has expired
Explanation: GitHub OIDC tokens expire after 15 minutes. This is normal and should not occur during typical workflow execution.
Solution: Rerun the workflow. If issue persists, check for workflow steps that take longer than 15 minutes before AWS authentication.
# Test BUILD workflow with authentication
gh workflow run build.yml --field force_build=true --field environment=dev
# Test TEST workflow
gh workflow run test.yml --field environment=dev
# Test RUN workflow
gh workflow run run.yml --field environment=dev --field deploy_infrastructure=true
# Monitor workflow execution
gh run watch# Check OIDC provider exists in dev account
aws iam list-open-id-connect-providers \
--query 'OpenIDConnectProviderList[?contains(Arn, `token.actions.githubusercontent.com`)]'
# Verify deployment role exists
aws iam get-role --role-name GitHubActions-Static-site-dev
# Check trust relationship
aws iam get-role --role-name GitHubActions-Static-site-dev \
--query 'Role.AssumeRolePolicyDocument' \
--output json | jq .The best way to test OIDC authentication is to trigger a workflow:
# Push a test commit to trigger workflow
git commit --allow-empty -m "Test OIDC authentication"
git push
# Watch the workflow run
gh run watchIf the workflow successfully authenticates and runs AWS CLI commands, OIDC is working correctly.
- IAM Deep Dive - Complete OIDC architecture documentation
- Bootstrap Scripts README - Infrastructure setup guide
- Deployment Guide - Deployment procedures
- Policy Documentation - IAM policy details
Last Updated: 2025-11-04 Version: 2.0.0
💡 Note: This configuration uses Direct OIDC authentication, eliminating the need for stored AWS credentials in GitHub. All authentication is handled through short-lived OIDC tokens generated automatically by GitHub Actions.