概要 #
TerraformでSecretをそのままgoogle_secret_manager_secret_versionへ書くと、値が平文でPlanやStateに残ります。Stateファイルへのアクセス権限を絞っていても、漏洩の経路が増える課題は残ります。
Terraform 1.11以降のwrite-only argumentを使えば、Secret値をPlanやStateへ残さず登録できます。ここではSecret ManagerへVersionを実際に登録し、値がStateに残らないことを確認します。
Terraformの基本操作は前提としています。Secret Managerを初めて扱う方向けです。
Secretの自動Rotationは扱いません。他ResourceからのSecret参照(例: Cloud Runの環境変数注入)も扱いません。
検証すること #
- Secret ManagerのSecretとVersionを作成できること
- Write-only ArgumentでSecret値をStateへ保存せず登録できること
- Version番号によってSecret更新をTerraformへ伝えられること
- Google Cloud CLIで登録結果を確認できること
今回の構成 #
SecretはGlobalなResourceで、Replicationの方式だけを指定します。実体の配置はGoogle Cloudが決めます。
flowchart TB
subgraph GCP["Google Cloud"]
subgraph Project["Project"]
subgraph SM["Secret Manager(Global)"]
Secret["Secret: tf-example-secret
automatic replication"]
Ver["Secret Version 1
enabled"]
Secret --- Ver
end
end
end
値の渡し方が要点です。terraform.tfvarsはGit管理外に置き、write-only argumentでStateへ書き込まれないようにします。
sequenceDiagram
participant Tfvars as terraform.tfvars
(Git管理外)
participant TF as Terraform
participant State as State
participant SM as Secret Manager
Tfvars->>TF: sensitive variable で値を渡す
TF->>SM: secret_data_wo で送信
Note over TF,State: write-only なので
Stateへは書かない
TF->>State: バージョン番号だけ記録
SM-->>TF: Secret Version 1 を作成
secret_data_wo_versionを変えると、Terraformは値が変わったと判断して新しいVersionを作ります。値そのものはStateに残りません。
使用するTerraformコード #
前提 #
- Terraform 1.11以上
- ADCで認証済み
- Secret Manager Admin相当の権限
- 検証専用のSecret値
- 検証時のバージョン:Terraform 1.14.3、google 7.43.0
Secretと自動Replication #
resource "google_secret_manager_secret" "example" {
secret_id = var.secret_id
replication {
auto {}
}
}
Secretは値を格納する親Resourceです。実際の値はSecret Versionとして追加します。autoReplicationではGoogle Cloudが保存Locationを管理します。
write-only argument #
variable "secret_data" {
type = string
sensitive = true
}
variable "secret_data_version" {
type = number
default = 1
}
resource "google_secret_manager_secret_version" "example" {
secret = google_secret_manager_secret.example.id
secret_data_wo = var.secret_data
secret_data_wo_version = var.secret_data_version
}
secret_data_woはwrite-onlyなので、値はProviderへ渡されますがTerraform PlanやStateには保存されません。
値をStateへ保持しないため、Terraformは値そのものの変更を比較できません。Secretを更新するときはsecret_data_wo_versionも増加させ、更新のTriggerとして使います。
sensitive = trueはCLI表示を隠す設定ですが、それだけで通常の値がStateへ保存されなくなるわけではありません。今回のポイントはwrite-only argumentを使用することです。
設定と実行 #
cd Basic-Examples/09-secret-manager
cp terraform.tfvars.example terraform.tfvars
project_id = "your-project-id"
secret_data = "replace-with-test-secret"
secret_data_version = 1
terraform.tfvarsはGitへコミットせず、本番のSecretではなく検証専用値を使用します。
terraform init
terraform fmt -check
terraform validate
terraform plan
terraform apply
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
Outputs:
secret_id = "tf-example-secret"
secret_name = "projects/YOUR_PROJECT_ID/secrets/tf-example-secret"
secret_version = "1"
GCP側で確認する #
Metadataを確認します。
gcloud secrets describe \
"$(terraform output -raw secret_id)" \
--project=YOUR_PROJECT_ID
値を確認します。Terminal履歴や画面共有への露出に注意してください。
gcloud secrets versions access latest \
--secret="$(terraform output -raw secret_id)" \
--project=YOUR_PROJECT_ID
値を変更する場合は次のようにVersion Triggerも更新します。
secret_data = "new-test-secret"
secret_data_version = 2
後片付けと注意点 #
terraform destroy
Secret Versionの保存やアクセスには料金が発生する場合があります。State Backend自体の暗号化・アクセス制御も引き続き必要です。
まとめ #
- SecretとSecret Versionを分けて管理できる
- write-only argumentでSecret値をStateへ残さず渡せる
- Version Triggerで値の更新タイミングを管理する
- tfvars、CLI出力、実行環境からの漏えいにも注意する
参考資料 #
- Terraform: Ephemeral values and write-only arguments
- Terraform: google_secret_manager_secret_version
次回 #
次はPub/Sub TopicとPull Subscriptionを作成します。