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エンジニア詳細ページ)よりお問い合わせ下さい。
コメント
コメントを投稿