BicepによるAzure VMデプロイのCI/CDパイプラインを作ってみた

Azure
前の記事

 

 

これまで、Bicepで作ったVMをPowerShellのコマンドで実行してデプロイしてきましたが、Githubを使ったCI/CDパイプラインを構築してみます。

ご存じのとおり、Githubは2018年にMicrosoftに買収されているので、

その影響かいろいろなリソースでCI/CDのパイプラインが組みやすくなっています。

Azure Pipelinesというサービスもあり具体的な違いは調査してませんが、

Learnのこの書きっぷりを見るにGithubのほうにシフトしようとしてるのかなと思ってます。

 

全体の作業フロー

Microsoft LearnのドキュメントにはAzure VMをGithubでCI/CDパイプラインを作ってデプロイする直接的な方法は見つけれていませんでした。

一番雰囲気近そうなのが以下のURLです

GitHub Actions と Azure を使用してカスタム仮想マシン イメージを構築する
GitHub Actions と Azure を使用してカスタム仮想マシン イメージを構築する方法について説明します

 

ざっくり、以下のような流れで構築していく必要がありそうです。

  1. マネージドIDをGithubに割り当てて認証できるようにする
  2. Github Actions(.github/workflowsのYAMLファイル)でトリガーと動作を定義する
  3. Git pushなどでトリガーさせデプロイを実行する

 

マネージドIDをGithubに割り当てて認証できるようにする

作業内容は複雑なので分解していきます。

アプリ登録

Github ActionsがAzureへ認証するために、Github Actionsをアプリとして登録します。

ここで、以下の3点の情報を押さえておきます。

  • アプリケーション (クライアント) ID
  • ディレクトリ (テナント) ID
  • サブスクリプション ID

アプリケーションIDとディレクトリIDはアプリ登録後に表示されるため、その値をコピーします。

サブスクリプションIDはAzure Portalからサブスクリプションのページに飛んで確認します。

 

クライアント シークレットの作成

次に、このアプリが使用するパスワードを生成します。

規定で180日とあるので、半年ごとにシークレットのローテーションが必要になりそうです。

追加を押すとシークレット情報が出てくるので、「値」をコピーしておきます(ここでコピーしないと2度と表示されないそうな)

 

登録したアプリケーションに権限を割り当て

Github Actions用のアプリは作成したので、これに対象のリソースグループに対する共同作成者権限を割り当てます。

対象のリソースグループのIAMからロールの割り当ての追加を選択し

ロールの種類:共同作成者

メンバー:登録したアプリ

で割り当てを行います。

 

Githubシークレットの設定

アプリ登録の際に控えたシークレットの情報などをGithub側にも登録していきます。

Githubの対象のリポジトリを開いて、

Setting→Secrets and variables→Actionsを開きます。

New repository secretから事前に控えた4つの情報を使って、以下のシークレットを作成します。

Name: AZURE_CREDENTIALS

{
  "clientId": "アプリケーション (クライアント) ID",
  "clientSecret": "シークレットの 値 (Value)",
  "subscriptionId":"サブスクリプション ID",
  "tenantId": "ディレクトリ (テナント) ID"
}

また、これまでコマンドで渡していた引数もGitHub Secretsで渡します。

  • Name: EXISTING_KEYVAULT_ID
    • Secret: リソースID(リソースのプロパティからコピー可能)
  • Name: VM_ADMIN_USERNAME
    • Secret: VMのadminUser名

その他コマンドで引き渡ししていたけれども機密でないような(vmNameなどの)情報は直接main.bicepなどに書き直します。

ワークフローファイルの変更

VSCodeに戻り、現在開いているフォルダに「.github\workflows」というフォルダを作成します。

作成したフォルダの中に「deploy-azure-vm.yml」という以下のファイルを作成します。

# .github/workflows/deploy-azure-vm.yml

name: Deploy Azure VM Bicep (from main.bicep)

