メインコンテンツへスキップ

ステートとプランの暗号化

OpenTofuは、ローカルストレージとバックエンドを使用する場合の両方で、保存時のステートファイルとプランファイルの暗号化をサポートしています。さらに、terraform_remote_stateデータソースで暗号化を使用することもできます。このページでは、暗号化の設定方法と、どのユースケースに適した暗号化方式であるかを説明します。

一般的なガイダンスと注意点(必ずお読みください)

暗号化を有効にすると、適切な暗号化キーがない限り、ステートファイルとプランファイルは復元できなくなります。暗号化を有効にする前に、このセクションを注意深くお読みください。

暗号化はどのような攻撃を防ぐのか?

暗号化を有効にすると、OpenTofuはステートデータを保存時に暗号化します。攻撃者がステートファイルへのアクセス権を取得した場合でも、ステートファイルに含まれる機密値(アクセスキーなど)を読み取ったり使用したりすることはできないはずです。

ただし、暗号化はデータ損失(ステートファイルの破損)を防ぐことはできず、リプレイ攻撃(攻撃者が古いステートファイルまたはプランファイルを使用して、実行するようにだます)も防ぐことはできません。さらに、OpenTofuはtofuコマンドを実行する人からステートファイル内の機密値を保護することはできず、また保護しません。

どのような予防措置が必要ですか?

暗号化を有効にするときは、誰がステートファイルに直接アクセスする必要があるかを検討してください。非常に少数のユーザーしかアクセスする必要がない場合は、本番環境のplanおよびapply実行を継続的インテグレーションシステムから実行して、暗号化キーとステート内の機密値の両方を保護することを検討してください。

また、セキュリティ要件に基づいて、どの種類のキーを使用するかを決定する必要があります。静的なパスフレーズを選択することも、キー管理システムを選択することもできます。キー管理システムを選択する場合は、一部の暗号化方式で自動キーローテーションを構成することが不可欠です。これは、選択した暗号化アルゴリズムが、AES-GCMなどのキーの最大安全使用制限に近づく「キー飽和」に達する可能性がある場合に特に重要です。詳細については、以下の暗号化方式セクションをご覧ください。

最後に、暗号化を有効にする前に、障害復旧計画を実行し、暗号化されていないステートファイルの仮バックアップを作成してください。また、キーのバックアップがあることを確認してください。暗号化を有効にすると、OpenTofuは正しいキーがないとステートファイルを読み取ることができなくなります。

暗号化されていないステート/プランからの移行

既存のステートファイルがあり、暗号化を有効にしたい場合は、OpenTofuがプレーンテキストデータの読み取りを拒否するため、暗号化を有効にするだけでは不十分です。これは、OpenTofuが操作された暗号化されていないデータを読み取るのを防ぐための保護メカニズムです。詳細な移行手順については、以下の初期設定セクションをご覧ください。

互換性の保証

暗号化の研究は急速に進歩する可能性があります。ドキュメントに記載されているすべてのキープロバイダーと方式は+1マイナーバージョンでサポートしますが、同じキープロバイダーと方式(例:aes_gcm_v2)の新しいバージョン、または任意のマイナーバージョンで新しいキープロバイダーと方式を導入する可能性があります。キープロバイダーまたは方式を非推奨にする場合は、tofu planまたはtofu applyを実行するときにコンソールに警告が表示されます。そのような警告が表示された場合は、次のバージョンにアップグレードする前に切り替えてください。

設定

OpenTofuでは、OpenTofuコードで設定を指定するか、TF_ENCRYPTION環境変数を使用することで暗号化を設定できます。どちらの解決策も同等であり、両方を使用する場合は、OpenTofuが2つの設定をマージし、コードベースの設定を環境設定で上書きします。

基本的な設定構造は次のようになります。

コードブロック
terraform {
encryption {
key_provider "some_key_provider" "some_name" {
# Key provider options here
}

method "some_method" "some_method_name" {
# Method options here
keys = key_provider.some_key_provider.some_name
}

state {
# Encryption/decryption for state data
method = method.some_method.some_method_name
}

plan {
# Encryption/decryption for plan data
method = method.some_method.some_method_name
}

remote_state_data_sources {
# See below
}
}
}

キーとメソッドのロールオーバー

場合によっては、暗号化設定を変更したい場合があります。これには、キープロバイダーまたはメソッドの名前の変更、キープロバイダーのパスフレーズの変更、キー管理システムの切り替えなどが含まれます。OpenTofuは、古い設定をfallbackブロックで提供すれば、暗号化設定の自動ロールオーバーをサポートします。

