💬

GitHub-hosted-runnnerをBicepでVNET統合する

に公開

0. はじめに

GitHub ActionsでWorkflowを実行時に、AzureのPrivate Network経由で
GitHub-Azure間の通信ができるようにするための手順を記載します。

※本ドキュメントは、以下のドキュメントをベースに手順化したものです。
企業内の GitHub ホストランナー向けの Azure プライベート ネットワークについて

https://docs.github.com/ja/enterprise-cloud@latest/admin/configuring-settings/configuring-private-networking-for-hosted-compute-products/about-azure-private-networking-for-github-hosted-runners-in-your-enterprise

■アーキテクチャ

https://github.com/yutaka-art/gh-runner-azure-vnet

1. 事前準備

1.1 GraphQLでデータベースIDを取得

以下のページを開き、Enterprise owner権限を保持するユーザでサインインし、以下のコマンドを入力し、データベースIDを取得してください。

GraphQLエクスプローラ

query {
  enterprise (slug: <your-githubenterprise-name>) {
    databaseId
    name
  }
}

1.2 Bicepファイルの作成

以下の Bicep ファイルを作成し、それぞれ、ローカル端末任意のディレクトリへ配置してください。

1.2.1 actions-nsg-deployment.bicep

GitHub Actions Runner などのワークロードが Azure 仮想ネットワークからインターネット上の特定サービスへ通信できるようにするためのネットワークセキュリティグループ(NSG)を構成します。

actions-nsg-deployment.bicep
@description('NSG for outbound rules')
param location string
param nsgName string = 'actions_NSG'

