Terraform Cloud Provider Authentication Best Practices Prompt
Authenticate Terraform to cloud providers safely — AWS IAM roles, GCP service accounts, Azure managed identity, OIDC from CI.
- Target user
- Platform engineers configuring Terraform auth
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT
The prompt
You are a senior platform engineer who has set up Terraform auth from CI/CD — OIDC federation, assume role, service accounts. I will provide: - Cloud + CI environment - Current auth method - Symptom (auth fails, too privileged, leaked) Your job: 1. **For AWS auth**: - **IAM role** on runner (EC2/ECS) — preferred for self-hosted - **Static keys** (AWS_ACCESS_KEY_ID) — last resort - **OIDC from CI** (GitLab/GitHub) — modern; short-lived - **Assume role** for cross-account 2. **For GCP auth**: - **Service account** with key file (legacy) - **Workload Identity Federation** from CI (modern) - **GCE metadata** on runner 3. **For Azure auth**: - **Service Principal** (client_id + secret) - **Managed Identity** on runner - **OIDC federation** from CI 4. **For Terraform Cloud**: - Dynamic provider credentials (TFC + cloud OIDC) - Static workspace variables (fallback) 5. **For OIDC pattern** (most modern): - CI emits JWT - Cloud trusts CI as IdP - Terraform assumes role via JWT - Short-lived; no static creds 6. **For least privilege**: - Terraform role scoped to what it manages - Per-environment role - Audit via CloudTrail 7. **For local development**: - SSO / AWS CLI profile - Don't commit credentials - Use direnv / aws-vault 8. **For credential rotation**: - OIDC eliminates rotation - Static keys: rotation policy Mark DESTRUCTIVE: committing service account keys, broad permissions on Terraform role, sharing creds across teams, OIDC trust too broad. --- Cloud + CI: [DESCRIBE] Current auth: [DESCRIBE] Symptom: [DESCRIBE]
Why this prompt works
Auth is foundational and often misdone. This prompt walks modern patterns.
How to use it
- OIDC from CI preferred.
- Least privilege role.
- No static creds in code.
- Audit cloud trail.
Patterns
AWS OIDC from GitLab CI
# .gitlab-ci.yml
terraform-apply:
id_tokens:
AWS_JWT:
aud: https://gitlab.com
variables:
AWS_ROLE_ARN: arn:aws:iam::123456789012:role/GitLabCITerraform
AWS_WEB_IDENTITY_TOKEN_FILE: /tmp/jwt
script:
- echo "$AWS_JWT" > /tmp/jwt
- terraform apply -auto-approve
# IAM role trust policy (one-time setup)
resource "aws_iam_role" "ci_terraform" {
name = "GitLabCITerraform"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
Federated = "arn:aws:iam::123456789012:oidc-provider/gitlab.com"
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringLike = {
"gitlab.com:sub" = "project_path:myorg/infrastructure:ref_type:branch:ref:main"
}
StringEquals = {
"gitlab.com:aud" = "https://gitlab.com"
}
}
}]
})
}
AWS local dev (aws-vault)
# Install aws-vault
brew install aws-vault
# Add profile (encrypted)
aws-vault add myorg-dev
# Run terraform with creds
aws-vault exec myorg-dev -- terraform plan
GCP Workload Identity Federation
# Provider pool + workload identity pool (one-time)
resource "google_iam_workload_identity_pool" "github" {
workload_identity_pool_id = "github-actions"
}
resource "google_iam_workload_identity_pool_provider" "github" {
workload_identity_pool_id = google_iam_workload_identity_pool.github.workload_identity_pool_id
workload_identity_pool_provider_id = "github-provider"
oidc {
issuer_uri = "https://token.actions.githubusercontent.com"
}
attribute_mapping = {
"google.subject" = "assertion.sub"
"attribute.repository" = "assertion.repository"
}
attribute_condition = "attribute.repository == 'myorg/infrastructure'"
}
resource "google_service_account" "ci_terraform" {
account_id = "ci-terraform"
}
resource "google_service_account_iam_binding" "wif" {
service_account_id = google_service_account.ci_terraform.name
role = "roles/iam.workloadIdentityUser"
members = [
"principalSet://iam.googleapis.com/projects/${data.google_project.current.number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.github.workload_identity_pool_id}/attribute.repository/myorg/infrastructure"
]
}
# GitHub Actions
jobs:
terraform:
permissions:
id-token: write
steps:
- uses: google-github-actions/auth@v2
with:
workload_identity_provider: 'projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/github-actions/providers/github-provider'
service_account: 'ci-terraform@myorg.iam.gserviceaccount.com'
- run: terraform apply -auto-approve
Azure Managed Identity (runner)
provider "azurerm" {
features {}
use_msi = true # use managed identity
}
Cross-account assume role
provider "aws" {
alias = "audit"
region = "us-east-1"
assume_role {
role_arn = "arn:aws:iam::AUDIT_ACCOUNT:role/TerraformAudit"
session_name = "TerraformAuditSession"
external_id = "myorg-tf-external-id"
}
}
Common findings this catches
- Static key in committed .tfvars → rotate; remove; use OIDC.
- Admin permissions on Terraform role → least privilege.
- OIDC trust matches any branch → restrict via
sub. - No external_id on cross-account → CD attack.
- Local creds in shell history → aws-vault.
- TFC variables containing secrets — mark sensitive.
- Cloud trail not capturing Terraform actions → enable.
When to escalate
- Org-wide IAM design — security.
- OIDC integration across CIs — coordinate.
- Compliance audit of Terraform access — security.
Related prompts
-
GitLab CI/CD Pipeline & Access Tokens Security Prompt
Manage and secure GitLab tokens — trigger tokens, project access tokens, group access tokens, $CI_JOB_TOKEN scope, leak detection and rotation.
-
Terraform CI/CD: Atlantis, Cloud, GitOps Prompt
Choose and configure Terraform CI/CD — Atlantis, Terraform Cloud, Spacelift, custom CI; plan/apply workflows, approvals.
-
Terraform Provider Configuration & Aliases Prompt
Configure Terraform providers — version constraints, aliases for multi-region/multi-account, required_providers.