Upgrade to Pro — share decks privately, control downloads, hide ads and more …

2026-04-14 Jagu'e'r Cloud Native分科会 Terraform S...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

2026-04-14 Jagu'e'r Cloud Native分科会 Terraform Stateにおけるシークレットの平文保存という課題とその解決

Terraform Stateにおけるシークレットの平文保存という課題とその解決

[0ベースから学ぶ、クラウドネイティブの春! - connpass](https://jaguer-cloud-native.connpass.com/event/387350/) で発表した内容

Avatar for SUZUKI Masashi

SUZUKI Masashi

April 14, 2026

More Decks by SUZUKI Masashi

Other Decks in Technology

Transcript

  1. おまえだれよ 名前: すずきまさし/x:@masasuz/masasuzu 所属: 株式会社スリーシェイク シニアアーキテクト クラウドインフラ何でも屋さん すきなもの: AWS, Google

    Cloud, Terraform 2024-2025 AWS Community Builder Cloud Operations 2025 Japan All AWS Certifications Engineers Google Cloud Partner Top Engineer 2026 2
  2. TerraformとStateの関係 .tf ファイル リソース定義(コード) Terraform plan / apply で差分を検出・適⽤ ↕

    両者を⽐較 Google Cloud 実際のクラウドリソース terraform.tfstate リソースの現在の状態 全属性値を平⽂で記録 読み取り API呼び出し 状態を記録 .tf ファイルが設計図、Stateが現場の台帳 Terraformは両者を比較して差分を検出・適用する Stateにはリソースの全属性値が平文で記録される ← ここが問題 5
  3. Stateファイルの中身 実際のstateファイルを見てみると... { "type": "google_secret_manager_secret_version", "name": "api_key", "instances": [ {

    "attributes": { "secret": "projects/my-project/secrets/my-api-key", "secret_data": "sk-1234567890abcdef", // ← 平文! "version": "1" }, "sensitive_attributes": [[{ "type": "get_attr", "value": "secret_data" }]] } ] } Secret Managerに保存したはずのシークレットが、stateに平文で入っている ※ sensitive_attributes はCLI表示をマスクするためのメタデータ。state内の値自体は保護しない 6
  4. ワークツリーを守っても、stateから漏れる sops provider や google_kms_secret でシークレットを暗号化してリポジトリに保存していても、 Terraformが復号した値はstateに平文で書き込まれる 暗号化された値 sops provider

    google_kms_secret 🔒 安全 Terraform Cloud KMS等で復号 plan / apply terraform.tfstate 平⽂で保存! ⚠ ここから漏れる リポジトリ上のシークレット管理に気を配っていても、stateという意外な場所から漏れうる ※ google_kms_secret にはephemeral版が存在しない。 sops provider の sops_file にはephemeralがありま す。 7
  5. sensitive = true では不十分 sensitive = true は、 terraform plan

    / apply / output のCLI出力時に値を <sensitive> にマスクするため のフラグ output "api_key" { value = data.google_secret_manager_secret_version.api_key.secret_data sensitive = true } CLI出力はマスクされる: $ terraform output api_key = <sensitive> ここまでは安心。では stateファイルの中身は? 8
  6. sensitive = true では不十分(続き) しかし stateファイル内は: "outputs": { "api_key": {

    "value": "sk-1234567890abcdef", "sensitive": true } } "sensitive": true のすぐ隣に平文でAPIキーが並んでいる 9
  7. Stateが漏洩したら? Stateファイルへの読み取り権 = 全シークレットへのアクセス権 → サービスアカウントキーの窃取、APIキーの不正利用に直結する  DBパスワードはPrivate Network内なのでまだマシ。APIキーは外から直接使えてしまう よくある漏洩経路 Gitへの誤コミット

    — .gitignore への追加忘れ GitHubで path:**/terraform.tfstate を検索すると...なんかいっぱいありますね 共有ストレージの権限設定ミス — GCS/S3バケットの公開 CI/CDログ — TF_LOG=TRACE でHTTPボディが丸見え stateに書かれないようにしたい。 でもどうやって? Terraform 1.10 / 1.11 で、stateに書かないための仕組みが導入された 10
  8. Ephemeral Resourcesとは 一時的なリソース。Stateに一切保存されない。 最高。 Data Source の代わりに、機密情報をGoogle Cloudから取得するときに使用する Terraform 1.10

    で導入(2024年11月) plan / apply の実行中のみ存在し、実行後は破棄される Stateファイルにもplanファイルにも書き込まれない 毎回新鮮な値が取得される ユースケース サービスアカウントの一時アクセストークン Secret Managerのシークレット値の読み取り 短命の認証情報全般 12
  9. Before: data で取得するとstateに残る # Secret Managerからシークレットを取得 data "google_secret_manager_secret_version" "api_key" {

    secret = "my-api-key" } # → stateにシークレットの値が平文で保存される "attributes": { "secret_data": "sk-1234567890abcdef", // ← stateに残る! "secret": "projects/my-project/secrets/my-api-key" } 13
  10. After: ephemeral で取得するとstateに残らない # 同じSecret Managerからシークレットを取得 ephemeral "google_secret_manager_secret_version" "api_key" {

    secret = "my-api-key" } # → stateには何も保存されない data を ephemeral に変えるだけ。stateにシークレットが残らなくなる 14
  11. Google Providerの対応リソース Ephemeral Resource 用途 google_service_account_access_token SAの一時アクセストークン google_service_account_id_token SAのIDトークン google_service_account_jwt

    SAのJWT生成 google_service_account_key SAキー情報の取得 google_secret_manager_secret_version Secret Managerのシークレット値 google_client_config Provider設定情報(access_token含む) 6リソース対応(2026年4月 / Provider v7.27.0時点) 16
  12. 既存コードの修正は実質2行 resource "google_sql_user" "db_user" { name = "app-user" instance =

    google_sql_database_instance.main.name # password ではなく password_wo を使う password_wo = var.db_password # stateに保存されない password_wo_version = 1 # 変更時にインクリメント } password → password_wo に変えて、 password_wo_version を追加するだけ 19
  13. _wo_version の仕組み Stateに値が保存されない = Terraformは前回と今回でパスワードが変わったか比較できない → 変更を伝える別の手段が必要 → それが _wo_version

    _wo_version (整数)はstateに保存される パスワードを変更したら _wo_version をインクリメント Terraformは _wo_version の変更を検知してapplyを実行する 注意: _wo_version をインクリメントし忘れると、パスワードを変えても反映されない 20
  14. Before / After: Stateの中身 Before: password を使った場合 "attributes": { "name":

    "app-user", "password": "S3cret!P@ssw0rd-12345", // ← 平文で保存 "project": "my-gcp-project-id" } After: password_wo を使った場合 "attributes": { "name": "app-user", "password_wo": null, // ← 保存されない! "password_wo_version": 1, "project": "my-gcp-project-id" } たったこれだけで、パスワードがstateから消える 21
  15. Google Providerの対応リソース リソース Write-Only属性 google_sql_user password_wo google_secret_manager_secret_version secret_data_wo google_bigquery_data_transfer_config sensitive_params.secret_access_key_wo

    google_compute_vpn_tunnel shared_secret_wo google_alloydb_cluster initial_user.password_wo google_alloydb_user password_wo google_compute_ssl_certificate private_key_wo google_compute_region_ssl_certificate private_key_wo google_monitoring_notification_channel sensitive_labels.*_wo (3属性) 9リソース / 11属性対応(同時点) 22
  16. 使い分けの目安 Ephemeral Resources Write-only Attributes 方向 読み取り専用 書き込み専用 用途 トークン取得、シークレット参照

    パスワード設定、秘密鍵設定 例 SAアクセストークン、Secret Manager Cloud SQLパスワード、SSL秘密鍵 迷ったら: 「値を取得して使う」→ Ephemeral、 「値を設定する」→ Write-only 23
  17. まとめ 1. Terraform stateにはシークレットが平文で保存される sensitive = true はCLI表示のマスクのみ。stateは守れない 2. Ephemeral

    Resources で一時認証情報をstateに残さない Terraform 1.10+ / SA トークンやSecret Manager の値に対応 3. Write-only Attributes でパスワードをstateに残さない Terraform 1.11+ / Cloud SQL, AlloyDB, Secret Manager 等に対応 やること Terraform 1.11+ / Google Provider 7.6+ にアップデートして、 _wo 属性と ephemeral リソースへの移行を始めよう Stateの中身、一度覗いてみてください。思ったより怖いものが見えるかもしれません。 26
  18. sensitive vs Ephemeral vs Write-only 比較 観点 sensitive = true

    Ephemeral Resources Write-only ( _wo ) Stateへの保存 保存される(平文) 保存されない 保存されない CLI表示 <sensitive> 非表示 (write-only) 変更検知 値の差分で検知 毎回再取得 _wo_version で検知 用途 最低限のマスキング 一時認証情報 パスワード・APIキー Terraformバージョン v0.14+ v1.10+ v1.11+ 29
  19. バージョン要件 Terraform本体 機能 必要バージョン sensitive = true v0.14+ Ephemeral Resources

    v1.10+ Write-only Attributes v1.11+ Google Cloud Provider 機能 必要バージョン 初のEphemeral Resource(SA系4種) v6.13.0+ 初のWrite-only Attribute v6.23.0+ Secret Manager ephemeral対応 v7.6.0+ client_config ephemeral対応 v7.10.0+ 推奨: Terraform >= 1.11 + Google Provider >= 7.6+ 30
  20. 多層防御(Defense in Depth) シークレット管理は一つの対策だけでは不十分。組み合わせが重要。 レイヤー 対策 効果 1. リポジトリ sops

    provider / google_kms_secret 等で暗 号化 Gitリポジトリに平文シークレットを残 さない 2. Stateソースレベ ル Ephemeral / Write-only シークレットをstateに保存しない 3. State保存時暗号 化 GCS + Cloud KMS (CMEK) stateファイルを暗号化保存 4. アクセス制御 IAM最小権限 + 公開防止 不正アクセスを防止 5. 運用 .gitignore + バージョニング 誤コミット防止 + リカバリ 32
  21. シークレット取得方法のephemeral対応状況 方式 stateに残る ephemeral対応 data "sops_file" 残る あり(sops provider v1.3.0+)

    data "google_kms_secret" 残る なし(ephemeral版が存在しない) data "google_secret_manager_secret_version" 残る あり(Google Provider v7.6.0+) google_kms_secret を使っている場合は現状だと別の方式を利用したほうが良い 33
  22. 参考リンク Terraform provider for Google Cloud 7.0 is now GA

    (HashiCorp Blog) Terraform 1.10: Ephemeral Values (HashiCorp Blog) Terraform 1.11: Write-only Arguments (HashiCorp Blog) Use ephemeral resources in the Google Cloud provider Use write-only attributes in the Google Cloud provider Sensitive Data in State (HashiCorp) Google Provider 7.0 Upgrade Guide 34