Adminがいないクリスマス・イブでも安心してインフラ構築するためのTerraform, Vault, AWS
Adminがいないクリスマス・イブでも安心してインフラ構築するためのTerraform, Vault, AWS:
この記事はエイチームブライズ/エイチームコネクト/エイチーム引越し侍 Advent Calendar 2018 24日目の記事です。
TerraformはIaC(Infrastructure as Code)を実現するための最も重要なツールの一つといっても
過言ではないと思います。AWS, GCPはもちろんのこと様々なクラウドサービスの機能をコード化する
ことができます。
Terraformを習得すれば、AWS上に数百台のインスタンスをあっと言う間に起動することだって
いとも簡単にできます。
当然、TerraformでAWS上のリソースを操作するためには、AWSのアクセスキーとシークレットキー、
そして、リソースを操作するためのIAMの権限が必要です。アクセスキーとシークレットキーは定期的
に交換することや、IAMの権限は定期的に見直すことが望ましいですが、特にインフラエンジニアが
増えてくるとこれらの管理は苦痛を伴うものになってきます。
そこで今回はTerraformとVaultを用いて、インフラ管理者以外にアクセスキーとシークレットキーを
配布しないでTerraformの実行環境を整えたいと思います。
まずはVaultの環境を構築します。ローカルでVaultを構築したい場合には、Hashicorp Vault 1.0で追加されるauto-unsealを試してみたを参考に
環境を構築することをおすすめします(これはお試し用の環境ですので、本番環境には適用しないで下さい)。
Terraformと連携する場合にはコンテナの外からVaultにアクセスする必要がありますので、上記の記事を参考
にする場合にdemo.hclのlistnerの部分を以下の用に変更してください。
terraformからVaultに接続するためのトークンをVaultのコマンドで作成します。
管理者用のTerraformと作業者用のTerraform用に2つトークンが必要になりますが、まずは
管理者用のトークンを作成します。ポリシーはrootと同じものでいいと思いますが念の為ttlを設定して
作成しました。
次に作業者用のトークンを作成します。さすがにrootポリシーのトークンを発行するのはよろしくないことですので、
作業者に必要なポリシーを作成しました。
上記の内容をaws.hclというファイルに保存して、以下のコマンドを実行してポリシーを作成します。
そして作成したポリシーを使用した作業者用のトークンを作成します。
Vaultと連携してAWSのアクセスキーとシークレットキーを管理するTerraformプロジェクトを作成します。
簡略化のためにバックエンド等の設定はしていませんが、以下のように構成にします。
Vaultをローカル環境で立ち上げている場合はvault_addrはhttp://127.0.0.1:8200
にしておけばいいでしょう。
vault_tokenは先程の作業で発行した管理者用のトークンを指定します。
これらの情報を元にTerraformからVaultのプロバイダーを使う設定を行います。
上記の状態でterraform applyを完了すると、VaultにAWSのadmin roleの情報が保存されます。
念の為Vault側で確認してみると以下の情報が見れると思います。
実際にAWSのリソースを操作してインフラ構築を行う作業者用のTerraformは以下の用に作成します。
vault_tokenには作業者用に作成したトークンを指定します。
管理者用のTerraformプロジェクトではaws_access_keyとaws_secret_keyを定義していましたが、
作業者用のTerraformプロジェクトでは定義しません。これらの情報はVaultから取得出来るように
なるからです。このTerraformプロジェクトでVaultとAWSのproviderを使う設定以下のように
記述します。
この状態でTerraform applyを行うとVault側から取得したAWSのアクセスキーとシークレットキー
を使用してAWSのリソースを操作することができます。
これまでで、作業者向けのAWSのアクセスキーとシークレットキーをVault側から取得することが
できましたが、作業者向けのTerraformをApplyしたとき、AWS側ではどのようなIAM情報が作られているのか
AWSのコンソールから確認してみます。ユーザー名でvaultで検索すると今回のTerraformで作成された
IAMのユーザーを見ることができます。
ユーザー詳細画面でユーザーに付与されたポリシーを確認するとインラインポリシーで、管理者用のTerraform
で定義したポリシーが付与されていることが確認できます。
また、このユーザーは永久に残されるわけではなく、default_lease_ttl_secondsに従って自動的に削除されます。しばらく時間が経ってからユーザー名をvaultで検索しても何もヒットしないことが確認出来ると思います。
Vault側のログを確認してみると上記のようなログが残っており、Vault側からIAMのユーザーを削除してくれたことが確認できます。AWS側のリソースがどうなっているかを意識することなくVault側でユーザーの追加と削除を行ってくれるのは素晴らしいことだと思います。
AWSのアクセスキーとシークレットキー以外にも、Vaultから情報を取得することを考えてみます。
例えばRDSを作成する際のDBのパスワードを当然必要ですが、作業者はパスワードを知る必要も
ありませんし、それを平文でGitリポジトリにコミットする必要はないでしょう。
TerraformからVaultにこのような情報を登録する際はvault_generic_secretを利用します。
下記のようなtfファイルを作成してterraform applyするとVault側にはsecret/dbというキー名で
情報が登録されます。作業者側で呼び出す前にVaultのポリシーを更新する必要があります。
今回の例の場合ではaws.hclの末尾に以下の記述を追加して、再度ポリシーをアップロードします。
作業者側ではTerraformのtfファイルを以下のように記述すれば、管理者側で設定した
パスワードを呼び出すことができます。
TerraformとVaultを連携させることにより、有効期限の短いAWSのシークレットキーの発行と利用
を透過的の行えるようになりました。この方法であれば、AWSのシークレットキーを平文で記述する
必要がないので、漏洩のリスクを抑えることができます。
またシークレットキーが必要な管理者側のTerraformでもIAMを作る権限さえあればいいため、
AdministratorAccessのような強いポリシーを持つ必要がないのもメリットです。
Vault側のトークンにもポリシーと有効期限
を設定することが出来るので、こちらも適切なポリシーを設定して有効期限を短くすることにより、
漏洩の影響を最低限に留めることが出来ると思います。
エイチームグループでは一緒に活躍してくれる優秀な人材を募集中です。
興味のある方はぜひともエイチームグループ採用ページ(Webエンジニア詳細ページ)よりお問い合わせ下さい。
この記事はエイチームブライズ/エイチームコネクト/エイチーム引越し侍 Advent Calendar 2018 24日目の記事です。
はじめに
TerraformはIaC(Infrastructure as Code)を実現するための最も重要なツールの一つといっても過言ではないと思います。AWS, GCPはもちろんのこと様々なクラウドサービスの機能をコード化する
ことができます。
Terraformを習得すれば、AWS上に数百台のインスタンスをあっと言う間に起動することだって
いとも簡単にできます。
当然、TerraformでAWS上のリソースを操作するためには、AWSのアクセスキーとシークレットキー、
そして、リソースを操作するためのIAMの権限が必要です。アクセスキーとシークレットキーは定期的
に交換することや、IAMの権限は定期的に見直すことが望ましいですが、特にインフラエンジニアが
増えてくるとこれらの管理は苦痛を伴うものになってきます。
そこで今回はTerraformとVaultを用いて、インフラ管理者以外にアクセスキーとシークレットキーを
配布しないでTerraformの実行環境を整えたいと思います。
Vaultの準備
まずはVaultの環境を構築します。ローカルでVaultを構築したい場合には、Hashicorp Vault 1.0で追加されるauto-unsealを試してみたを参考に環境を構築することをおすすめします(これはお試し用の環境ですので、本番環境には適用しないで下さい)。
Terraformと連携する場合にはコンテナの外からVaultにアクセスする必要がありますので、上記の記事を参考
にする場合にdemo.hclのlistnerの部分を以下の用に変更してください。
demo.hcl
listener "tcp" { address = "0.0.0.0:8200" tls_disable = 1 }
管理者、作業者用のトークンの発行とポリシーの設定
terraformからVaultに接続するためのトークンをVaultのコマンドで作成します。管理者用のTerraformと作業者用のTerraform用に2つトークンが必要になりますが、まずは
管理者用のトークンを作成します。ポリシーはrootと同じものでいいと思いますが念の為ttlを設定して
作成しました。
# vault token create -ttl=168h Key Value --- ----- token s.4hD6KBn9U20TxwpUMvzoKdzm token_accessor 4RpO0YsQVM7PHG7FS3jnPgoJ token_duration 168h token_renewable true token_policies ["root"] identity_policies [] policies ["root"]
作業者に必要なポリシーを作成しました。
aws.hcl
path "aws/*" { capabilities = ["read"] } path "auth/token/*" { capabilities = ["update"] }
# vault policy write aws aws.hcl Success! Uploaded policy: aws # vault policies aws default root
# vault token-create -policy="aws" -ttl=24h Key Value --- ----- token s.12jFUtLq811lJDWLFQnevcTs token_accessor 33V4nGl9EK3aTE0WYndFLNaO token_duration 24h token_renewable true token_policies ["aws" "default"] identity_policies [] policies ["aws" "default"]
インフラ管理者用のTerraformの作成
Vaultと連携してAWSのアクセスキーとシークレットキーを管理するTerraformプロジェクトを作成します。簡略化のためにバックエンド等の設定はしていませんが、以下のように構成にします。
├── admin │ ├── 01_vault.tf │ ├── terraform.tfvars │ └── variable.tf
variables.tf
variable "aws_access_key" {} variable "aws_secret_key" {} variable "vault_addr" {} variable "vault_token" {}
terraform.tfvars
aws_access_key = "AWS_ACCESS_KEY" aws_secret_key = "AWS_SECRET_KEY" vault_addr = "VAULT_ADDR" vault_token = "s.4hD6KBn9U20TxwpUMvzoKdzm"
にしておけばいいでしょう。
vault_tokenは先程の作業で発行した管理者用のトークンを指定します。
これらの情報を元にTerraformからVaultのプロバイダーを使う設定を行います。
01_vault.tf
provider "vault" { address = "${var.vault_addr}" token = "${var.vault_token}" } resource "vault_aws_secret_backend" "aws" { access_key = "${var.aws_access_key}" secret_key = "${var.aws_secret_key}" region = "ap-northeast-1" default_lease_ttl_seconds = "120" max_lease_ttl_seconds = "240" } resource "vault_aws_secret_backend_role" "ec2-admin" { backend = "${vault_aws_secret_backend.aws.path}" name = "ec2-admin-role" policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:*", "ec2:*", "rds:*" ], "Resource": "*" } ] } EOF }
念の為Vault側で確認してみると以下の情報が見れると思います。
/ # vault read aws/roles/ec2-admin-role Key Value --- ----- credential_types [iam_user federation_token] default_sts_ttl 0s max_sts_ttl 0s policy_arns <nil> policy_document {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["iam:*","ec2:*","rds:*"],"Resource":"*"}]} role_arns <nil>
作業者用のTerraformの作成
実際にAWSのリソースを操作してインフラ構築を行う作業者用のTerraformは以下の用に作成します。└── operator ├── 01_vault.tf ├── terraform.tfvars └── variable.tf
variables.tf
variable "vault_addr" {} variable "vault_token" {} variable "aws_region" {}
terraform.tfvars
vault_addr = "VAULT_ADDR" vault_token = "s.12jFUtLq811lJDWLFQnevcTs" aws_region = "ap-northeast-1"
管理者用のTerraformプロジェクトではaws_access_keyとaws_secret_keyを定義していましたが、
作業者用のTerraformプロジェクトでは定義しません。これらの情報はVaultから取得出来るように
なるからです。このTerraformプロジェクトでVaultとAWSのproviderを使う設定以下のように
記述します。
01_vault.tf
provider "vault" { address = "${var.vault_addr}" token = "${var.vault_token}" } data "vault_aws_access_credentials" "creds" { backend = "aws" role = "ec2-admin-role" } provider "aws" { access_key = "${data.vault_aws_access_credentials.creds.access_key}" secret_key = "${data.vault_aws_access_credentials.creds.secret_key}" region = "${var.aws_region}" }
を使用してAWSのリソースを操作することができます。
AWSコンソールでのIAMの確認
これまでで、作業者向けのAWSのアクセスキーとシークレットキーをVault側から取得することができましたが、作業者向けのTerraformをApplyしたとき、AWS側ではどのようなIAM情報が作られているのか
AWSのコンソールから確認してみます。ユーザー名でvaultで検索すると今回のTerraformで作成された
IAMのユーザーを見ることができます。
ユーザー詳細画面でユーザーに付与されたポリシーを確認するとインラインポリシーで、管理者用のTerraform
で定義したポリシーが付与されていることが確認できます。
また、このユーザーは永久に残されるわけではなく、default_lease_ttl_secondsに従って自動的に削除されます。しばらく時間が経ってからユーザー名をvaultで検索しても何もヒットしないことが確認出来ると思います。
vault_1 | 2018-12-19T11:31:33.876Z [INFO] expiration: revoked lease: lease_id=aws/creds/ec2-admin-role/KXEYNFRvp21mgAsVtnaAzfNS
その他の秘密情報もVaultから取得する
AWSのアクセスキーとシークレットキー以外にも、Vaultから情報を取得することを考えてみます。例えばRDSを作成する際のDBのパスワードを当然必要ですが、作業者はパスワードを知る必要も
ありませんし、それを平文でGitリポジトリにコミットする必要はないでしょう。
TerraformからVaultにこのような情報を登録する際はvault_generic_secretを利用します。
admin/vault_generic_secret.tf
resource "random_id" "db_password" { byte_length = 8 } resource "vault_generic_secret" "db" { path = "secret/db" data_json = <<EOT { "password": "${random_id.db_password.b64}" } EOT }
情報が登録されます。作業者側で呼び出す前にVaultのポリシーを更新する必要があります。
今回の例の場合ではaws.hclの末尾に以下の記述を追加して、再度ポリシーをアップロードします。
aws.hcl
... path "secret/*" { capabilities = ["read"] }
パスワードを呼び出すことができます。
operator/02_rds.tf
data "vault_generic_secret" "db" { path = "secret/db" } resource "aws_db_instance" "db" { allocated_storage = 10 storage_type = "gp2" engine = "mysql" engine_version = "5.7" password = "${data.vault_generic_secret.db.data["password"]}" ...
まとめ
TerraformとVaultを連携させることにより、有効期限の短いAWSのシークレットキーの発行と利用を透過的の行えるようになりました。この方法であれば、AWSのシークレットキーを平文で記述する
必要がないので、漏洩のリスクを抑えることができます。
またシークレットキーが必要な管理者側のTerraformでもIAMを作る権限さえあればいいため、
AdministratorAccessのような強いポリシーを持つ必要がないのもメリットです。
Vault側のトークンにもポリシーと有効期限
を設定することが出来るので、こちらも適切なポリシーを設定して有効期限を短くすることにより、
漏洩の影響を最低限に留めることが出来ると思います。
お知らせ
エイチームグループでは一緒に活躍してくれる優秀な人材を募集中です。興味のある方はぜひともエイチームグループ採用ページ(Webエンジニア詳細ページ)よりお問い合わせ下さい。
コメント
コメントを投稿