しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

Managed Identity と GitHub Actions OIDC を使って Azure Container Registry の Admin user を不要にする

Azure でコンテナー系のサービスを利用する上で必須となる Azure Container Registry ですが、実際に利用する上で割とハマりがちなポイントとして Admin user の存在があります。

Azure Container Registry での認証については以下のドキュメントにまとめられています。

Admin user は名前の通り管理者として何でもできる Username / Password を有効化する設定で、権限が強い割に雑に使ってしまいがちですし、Web App for Containers などは基本的に Docker Image の Pull しか行わないのに強すぎる権限を与えてしまう問題があります。

今では Azure Container Registry や Web App for Containers が Azure AD ベースの RBAC に対応しているので、Admin user を完全に無効化した状態でも利用できるようになりました。

今回はこの Admin user を無効化した状態で GitHub Actions での CI/CD と Web App for Containers (Linux / Windows) での実行までの流れを確認しておきました。

GitHub Actions からの Push を OIDC / RBAC にする

Docker Image を GitHub Actions で作成したら Azure Container Registry に Push する必要がありますが、Azure Portal から Workflow を自動生成すると大体 Admin user を利用したものが出来上がります。

以前に紹介した Container Apps の Portal から作成したものは Admin user がガッツリ使われています。

Admin user を不要にするために必要となる RBAC は Azure AD というか Service Principal が必要となるので、まずは GitHub Actions が利用する認証情報を Service Principal に統一する必要があります。

現在は GitHub Actions の OpenID Connect 対応を利用すれば、非常に簡単かつセキュアに Service Principal を GitHub Actions から利用することが出来ます。詳しくは以下のエントリを参照してください。

Azure CLI を使ってログインが完了してしまえば、ACR へのログインは az acr login コマンドだけで行えます。ローカル環境で Docker CLI を使いたい場合でも同じ方法が使えるので便利です。ACR への Push を行うには AcrPush 以上の権限が必要になります。

先日書いた Web App for Containers (Windows) へのデプロイに、Admin user ではなく RBAC を使うように修正したものが以下になります。Azure Login が増えていますがシンプルなコマンドで済んでいます。

permissions:
  id-token: write
  contents: read

jobs:
  build:
    runs-on: windows-latest
    steps:
    - uses: actions/checkout@v3

    - name: Azure Login
      uses: azure/login@v1
      with:
        client-id: ${{ secrets.AZURE_CLIENT_ID }}
        tenant-id: ${{ secrets.AZURE_TENANT_ID }}
        subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

    - name: Log in to container registry
      run: az acr login -n xxxx

    - name: Build and push container image to registry
      run: |
        docker build -t xxxx.azurecr.io/wincontainer-test:${{ github.sha }} -f ./app/Dockerfile ./app/
        docker push xxxx.azurecr.io/wincontainer-test:${{ github.sha }}

この Workflow を実際に動かしてみると、OIDC を使った Azure CLI と ACR へのログインがそれぞれ完了して、作成された Docker Image が正常に Push されていることが確認出来ます。

作成した Service Principal に AcrPush 以外にデプロイする App Service への権限を割り当てれば、1 つの Service Principal で ACR への Push と特定の App Service へのデプロイが行えるようになります。最低限の権限だけを割り当て可能なので、GitHub Actions OIDC は管理面でも有利です。

Managed Identity を利用した Docker Image の Pull 設定

作成した Docker Image の Push は Admin user 無しで行えるようになったので、後は Web App for Containers の Pull で Admin user を使わないようにすれば良いです。

この辺りは割と最近になって追加された機能ですが、Azure Portal から簡単に設定できるのと、ドキュメントも Linux と Windows でそれぞれ用意されているので、その手順通りに実行すれば完了です。

Azure Portal から設定する場合は Deployment Center を開くと、Authentication として Admin credentials か Managed Identity を選択出来ます。Managed Identity を選ぶと Identity として更に System assigned か User assigned を選択できるので、一先ずは System assigned を選んでおくと良いです。

Deployment Center のメッセージにも出ているように Managed Identity を選ぶと ACR の Docker Image とタグの一覧は表示されなくなります。これは権限の問題なので初回だけ手動で入力しておきます。次回以降は GitHub Actions が更新してくれるので必要ありません。

これで設定を保存すると System Assigned Managed Identity が有効化されるので、忘れずに ACR の IAM 設定から、先ほど作成された Managed Identity に対して AcrPull を割り当てておきます。

RBAC の設定後に Deployment Center からログを確認すると AuthType として Token が使われているのと、正常に Docker Image の Pull が行われていることが確認出来ます。

ACR からの Pull には User Assigned Managed Identity も利用可能です。System Assigned Managed Identity はアプリケーションが必要とするリソース専用にして、Key Vault Reference や ACR へのアクセスといったインフラ寄りの部分は User Assigned Managed Identity にするという戦略が良さそうです。

User Assigned Managed Identity を使うには App Service への割り当てが必要ですが、何故か Web App for Containers (Windows) では Azure Portal で割り当て出来なかったので、Azure CLI を使って行いました。

こういう時に Azure CLI の使い方を知っておくと時間を無駄にせずに済みます。特に Managed Identity 周りは ARM レベルでほぼ同じ仕様なので ARM Explorer でも同じように行えます。

Web App for Containers では非常にスムーズに Managed Identity を利用出来ましたが、Container Apps の場合は Admin user は有効にしておかないといけないらしく残念な仕様になっています。

実際に確認はしていないので、CI/CD を使うと Admin user が無効でも動作するかもしれませんが、将来的には無効でも利用できるようになって欲しいところです。

設定後に Deployment Slot を作成する際の注意点

特にここまでは問題なく Managed Identity を使って Web App for Containers への Docker Image のデプロイが行えましたが、Deployment Slot を使った場合のみ注意点があります。

Production スロットで Managed Identity の設定をした後に、Deployment Slot を追加すると動いているように見えますが、実際には Managed Identity が作成されていないので Pull に失敗しています。以下のログを見ると分かるように、ローカルキャッシュで動いています。

Deployment Slot を新しく作成した場合には、Managed Identity の有効化と RBAC の設定を忘れないようにしましょう。User Assigned Managed Identity を使っていても、Deployment Slot の作成時に設定をコピーしてくれないので同じ問題が発生します。

そして Windows Containers の場合には挙動が変わって、こちらでは以下のようなエラーが出て Deployment Slot の作成自体に失敗します。内容からして RBAC 絡みなのは間違いなさそうですが、Deployment Slot の作成と同時に Managed Identity の作成と RBAC の設定は行えないので不可避の予感です。

これは App Service 側の不具合だと思うので、フィードバックを行って修正されるのを願うことにします。

Web App for Containers (Windows) は Azure Portal 周りでちょいちょい不具合があるとはいえ、かなり進化はしていると思うので継続的に触ってフィードバック出来ればと思っています。