resource actions_NSG 'Microsoft.Network/networkSecurityGroups@2024-07-01' = {
  name: nsgName
  location: location
  properties: {
    securityRules: [
      {
        name: 'AllowVnetOutBoundOverwrite'
        properties: {
          protocol: 'TCP'
          sourcePortRange: '*'
          destinationPortRange: '443'
          sourceAddressPrefix: '*'
          destinationAddressPrefix: 'VirtualNetwork'
          access: 'Allow'
          priority: 200
          direction: 'Outbound'
          destinationAddressPrefixes: []
        }
      }
      {
        name: 'AllowOutBoundActions'
        properties: {
          protocol: '*'
          sourcePortRange: '*'
          destinationPortRange: '443'
          sourceAddressPrefix: '*'
          access: 'Allow'
          priority: 210
          direction: 'Outbound'
          destinationAddressPrefixes: [
            '4.175.114.51/32'
            '20.102.35.120/32'
            '4.175.114.43/32'
            '20.72.125.48/32'
            '20.19.5.100/32'
            '20.7.92.46/32'
            '20.232.252.48/32'
            '52.186.44.51/32'
            '20.22.98.201/32'
            '20.246.184.240/32'
            '20.96.133.71/32'
            '20.253.2.203/32'
            '20.102.39.220/32'
            '20.81.127.181/32'
            '52.148.30.208/32'
            '20.14.42.190/32'
            '20.85.159.192/32'
            '52.224.205.173/32'
            '20.118.176.156/32'
            '20.236.207.188/32'
            '20.242.161.191/32'
            '20.166.216.139/32'
            '20.253.126.26/32'
            '52.152.245.137/32'
            '40.118.236.116/32'
            '20.185.75.138/32'
            '20.96.226.211/32'
            '52.167.78.33/32'
            '20.105.13.142/32'
            '20.253.95.3/32'
            '20.221.96.90/32'
            '51.138.235.85/32'
            '52.186.47.208/32'
            '20.7.220.66/32'
            '20.75.4.210/32'
            '20.120.75.171/32'
            '20.98.183.48/32'
            '20.84.200.15/32'
            '20.14.235.135/32'
            '20.10.226.54/32'
            '20.22.166.15/32'
            '20.65.21.88/32'
            '20.102.36.236/32'
            '20.124.56.57/32'
            '20.94.100.174/32'
            '20.102.166.33/32'
            '20.31.193.160/32'
            '20.232.77.7/32'
            '20.102.38.122/32'
            '20.102.39.57/32'
            '20.85.108.33/32'
            '40.88.240.168/32'
            '20.69.187.19/32'
            '20.246.192.124/32'
            '20.4.161.108/32'
            '20.22.22.84/32'
            '20.1.250.47/32'
            '20.237.33.78/32'
            '20.242.179.206/32'
            '40.88.239.133/32'
            '20.121.247.125/32'
            '20.106.107.180/32'
            '20.22.118.40/32'
            '20.15.240.48/32'
            '20.84.218.150/32'
          ]
        }
      }
      {
        name: 'AllowOutBoundGitHub'
        properties: {
          protocol: '*'
          sourcePortRange: '*'
          destinationPortRange: '443'
          sourceAddressPrefix: '*'
          access: 'Allow'
          priority: 220
          direction: 'Outbound'
          destinationAddressPrefixes: [
            '140.82.112.0/20'
            '143.55.64.0/20'
            '185.199.108.0/22'
            '192.30.252.0/22'
            '20.175.192.146/32'
            '20.175.192.147/32'
            '20.175.192.149/32'
            '20.175.192.150/32'
            '20.199.39.227/32'
            '20.199.39.228/32'
            '20.199.39.231/32'
            '20.199.39.232/32'
            '20.200.245.241/32'
            '20.200.245.245/32'
            '20.200.245.246/32'
            '20.200.245.247/32'
            '20.200.245.248/32'
            '20.201.28.144/32'
            '20.201.28.148/32'
            '20.201.28.149/32'
            '20.201.28.151/32'
            '20.201.28.152/32'
            '20.205.243.160/32'
            '20.205.243.164/32'
            '20.205.243.165/32'
            '20.205.243.166/32'
            '20.205.243.168/32'
            '20.207.73.82/32'
            '20.207.73.83/32'
            '20.207.73.85/32'
            '20.207.73.86/32'
            '20.207.73.88/32'
            '20.217.135.1/32'
            '20.233.83.145/32'
            '20.233.83.146/32'
            '20.233.83.147/32'
            '20.233.83.149/32'
            '20.233.83.150/32'
            '20.248.137.48/32'
            '20.248.137.49/32'
            '20.248.137.50/32'
            '20.248.137.52/32'
            '20.248.137.55/32'
            '20.26.156.215/32'
            '20.26.156.216/32'
            '20.26.156.211/32'
            '20.27.177.113/32'
            '20.27.177.114/32'
            '20.27.177.116/32'
            '20.27.177.117/32'
            '20.27.177.118/32'
            '20.29.134.17/32'
            '20.29.134.18/32'
            '20.29.134.19/32'
            '20.29.134.23/32'
            '20.29.134.24/32'
            '20.87.245.0/32'
            '20.87.245.1/32'
            '20.87.245.4/32'
            '20.87.245.6/32'
            '20.87.245.7/32'
            '4.208.26.196/32'
            '4.208.26.197/32'
            '4.208.26.198/32'
            '4.208.26.199/32'
            '4.208.26.200/32'
            '4.225.11.196/32'
            '4.237.22.32/32'
          ]
        }
      }
      {
        name: 'AllowStorageOutbound'
        properties: {
          protocol: '*'
          sourcePortRange: '*'
          destinationPortRange: '443'
          sourceAddressPrefix: '*'
          destinationAddressPrefix: 'Storage'
          access: 'Allow'
          priority: 230
          direction: 'Outbound'
          destinationAddressPrefixes: []
        }
      }
    ]
  }
}

1.2.2 networkSettings.bicep

GitHub Hosted Runner 向けの VNET 統合設定(networkSettings リソース)を作成しています。
指定したサブネットとビジネスID(databaseId)を使って、GitHub Actions Hosted Runner の仮想ネットワーク統合を定義しています。

networkSettings.bicep
param location string
param subscriptionId string
param resourceGroupName string
param vnetName string
param subnetName string
param networkSettingsName string
param databaseId string

