ちょっと話題の記事

AWS IAMロールAnywhereのPKI基盤にHashicorp Vaultを使う

2022.07.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、ゲストのNTT東日本 大瀧です。

本日IAMロールAnywhereがリリースされました。IAMロールAnywhereは、AWSの認証基盤であるIAMの認証をPKI(公開鍵基盤)に外出しできる仕組みです。本ブログでは、手軽に試せるPKIとしてHashicorp Vaultを試す様子をご紹介します。

  • 動作確認環境
    • OS : Ubuntu 20.04.4 LTS
    • Vault : バージョン v1.11.0
    • AWS : 東京リージョン

1. Hashicorp Vaultのセットアップ

まずはPKIのCA(認証局)となるVaultサーバーを立ち上げます。Vaultのダウンロードページの [Linux] - [LINUX BINARY DOWNLOAD]で Amd64 のリンクをコピーし、 wget の引数にしてダウンロードします。

$ wget https://releases.hashicorp.com/vault/1.11.0/vault_1.11.0_linux_amd64.zip
--2022-07-07 21:09:51--  https://releases.hashicorp.com/vault/1.11.0/vault_1.11.0_linux_amd64.zip
  :(略)
vault_1.11.0_linux_amd64.zip  100%[=================================================>]  70.07M  24.6MB/s    in 2.9s

2022-07-07 21:09:54 (24.6 MB/s) - ‘vault_1.11.0_linux_amd64.zip’ saved [73474942/73474942]

$ unzip vault_1.11.0_linux_amd64.zip
Archive:  vault_1.11.0_linux_amd64.zip
  inflating: vault
$

以下のように実行し、ヘルプメッセージが出ればOKです。

$ ./vault
Usage: vault <command> [args]

Common commands:
    read        Read data and retrieves secrets
    write       Write data, configuration, and secrets
    delete      Delete secrets and configuration
    list        List data or secrets
    login       Authenticate locally
    agent       Start a Vault agent
    server      Start a Vault server
    status      Print seal and HA status
    unwrap      Unwrap a wrapped secret
  :(略)
$

今回はお試しなので、Devモードでサーバーをバックグラウンド起動しておきます。

$ ./vault server -dev &
==> Vault server configuration:

             Api Address: http://127.0.0.1:8200
                     Cgo: disabled
         Cluster Address: https://127.0.0.1:8201
              Go Version: go1.17.11
              Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
               Log Level: info
                   Mlock: supported: true, enabled: false
           Recovery Mode: false
                 Storage: inmem
                 Version: Vault v1.11.0, built 2022-06-17T15:48:44Z
             Version Sha: ea296ccf58507b25051bc0597379c467046eb2f1

==> Vault server started! Log data will stream in below:
  :(略)

続いてドキュメントに従い、PKIをセットアップします。

以下の6つのコマンドを順に実行していきます。4番目のコマンドでCA証明書が表示されるので、-----BEGIN CERTIFICATE-----から-----END CERTIFICATE-----までをコピーして控えておきます(2つ表示されますが自己署名証明書のため中身は同じでどちらでもOKです)。あとのトラストアンカー設定に利用します。

$ export VAULT_ADDR='http://127.0.0.1:8200'
$ ./vault secrets enable pki
2022-07-07T18:03:43.478+0900 [INFO]  core: successful mount: namespace="" path=pki/ type=pki
Success! Enabled the pki secrets engine at: pki/
$ ./vault secrets tune -max-lease-ttl=8760h pki
2022-07-07T18:03:50.060+0900 [INFO]  core: mount tuning of leases successful: path=pki/
Success! Tuned the secrets engine at: pki/
$ ./vault write pki/root/generate/internal \
  common_name=my-website.com \
  ttl=8760h
WARNING! The following warnings were returned from Vault:

  * This mount hasn't configured any authority access information fields;
  this may make it harder for systems to find missing certificates in the
  chain or to validate revocation status of certificates. Consider updating
  /config/urls with this information.

Key              Value
---              -----
certificate      -----BEGIN CERTIFICATE-----
MIIDPjCCAiagAwIBAgIUCyC8uqaeOkgcbvciBnJHUKFY/rAwDQYJKoZIhvcNAQEL
  :(略)
