LoginSignup
0
0

Terraform シークレット管理を試してみた

Posted at

背景・目的

以前、下記のとおり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で作成

  1. AWSにサインインし、Secrets Managerに移動します
  2. 「新しいシークレットを保存する」をクリックします
  3. シークレットのタイプ「その他のシークレットのタイプ」、キー/値のペアを設定し、「次」をクリックします
    image.png
  4. シークレットの名前を設定し、「次」をクリックします
    image.png
  5. 保存します
  6. 作成されました
    image.png

moduleの作成

  1. 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 の作成

  1. environments/rdsディレクトリを作成後、main.tfを作成します
    module "rdb" {
      source = "../../../modules/rdb"
    
      db_name = local.db_name
    }
    
  2. local.tfを作成します
    locals {
      db_name = "mydb"
    }
    
  3. terraform init --backend-config=backend.hclを実行します
  4. terraform planとapplyを実行します
  5. クラスタが作成されました。マスターユーザ名も設定された名前になっています
    image.png

考察

今回、Terraformでシークレットを管理する方法を整理してみました。
今後は、こちらを活用し構築していきたいと思います。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0