💬

Azure で IaC (ARM Template/Bicep) するなら PSRule for Azure!#2 [CI パイプライン編]

2022/09/08に公開

先日書いた PSRule for Azure 記事の続きです。今回は、PSRule for Azure を GitHub Actions に導入する方法と、Azure Monitor との連携について紹介したいと思います。

PSRule for Azure の概要や、ローカル環境での使い方については、前回の記事を参照してみてください。

CI パイプラインへの導入

PSRule を CI パイプラインに導入するには、次のアクションを使います。

本記事では、個人的に使い慣れている GitHub Actions を例に取り、導入方法を簡単に説明したいと思います(といってもめちゃくちゃ簡単なので特に難しい点はありません)。

準備

パイプラインを導入するにあたり事前準備すべきことは、ディレクトリ構造の設計と、ps-rule.yaml の配置だけです。今回想定するディレクトリ構造と ps-rule.yaml は、以下の通りです (これは前回の記事と同じですが念のため再掲しておきます)。

.
├── .devcontainer/
├── .ps-rule/ <------------------------- 独自ルールを定義するディレクトリ
├── .vscode/
├── azure/
│   ├── deployment/
│   │   ├── project01/
│   │   │   └── main.bicep <------------ project01 の Bicep ファイル
│   │   └── project02/
│   │       └── main.bicep <------------ project02 の Bicep ファイル
│   └── modules/
│       └── my-module/
│           ├── main.bicep <------------ Bicep Module の定義ファイル
│           └── .tests/
│               └── main.tests.bicep <-- Bicep Module のテスト
└── ps-rule.yaml <---------------------- PSRule の設定
ps-rule.yaml
ps-rule.yaml
#
# PSRule for Azure configuration
#

# Please see the documentation for all configuration options:
# https://aka.ms/ps-rule/options
# https://aka.ms/ps-rule-azure/options

# Configure binding for local rules.
binding:
  preferTargetInfo: true
  targetType:
    - type
    - resourceType

# Require minimum versions of modules.
requires:
  PSRule: "@pre >=2.2.0"
  PSRule.Rules.Azure: "@pre >=1.17.1"

# Use PSRule for Azure.
include:
  module:
    - PSRule.Rules.Azure

output:
  culture:
    - "ja-JP"

input:
  pathIgnore:
    # Ignore other files in the repository.
    - ".devcontainer/"
    - ".vscode/"
    - ".github/"
    - "*.md"

    # Exclude modules but not tests.
    - "azure/modules/**/*.bicep"
    - "!azure/modules/**/*.tests.bicep"

configuration:
  # Enable automatic expansion of Azure parameter files.
  AZURE_PARAMETER_FILE_EXPANSION: true

  # Enable automatic expansion of Azure Bicep source files.
  AZURE_BICEP_FILE_EXPANSION: true

  # Configures the number of seconds to wait for build Bicep files.
  AZURE_BICEP_FILE_EXPANSION_TIMEOUT: 10

Action の定義

以下のような情報を参考にしながら、.github/workflows/test-azure-infra-code.yaml にアクションを定義しました。Pull Request を発行した時に Bicep / ARM Template の検証を実行するアクションです。

.github/workflows/test-azure-infra-code.yaml
name: Test Azure Infra code with PSRule

on:
  pull_request:
    branches:
      - main
    paths:
      - ".github/workflows/*"
      - "azure/**.bicep"
      - "azure/**.json"

permissions:
  contents: read

jobs:
  psrule_for_azure:
    name: Analyze templates
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Analyze Azure template files
        uses: microsoft/ps-rule@main
        with:
          modules: "PSRule.Rules.Azure"

microsoft/ps-rule@main に関する躓きポイントを一つ。なぜか (with.path で明示的に指定しても) PSRule の config ファイル ps-rule.yaml 読み取って実行してくれないみたいで、with.modules で利用するモジュール (PSRule.Rules.Azure) を明示的に指定しない限り、プリセットルールなしで実行されてしまいます。ちょっと解せない動作ですが、PSRule for Azure を動かすだけならこの設定で特に問題はないのでこのまま進めます。

Pull Request 時の動作確認

GitHub Action の設定が完了したところで、動作確認してみましょう。適当なブランチに以下の Bicep ファイルをつっこんで、Pull Request を発行してみます。

動作確認に使った bicep コード
azure/deployment/project02/main.bicep
@description('Location for all resources.')
param location string = resourceGroup().location

var vnetName = 'vnet-test'

resource vnet 'Microsoft.Network/virtualNetworks@2021-05-01' = {
  name: vnetName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.0.0.0/16'
      ]
    }
    subnets: [
      {
        name: 'default'
        properties: {
          addressPrefix: '10.0.2.0/24'
        }
      }
    ]
  }
}

期待通り (?) テストがこけてくれました。

ログを見てみると、サブネットに NSG を関連付けていないことと、タグが付いてないことで怒られているようですね。

公式ドキュメント 内でルール ID (たとえば AZR-000263) を検索すると、ルールの詳細ページに飛ぶことができます。エラーが発生したルールを修正する際に役立ててください。

応用: Azure Monitor との連携