var subnetResourceId = resourceId(
  subscriptionId,
  resourceGroupName,
  'Microsoft.Network/virtualNetworks/subnets',
  vnetName,
  subnetName
)

resource networkSettings 'GitHub.Network/networkSettings@2024-04-02' = {
  name: networkSettingsName
  location: location
  properties: {
    subnetId: subnetResourceId
    businessId: databaseId
  }
}

2. 構築

2.1 Azureコンポーネントの作成

管理者で PowerShell を起動します。以下のコマンドを実行してください。
※パラメータは適宜調整してください。

execute.ps1
# 以下が設定する必要があるパラメータです
#export AZURE_LOCATION=YOUR_AZURE_LOCATION
#export SUBSCRIPTION_ID=YOUR_SUBSCRIPTION_ID
#export TENANT_ID=YOUR_TENANT_ID
#export RESOURCE_GROUP_NAME=YOUR_RESOURCE_GROUP_NAME
#export VNET_NAME=YOUR_VNET_NAME
#export SUBNET_NAME=YOUR_SUBNET_NAME
#export NSG_NAME=YOUR_NSG_NAME
#export NETWORK_SETTINGS_RESOURCE_NAME=YOUR_NETWORK_SETTINGS_RESOURCE_NAME
#export DATABASE_ID=YOUR_DATABASE_ID

# 0. 変数の設定
$AZURE_LOCATION='japaneast'
$SUBSCRIPTION_ID='99999999-XXXX-XXXX-XXXX-XXXXXXXXXXXX'     # 環境に合わせて設定してください
$TENANT_ID='99999999-XXXX-XXXX-XXXX-XXXXXXXXXXXX'           # 環境に合わせて設定してください
$RESOURCE_GROUP_NAME='rg-integrated-runner'                 # 任意の値としてください。「rg」はリソースグループの推奨される命名規則です
$VNET_NAME='vnet-integrated-runner'                         # 任意の値としてください。「vnet」は仮想ネットワークの推奨される命名規則です
$SUBNET_NAME='snet-integrated-runner'                       # 任意の値としてください。「snet」はサブネットの推奨される命名規則です
$NSG_NAME='nsg-integrated-runner'                           # 任意の値としてください。「nsg」はネットワークセキュリティグループの推奨される命名規則です
$NETWORK_SETTINGS_RESOURCE_NAME='nsr-integrated-runner'     # 任意の値としてください。「nsr」はネットワークセキュリティルールの推奨される命名規則です
$DATABASE_ID='999999'                                       # 1.1で取得したデータベースID

# これらはデフォルト値です。アドレスとサブネットプレフィックスを任意の値へ調整してください。
$ADDRESS_PREFIX='10.100.0.0/16'
$SUBNET_PREFIX='10.100.1.0/24'

# 0. Azure CLI ログイン
az login --tenant $TENANT_ID
# 1. Register resource provider GitHub.Network
az provider register --namespace GitHub.Network
# 2. Create resource group $RESOURCE_GROUP_NAME at $AZURE_LOCATION
az group create --name $RESOURCE_GROUP_NAME --location $AZURE_LOCATION
# 3. Create NSG rules deployed with 'actions-nsg-deployment.bicep' file
az deployment group create --resource-group $RESOURCE_GROUP_NAME --template-file ./bicep/actions-nsg-deployment.bicep --parameters location=$AZURE_LOCATION nsgName=$NSG_NAME
# 4. Create vnet $VNET_NAME and subnet $SUBNET_NAME
az network vnet create --resource-group $RESOURCE_GROUP_NAME --name $VNET_NAME --address-prefix $ADDRESS_PREFIX --subnet-name $SUBNET_NAME --subnet-prefixes $SUBNET_PREFIX
# 5. Delegate subnet to GitHub.Network/networkSettings and apply NSG rules
az network vnet subnet update --resource-group $RESOURCE_GROUP_NAME --name $SUBNET_NAME --vnet-name $VNET_NAME --delegations GitHub.Network/networkSettings --network-security-group $NSG_NAME
# 6.Create network settings resource $NETWORK_SETTINGS_RESOURCE_NAME with 'networkSettings.bicep' file
az deployment group create --resource-group $RESOURCE_GROUP_NAME --template-file ./bicep/networkSettings.bicep --parameters location=$AZURE_LOCATION subscriptionId=$SUBSCRIPTION_ID resourceGroupName=$RESOURCE_GROUP_NAME vnetName=$VNET_NAME subnetName=$SUBNET_NAME networkSettingsName=$NETWORK_SETTINGS_RESOURCE_NAME databaseId=$DATABASE_ID
# 7. Get GitHubId from network settings resource
az resource show --resource-group $RESOURCE_GROUP_NAME --name $NETWORK_SETTINGS_RESOURCE_NAME --resource-type GitHub.Network/networkSettings --api-version 2024-04-02 --query "tags.GitHubId" --output tsv

