AWS IAM Roles Anywhereを使うと、AWSのワークロードの外でもIAMロールによるAWSのアクセス制御を利用できるようになります。
本稿ではHashicorp Vaultによるルート証明書の構築とIAM Roles Anywhereの信頼アンカーとプロファイルの構築をTerraformを用いて行います。
Vaultでのプライベート認証局の作成
IAM Roles Anywhereの信頼アンカーに証明書を登録するため認証局が必要です。
AWS Private Certificate Authorityでマネージドなプライベート認証局を作成することも出来ますが、
今回はVaultでプライベート認証局を作成します。
resource "vault_mount" "pki-example" {
path = "pki-example"
type = "pki"
description = "This is an example PKI mount"
max_lease_ttl_seconds = 20 * 365 * 24 * 3600
}
resource "vault_pki_secret_backend_root_cert" "pki-example" {
depends_on = [vault_mount.pki-example]
backend = vault_mount.pki-example.path
type = "internal"
common_name = "Root CA"
ttl = "630720000"
}
IAM Roles Anywhereでの信頼アンカーの作成
先ほどのステップで作成した認証局の証明書を用いてIAM Roles Anywhereの信頼アンカーを作成します。
vault_pki_secret_backend_root_cert.pki-example.certificateに作成したプライベート認証局の証明書が
あるので、それをx509_certificate_dataに指定します。
...
resource "aws_rolesanywhere_trust_anchor" "this" {
name = "example-trust-anchor"
enabled = true
source {
source_data {
x509_certificate_data = <<-EOF
${vault_pki_secret_backend_root_cert.pki-example.certificate}
EOF
}
source_type = "CERTIFICATE_BUNDLE"
}
}
IAMロールとRoles Anywhere プロファイルの作成
IAM Roles Anywhereで利用するIAMロールと利用可能なIAMロールを定めたRoles Anywhere プロファイル
を作成します。
...
data "aws_iam_policy_document" "example-assume-role-policy" {
statement {
actions = [
"sts:AssumeRole",
"sts:TagSession",
"sts:SetSourceIdentity"
]
principals {
type = "Service"
identifiers = ["rolesanywhere.amazonaws.com"]
}
condition {
test = "StringEquals"
values = [
"example.com"
]
variable = "aws:PrincipalTag/x509Subject/CN"
}
}
}
resource "aws_iam_role" "example" {
name = "roles-anywhere-example"
path = "/"
assume_role_policy = data.aws_iam_policy_document.example-assume-role-policy.json
}
resource "aws_rolesanywhere_profile" "this" {
name = "example"
enabled = true
role_arns = [aws_iam_role.example.arn]
}
Vaultでの証明書の署名要求を処理するロールと証明書の作成
Vaultで証明書の署名要求を処理するロールと証明書の作成を行います。common_nameにはIAMロールのポリシーで指定した
CNと同じものを指定します。
...
resource "vault_pki_secret_backend_role" "role" {
backend = vault_mount.pki-example.path
name = "my_role"
allowed_domains = ["example.com", "my-instance"]
allow_bare_domains = true
allow_subdomains = true
}
resource "vault_pki_secret_backend_cert" "app" {
depends_on = [vault_pki_secret_backend_role.role]
backend = vault_mount.pki-example.path
name = vault_pki_secret_backend_role.role.name
common_name = "example.com"
}
証明書と秘密鍵を利用したAWSクレデンシャルの取得
作成した証明書はvault_pki_secret_backend_cert.app.certificateに存在するので、
それをoutput.tfに指定してoutputコマンドを利用してファイルに書き出します。
...
output "backend_cert" {
value = vault_pki_secret_backend_cert.app.certificate
}
$ terraform output -raw backend_cert > cert.pem
対応する秘密鍵はvault_pki_secret_backend_cert.app.private_keyに存在しますが、
sensitive valueのためoutputには出力せずにterraform consoleで出力した値を
コピーしてkey.pemというファイルに保存します。
$ terraform console
> nonsensitive(vault_pki_secret_backend_cert.app.private_key)
<<EOT
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA0g6Kv59wqvS4YshmFuNHdqAjTiQyiKxRnrolNxNACBeSbhlI
...
...
jZTv+kMEYeTfbV4nguo26hWgZDwbe696nU2dQvz3BcF8/zYcE0lo
-----END RSA PRIVATE KEY-----
EOT
>
秘密鍵と証明書を使ってaws_signing_helperからクレデンシャルを取得します。今までの工程で作成した
信頼アンカーのARN、Roles Anywhere Profile、IAMロールのARNを使うので、以下のような形で、
output.tfを書いておくと利用すべきコマンドを出力できます。
...
output "helper_command" {
value = "./aws_signing_helper credential-process --certificate cert.pem --private-key key.pem --trust-anchor-arn ${aws_rolesanywhere_trust_anchor.this.arn} --profile-arn ${aws_rolesanywhere_profile.this.arn} --role-arn ${aws_iam_role.example.arn}"
}
$ terraform output -raw helper_command > get_roles_anywhere_credentials.sh
aws_signing_helperと証明書、秘密鍵を同じディレクトリに配置した状態で出力したコマンドを実行すると以下のようにAWS IAMのクレデンシャルを取得できます。
$ sh get_roles_anywhere_credentials.sh
{"Version":1,"AccessKeyId":...}
以上です。
Vault,AWSと異なるリソースに跨る処理でしたが、Terraformを用いることによって、証明書のコピーなどの手間を極力省いた処理が書けたのではないかと思います。