Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
stop-slop, taste-skill, terrashark had embedded .git dirs causing Woodpecker clone to fail on submodule update.
92 lines
2.5 KiB
Markdown
92 lines
2.5 KiB
Markdown
# Secret Exposure
|
|
|
|
Use this guide when secrets may leak into state, logs, defaults, or CI artifacts.
|
|
|
|
## Symptoms
|
|
|
|
- secret values appear in plan output or logs
|
|
- credentials are defined in variable defaults
|
|
- sensitive outputs are printed in CI
|
|
- generated passwords are stored in state unintentionally
|
|
|
|
## Exposure paths
|
|
|
|
- hardcoded defaults in `variables.tf`
|
|
- secret-bearing resources whose values are persisted in state
|
|
- logging `terraform show` outputs without redaction
|
|
- artifact retention policies that keep plan/state exports too long
|
|
|
|
## Prevention baseline
|
|
|
|
- never set secret defaults in code
|
|
- source secrets from managed secret stores at runtime
|
|
- mark secret variables and outputs as `sensitive = true`
|
|
- restrict state backend access aggressively
|
|
- avoid publishing raw plan JSON as broadly accessible artifact
|
|
|
|
## Runtime patterns
|
|
|
|
Preferred order:
|
|
1. external secret manager lookup
|
|
2. workload identity federation for providers
|
|
3. short-lived credentials from trusted broker
|
|
|
|
Avoid long-lived static credentials in repository or runner config.
|
|
|
|
## Write-only and sensitive handling
|
|
|
|
- `sensitive = true` masks display, but value can still exist in state depending on provider behavior
|
|
- `write_only` arguments (where supported) reduce state persistence risk
|
|
- always verify provider docs before assuming secret material is excluded from state
|
|
|
|
## Rotation playbook
|
|
|
|
1. create new secret version in manager
|
|
2. update application to consume new version
|
|
3. roll infrastructure safely
|
|
4. revoke old credential
|
|
5. verify no leaked copies remain in logs/artifacts
|
|
|
|
## Good example
|
|
|
|
```hcl
|
|
variable "db_admin_username" {
|
|
description = "Database admin user"
|
|
type = string
|
|
}
|
|
|
|
data "aws_secretsmanager_secret_version" "db_password" {
|
|
secret_id = "prod/db/admin"
|
|
}
|
|
|
|
resource "aws_db_instance" "core" {
|
|
identifier = "core-db-prod"
|
|
username = var.db_admin_username
|
|
password = jsondecode(data.aws_secretsmanager_secret_version.db_password.secret_string)["password"]
|
|
}
|
|
```
|
|
|
|
## Bad example
|
|
|
|
```hcl
|
|
variable "db_password" {
|
|
type = string
|
|
default = "ChangeMe123!"
|
|
}
|
|
```
|
|
|
|
## LLM mistake checklist
|
|
|
|
Common model mistakes to correct:
|
|
- assumes `sensitive` alone means "not in state"
|
|
- proposes plaintext defaults for demo convenience
|
|
- uses outputs that expose full connection strings in PR comments
|
|
- forgets artifact retention and access controls in CI
|
|
|
|
## Verification commands
|
|
|
|
```bash
|
|
terraform plan -out=plan.bin
|
|
terraform show -json plan.bin > plan.json
|
|
# Ensure secret fields are not emitted to shared artifacts/logs
|
|
```
|