Claude
Skills
Sign in
Back

terraform-secrets-management

Included with Lifetime
$97 forever

Handles sensitive data securely in Terraform. Use when managing passwords, API keys, database credentials, encryption keys, or other secrets. Covers Google Secret Manager integration, preventing secrets in state, IAM-based secret access, encryption, and security best practices.

Backend & APIs

What this skill does


# Terraform Secrets Management Skill

## Table of Contents

**Quick Start** → [What Is This](#purpose) | [When to Use](#when-to-use) | [Simple Example](#quick-start)

**How to Implement** → [Step-by-Step](#instructions) | [Examples](#examples)

**Help** → [Requirements](#requirements) | [See Also](#see-also)

## Purpose

Manage sensitive data securely without storing secrets in Terraform code or state files. Learn to use Google Secret Manager, IAM bindings, sensitive outputs, and secure secret workflows.

## When to Use

Use this skill when you need to:

- **Manage passwords securely** - Database passwords, admin credentials
- **Handle API keys** - External service authentication tokens
- **Store database credentials** - Connection strings, usernames, passwords
- **Manage encryption keys** - KMS keys, JWT secrets
- **Pass secrets to applications** - Environment variables, Kubernetes secrets
- **Rotate secrets safely** - Update secret versions without downtime
- **Prevent secrets in state** - Keep sensitive data out of Terraform state files

**Security Requirements:**
- Never hardcode secrets in .tf files
- Never commit secrets to Git
- Use Google Secret Manager for all sensitive values
- Apply least privilege IAM permissions

**Trigger Phrases:**
- "Store database password in Secret Manager"
- "Retrieve secret from Google Secret Manager"
- "Pass secrets to Kubernetes deployment"
- "Rotate secrets safely"
- "Prevent secrets in Terraform state"

## Quick Start

Retrieve a secret from Google Secret Manager safely in 3 steps:

```bash
# 1. Create secret in GCP
echo -n "MySecretPassword123" | gcloud secrets create db-password --data-file=-

# 2. Grant service account access
gcloud secrets add-iam-policy-binding db-password \
  --member="serviceAccount:[email protected]" \
  --role="roles/secretmanager.secretAccessor"

# 3. Use in Terraform
data "google_secret_manager_secret_version" "db_password" {
  secret = "db-password"
}

resource "google_sql_database_instance" "main" {
  settings {
    database_flags {
      name  = "password"
      value = data.google_secret_manager_secret_version.db_password.secret_data
    }
  }
}
```

## Instructions

### Step 1: Understand Secret Management Problem

**The Problem**:
```hcl
# ❌ NEVER DO THIS
variable "db_password" {
  type    = string
  default = "SuperSecret123"  # Now in Git history forever!
}

# Even worse
resource "google_sql_database_instance" "main" {
  settings {
    database_flags {
      name  = "password"
      value = "SuperSecret123"  # Hardcoded secret!
    }
  }
}
```

**Why This is Bad**:
- ✗ Secrets exposed in Git history (impossible to remove)
- ✗ Secrets in `.tfstate` file
- ✗ Secrets visible in plan output
- ✗ Secrets accessible to anyone with Git access
- ✗ Violates compliance (SOC2, PCI-DSS)

**The Solution**: Use Google Secret Manager

### Step 2: Set Up Google Secret Manager

**Create Secrets**:
```bash
# Create secret
echo -n "database-password-here" | gcloud secrets create db-password \
  --data-file=-

# Or create empty secret
gcloud secrets create api-key

# Update secret value
echo -n "new-password-value" | gcloud secrets versions add db-password \
  --data-file=-

# List secrets
gcloud secrets list

# View secret value (be careful!)
gcloud secrets versions access latest --secret="db-password"
```

**Secret Naming Convention**:
- Use lowercase with hyphens: `db-password`, `api-key`, `jwt-secret`
- Include environment: `db-password-prod`, `api-key-labs`
- Be specific: `github-pat` (Personal Access Token) instead of `github-key`

### Step 3: Configure IAM for Secrets

**Principle**: Only grant access to secrets that services actually need.

```bash
# Grant service account access to specific secret
gcloud secrets add-iam-policy-binding db-password \
  --member="serviceAccount:app-runtime@ecp-wtr-supplier-charges-prod.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

# Grant access to multiple secrets
gcloud secrets add-iam-policy-binding db-password \
  --member="serviceAccount:app-runtime@..." \
  --role="roles/secretmanager.secretAccessor"

gcloud secrets add-iam-policy-binding api-key \
  --member="serviceAccount:app-runtime@..." \
  --role="roles/secretmanager.secretAccessor"

# View who has access
gcloud secrets get-iam-policy db-password
```

**Terraform IAM**:
```hcl
# Grant service account secret access
data "google_service_account" "app_runtime" {
  account_id = "app-runtime"
}

resource "google_secret_manager_secret_iam_member" "db_password_access" {
  secret_id = "db-password"
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${data.google_service_account.app_runtime.email}"
}
```

### Step 4: Read Secrets in Terraform

**Read Secret Value**:
```hcl
# Data source to read secret
data "google_secret_manager_secret_version" "db_password" {
  secret = "db-password"
  # version defaults to "latest"
}

# Use secret in resource
resource "google_sql_database_instance" "main" {
  settings {
    database_flags {
      name  = "password"
      value = data.google_secret_manager_secret_version.db_password.secret_data
    }
  }
}

# Output (marks as sensitive to hide in logs)
output "db_instance_connection_string" {
  value     = google_sql_database_instance.main.connection_name
  sensitive = true  # Won't print to console
}
```

**Secret Versions**:
```hcl
# Read latest version
data "google_secret_manager_secret_version" "latest" {
  secret = "db-password"
  version = "latest"
}

# Read specific version
data "google_secret_manager_secret_version" "v1" {
  secret = "db-password"
  version = "1"
}

# Read all versions
data "google_secret_manager_secret" "db_password" {
  secret_id = "db-password"
}

# List versions
data "google_secret_manager_secret_version" "versions" {
  for_each = data.google_secret_manager_secret.db_password.versions
  secret   = "db-password"
  version  = each.key
}
```

### Step 5: Pass Secrets to Applications

**Method 1: Environment Variables**:
```hcl
# GKE deployment
resource "kubernetes_deployment" "app" {
  spec {
    template {
      spec {
        container {
          env {
            name = "DB_PASSWORD"
            value_from {
              secret_key_ref {
                name = "db-credentials"
                key  = "password"
              }
            }
          }
        }
      }
    }
  }
}
```

**Method 2: Kubernetes Secrets**:
```hcl
# Create Kubernetes secret from Google Secret Manager
resource "kubernetes_secret" "db_credentials" {
  metadata {
    name      = "db-credentials"
    namespace = "default"
  }

  data = {
    "password" = data.google_secret_manager_secret_version.db_password.secret_data
    "username" = "postgres"
    "host"     = google_sql_database_instance.main.private_ip_address
  }

  type = "Opaque"
}

# Use in deployment
resource "kubernetes_deployment" "app" {
  spec {
    template {
      spec {
        container {
          env_from {
            secret_ref {
              name = kubernetes_secret.db_credentials.metadata[0].name
            }
          }
        }
      }
    }
  }
}
```

**Method 3: Cloud Run Environment**:
```hcl
resource "google_cloud_run_service" "api" {
  template {
    spec {
      containers {
        env {
          name = "DATABASE_PASSWORD"
          value_from {
            secret_key_ref {
              name = "db-password"
            }
          }
        }
      }
    }
  }
}
```

### Step 6: Rotate Secrets Safely

**Update Secret Version**:
```bash
# Create new secret version
echo -n "new-password-value" | gcloud secrets versions add db-password \
  --data-file=-

# List versions
gcloud secrets versions list db-password

# Destroy old version (optional, usually keep for rollback)
gcloud secrets versions destroy 1 --secret="db-password"
```

**Terraform Handling of Rotation**:
```hcl
# Terraform will update to latest version automatically
data "google_secret_manager_secret_version" "db_password" {
  secret

Related in Backend & APIs