kWBT7k944hCusBIGiy4LELneaJuDDG+ea/Aq2XB+ePhiIUgYh4IDagj05SSCCWh9
e0HfxqSfSYknFqpGw/SAhjfo
-----END CERTIFICATE-----
expiration       1688720638
issuer_id        3e02420a-d003-ee56-d566-72ef7c3cc8f0
issuer_name      n/a
issuing_ca       -----BEGIN CERTIFICATE-----
MIIDPjCCAiagAwIBAgIUCyC8uqaeOkgcbvciBnJHUKFY/rAwDQYJKoZIhvcNAQEL
  :(略)
kWBT7k944hCusBIGiy4LELneaJuDDG+ea/Aq2XB+ePhiIUgYh4IDagj05SSCCWh9
e0HfxqSfSYknFqpGw/SAhjfo
-----END CERTIFICATE-----
key_id           002874cf-7dd7-cb56-ea5e-d0d760037adf
key_name         n/a
serial_number    0b:20:bc:ba:a6:9e:3a:48:1c:6e:f7:22:06:72:47:50:a1:58:fe:b0
$ ./vault write pki/config/urls \
  issuing_certificates="http://127.0.0.1:8200/v1/pki/ca" \
  crl_distribution_points="http://127.0.0.1:8200/v1/pki/crl"
Success! Data written to: pki/config/urls
$ ./vault write pki/roles/example-dot-com \
  allowed_domains=my-website.com \
  allow_subdomains=true \
  max_ttl=72h
Success! Data written to: pki/roles/example-dot-com

これでOKです。

2. IAMロールAnywhereのセットアップ

Management ConsoleのIAMロールAnywhere画面にアクセスし、[信頼アンカーを作成する]ボタンをクリックします。

IAM管理画面はリージョンに依存しないグローバル扱いですが、IAMロールAnywhereはリージョンごとの設定のためリージョンを選択することに注意します。

[信頼アンカー名]は任意の名前を入力、[認証機関(CA)ソース]は「外部証明書バンドル」を選択し、[外部証明書バンドル]に手順1で控えておいたCA証明書をペーストします。他の項目は未選択にし、[信頼アンカーを作成する]ボタンをクリックし登録します。

続いて、IAM管理画面から任意のロールを新規作成します。今回はマネージドポリシーAmazonS3ReadOnlyAccessを持つIAMRoleAnywhereEvalRoleロールを作成しました。作成したロールの[信頼関係]タブをクリック、[信頼関係を編集]ボタンをクリックして以下のJSONを貼り付け[ポリシーを更新]ボタンで保存します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "rolesanywhere.amazonaws.com"
                ]
            },
            "Action": [
                "sts:AssumeRole",
                "sts:TagSession",
                "sts:SetSourceIdentity"
            ]
        }
    ]
}

IAMロールAnywhereの画面に戻り、プロファイル一覧の右にある[プロファイルを作成]ボタンをクリックします。

プロファイル作成画面では、任意のプロファイル名とロールに先ほど作成したIAMロールを指定、他の項目は既定のまま[プロファイルを作成]をクリックします。

これでOKです。

動作確認

では、動かしてみましょう。まずはVaultで証明書を発行します。

$ ./vault write pki/issue/example-dot-com \
  common_name=www.my-website.com
Key                 Value
---                 -----
ca_chain            [-----BEGIN CERTIFICATE-----
MIIDPjCCAiagAwIBAgIUCyC8uqaeOkgcbvciBnJHUKFY/rAwDQYJKoZIhvcNAQEL
  :(略)
-----END CERTIFICATE-----]
certificate         -----BEGIN CERTIFICATE-----
MIIDxzCCAq+gAwIBAgIUQkSqI2Gb59LiQw8hw/O/YGQfuR4wDQYJKoZIhvcNAQEL
  :(略)