コードブロック
terraform {
encryption {
# Methods and key providers here.

state {
method = method.some_method.new_method
fallback {
method = method.some_method.old_method
}
}

plan {
method = method.some_method.new_method
fallback {
method = method.some_method.old_method
}
}
}
}

OpenTofuが新しいメソッドで状態ファイルまたはプランファイルを読み込むことに失敗した場合、フォールバックメソッドを自動的に試行します。OpenTofuが状態ファイルまたはプランファイルを保存する際、常に新しいメソッドを使用し、フォールバックメソッドは使用しません。

初期設定

新しいプロジェクト

新しいプロジェクトをセットアップし、まだ状態ファイルがない場合は、このサンプル設定でパスフレーズベースの暗号化を開始できます。

コードブロック
variable "passphrase" {
# Change passphrase to be at least 16 characters long:
default = "changeme!"
}

terraform {
encryption {
## Step 1: Add the desired key provider:
key_provider "pbkdf2" "mykey" {
passphrase = var.passphrase
}
## Step 2: Set up your encryption method:
method "aes_gcm" "new_method" {
keys = key_provider.pbkdf2.mykey
}

state {
## Step 3: Link the desired encryption method:
method = method.aes_gcm.new_method

## Step 4: Run "tofu apply".

## Step 5: Consider adding the "enforced" option:
# enforced = true
}

## Step 6: Repeat steps 3-5 for plan{} if needed.
}
}

既存のプロジェクト

既存のプロジェクトで最初に暗号化を構成する場合、状態ファイルとプランファイルは暗号化されていません。OpenTofuはデフォルトで、それらが操作された可能性があるため、読み込みを拒否します。暗号化されていないデータの読み込みを有効にするには、unencryptedメソッドを指定する必要があります。

コードブロック
variable "passphrase" {
# Change passphrase to be at least 16 characters long:
default = "changeme!"
}

terraform {
encryption {
## Step 1: Add the unencrypted method:
method "unencrypted" "migrate" {}

## Step 2: Add the desired key provider:
key_provider "pbkdf2" "mykey" {
passphrase = var.passphrase
}

## Step 3: Add the desired encryption method:
method "aes_gcm" "new_method" {
keys = key_provider.pbkdf2.mykey
}

state {
## Step 4: Link the desired encryption method:
method = method.aes_gcm.new_method

## Step 5: Add the "fallback" block referencing the
## "unencrypted" method.
fallback {
method = method.unencrypted.migrate
}

## Step 6: Run "tofu apply".

## Step 7: Remove the "fallback" block above and
## consider adding the "enforced" option:
# enforced = true
}

## Step 8: Repeat steps 4-8 for plan{} if needed.
}
}

暗号化のロールバック

上記の初期設定と同様に、以下のようにunencryptedメソッドを使用することで、暗号化されていない状態ファイルとプランファイルへの移行も可能です。

コードブロック
terraform {
encryption {
## Step 1: Leave the original encryption method unchanged:
method "some_method" "old_method" {
## Parameters for the old method here.
}

# Step 2: Add the unencrypted method here:
method "unencrypted" "migrate" {}

state {
## Step 3: Disable or remove the "enforced" option:
enforced = false

## Step 4: Move the original encryption method into the "fallback" block:
fallback {
method = method.some_method.old_method
}

## Step 5: Reference the unencrypted method as your primary "encryption" method.
method = method.unencrypted.migrate
}

## Step 6: Run "tofu apply".

## Step 7: Remove the "state" block once the migration is complete.

## Step 8: Repeat steps 3-7 for plan{} if needed.
}
}

リモート状態データソース

terraform_remote_stateデータソースを使用するプロジェクトの暗号化設定も構成できます。これはメインの設定と同じ暗号化設定にすることができますが、別のキーとメソッドのセットを定義することもできます。設定構文は次のとおりです。

コードブロック
terraform {
encryption {
# Key provider and method configuration here

remote_state_data_sources {
default {
method = method.my_method.my_name
}
remote_state_data_source "my_state" {
method = method.my_method.my_other_name
}
}
}
}

data "terraform_remote_state" "my_state" {
# ...
}

特定のリモート状態については、次の構文を使用できます。

  • mynameは、メインプロジェクト内の指定された名前のデータソースをターゲットにします。
  • mymodule.mynameは、指定されたモジュール内の指定された名前のデータソースをターゲットにします。
  • mymodule.myname[0]は、指定されたモジュール内の指定された名前の最初のデータソースをターゲットにします。

キープロバイダー

PBKDF2

PBKDF2キープロバイダーを使用すると、長いパスフレーズを使用して、AES-GCMなどの暗号化メソッドのキーを生成できます。次のように構成できます。

