Slide 1

Slide 1 text

Secrets ManagerにおけるSecret値の管理 (Terraformの場合) 2026-08-15 JAWS-UG 茨城 #16 LT&BBQ大会 すずきまさし Copyright © 3-shake, Inc. All Rights Reserved.

Slide 2

Slide 2 text

おまえだれよ ● ● ● ● ● すずきまさし/masasuzu/@masasuz 株式会社スリーシェイク クラウドインフラなんでも屋さんをしてます 2026年はGoogle Cloudばかりしてます 茨城は小中高の頃毎年キャンプに来ていました ● 得意領域 ○ AWS ■ AWS Community Builder Cloud Operation Since 2024~2026 ■ 2026 Japan All AWS Certifications Engineers ○ Google Cloud ■ Google Cloud Partner Top Engineer 2026 ○ Terraform Copyright © 3-shake, Inc. All Rights Reserved. 2

Slide 3

Slide 3 text

"Secrets Managerにおける" という題にしてしまいましたが、Secrets Manager に限らず、RDSのパスワード、Parameter Store Secure StringなどのAWSリ ソースに設定するSecret値全般の課題とその取り扱いについて、今回取り扱い ます Copyright © 3-shake, Inc. All Rights Reserved. 3

Slide 4

Slide 4 text

ちなみにIaCなに使ってますか? ● ● ● ● ● Terraform? CloudFormation? CDK? Pulumi? CDK Terrain? (旧CDKTF) Copyright © 3-shake, Inc. All Rights Reserved. 4

Slide 5

Slide 5 text

目次 1. 2. 3. TerraformでSecrets値を管理することの課題 管理方法 まとめ Copyright © 3-shake, Inc. All Rights Reserved. 5

Slide 6

Slide 6 text

01 TerraformでSecrets値を管理することの課題 Copyright © 3-shake, Inc. All Rights Reserved. 6

Slide 7

Slide 7 text

素直に書いてみる resource "aws_secretsmanager_secret" "db" { name = "prd-app-db" } resource "aws_secretsmanager_secret_version" "db" { secret_id = aws_secretsmanager_secret.db.id secret_string = jsonencode({ username = "app" password = var.db_password }) } ● Secrets ManagerとSecrets ManagerのSecret値を設定しています Copyright © 3-shake, Inc. All Rights Reserved. 7

Slide 8

Slide 8 text

tfstateにはこう書かれる { } ● ● "type": "aws_secretsmanager_secret_version", "instances": [{ "attributes": { "secret_string": "{\"username\":\"app\",\"password\":\"P@ssw0rd\"}" } }] パスワードが平文で載っている !!! これはよくない Copyright © 3-shake, Inc. All Rights Reserved. 8

Slide 9

Slide 9 text

そもそも tfstateって?(状態の同期とマッピング) ① あるべき姿 (コード ) ② 前回の状態 (tfstate) # main.tf resource "aws_instance" "web" { ami = "ami-123456" instance_type = "t3.micro" tags = { Name = "web-server" } } # terraform.tfstate マッピング { } 作成したいインフラ構成の定義定義書。 Copyright © 3-shake, Inc. All Rights Reserved. ③ 実際のインフラ (AWS等) "resources": [{ "type": "aws_instance", "name": "web", "instances": [{ "attributes": { "id": "i-0abcd1234ef", "public_ip": "1.2.3.4" } }] }] 前回applyしたときの記録。 コードと実際のAWSリソースを紐付けるマッ ピングデータ。 状態検知 EC2 Instance ID: i-0abcd1234ef Status: running クラウド上に実際にプロビジョニングされ た実世界のリソース。

Slide 10

Slide 10 text

つまり、避けようがない ● ● ● terraform plan/apply時にはあるべき姿、前回の記録、実物の状態を突き合わせます 差分を出すには前回の値を覚えている必要があります tfstate はリソースの値そのものを持ちます terraform state showなどではsensitive扱いされるのでマスクがされます。 しかしながらtfstateを直接見ることができる人には Secret値が見えてしまいます。 tfsateは通常S3に保存することが多いので、 tfsate用のS3バケットにアクセス権がある人には見えうります。 Copyright © 3-shake, Inc. All Rights Reserved. 10

Slide 11

Slide 11 text

他のSecretなリソースや値も同じ 例として、Secrets Managerをあげていますが、例として以下のものも同じです。 ● ● Parameter Store の Secure String Redshift/RDSのパスワード値 Copyright © 3-shake, Inc. All Rights Reserved. 11

Slide 12

Slide 12 text

