掲載内容は個人の見解であり、所属する企業を代表するものではありません.
最近は Managed ID が充実してきたのでとっても便利なのですが、 Azure AD 認証が必要なアプリケーションが必ずしも Azure 上で動作するとも限りませんので、相変わらずサービスプリンシパルを使用したサインインも必要なわけです。 サービスプリンシパルでサインインするということは、そのアプリケーションは証明書かクライアントシークレットを保有している必要があります。 この証明書の発行方法や利用方法について微妙に手こずったので整理してみます。
Azure PowerShell や Azure CLI でサービスプリンシパルを作り証明書を使用してサインインする方法については下記をご参照いただければと思いますが、 本記事の執筆の切っ掛けとなったのはこの中で出てくる証明書のフォーマットです。
まず Azure PowerShell の場合は証明書を拇印(Thumbprint)で指定します。 これは Windows の証明書ストアに秘密鍵を持った証明書がインストールされていることを前提としています。
Connect-AzAccount -ServicePrincipal -ApplicationId $APP_ID -Tenant $TENANT_ID -CertificateThumbprint <thumbprint>
次に Azure CLI の場合ですが、こちらの場合はシンプルに証明書ファイルに対するパスを指定します。 ただしこの証明書は PEM という形式であり秘密鍵が含まれている必要があります。
az login --service-principal --username $APP_ID --tenant $TENANT_ID --password $pathToCertFile
つまり同じサービスプリンシパルを使用する場合であっても、環境によって使用できる証明書の格納方式や利用できるフォーマットが異なるわけです。 これが切っ掛けでいろいろ調べてみましたが、 Windows と Linux で扱う証明書が異なるという話は昔からあった話なんですね・・・。
Windows 端末で作業されている方は ファイル名を指定して実行
で certmgr.msc
を実行するか、
スタートメニューで certification
を検索して ユーザー証明書の管理
を選択して、証明書を確認してみましょう。
Azure PowerShell の Connect-AzAccount -CertificateThumbprint
で指定した拇印に一致する証明書が自動的に選択されていることになります。
では、これを Azure CLI で使用したい場合はどうでしょう。 Azure CLI の場合は証明書ファイルのパスを明示してやる必要がありますので、証明書をエクスポートしてやります。 証明書のエクスポートウィザードでのポイントは以下の 3 点です。
エクスポートした PFX ファイルを利用して試しに az login
してみると、証明書が正しくないと、PEM ファイルを使えと怒られます。
$ az login --service-principal --username $APP_ID --tenant $TENANT_ID --password ./exported-certificate.pfx
ValidationError: Invalid certificate, please use a valid PEM file.
というわけで、この PFX 形式のファイルを PEM 形式に変換してみましょう。
証明書の変換には OpenSSL を使用するのが定番みたいですね。
下記のスクリプト内で $PFXPASS
で指定しているファイルは、エクスポート時に指定したパスワードを記載したテキストファイルです。
PFXFILE=./exported-certificate.pfx
PFXPASS=./password.txt
PEMFILE=./converted-certificate.pem
openssl pkcs12 -in ${PFXFILE} -password file:${PFXPASS} -nocerts -nodes | openssl pkcs8 -nocrypt >> ${PEMFILE}
openssl pkcs12 -in ${PFXFILE} -password file:${PFXPASS} -clcerts -nokeys | openssl x509 >> ${PEMFILE}
出力した PEM 形式のファイルをテキストエディタで開いてみると、以下のようなフォーマットのテキストファイルになっていることが分かります。
-----BEGIN PRIVATE KEY-----
Base 64 でエンコードされた秘密鍵
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
Base 64 でエンコードされた証明書
-----END CERTIFICATE-----
さてそれでは、この証明書を使って az login
してみましょう。
以下のような結果が返ってくれば成功です。
az login --service-principal --allow-no-subscriptions --username $APP_ID --tenant $TENANT_ID --password ./converted-certificate.pem
[
{
"cloudName": "AzureCloud",
"id": "guid-of-tenantid",
"isDefault": true,
"name": "N/A(tenant level account)",
"state": "Enabled",
"tenantId": "guid-of-tenantid",
"user": {
"name": "guid-of-application-id",
"type": "servicePrincipal"
}
}
]
ここでは --allow-no-subscriptions
オプションを指定していますが、これは純粋に AAD ログインに成功するか否かを検証するためです。
Azure RBAC のアクセス権を全く付与されていないサービスプリンシパルで、このオプション抜きでサインインすると下記のようなエラーが帰ってきます。
ValidationError: No subscriptions found for application-name-or-guid.
そもそも Azure 操作をするための Azure CLI なので、アクセス権を持つサブスクリプションが1つも無い場合にはエラーと判定されますよね。
ですがここでは、サブスクリプションの有無は問題ではないので --allow-no-subscriptions
としています。
与えられた PFX 形式の証明書でどうにかやりくりしなければならない事情がある場合には、前述のような証明書変換アプローチは有効でしょう。 ただそもそも Azure AD のアプリケーションに登録する証明書やシークレットは 1 つである必要はありません。 いま持っている証明書が Azure CLI で使用できないならば、新規に発行してしまえば良い、という考え方もあるわけです。 その証明書発行と Azure AD への登録権限があり、証明書の運用が少し増えることを受け入れられるのならば。
証明書を発行する方法はいくつかありますが、Azure CLI
を使用するのが最も簡単だと思います。
az ad sp credential reset
を使用してサービスプリンシパルのシークレットや証明書を変更することができるのですが、
--create-cert
オプションを付与することで自己署名証明書を発行することができます。
その際に --append
を指定しないと既存の証明書を上書きしてしまうのでご注意ください。
コマンドオプションの詳細は こちら をご参照ください。
# サービスプリンシパルの設定を変更するので、開発に使用しているユーザーアカウントでサインインしなおす
az login
# 既存のサービスプリンシパルに対して証明書を作成して追加する
az ad sp credential reset --append --create-cert --name $APP_ID
{
"appId": "guid-of-application",
"fileWithCertAndPrivateKey": "C:\\Users\\username\\tempfilename.pem",
"name": "name-of-application",
"password": null,
"tenant": "guid-of-registered-tenant"
}
実行結果の fileWithCertAndPrivateKey
に記載されたパスに証明書ファイルが出力されているはずです。
これを適当な場所にコピーしてログインしてみましょう。
ちなみに私の環境では証明書を生成してから実際にログインできるようになるまで数分かかっていました。
エラーが出てしまった場合には少し間をおいてみてください。
az login --service-principal --allow-no-subscriptions -u $APP_ID --tenant $TENANT_ID -p ./created.pem
[
{
"cloudName": "AzureCloud",
"id": "guid-of-tenantid",
"isDefault": true,
"name": "N/A(tenant level account)",
"state": "Enabled",
"tenantId": "guid-of-tenantid",
"user": {
"name": "guid-of-application-id",
"type": "servicePrincipal"
}
}
]
余談ですが、この --create-cert
オプションはサービスプリンシパルの生成時にも利用できます。
az ad sp create-for-rbac --skip-assignment -n $APP_NAME --create-cert
さらに余談ですが、--keyvault
オプションを指定するとローカルに証明書を生成することなく Key Vault でキーを管理させることができます。
この証明書は Key Vault からダウンロードできますが、パスワードなしのPFX形式
になるようです。
Key Vault を使って証明書を管理したいが PEM
形式が必要な場合は、後述の手順を利用してください。
az ad sp create-for-rbac --skip-assignment -n $APP_NAME --create-cert --keyvault $KEYVAULT_NAME --cert $CERTIFICATE_NAME
Azure Key Vault で自己署名証明書を発行することが出来ます。
Key Vault で自己署名証明書を 生成
する際に PEM 形式を指定しておきます。
生成が完了したら公開キー部分のみの証明書を cer
形式で、秘密キーも含む証明書を pem
形式でダウンロードすることが出来ます。
Azure Portal でサインインしたい Azure AD アプリケーションの証明書として cer
証明書をアップロードしておき、実際にサインインしたい環境には pem
証明書を配置して利用します。
なお余談ですが前述のaz ad sp create-for-rbac
や az ad sp credential reset
等のコマンドで --create-cert
オプションを指定しない場合、
--keyvault
や --cert
オプションは Key Vault で管理された証明書を使用する、という意味合いになります。
このため既存のサービスプリンシパルに Key Vault で管理している証明書(Key Vault で発行したものでなくともよい)を紐付けたい場合には下記のコマンドが利用できます。
az ad sp credential reset --name $APP_NAME --append --create-cert --keyvault $KEYVAULT_NAME --cert $CERTIFICATE_NAME
ここまで自己署名証明書の生成と管理についてつらつらと記載してみましたが一応まとめです。
最終利用形式 | 証明書生成方法 | インストール | 備考 |
---|---|---|---|
PKCS #12 (PFX) | Azure CLI でサービスプリンシパル作成・更新と同時に証明書を生成しつつ Key Vault に保存する | Key Vault から PFX 形式でダウンロードして実行環境の Windows 証明書ストアにインストール | 記事内の余談を参照 |
PKCS #12 (PFX) | Azure Key Vault で PFX 形式で作成 | Key Vault から CER 形式でダウンロードしてAzure AD アプリケーションに登録、PFX 形式でダウンロードして実行環境の Windows 証明書ストアにインストール | 本記事では未紹介 |
PKCS #12 (PFX) | PowerShell コマンド New-SelfSignedCertificate で生成 | 証明書ストアから公開キーをエクスポートして Azure AD アプリケーションに登録 | 参考情報 |
PKCS #12 (PFX) | Windows SDK に含まれる makecert と pvk2pfx ツールで生成 | 公開キー部分をAzure AD アプリケーションに登録、PFXファイルを生成して証明書ストアにインストール | 参考情報 |
PEM | PFX パターンで生成 | Windows 証明書ストアから秘密キー付きでエクスポートし、OpenSSL で PEM 形式に変換 | 解説済み |
PEM | Azure CLI でサービスプリンシパル作成・更新と同時に証明書を生成しつつローカルに保存する | ローカルディレクトリに生成された PEM ファイルを実行環境にコピー | 解説済み |
PEM | Azure Key Vault で PEM 形式で作成 | Key Vault から CER 形式でダウンロードしてAzure AD アプリケーションに登録、PEM 形式でダウンロードして実行環境の ローカルディレクトリに配置 | 解説済み |
さて本記事はどういう用途に役立つかというと Azure Batch で証明書を管理し、それを Linux プールで使うケースです。
公式ドキュメント や
az batch certificate create
のヘルプに記載があるように、
Batch アカウントが管理できる証明書形式で秘密キーも管理できるのは PFX
だけで PEM
には対応していません。
PFX
のままだと Linux 環境では使いにくいので、実行時に OpenSSL を使用して PEM
に変換するという方式に行きつきました。
Azure Batch が Managed ID に対応してくれれば不要なワークアラウンドなのですが、ノウハウとしては Batch 以外でも有用そうなので整理してみました。 例えばこちら にも以下のような記載があるので、 たまによくあるシチュエーションなのでしょう。
証明書と共にサービス プリンシパルを使用して Azure CLI にサインインするには、証明書を PEM 形式にして、秘密キーを含める必要があります。 証明書が必要な形式ではない場合は、openssl などのツールを使用して変換します。
参考になれば幸いです。