Skip to content
CloudOps
All prompts
AI for Terraform Difficulty: Intermediate ClaudeChatGPT

Terraform Secrets & Sensitive Variables Prompt

Manage secrets in Terraform — sensitive flag, ephemeral resources, external secret managers, plan/state masking.

Target user
Terraform engineers handling production secrets
Difficulty
Intermediate
Tools
Claude, ChatGPT

The prompt

You are a senior platform engineer who has handled secrets in Terraform — sensitive variables, external lookups, ephemeral resources (1.10+).

I will provide:
- The secret type
- Current handling
- Concerns

Your job:

1. **Sensitive flag**:
   - `sensitive = true` on variable / output
   - Masked in plan/apply output
   - Still in state (encrypted at rest)
2. **For ephemeral resources** (1.10+):
   - Not stored in state
   - Re-read on each plan
   - Good for short-lived secrets
3. **For external secret managers**:
   - **AWS Secrets Manager**: `data "aws_secretsmanager_secret"`
   - **HashiCorp Vault**: vault provider
   - **GCP Secret Manager**: `data "google_secret_manager_secret_version"`
   - **Azure Key Vault**: `data "azurerm_key_vault_secret"`
   - Fetch at apply time
4. **For state-stored secrets**:
   - Encrypt state at rest (KMS)
   - Restrict access
   - Audit
5. **For provider auth**:
   - Don't hardcode in .tf
   - Env vars / OIDC / instance role
6. **For Terraform Cloud variables**:
   - Mark sensitive in UI
   - Encrypted at rest
7. **For sensitive in outputs**:
   - `output "secret" { sensitive = true value = ... }`
   - Required for downstream consumers
8. **For preventing leak**:
   - No sensitive vars in logs / errors
   - Mask in CI output
   - Don't commit tfvars with secrets

Mark DESTRUCTIVE: secrets in committed tfvars, sensitive output passed to non-sensitive output, plan output captured in CI logs containing secrets.

---

Secret type: [DESCRIBE]
Current handling: [DESCRIBE]
Concerns: [DESCRIBE]

Why this prompt works

Secrets in Terraform need care. This prompt walks patterns.

How to use it

  1. Mark sensitive.
  2. External secrets for production.
  3. Encrypt state.
  4. No secrets in code.

Patterns

Sensitive variable + output

variable "db_password" {
  description = "Database master password"
  type        = string
  sensitive   = true
  nullable    = false

  validation {
    condition     = length(var.db_password) >= 16
    error_message = "db_password must be at least 16 chars."
  }
}

output "db_connection_string" {
  value     = "postgres://admin:${var.db_password}@${aws_db_instance.main.endpoint}/myapp"
  sensitive = true                       # required because depends on sensitive
}

In plan output:

db_password = (sensitive value)
db_connection_string = (sensitive value)

External secret (AWS Secrets Manager)

data "aws_secretsmanager_secret" "db" {
  name = "prod/db/master-password"
}

data "aws_secretsmanager_secret_version" "db" {
  secret_id = data.aws_secretsmanager_secret.db.id
}

resource "aws_db_instance" "main" {
  identifier        = "myapp-prod"
  engine            = "postgres"
  instance_class    = "db.t3.medium"
  allocated_storage = 100

  username = "admin"
  password = jsondecode(data.aws_secretsmanager_secret_version.db.secret_string)["password"]

  storage_encrypted = true
  kms_key_id        = aws_kms_key.rds.arn
}

HashiCorp Vault

provider "vault" {
  address = "https://vault.example.com"
  # Auth via VAULT_TOKEN env var
}

data "vault_kv_secret_v2" "db" {
  mount = "kv"
  name  = "prod/db"
}

resource "aws_db_instance" "main" {
  password = data.vault_kv_secret_v2.db.data["password"]
}

Ephemeral resource (1.10+)

ephemeral "aws_secretsmanager_secret_version" "db" {
  secret_id = "prod/db/master-password"
}

# Use in same plan; not stored in state
resource "aws_db_instance" "main" {
  password = ephemeral.aws_secretsmanager_secret_version.db.secret_string
}

Generated random password (stored in state)

resource "random_password" "db" {
  length  = 32
  special = true
  upper   = true
  lower   = true
  numeric = true

  lifecycle {
    ignore_changes = [length, special, upper, lower, numeric]
  }
}

resource "aws_secretsmanager_secret_version" "db" {
  secret_id     = aws_secretsmanager_secret.db.id
  secret_string = jsonencode({
    username = "admin"
    password = random_password.db.result
  })
}

resource "aws_db_instance" "main" {
  password = random_password.db.result
}

Auth via env (no hardcoded keys)

provider "aws" {
  region = "us-east-1"
  # Credentials via AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY env
  # OR shared profile (AWS_PROFILE)
  # OR IAM instance role (no env needed)
  # OR OIDC from CI
}

Terraform Cloud sensitive variables

TFC UI → Workspace → Variables:
- Name: db_password
- Value: (encrypted)
- Sensitive: true (masks UI + plan logs)
- Description: Database password
# In Terraform code, TFC injects as TF_VAR_db_password
variable "db_password" {
  sensitive = true
}

CI/CD masking

# GitLab CI: mark variable as Masked + Protected
# Settings → CI/CD → Variables:
# - TF_VAR_db_password
#   - Masked: true
#   - Protected: true
#   - Environment: production

terraform-apply:
  variables:
    TF_VAR_db_password: $DB_PASSWORD          # masked in CI logs
  script:
    - terraform apply -auto-approve 2>&1 | sed "s/$DB_PASSWORD/******/g"

Common findings this catches

  • Secret in committed .tfvars → rotate, remove, vault.
  • Sensitive var without flag → outputs show value.
  • Output without sensitive flag depends on sensitive → error.
  • Provider creds hardcoded → env / OIDC.
  • State file unencrypted → KMS.
  • CI logs containing plan output → mask + restrict.
  • Random_password regenerates on every apply → ignore_changes.

When to escalate

  • Compromised secret → rotate; IR.
  • Secret manager migration → staged.
  • Cross-org secret policy — security.

Related prompts

Newsletter

Get weekly AI workflows for DevOps engineers

Practical prompts, automation ideas, and tool reviews for infrastructure engineers. One email per week. No spam.