では、どうするか tfstateに値が載ってしまうのは通常に使う分には仕組み避けられない。 ここで取れるアプローチとしては 3つあります。 ● ● ● a. Secret値が平文で入り込むのは諦めて tfstateを守る Secret値をTerraformを管理しない ○ b. Secretなリソースを管理しない ○ c. Secretな値を管理しない (ignore_change) Secret値をtfstateに載せないようにする ○ d. ephemeral + write-only ○ e. sops 次ページからこれらの方法を見ていきます Copyright © 3-shake, Inc. All Rights Reserved. 12

Slide 13

Slide 13 text

02 対応策 Copyright © 3-shake, Inc. All Rights Reserved. 13

Slide 14

Slide 14 text

02-a 諦めてtfstateを守る Copyright © 3-shake, Inc. All Rights Reserved. 14

Slide 15

Slide 15 text

諦めてtfstateを守る Secret値がtfstateに入り込むこと自体は仕方ないと諦めて、 Secret値が見られないようにする ● ● ● tfstate用のバケットを最小権限にする ○ 可能な限り人間が Terraformを扱わず、機械 (CI/CD)からしか参照できないようにする CIのログにSecret値を出さないようにする ○ terraform show -json など生値が出力されるコマンドを実行しない planfileをアーティファクトに残さない いくら気を付けても、なんらかの方法で tfstateにアクセスできてしまったら Secret値は漏れることを留意すること Copyright © 3-shake, Inc. All Rights Reserved. 15

Slide 16

Slide 16 text

02-b SecretリソースをTerraform管理をそもそもしない Copyright © 3-shake, Inc. All Rights Reserved. 16

Slide 17

Slide 17 text

Secrets Managerを手動管理 そもそもTerraform管理せず、コンソールや CLIから作成すれば、 tfstateにそもそも残りません。 ただし、デメリットとして、 ● 特定のリソースだけ管理されていないので管理が煩雑に ● Secrets ManagerリソースがTerraform管理されないので、他のリソースに渡す際に arnの取り出しに一手 間必要 ● RDSのパスワードのようにリソースのパラメータが Secretなものは対応できない ○ RDSに関して言うなら自動ローテーションすれば良いという観点もある ● インフラの管理者と Secret値の管理者が別のときは良い気はしますが、同じ時は煩雑に感じます Copyright © 3-shake, Inc. All Rights Reserved. 17

Slide 18

Slide 18 text

02-c Secretなパラメータを管理しない(ignore_changes) Copyright © 3-shake, Inc. All Rights Reserved. 18

Slide 19

Slide 19 text

ignore_changes resource "aws_secretsmanager_secret_version" "db" { secret_id = aws_secretsmanager_secret.db.id secret_string = jsonencode({ username = "app" password = "PLACEHOLDER_REPLACE_ME" }) } ● ● lifecycle { ignore_changes = [secret_string] } ignore_changesに指定したパラメータは差分があっても無視されます 作成時にダミー値を入れることで tfstateは以降ダミー値しか保存されません ○ 逆に言うと最初に本当のSecret値を入れた永遠に残り続けます Copyright © 3-shake, Inc. All Rights Reserved. 19

Slide 20

Slide 20 text

02-d ephemeral + write-only Copyright © 3-shake, Inc. All Rights Reserved. 20

Slide 21

Slide 21 text

ephemeral とは Terraform 1.10 で入ったtfstate に残さないための仕組み # tfstateに記録される data "aws_secretsmanager_random_password" "db" { password_length = 32 exclude_punctuation = true } # tfstateに記録されない ephemeral "aws_secretsmanager_random_password" "db" { password_length = 32 exclude_punctuation = true } dataとして使っていたものを ephemeralにするだけで対応できます (対応data sourceのみ) Copyright © 3-shake, Inc. All Rights Reserved. 21

Slide 22

Slide 22 text

write-only 引数 Terraform 1.11 以降 ● これを使用して書かれたパラメータは tfstateに記録されません ● 従来のパラメータ名の suffixに _wo がつきます ● tfstate に無い値の差分は、原理的に計算できません ● そのためversionを利用する ○ versionがtfstateに保存されるので、この値が変わったことで変更されたと認識します ○ 逆に言うと、versionが変えなければ、 Secret値も変更されません resource "aws_secretsmanager_secret_version" "db" { secret_id = aws_secretsmanager_secret.db.id } secret_string_wo = jsonencode({ username = "app" password = ephemeral.aws_secretsmanager_random_password.db.random_password }) secret_string_wo_version = 1 Copyright © 3-shake, Inc. All Rights Reserved. 22