# このワークフローが実行されるトリガーを指定
on:
  push:
    branches:
      - master  # masterブランチへのpushで実行
    paths:
      # 変更を監視するファイルを指定
      - 'main.bicep'
      - 'modules/**.bicep'
      
  # GitHubのActionsタブから手動で実行できるようにする
  workflow_dispatch:

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest # 実行環境
    
    steps:
      # 1. リポジトリのコードをチェックアウト
      # (main.bicep と modules/ ディレクトリを読み込むため)
      - name: Checkout code
        uses: actions/checkout@v4

      # 2. Azure へのログイン
      # (Azure Portal で作成した個別のシークレットを使用)
      - name: Log in to Azure
        uses: azure/login@v1
        with:
          # 推奨: サービスプリンシパル情報を1つのシークレット(AZURE_CREDENTIALS)にまとめて渡します。
          # 内容は次の JSON(例)を GitHub Secrets に登録してください:
          # {"clientId":"...","clientSecret":"...","subscriptionId":"...","tenantId":"..."}
          creds: ${{ secrets.AZURE_CREDENTIALS }}

      # 3. Bicep ファイルのデプロイ
      - name: Deploy Bicep (main.bicep)
        uses: azure/arm-deploy@v1
        with:
          # スコープは必須入力です。resourceGroup を指定しているため以下を追加します。
          scope: 'resourcegroup'
          # デプロイ先のサブスクリプションID
          subscriptionId: ${{ secrets.AZURE_SUBSCRIPTION_ID }} 
          
          # ★ ターゲットのリソースグループ名
          resourceGroupName: 'rg-vmdeploy-bicep' 
          
          # ★ 実行するBicepファイル (main.bicep) のパス
          template: './main.bicep' 
          
          # デプロイが失敗した場合にエラーとする
          failOnStdErr: true

          parameters: >
            vmName=vm-deploy-bicep
            adminUsername=${{ secrets.VM_ADMIN_USERNAME }}
            existingKeyVaultId=${{ secrets.EXISTING_KEYVAULT_ID }}
            location=japaneast

masterブランチへpushしActionsを確認

Completeされていることを確認しました。

何か変更してみる

これまでのところでCI/CDパイプラインを組むことができましたが、変更点がないとうまくいっているのかどうかよくわからないので、適当にNSGルールの変更をしてみます。

変更前
## nsg.bicep
 
   securityRules: [
      {
        name: 'AllowRDPInbound'
        properties: {
          priority: 100
          direction: 'Inbound'
          access: 'Allow'
          protocol: 'Tcp'
          sourceAddressPrefix: '*'
          sourcePortRange: '*'
          destinationAddressPrefix: '*'
          destinationPortRange: '3389'
        }
      }
    ]

変更後
## nsg.bicep

    securityRules: [
      {
        name: 'AllowRDPInbound'
        properties: {
          priority: 100
          direction: 'Inbound'
          access: 'Allow'
          protocol: 'Tcp'
          sourceAddressPrefix: '*' 
          sourcePortRange: '*'
          destinationAddressPrefix: '*'
          destinationPortRange: '3389'
        }
      }
      {
        name: 'Allow-HTTP-8080-Test'
        properties: {
          priority: 500 
          access: 'Allow'
          direction: 'Inbound'
          protocol: 'Tcp'
          sourcePortRange: '*'
          destinationPortRange: '8080'
          sourceAddressPrefix: 'Internet'
          destinationAddressPrefix: '*'
        }
      }
    ]

インバウンドルールにインターネットから8080の通信許可を与えます。

保存してgit pushを行います。

 

Github Actionsの方もComplete jobになるのを確認します。

 

ポータル画面でNSGの設定画面を更新して確認します。

8080の許可ルールが追加されていることがわかります。

 

まとめ

Github Secretsを使って機密情報のコーディングは避けつつ、各リソースのCI/CDパイプラインを構成することができました。

CI/CDパイプラインを作ってデプロイ自動化しても、各モジュールをパラでデプロイするようなコード構成にすると、yamlで依存関係を処理しなければいけなくなります。

そのため、今回使っているmain.bicepのように、デプロイするコードは一元的に管理することが推奨されているみたいです。

※bicepは依存関係のあるリソースをうまいことやってくれたりする機能もあるし、depends onなどで明示的に整理することもできる。

コメント