Google CloudのSecret ManagerをTerraformで設定する
に公開
に公開
Google CloudでSecret Managerを使用する際に、以下のようなケースがあります。
今やってる個人開発ではTerraformを使ってインフラをコード化しているので、Secret ManagerのシークレットもTerraformで生成/管理したい気持ちがあったため、Terraformモジュールで両方に対応した方法を実装したので、その方法についてまとめていきます!
前述した通り、私はTerraformを使う時はモジュール構成で管理しているので、以下のようなディレクトリ構成になっています。
./terraform
├── gcp
│ ├── dev
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── versions.tf
│ │ └── terraform.tfvars
│ └── modules
│ ├── project_services
│ │ ├── main.tf
│ │ └── variables.tf
│ └── secret_manager
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
└── terraform.mk各ファイルは以下のようになっています。
variable "project_id" {
description = "Google CloudプロジェクトID"
type = string
}
variable "secret_id" {
description = "シークレットの名前"
type = string
}
variable "auto_generate" {
description = "パスワードを自動生成するか"
type = bool
default = true
}
variable "secret_data" {
description = "auto_generate=false の場合に使う値"
type = string
default = ""
sensitive = true
validation {
condition = var.auto_generate || var.secret_data != ""
error_message = "auto_generate=false の場合は secret_data が必須です"
}
}
variable "password_length" {
description = "自動生成するパスワードの長さ"
type = number
default = 24
}auto_generate 変数で自動生成するか手動設定するかを切り替えられるようにしています。
resource "random_password" "main" {
count = var.auto_generate ? 1 : 0
length = var.password_length
special = false
}
resource "google_secret_manager_secret" "main" {
project = var.project_id
secret_id = var.secret_id
replication {
auto {}
}
}
resource "google_secret_manager_secret_version" "main" {
secret = google_secret_manager_secret.main.id
secret_data = var.auto_generate ? random_password.main[0].result : var.secret_data
depends_on = [random_password.main]
}random_password リソースを count 属性で制御し、自動生成が有効な場合のみパスワードを生成するようにしています。
また、google_secret_manager_secret_version リソースの depends_on 属性で、random_password リソースの生成を待つようにしています。
output "secret_id" {
value = google_secret_manager_secret.main.secret_id
}
output "secret_data" {
value = var.auto_generate ? random_password.main[0].result : var.secret_data
sensitive = true
}outoputs.tfは生成されたsecretを参照するために用意しています。
secret_data 出力も auto_generate に応じて適切な値を返すようにしています。
# 手動設定用の変数(必要な場合のみ)
variable "external_api_key" {
type = string
default = ""
sensitive = true
}
locals {
env = "dev"
gcp_project = "your-project-id"
secrets = {
# 自動生成パターン
db_password = {
secret_id = "myapp-${local.env}-db-password"
auto_generate = true
}
# 手動設定パターン
external_api_key = {
secret_id = "myapp-${local.env}-external-api-key"
auto_generate = false
secret_data = var.external_api_key
}
}
}手動設定用の変数 external_api_key を定義し、locals ブロックで環境ごとの設定をまとめています。
secrets マップで各シークレットの設定を管理しています。
module "secrets" {
source = "../modules/secret_manager"
for_each = local.secrets
project_id = local.gcp_project
secret_id = each.value.secret_id
auto_generate = lookup(each.value, "auto_generate", true)
secret_data = lookup(each.value, "secret_data", "")
password_length = lookup(each.value, "password_length", 24)
depends_on = [module.project_services]
}for_each を使用して、locals.secrets マップに基づいて複数のシークレットを生成しています。
手動の値が必要な場合は、以下のように terraform.tfvars ファイルで指定します。
external_api_key = "your-api-key-here"terraform.tfvars ファイルで手動設定用のシークレット値を指定しています。
module "secrets" {
for_each = local.secrets
# ...
}こうしておくことで、シークレットを追加したい時はlocals.secrets に新しいエントリを追加するだけで済み、コードの重複を避けられます。
| 値 | 動作 |
|---|---|
true | random_password で自動生成 |
false | secret_data の値を使用 |
validation {
condition = var.auto_generate || var.secret_data != ""
error_message = "auto_generate=false の場合は secret_data が必須です"
}auto_generate = false で secret_data を渡し忘れるとplan時点でエラーになります。
variable "secret_data" {
sensitive = true
}これを入れることで、Terraformのログにシークレットの中身が出力されるのを防げます。
今回は、Google CloudのSecret ManagerでシークレットをTerraformで管理する方法について解説しました。 自動生成と手動設定の両方に対応できるようにすることで、柔軟にシークレット管理ができるようになって、個人的には便利な実装に感じています。