背景・目的
以前、下記のとおりTerraformについて整理・試してきました。
今回は、詳解 Terraform 第3版の、「第6章 シークレットを管理する」を整理、試します。
まとめ
下記に特徴をまとめます
特徴 | 説明 |
---|---|
シークレットの種類 | ・個人 ・顧客 ・インフラ |
個人シークレット | 個人に紐づくもの。下記のようなものがある ・Webサイトのユーザとパスワード ・SSHキー ・PGPキー |
顧客シークレット | 顧客に紐づくもの。下記のようなものがある ・顧客が自社の製品にログインするユーザとパスワード ・顧客の個人情報(PII) ・顧客の顧客健康情報(PHI) |
インフラシークレット | インフラに紐づくもの。下記のようなものがある ・DBのパスワード ・APIキー |
シークレットが必要な場面 | ・プロバイダの認証 ・リソースとデータソース ・ステートファイルとプランファイル |
概要
ソフトウェアでは、DBのパスワード、APIキー、TLS証明書、SSHキー、GPGキーなど様々なシークレットキーを使用します。
ここでは、このシークレット情報を安全に管理するために下記の内容を整理します。
- シークレット管理の基本
- シークレット管理ツール
- シークレット管理ツールとTerraform
シークレット管理の基本
- プレーンテキストで保存せずに、シークレット管理ツールを使用すること
シークレット管理ツール
保存するシークレットの種類
下記の3つの基本的種類がある
- 個人シークレット
- 個人に紐づき、下記のようなものがある
- Webサイトのユーザとパスワード
- SSHキー
- PGPキー
- 個人に紐づき、下記のようなものがある
- 顧客シークレット
- 顧客に紐づき、下記のようなものがある
- 顧客が自社の製品にログインするユーザとパスワード
- 顧客の個人情報(PII)
- 顧客の顧客健康情報(PHI)
- 顧客に紐づき、下記のようなものがある
- インフラシークレット
- インフラに紐づき、下記のようなものがある
- DBのパスワード
- APIキー
- インフラに紐づき、下記のようなものがある
ほとんどのシークレット管理ツールは、上記のシークレットのどれか1つを保存されているように設計されている。
他の種類のシークレットを無理やり保存できるが、セキュリティやユーザビリティの観点から推奨しない。
例えば、下記のようなものがある。
- 顧客シークレット
- ソルトを使ったハッシュアルゴリズムなどが使われる
- 元のパスワードを得る必要はない
- インフラシークレット
- AES256やワンタイムパスワードなどが使われる
- シークレットを複合し、元のパスワードを戻せるようにする
シークレットの保存方法
シークレットストアの保存方法として、よく使われるもの。
- ファイルベースのシークレットストア
- 集中型のシークレットストア
ファイルベースのシークレットストア
シークレットを暗号化されたファイルに保存する。この暗号化するには、暗号化キーが必要である。
そして、このキー自体がシークレットであり解決するには、キーマネージメントシステムがよく使われる。
- AWS KMS
- GCP KMS
- Azure Key Vault
または、PGPなどを利用する。
集中型のシークレットストア
ネットワーク越しにアクセスするWebサービスであることが多く、シークレットを暗号化し、それらをMySQLなどのデータストアに保存する。集中型のシークレットストアでは、これらのシークレットを保存するのに暗号化キーを必要とする。
この暗号化キーは、通常サービス自身で管理するか、クラウドプロバイダーのKMSに保存する
シークレットにアクセスするインターフェイス
API、CLI、UIなどがある。
シークレット管理ツールとTerraform
プロパイダ
AWSへの認証で、人が利用する場合は、aws-vault
ツールがある。
CI/CDなどの人間が介在しない場合、下記のようなものがある。
- CIサーバとしてのCircleCI(シークレットを保存)
- IAMユーザへのアクセスキーをCircleCIコンテキストに手動でコピーする
- JenkinsをCIサーバとして動かすEC2インスタンス(IAMロール)
- IAMロールを割り当てる
- CIサーバとしてのGitHub Action(OIDC)
- OIDCを使い、CIシステムとクラウドプロバイダーとの間に信頼された関係を作る
リソースとデータソース
リソースとデータソースを使う場合に、シークレットを扱う。下記のような方法で取り扱うことが可能である。
- 環境変数
- 暗号化されたファイル
- シークレットストア
環境変数
環境変数を通じて、シークレットを渡すことで、コードにプレーンテキストを保存しなくても良い。
環境変数を使う場合、セキュアに保存する方法として下記が挙げられる。
- 1Passwordなどのシークレットをマネージャーにシークレットを保存し、ターミナル上でシークレットを保存する事が可能
- 集中型のシークレットストア(Hashicorp Vaultなど)から、シークレットストアのAPIやCLIを使ってシークレットを読み出す
環境変数を使う場合の利点を下記に示す。
- コードやバージョン管理にプレーンテキストを保存する必要はない
- シークレットの保存が簡単
- どのようなプログラミング環境でも読み出し可能
欠点は下記の通り。 - コードの理解とメンテナンスが難しい
- シークレット管理方法を標準化が難しい。セキュリティ設定を強制できない
- 別の環境への追加を忘れる
下記に例を示す
-
変数をvariable.tfで宣言し、
sensitive = true
で宣言するvariable "db_passward" { type = string sensitive = true }
-
リソースでの渡し方
resource "aws_db_instance" "example" { identifier_prefix = "terraform-up-and-running" engine = "mysql" allocated_storage = 10 instance_class = "db.t2.micro" skip_final_snapshot = var.db_name # シークレットをリソースに渡す username = var.db_username password = var.db_password }
-
TF_VAR_から始まる環境変数を設定することで各変数に値を渡せる
export TF_VAR_db_username = (DB_USERNAME) export TF_VAR_db_password = (DB_PASSWORD)
暗号化されたファイル
シークレットを暗号化し、暗号文をファイルに保存し、バージョン管理システムに保存する方法について記載する。
ファイルに保存されたシークレットなどを保存するには、暗号化キーが必要である。
よくある解決策は、下記のとおりである。
- KMS
- PGP
利点と欠点は下記のとおりである。
- 利点
- 欠点
シークレットストア
シークレットを集中型シークレットストアに保存する方法を示す。
比較的ポビュラーなのは下記がある。
- AWS Secrets Manager
- Google Secret Manager
- Azure Key Vault
- HashiCorp Vault
利点と欠点は下記の通りである。
- 利点
- コードやバージョン管理にプレーンテキストを保存する必要はない
- すべてをコード内に記述できる
- 通常はWebUIを使用できるので、シークレットの保存が簡単
- シークレットが漏洩した際に、ローテートや無効化ができる(シークレットストアでサポートされている)
- 監査ログをサポートしている
- 暗号化、保存、アクセスパターンなどが強制されるので、取り扱いの標準化が簡単
- 欠点
- バージョン管理、パッケージ化、コードと合わせたテストを行えない。新たな環境に追加の手間など煩雑である
- コストがかかる
- 自動テストとの統合が難しく、モックなど用意するか、テストデータを保存する
ステートファイルとプランファイル
Terraformを使用する際に、シークレットにふれる場所は下記がある
- ステートファイル
- プランファイル
ステートファイル
Terraformリソースやデータソースに渡したどんなシークレットも、Terraformステートファイルにプレーンテキストで保存される。
環境変数、暗号化されたファイル、集中型シークレットストアなど、どこからデータベース認証情報を読んでも、リソースに認証情報を渡すと、プレーンテキストのterraform.tfstateファイルに保存してしまう。
これらを、回避するには下記を行う。
- 暗号化をサポートするバックエンドにTerraformステートを保存する
- 暗号化をネイティブにサポートしているバックエンドを使用する
- Terraformバックエンドのアクセス制御を強化する
- シークレット自体にアクセスできる人やリソースを制御する
プランファイル
terraform planコマンドでは、出力をファイルに保存できる。
このとき、Terraformリソースやデータソースに渡したシークレットがプレーンテキストで保存されてしまう。
回避するには、ステートファイルと同様に、「暗号化をサポートするバックエンドにTerraformステートを保存する」、「Terraformバックエンドのアクセス制御を強化する」
実践
シークレットストアを使用する方法
AWS Secret Managerで作成
- AWSにサインインし、Secrets Managerに移動します
- 「新しいシークレットを保存する」をクリックします
- シークレットのタイプ「その他のシークレットのタイプ」、キー/値のペアを設定し、「次」をクリックします
- シークレットの名前を設定し、「次」をクリックします
- 保存します
- 作成されました
moduleの作成
-
modules/rdb
ディレクトリを作成し、その下にmain.tfを作成しますlocals { db_creds = jsondecode( data.aws_secretsmanager_secret_version.db_creds.secret_string ) } data "aws_secretsmanager_secret_version" "db_creds" { secret_id = "db-creds" } resource "aws_db_instance" "example" { identifier_prefix = "terraform-up-and-running" engine = "mysql" allocated_storage = 10 instance_class = "db.t3.micro" skip_final_snapshot = true db_name = var.db_name username = local.db_creds.username password = local.db_creds.password }
environments の作成
-
environments/rds
ディレクトリを作成後、main.tfを作成しますmodule "rdb" { source = "../../../modules/rdb" db_name = local.db_name }
- local.tfを作成します
locals { db_name = "mydb" }
-
terraform init --backend-config=backend.hcl
を実行します - terraform planとapplyを実行します
- クラスタが作成されました。マスターユーザ名も設定された名前になっています
考察
今回、Terraformでシークレットを管理する方法を整理してみました。
今後は、こちらを活用し構築していきたいと思います。
参考