Slide 23

Slide 23 text

Copyright © 3-shake, Inc. All Rights Reserved. 23

Slide 24

Slide 24 text

パスワード生成から保存まで tfstate を通さない ephemeral "aws_secretsmanager_random_password" "db" { password_length = 32 exclude_punctuation = true } resource "aws_secretsmanager_secret_version" "db" { secret_id = aws_secretsmanager_secret.db.id } secret_string_wo = jsonencode({ username = "app" password = ephemeral.aws_secretsmanager_random_password.db.random_password }) secret_string_wo_version = 1 random passwordもephemeral、secret_string_woはwrite onlyなのでtfstateには残らない Copyright © 3-shake, Inc. All Rights Reserved. 24

Slide 25

Slide 25 text

外部からデータを取ってきてそれを設定する場合にも使える ephemeral "aws_ssm_parameter" "db" { arn = var.db_ssm_arn } resource "aws_secretsmanager_secret_version" "db" { secret_id = aws_secretsmanager_secret.db.id } secret_string_wo = jsonencode({ username = "app" password = ephemeral.aws_ssm_parameter.db.value }) secret_string_wo_version = 1 今回はParameter Storeからデータを取得して今すぐが、 ephemeralなのでこの値は tfstateには残らない Copyright © 3-shake, Inc. All Rights Reserved. 25

Slide 26

Slide 26 text

02-e sops Copyright © 3-shake, Inc. All Rights Reserved. 26

Slide 27

Slide 27 text

生成できない値はどうする 値がterraformで側で生成や呼び出せるものよいなら ephemeralで完結します。 でも、API キーのように値が外部で決まっているもので Terraformで呼び出せなかったり、呼び出し権限を与え たくない場合は ? terraformに -var-file オプションを付けることで gitレポジトリの外にあるパラメータファイルを読み取らせてそこか らSecret値を参照させることができます。 terraform plan -var-file="./secrets.tfvars" # git管理外のtfvarsファイルを参照 Copyright © 3-shake, Inc. All Rights Reserved. 27

Slide 28

Slide 28 text

Secret値の取り回しをしたい CI/CDでTerraformを実行するにしても、 Secret値をgit外の別の場所から持ってくるのは煩雑です。 しかしながら、 Secret値を平文でgitレポジトリに保存するのは漏洩ポイントになり得るので避けたい。 そこで利用できそうなのが sopsになります。 Copyright © 3-shake, Inc. All Rights Reserved. 28

Slide 29

Slide 29 text

sops とは ● ● ● { } 暗号化エディタ ○ https://github.com/getsops/sops YAML / JSON / ENV / INI / バイナリをサポート 暗号鍵は AWS KMSを使用 "db": { "username": "app", "password": "ENC[AES256_GCM,data:...,iv:...,tag:...,type:str]" } キーは読めるが、値は暗号化されて読めないようにできる。 これによりSecret値を”安全”にgitにコミットできます。 sops providerとしてTerraformから利用できます。 Copyright © 3-shake, Inc. All Rights Reserved. 29

Slide 30

Slide 30 text

Terraformでの利用 ● API キーをtfstateに残さないために、 ephemeralを使用する ephemeral "sops_file" "secrets" { source_file = "secrets/prod/app.enc.json" } resource "aws_secretsmanager_secret_version" "api_key" { secret_id = aws_secretsmanager_secret.api_key.id } secret_string_wo = jsondecode(ephemeral.sops_file.secrets.raw)["api_key"] secret_string_wo_version = 1 Copyright © 3-shake, Inc. All Rights Reserved. 30

Slide 31

Slide 31 text

タイトル ● ● 項目 項目 Copyright © 3-shake, Inc. All Rights Reserved. 31

Slide 32

Slide 32 text

03 まとめ Copyright © 3-shake, Inc. All Rights Reserved. 32

Slide 33

Slide 33 text

まとめ ● ● ● ● TerraformにおけるSecret値の課題を説明しました ○ tfstateファイルにはSecret値が平文で入りうります Secret値を管理するかについて説明しました ○ リソース自体管理しない ○ Secretなパラメータだけ管理しない (ignore_change) ○ tfstateに残さない方法を使う ○ Secrets値はsopsで暗号化して gitで管理できるようにする チーム状況やアプリの特性に合わせて使い分けていただけたらと思います。 Terraformについては説明しましたが、 CDKやCloudFormation、Pulumi、CDK Terrainなどではどうなの か知見が薄いので懇親会等で教えてください。 Copyright © 3-shake, Inc. All Rights Reserved. 33