-----END CERTIFICATE-----
expiration          1657443883
issuing_ca          -----BEGIN CERTIFICATE-----
MIIDPjCCAiagAwIBAgIUCyC8uqaeOkgcbvciBnJHUKFY/rAwDQYJKoZIhvcNAQEL
  :(略)
-----END CERTIFICATE-----
private_key         -----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAvs5mGTllc45uRurm69V/w/LxElhh0w45blPi/ROnjZ5IgII1
  :(略)
-----END RSA PRIVATE KEY-----
private_key_type    rsa
serial_number       42:44:aa:23:61:9b:e7:d2:e2:43:0f:21:c3:f3:bf:60:64:1f:b9:1e

いくつか出てくる項目のうち、以下をそれぞれテキストファイルに保存します。

  • certファイル : certificate-----BEGIN CERTIFICATE----------END CERTIFICATE-----まで
  • keyファイル : private_key-----BEGIN RSA PRIVATE KEY----------END RSA PRIVATE KEY-----まで

続いてIAMロールAnywhereを利用するヘルパースクリプトをドキュメントにあるリンクから環境にあったリンクをコピーし、wgetコマンドでダウンロードします。

$ wget https://s3.amazonaws.com/roles-anywhere-credential-helper/CredentialHelper/latest/linux_amd64/aws_signing_helper
  :(略)
$ chmod +x aws_signing_helper

これで準備OKです。IAMロールAnywhereのAPIをコールし、一時クレデンシャルを取得してみましょう。AWS管理コンソールから、以下のコマンドラインに対応する各項目のARNをコピーし、コマンドラインを完成させ実行します。

$ ./aws_signing_helper credential-process --certificate ./cert --private-key ./key \
  --trust-anchor-arn <IAMロールAnywhere トラストアンカーのARN> \
  --profile-arn <IAMロールAnywhere プロファイルのARN> \
  --role-arn <手順2で作成したIAMロールのARN>
{"Version":1,"AccessKeyId":"ASIAXXXXXXXXXXXX","SecretAccessKey":"XXXXXXXXXXXXXXXXXXXXXXXX","SessionToken":"XXXXXXXXXXXXXXXXXXXXXXXX","Expiration":"2022-07-07T11:02:01Z"}

正常に実行できると、JSON形式のレスポンスに一時クレデンシャルの情報が含まれている様子がわかります。AWS CLIで利用する場合は、上記コマンドを ~/.aws/config ファイル内に以下の形式で記載します。(プロファイル名は好きなものでOKです)

config

[profile developer]
    credential_process = ./aws_signing_helper credential-process --certificate ./cert --private-key ./key --trust-anchor-arn <IAMロールAnywhere トラストアンカーのARN> --profile-arn <IAMロールAnywhere プロファイルのARN> --role-arn <手順2で作成したIAMロールのARN>

これを設定すると、本来APIキーなどを設定する ~/.aws/credentials ファイルが空でも...

$ aws s3 ls --profile developer
2022-05-18 15:57:09 takipone-lambda-layers
2022-03-04 14:56:12 takipone-transcribe
$

クレデンシャルなしで、証明書から一時クレデンシャルを取得しAWS APIを呼ぶことができました!

まとめ

IAMロールAnywhereのPKI基盤としてHashicorp Vaultを試してみる様子をご紹介しました。

リリース文だけ見るとPKIで発行した証明書がどうIAMと連携するのかイメージしずらいと思うので、こうやってまずは試してみてできること、そうでないことを検証してみるのがオススメです。

私見として、以下をメモしておきます。

  • x.509証明書で認証といっても、mTLSのようなクライアント証明書として使うものではない。証明書をIAMロールAnywhereに提示して一時クレデンシャルを取得するものなので、AWS SDKやAWS CLIなどAWS APIに準拠するクライアントで利用するもの。
  • といっても現状ヘルパースクリプトを噛ませる形なので、コンテナ環境などファイルを扱いにくい環境では使いずらい印象。AWS SDKの各言語でネイティブに対応してくれるのを待つのがいいかしら。
  • 証明書の漏洩に備えるCRLは、IAMロールAnywhere APIのImportCrlで扱える。Vault EnterpriseあたりでSync機能が出てきたりすると便利そう。