- OpenTofu言語
- ステート
- ステートとプランの暗号化
ステートとプランの暗号化
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つの設定をマージし、コードベースの設定を環境設定で上書きします。
基本的な設定構造は次のようになります。
- コード
- 環境(Linux/UNIXシェル)
- 環境(Powershell)
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
}
}
}
TF_ENCRYPTION=$(cat <<EOF
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
}
EOF)
$Env:TF_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
}
"@
データを暗号化したら、設定内のキープロバイダーやメソッドの名前を変更しないでください。バックエンドに保存された暗号化データには、それらの具体的な名前に関連するメタデータが含まれています。代わりに、キープロバイダーの変更を処理するためにフォールバックブロックを使用してください。
暗号化設定には、HCLの代わりにJSON設定構文を使用できます。
環境設定を使用する場合、環境変数が存在しない場合に暗号化されていないデータが書き込まれないように、次のコード設定を含めることができます。
terraform {
encryption {
state {
enforced = true
}
plan {
enforced = true
}
}
}
キーとメソッドのロールオーバー
場合によっては、暗号化設定を変更したい場合があります。これには、キープロバイダーまたはメソッドの名前の変更、キープロバイダーのパスフレーズの変更、キー管理システムの切り替えなどが含まれます。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.
}
}
変数とローカル変数は設定で使用できますが、状態またはプロバイダーで定義された関数内のデータへの参照を含めることはできません。すべての値は、状態が利用可能になる前のtofu init
中に解決できる必要があります。
暗号化のロールバック
上記の初期設定と同様に、以下のように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 | キーとして生成するバイト数。 | 1 | 32 |
iterations | 繰り返しの回数。推奨事項については、このドキュメントを参照してください。 | 200.000 | 600.000 |
salt_length | キー導出のためのソルトの長さ。 | 1 | 32 |
hash_function | ハッシュ関数として使用するsha256 またはsha512 のいずれかを指定します。sha1 はサポートされていません。 | N/A | sha512 |
AWS KMS
このキープロバイダーは、Amazon Web Servers Key Management Serviceを使用してキーを生成します。認証オプションは、非推奨のオプションを除き、S3バックエンドと同じです。さらに、次のオプションを指定してください。
オプション | 説明 | 最小 | デフォルト |
---|---|---|---|
kms_key_id | AWS KMSのキーID. | 1 | - |
key_spec | AWS 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 | - |
token | OpenBao APIへのアクセス時に使用する認証トークン。OpenTofuは、BAO_TOKEN 環境変数からも読み取ることができます。 | N/A | - |
address | APIにアクセスするためのOpenBaoサーバーのアドレス。OpenTofuは、BAO_ADDR 環境変数からも読み取ることができます。システムは、サーバーのTLS証明書を信頼する必要があります。 | N/A | https://127.0.0.1:8200 |
transit_engine_path | Transit Secret EngineがOpenBaoで有効になっているパス。トランジットエンジンのパスを変更した場合は、これをカスタマイズします。 | N/A | /transit |
key_length | キーとして生成するバイト数。使用可能なオプションは、16 、32 、または64 バイトです。 | 16 | 32 |
次の例は、可能な構成を示しています。
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
}
}
}
OpenTofuリリースが作成された時点でOpenBaoの安定版リリースがなかったため、OpenBaoキープロバイダーは現在実験段階です。
OpenBaoキープロバイダーは、HashiCorp Vaultの最後のMPLライセンスバージョン(1.14)と互換性がありますが、後続のBUSLライセンスバージョンはサポートしていません。
メソッド
AES-GCM
現在サポートされている唯一の暗号化メソッドはAES-GCMです。次の方法で構成できます。
terraform {
encryption {
# Key provider configuration here
method "aes_gcm" "yourname" {
keys = key_provider.yourkeyprovider.yourname
}
}
}
AES-GCMメソッドには、16、24、または32バイトのキーが必要です。この正確な長さのキーを提供するようにキープロバイダーを構成してください。
AES-GCMは安全な業界標準の暗号化アルゴリズムですが、「キー飽和」の影響を受けます。安全なセットアップを構成するには、長く複雑なパスフレーズを使用したキー導出キープロバイダー(PBKDF2など)を使用するか、キーを定期的に自動的にローテーションするキー管理システムを使用する必要があります。短く静的なキーを使用すると、暗号化が低下します。
暗号化されていない
unencrypted
メソッドは、暗号化との間で明示的な移行パスを提供するために使用されます。構成は必要なく、上記の初期設定ブロックで使用されていることがわかります。