13. Secrets Manager / SSM Parameter Store
API キー・DB パスワード・設定値を コードに書かず 安全に保管する仕組み 2 種。料金・自動回転・容量で使い分けます。
どちらを使うか
| Secrets Manager | SSM Parameter Store | |
|---|---|---|
| 料金 | $0.40/secret/月 + API $0.05/10k | Standard 無料 / Advanced $0.05/parameter/月 |
| 容量上限 | 64 KB | 4 KB (Standard) / 8 KB (Advanced) |
| 自動回転 | あり(Lambda 連携) | なし |
| クロスリージョンレプリ | あり | なし |
| 適した用途 | DB / API キーで自動回転したい | 環境設定値、軽い秘密、エンドポイント等 |
原則: パスワード/API トークンは Secrets Manager、設定値・接続文字列・URL は SSM Parameter Store。
Secrets Manager
resource "random_password" "db" {
length = 32
special = true
override_special = "!#$%&*()-_=+[]{}<>:?"
}
resource "aws_secretsmanager_secret" "db" {
name = "myapp/db/master"
description = "Master credentials for myapp DB"
kms_key_id = aws_kms_key.app.arn
recovery_window_in_days = 7 # 削除後 7 日間は復旧可(即座に消すなら 0)
}
resource "aws_secretsmanager_secret_version" "db" {
secret_id = aws_secretsmanager_secret.db.id
secret_string = jsonencode({
username = "admin"
password = random_password.db.result
host = aws_db_instance.main.address
port = aws_db_instance.main.port
dbname = aws_db_instance.main.db_name
})
}
自動回転
Secrets Manager は「N 日ごとに Lambda を呼んでパスワードを変える」を組み込みでサポート。RDS なら AWS 提供の rotation Lambda がそのまま使えます。
resource "aws_secretsmanager_secret_rotation" "db" {
secret_id = aws_secretsmanager_secret.db.id
rotation_lambda_arn = aws_lambda_function.rotation.arn
rotation_rules {
automatically_after_days = 30
}
}
SSM Parameter Store
# 平文(設定値、URL など)
resource "aws_ssm_parameter" "api_endpoint" {
name = "/myapp/api/endpoint"
type = "String"
value = "https://api.example.com/v1"
}
# 暗号化(API キー、Webhook シークレット)
resource "aws_ssm_parameter" "api_key" {
name = "/myapp/external/stripe-key"
type = "SecureString"
key_id = aws_kms_alias.app.arn # CMK で暗号化(省略すると aws/ssm デフォルト)
value = var.stripe_key
lifecycle {
ignore_changes = [value] # 値は外部で更新する運用なら
}
}
# 階層構造で複数並べる
locals {
config = {
"/myapp/feature/dark_mode" = "true"
"/myapp/feature/new_ui" = "false"
"/myapp/limit/rate_per_min" = "100"
}
}
resource "aws_ssm_parameter" "feature" {
for_each = local.config
name = each.key
type = "String"
value = each.value
}
階層命名のコツ
/myapp/feature/... のようにスラッシュ区切りで名前付けすると、IAM ポリシーで arn:...:parameter/myapp/* のようにまとめて権限制御できます。
アプリから読む
# AWS CLI から
aws secretsmanager get-secret-value --secret-id myapp/db/master --query SecretString --output text
aws ssm get-parameter --name /myapp/api/endpoint --query Parameter.Value --output text
aws ssm get-parameters-by-path --path /myapp/feature/ --recursive
# ECS タスク定義から直接環境変数に注入
# secrets = [
# { name = "DB_PASSWORD", valueFrom = aws_secretsmanager_secret.db.arn }
# ]
Terraform から読む(data ソース)
data "aws_secretsmanager_secret_version" "db" {
secret_id = "myapp/db/master"
}
locals {
db = jsondecode(data.aws_secretsmanager_secret_version.db.secret_string)
}
# 使い方: locals.db.username, locals.db.password
data "aws_ssm_parameter" "api_endpoint" {
name = "/myapp/api/endpoint"
}
resource "aws_lambda_function" "x" {
environment {
variables = {
API_ENDPOINT = data.aws_ssm_parameter.api_endpoint.value
}
}
}
state に平文で残る
data ソースで取得した値は state に平文で書かれます。state を S3 に置く時は必ず KMS 暗号化+IAM 制限。最も安全なのは「Terraform で値を読まず、ARN/名前だけ渡してアプリ側で取得」する方式。