PSRule には、検証結果を Azure Monitor (Log Analytics Workspace) に出力するためのモジュール PSRule.Monitor が用意されています。ここからは、CI パイプラインのテスト結果を、Log Analytics Workspace にログ出力する機能を試していきたいと思います。

手順 1. Log Analytics Workspcae を作成する

https://docs.microsoft.com/ja-jp/azure/azure-monitor/logs/quick-create-workspace?tabs=azure-portal

まずは Log Analytics Workspace を作成します。

作成できたら、連携のために利用する Workspace ID とアクセスキー (Primary/Secondary どちらでも可) を控えておきます。これらの値は、Azure Portal のエージェント管理ページから確認できます。

手順 2. モジュール PSRule.Monitor を追加する

公式ドキュメントのガイド通り GitHub Actions の設定を編集します。具体的には、microsoft/ps-rulePSRule.Monitor を読み込ませつつ、環境変数に Workspace ID とアクセスキーを設定します。

  psrule_for_azure:
    name: Analyze templates
    runs-on: ubuntu-latest
+   environment: psrule-for-azure
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Analyze Azure template files
        uses: microsoft/ps-rule@main
        with:
-         modules: "PSRule.Rules.Azure"
+         modules: PSRule.Rules.Azure,PSRule.Monitor
+         conventions: Monitor.LogAnalytics.Import
+       env:
+         PSRULE_CONFIGURATION_MONITOR_WORKSPACE_ID: ${{ secrets.MONITOR_WORKSPACE_ID }}
+         PSRULE_CONFIGURATION_MONITOR_WORKSPACE_KEY: ${{ secrets.MONITOR_WORKSPACE_KEY }}

手順 3. シークレットを作成する

最後に、WorkspaceID とアクセスキーをシークレットに保存すれば設定完了です。GitHub レポジトリの設定画面から追加します (今回の場合、Environment 名は psrule-for-azure にしてます)。

GitHub シークレット名 設定する値
MONITOR_WORKSPACE_ID Log Analytics Workspace の Workspace ID
MONITOR_WORKSPACE_KEY Log Analytics Workspace の アクセスキー

https://docs.github.com/ja/actions/deployment/targeting-different-environments/using-environments-for-deployment

ログの出力を確認する

以上の手順を完了すれば、新たに GitHub 上でパイプラインを走らせる度に、自動的に結果が Azure Monitor 側にログが出力されるようになります。

体感だと 5 分くらいデータインジェスト レイテンシがあるので、少し時間をおいて確認すると良いでしょう。Log Analytics Workspace の [Logs] ページから、PSRule_CL テーブルのログを検索してみてください。

  • テーブル名: PSRule_CL
  • スキーマ
カラム名 説明
TimeGenerated データが生成された時刻 9/8/2022, 5:35:49.822 AM (UTC)
RuleId_s ルールの正式な ID。PSRule for Azure の場合 PSRule.Rules.Azure\... となる PSRule.Rules.Azure\Azure.VNET.UseNSGs
RuleName_s ルール名 Azure.VNET.UseNSGs
DisplayName_s ルールのユーザーフレンドリー名。ルール名と変わらん気がする Azure.VNET.UseNSGs
TargetName_s 検証対象リソースの名前 vnet-test
TargetType_s 検証対象リソースのリソース種別 Microsoft.Network/virtualNetworks
Outcome_s 検証結果。Pass または Fail Fail
Duration_d 実行時間 (ms) 1
RunId_s 実行時の ID。GitHub Actions から実行すると <username>/<repo-name>/<unique-id> となる OpenJNY/psrule-demo/3012702015
CorrelationId 実行時の ID と同義の UUID aa1cb324-d815-4f1b-b86a-d0bfc922eb56

たとえば、リソースごとに Pass した割合と失敗ルールの一覧を表示したければ、次のクエリを実行すれば良いです。

let repo = "OpenJNY/psrule-demo";
//
PSRule_CL 
| where RunId_s startswith repo
| summarize
    TimeGenerated = min(TimeGenerated),
    PassRate = 100 * sum(iff(Outcome_s == "Pass", 1, 0)) / count(),
    FailedRules = make_set_if(RuleName_s, Outcome_s != "Pass")
    by RunId_s, TargetType_s, TargetName_s
| project TimeGenerated, RunId_s, TargetType_s, TargetName_s, PassRate, FailedRules
| sort by TimeGenerated asc, TargetType_s asc, TargetName_s asc
実行結果

まとめ

ということで、以上が GitHub Actions を使う場合の PSRule for Azure 導入方法でした。

前回の記事とあわせて PSRule for Azure の使い方を簡単にさらってみましたが、容易に導入できたのが非常に印象的でした。もし Azure ARM Template や Bicep の自動テストをどうしようか悩んでいる方がいれば、ぜひテイスティングだけでもしてみてください。

また、Azure でガバナンス確保に使える機能/製品には、IAM、リソースロック、Azure Policy、Azure Blueprints などなど、様々なものがあります。以下の MSLearn でざっと把握することが出来るので、ぜひデザートとしてご賞味ください🍰

https://docs.microsoft.com/ja-jp/training/modules/build-cloud-governance-strategy-azure/

参考文献

https://zenn.dev/openjny/articles/dbf98272d2317b

Discussion