コードブロック
terraform {
encryption {
key_provider "pbkdf2" "foo" {
# Specify a long / complex passphrase (min. 16 characters)
passphrase = "correct-horse-battery-staple"

# Adjust the key length to the encryption method (default: 32)
key_length = 32

# Specify the number of iterations (min. 200.000, default: 600.000)
iterations = 600000

# Specify the salt length in bytes (default: 32)
salt_length = 32

# Specify the hash function (sha256 or sha512, default: sha512)
hash_function = "sha512"
}
}
}
オプション説明最小デフォルト
パスフレーズ(必須)長く複雑なパスフレーズを入力します。16文字。-
key_lengthキーとして生成するバイト数。132
iterations繰り返しの回数。推奨事項については、このドキュメントを参照してください。200.000600.000
salt_lengthキー導出のためのソルトの長さ。132
hash_functionハッシュ関数として使用するsha256またはsha512のいずれかを指定します。sha1はサポートされていません。N/Asha512

AWS KMS

このキープロバイダーは、Amazon Web Servers Key Management Serviceを使用してキーを生成します。認証オプションは、非推奨のオプションを除き、S3バックエンドと同じです。さらに、次のオプションを指定してください。

オプション説明最小デフォルト
kms_key_idAWS KMSのキーID.1-
key_specAWS KMSのキースペック。これを暗号化メソッド(例:AES_256)に適合させます。1-

次の例は、最小限の構成を示しています。

コードブロック
terraform {
encryption {
key_provider "aws_kms" "basic" {
kms_key_id = "a4f791e1-0d46-4c8e-b489-917e0bec05ef"
region = "us-east-1"
key_spec = "AES_256"
}
}
}

GCP KMS

このキープロバイダーは、Google Cloud Key Management Serviceを使用してキーを生成します。認証オプションは、非推奨のオプションを除き、GCSバックエンドと同じです。さらに、次のオプションを指定してください。

オプション説明最小デフォルト
kms_encryption_key (必須)GCP KMSのキーID.N/A-
key_length (必須)キーとして生成するバイト数。1から1024バイトの範囲内である必要があります。1-

次の例は、最小限の構成を示しています。

コードブロック
terraform {
encryption {
key_provider "gcp_kms" "basic" {
kms_encryption_key = "projects/local-vehicle-id/locations/global/keyRings/ringid/cryptoKeys/keyid"
key_length = 32
}
}
}

OpenBao(実験的)

このキープロバイダーは、OpenBao Transit Secret Engineを使用してデータキーを生成します。次のように構成できます。

オプション説明最小デフォルト
key_name (必須)データキーの暗号化/復号化に使用するトランジット暗号化キーの名前。OpenBaoサーバーで事前構成します。N/A-
tokenOpenBao APIへのアクセス時に使用する認証トークン。OpenTofuは、BAO_TOKEN環境変数からも読み取ることができます。N/A-
addressAPIにアクセスするためのOpenBaoサーバーのアドレス。OpenTofuは、BAO_ADDR環境変数からも読み取ることができます。システムは、サーバーのTLS証明書を信頼する必要があります。N/Ahttps://127.0.0.1:8200
transit_engine_pathTransit Secret EngineがOpenBaoで有効になっているパス。トランジットエンジンのパスを変更した場合は、これをカスタマイズします。N/A/transit
key_lengthキーとして生成するバイト数。使用可能なオプションは、1632、または64バイトです。1632

次の例は、可能な構成を示しています。

コードブロック
terraform {
encryption {
key_provider "openbao" "my_bao" {

# Required. Name of the transit encryption key
# to use to encrypt/decrypt the data key.
key_name = "test-key"

# Optional. Authorization Token to use when accessing OpenBao API.
# You can also set this in the BAO_TOKEN environment variable.
token = "s.Fg8wA4nDrP08TirpjEXkrTmt"

# Optional. OpenBao server address to access the API on.
# You can also set this using the BAO_ADDR environment variable.
address = "http://127.0.0.1:8200"

# Optional. You can customize this if you mounted the
# transit engine on a different path. Default: /transit
transit_engine_path = "/my-org/transit"

# Optional. Number of bytes to generate as a key. Default: 32
key_length = 16
}
}
}

メソッド

AES-GCM

現在サポートされている唯一の暗号化メソッドはAES-GCMです。次の方法で構成できます。

コードブロック
terraform {
encryption {
# Key provider configuration here

method "aes_gcm" "yourname" {
keys = key_provider.yourkeyprovider.yourname
}
}
}

暗号化されていない

unencryptedメソッドは、暗号化との間で明示的な移行パスを提供するために使用されます。構成は必要なく、上記の初期設定ブロックで使用されていることがわかります。