詳しくは Azure VM 上で Azure リソースのマネージド ID を使用してアクセス トークンを取得する方法 をお読みください。
前提
- マネージドIDを有効にしてある状態
- KeyVaultに対するアクセスポリシーは適宜許可してある状態
- CentOS 7上での実行を想定(Bash,curl,Python 3があるLinuxであれば動くはず)
以下、BashでSecret値を得る例。Bashだけど、肝はHTTP通信なので同じ操作なら言語は何でも良いです。
# KeyVaultの適宜いい感じに設定する
KEYVAULT_NAME=your-keyvault-name
SECRET_NAME=your-secret-name
# アクセストークンを得る
ACCESS_TOKEN=$(curl --fail -H "Metadata: true" "http://169.254.169.254/metadata/identity/oauth2/token?resource=https://vault.azure.net&api-version=2018-02-01" | python -c 'import sys,json; print(json.load(sys.stdin)["access_token"])')
# KeyVaultのSecretなURLを作る(secretsの部分は適宜keysやcertificatesに置き換えて良い)
SECRET_URL="https://${KEYVAULT_NAME}.vault.azure.net/secrets/${SECRET_NAME}/?api-version=2016-10-01"
# 値を得る
curl --fail -Lv -H "Authorization: Bearer $ACCESS_TOKEN" "$SECRET_URL" | python -c 'import sys,json; print(json.load(sys.stdin)["value"])'
解説
AzureではVM等から http://169.254.169.254/metadata/identity/oauth2/token
というエンドポイントにアクセスすると、アクセストークンが得られる仕組みになっています。
ただ、レート制限が結構厳しいので、適当に連打するような事はないように注意しましょう。実運用するときは、アクセストークンを使いまわす(有効期限切れを考慮する)、1時間に1回使うだけにする、ちゃんとリトライを入れる、など少し考える必要があります。
次に、Metadata: true
というヘッダはSSRF対策につける必要があります。SSRFについては徳丸先生のBlog記事が詳しいです。
万が一、外部から来るデータ(リクエストデータやURL入力欄などテキストデータ等)を接続先に使いつつMetadata: true
ヘッダを使ってリクエストを行うようなアプリを動かす場合は、SSRF対策出来ているか少し考慮する必要があります。そんなにないと思いますが。
次に、resource=https://vault.azure.net
という所でどのリソースに対する操作かを指定しています。https://vault.azure.net
はKeyVaultを指します。
もし、Azureのリソース操作を行いたい場合はresource=https://management.azure.com/
という形になります。この時末尾のスラッシュ1文字の漏れも許してくれないので注意しましょう。
詳しくはAzure リソースのマネージド ID をサポートするサービスあたりをお読みください。他のクエリパラメータは環境によっては必須になりますので適宜確認します。
使用例
これを書きたいだけだったので、実質本編
Nginx向けにKeyVaultで管理しているSSL証明書+秘密鍵をVM上に保存するバッチスクリプト(nginx.conf付)
KeyVault上ではsecretsでPFX(PKCS12)で記録されているので、それをopensslで紐解いて配置するだけのスクリプトです。VM上に適当に配置して1日1回Cronで回しておけばよいでしょう。
PassPhraseがある場合は、opensslコマンドにある"Pass:"の部分を"Pass:password"となるようにします。(そこもkeyvaultから取るようにすると尚よい)
配置された秘密鍵はパスフレーズ無しになるので、困る場合は何か考えてください。