2.2 Enterprise hosted compute networkの構築

Enterprise > settings > hosted compute networking を開き、2.1で取得したGitHubIdを入力し設定します。

2.3 Runnerグループの構築

Enterprise > Policies > Actions > Runner groups を開き、New runner group を押下します。
Group name は、integrated-azure-runner-group とします。
※任意の名称で問題ありません。

2.4 Runnerの構築

Enterprise > Policies > Actions>Runner groups > integrated-azure-runner-group > New runner を押下し、New GitHub-hosted runner を選択します。
Nameは、integrated-azure-runnerとします。
※任意の名称で問題ありません。

2.5 Runnerのアクセス許可

Organization > Settings > Actions > Runner groups > integrated-azure-runner-group を開き、 Repository access で使用を許可するリポジトリを設定してください。

3. 動作確認

以下のActionsを実装し、実際にVNET統合された環境で動作しているかを確認します。

ipcheck.yml
name: ipcheck

on:
  workflow_dispatch:

jobs:
  check-network:
    runs-on: integrated-azure-runner
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Install net-tools and iproute2 (if needed)
        run: |
          sudo apt-get update
          sudo apt-get install -y net-tools iproute2

      - name: Show network interface and IP address
        run: |
          echo "=== ip addr ==="
          ip addr
          echo "=== ip route ==="
          ip route
          echo "=== curl to check public IP ==="
          curl -s https://api.ipify.org

      - name: DNS resolution test
        run: |
          echo "=== DNS resolution ==="
          nslookup github.com
取得した値 期待値 説明
プライベート IP: 10.100.1.4/24 10.100.1.0/24 (Bicep で作った $SUBNET_PREFIX Runner NIC が作成したサブネット上にあることを示す最重要証拠
デフォルト GW: 10.100.1.1 同じサブネット内 Azure 仮想ネットワークの既定ルータ
メタデータ ルート: 168.63.129.16 / 169.254.169.254 Azure 固有 Azure IaaS VM/NIC が生成された証拠
パブリック IP: 20.222.184.86 Microsoft (AS 8075) 範囲 Azure VNET NAT から外向けにスナットされている IP (Japan East リージョン) (ipinfo.io)
nslookup github.com 結果: 20.27.177.113 NSG の AllowOutBoundGitHub ルールに含まれる NSG が想定どおり GitHub 宛通信を許可

これらを要約すると、以下のことがわかります。

  • 取得した プライベート IP が Bicep で指定したサブネット範囲に一致している
  • ルートテーブル・メタデータ IP・NSG ルールとも整合が取れている

GitHub-hosted Runner が Azure VNET へプライベート接続された状態でジョブを実行しています。

4. 削除

リファレンス

https://docs.github.com/ja/enterprise-cloud@latest/admin/configuring-settings/configuring-private-networking-for-hosted-compute-products/about-azure-private-networking-for-github-hosted-runners-in-your-enterprise

https://github.com/yutaka-art/gh-runner-azure-vnet

GitHubで編集を提案

Discussion