🐨

IP制限をかけているAzure Container RegistryにGitHub ActionsからPushする方法

に公開

やりたいこと

Azureに構築したContainer RegistryにIP制限をかけており、パブリックIPでの接続は社内の規定のネットワークのみ許可しています。
Container Registryに保存するImageはApp ServiceにPushして動かしますが、Azureリソース間はVnet統合でプライベートエンドポイント経由で接続が可能となっています。

GitHub ActionsはSaaSであり、ランナーを実行するとGitHubのクラウド上で動作するためIPが動的です。
そのため、設定したActionsの環境のIPを登録するということは不可能。
しかしContainer Regsitryを全てのIPからアクセスできるようにはしたくない。

解決方法

思いついたのは二つ

1. Actionsのワークフロー内でIPを一時的に解放させる

こちらはワークフローにスクリプトを追加するだけで実現が可能です。

  1. ワークフロー開始時にIPを取得
  2. 対象のAzure Container Registryの許可IPに追加
  3. デプロイ処理
  4. 完了後に追加したIPを削除

という流れです。
今回はこっちを紹介します。

2. セルフホストランナーを使用

自社環境にVM等のサーバーを立てて、そこにActionsのランナー環境を構築します。
そうすることで他のリソース同様にプライベートエンドポイント経由での接続が可能となりセキュアなデプロイパイプラインの構築が可能です。

本番運用等を考えると、こちらが適切なのかもしれません。

ワークフロー内で一時解放する

設定方法

対象のAzureテナントにログイン後、Azure CLIを使って、対象のContainer Registryリソースのネットワーク設定を更新させます。
IPは動的に変わるため、実行のたびにcurlコマンドで現在のIPを取得してきます。

deploy-to-acr-app-service.yml
name: コンテナベースのアプリのデプロイ

on:
  workflow_dispatch:
  push:
    branches:
      - develop

jobs:
  build-and-deploy:
    name: Build and Push to ACR → Deploy to App Service
    runs-on: ubuntu-24.04


    permissions:
      contents: read
      id-token: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        
      # AzureにOICDでログイン(ログインしないとazコマンドが使えない)
      - 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 }}

      # このワークフロー環境のIPを取得して、Azure CLIで対象リソースのネットワーク設定を変更
      - name: Allow ACR Firewall
        run: |
          set -eu
          workflowIP=$(curl -s https://api.ipify.org/)
          echo $workflowIP
          az acr network-rule add \
            --resource-group "${{ secrets.RESOURCE_GROUP_NAME }}" \
            --name "${{ secrets.ACR_RESOURSE_NAME }}" \
            --ip-address $workflowIP
          sleep 60


デプロイが完了したら、追加したIPをネットワーク設定から削除します。
再びAzure CLIで対象のContainer Registryリソースのネットワーク設定を修正します。

deploy-to-acr-app-service.yml
name: コンテナベースのアプリのデプロイ

on:
  workflow_dispatch:
  push:
    branches:
      - develop

jobs:
  build-and-deploy:
    name: Build and Push to ACR → Deploy to App Service
    runs-on: ubuntu-24.04

    permissions:
      contents: read
      id-token: write

    steps:
      ...

      - name: Deny ACR Firewall
        if: always()
        run: |
          workflowIP=$(curl -s https://api.ipify.org/)
          az acr network-rule remove \
            --resource-group "${{ secrets.RESOURCE_GROUP_NAME }}" \
            --name "${{ secrets.ACR_RESOURSE_NAME }}" \
            --ip-address $workflowIP

補足

Azure CLIで対象のリソースにIPを追加した後、反映用に60秒間待たせていますがそれでも反映ができておらずデプロイ時にIP制限エラーになることがたまにあります。

ですので、デプロイ実行直前に再度ネットワーク設定が反映されているか確認することを推奨します。
Azure CLIで対象リソースの許可しているIP一覧を取得して今のIPが存在するかをチェックします。
もし反映されてたら次のステップに進みますが、存在していなければ10秒待機して再度確認するようにしています。

deploy-to-acr-app-service.yml
name: コンテナベースのアプリのデプロイ

on:
  workflow_dispatch:
  push:
    branches:
      - develop

jobs:
  build-and-deploy:
    name: Build and Push to ACR → Deploy to App Service
    runs-on: ubuntu-24.04

    permissions:
      contents: read
      id-token: write

    steps:
      ...

      - name: Verify ACR Firewall Rule Applied
        run: |
          set -eu
          workflowIP=$(curl -s https://api.ipify.org/)
          echo "Wokiflow IP: $workflowIP"

          # ACRのネットワークルールを取得して、IPが含まれているか確認
          for i in {1..10}; do
            echo "Attempt $i: Checking if IP $workflowIP is in ACR firewall rules..."
            
            rules=$(az acr network-rule list \
              --resource-group "${{ secrets.RESOURCE_GROUP_NAME }}" \
              --name "${{ secrets.ACR_RESOURSE_NAME }}" \
              --query "ipRules[?ipAddressOrRange=='$workflowIP'].ipAddressOrRange" \
              -o tsv)
            
            if [ -n "$rules" ]; then
              echo "✅ IP $workflowIP is allowed in ACR firewall"
              exit 0
            fi
            
            if [ $i -lt 10 ]; then
              echo "⏳ IP not found yet, waiting 10 seconds..."
              sleep 10
            fi
          done

          echo "❌ Failed to verify IP in ACR firewall after 10 attempts"
          exit 1

最後に

もし今回取ったような「一時的にActionsのIPを解放する」とか、「セルフホストランナーのGitHub Actionsを使う」以外にいい方法がありましたらご教示いただきたいです!

ヘッドウォータース

Discussion