👮‍♂️

GitHub Copilot を利用して上手く動かないサンプル Policy をサクッと修正

に公開

はじめに

以前 Azure Policy について の記事を作成しましたが、今回は Policy をより簡単に作成しましょうというお話です

当時は特に意識してサンプル Policy を選択したわけではなかったのですが AzAdvertizer から選んだ Policy はそのまま適用することができませんでした。記事にはさらっと「ここ修正するんだよ」と記載していますが、実は修正に時間が掛かっています。。

で、ちょうど同僚が公開している以下の記事を見てみたところ、この方法なら楽に修正ができるのでは?!と思って試してみたのでその内容を記載したいと思います

最近 AI が流行っているので AI 関連の記事も書きたいなぁ~。でも何書こうかなぁ・・・と思っていたところにおいしそうなネタ(記事)が降ってきた!!という感じです。内容もわかりやすく記載いただいており感謝です!

事前準備

以下の記事を参考に GitHub Copilot (カスタムチャットモード) が利用できるように構成します

なお、私の環境で作成されたカスタムチャットモードの Markdown ファイルは以下となります(model の指定は無しで作成されていますが、細かいことは気にしない)

https://github.com/takutsu001/github-chatmodes/blob/main/azure-policy.chatmode.md#L1-L152

今回利用するサンプル Policy

以前の記事で利用した Deny-Subnet-Without-Nsg.json を利用したいと思います

詳細は 以前の記事 を参照いただければと思いますが、「仮想ネットワーク(VNet)内のサブネットにネットワークセキュリティグループ(NSG)が設定されていない場合に、その状況を監査、拒否、または無効化する」というポリシーです

以前は作成したポリシーをイニシアティブに含めていますが、今回はイニシアティブに含めずにサンプルポリシーをリソースグループに適用して動作確認しています

実際に Policy を適用してみよう

では実際にやってみましょう。一応作業前提および作業の流れを記載しておきます

作業前提

  • VS Code でカスタムチャットモードが利用できる状態であること
  • 検証用のリソースが作成されていること(リソースグループ、VNet)

作業の流れ

  1. サンプル Policy を作成(失敗)
  2. GitHub Copilot を利用して Policy の修正
  3. サンプル Policy の再作成
  4. 動作確認

1. サンプル Policy を作成(失敗)

作成手順は こちら を参照してください

作成時にポリシーを保存しようとすると以下のエラーが発生して保存ができません

画像だと小さく文字が見えにくいので、テキストでも記載しておきます

要求の内容が無効であり、逆シリアル化できませんでした: 'Could not find member 'name' on object of type 'PolicyDefinitionProperties'. Path 'properties.name', line 1, position 337.'。

2. GitHub Copilot を利用して Policy の修正

利用するサンプル Policy がそのままでは作成できないため修正を行う必要があります。この修正を GitHub Copilot のカスタムチャットモードを利用して行います(今回の検証で利用したモデルは GPT-5

なお、MCP サーバの設定を入れておくと MCP サーバーに問い合わせしてしまうため、本検証ではカスタムチャットモードを利用する際に組み込みの機能以外は無効化して実行しています

また、参考までに入力したプロンプトを以下に記載しておきます

入力したプロンプト
以下のPolicyをAzure Portalを利用して作成しようとしましたが、失敗しました。修正してください。エラーメッセージは「要求の内容が無効であり、逆シリアル化できませんでした: 'Could not find member 'name' on object of type 'PolicyDefinitionProperties'. Path 'properties.name', line 1, position 337.'。」です。
-----
{
  "name": "Deny-Subnet-Without-Nsg",
  "type": "Microsoft.Authorization/policyDefinitions",
  "apiVersion": "2021-06-01",
  "scope": null,
  "properties": {
    "policyType": "Custom",
    "mode": "All",
    "displayName": "Subnets should have a Network Security Group",
    "description": "This policy denies the creation of a subnet without a Network Security Group. NSG help to protect traffic across subnet-level.",
    "metadata": {
      "version": "2.0.0",
      "category": "Network",
      "source": "https://github.com/Azure/Enterprise-Scale/",
      "alzCloudEnvironments": [
        "AzureCloud",
        "AzureChinaCloud",
        "AzureUSGovernment"
      ]
    },
    "parameters": {
      "effect": {
        "type": "String",
        "allowedValues": [
          "Audit",
          "Deny",
          "Disabled"
        ],
        "defaultValue": "Deny",
        "metadata": {
          "displayName": "Effect",
          "description": "Enable or disable the execution of the policy"
        }
      },
      "excludedSubnets": {
        "type": "Array",
        "metadata": {
          "displayName": "Excluded Subnets",
          "description": "Array of subnet names that are excluded from this policy"
        },
        "defaultValue": [
          "GatewaySubnet",
          "AzureFirewallSubnet",
          "AzureFirewallManagementSubnet"
        ]
      }
    },
    "policyRule": {
      "if": {
        "anyOf": [
          {
            "allOf": [
              {
                "equals": "Microsoft.Network/virtualNetworks",
                "field": "type"
              },
              {
                "count": {
                  "field": "Microsoft.Network/virtualNetworks/subnets[*]",
                  "where": {
                    "allOf": [
                      {
                        "exists": "false",
                        "field": "Microsoft.Network/virtualNetworks/subnets[*].networkSecurityGroup.id"
                      },
                      {
                        "field": "Microsoft.Network/virtualNetworks/subnets[*].name",
                        "notIn": "[[parameters('excludedSubnets')]"
                      }
                    ]
                  }
                },
                "notEquals": 0
              }
            ]
          },
          {
            "allOf": [
              {
                "field": "type",
                "equals": "Microsoft.Network/virtualNetworks/subnets"
              },
              {
                "field": "name",
                "notIn": "[[parameters('excludedSubnets')]"
              },
              {
                "field": "Microsoft.Network/virtualNetworks/subnets/networkSecurityGroup.id",
                "exists": "false"
              }
            ]
          }
        ]
      },
      "then": {
        "effect": "[[parameters('effect')]"
      }
    }
  }
}

作成された回答は以下の通りです

特に指示していませんが、不具合解消だけではなくベストプラクティスに沿うように Policy を修正してたり、IaC デプロイ時の補足事項を回答したり、指定したチェックリストに沿ってチェックしてくれたりしています(なにこれすごい)

問題点と原因

ポータルに貼る用(ラッパなし)完結形

ARM/Bicep 用リソースラッパ例

CLI での作成

チェックリスト適用結果

修正された Policy は以下です

修正後の Policy
policy-definition-subnet-nsg.json
{
  "policyType": "Custom",
  "mode": "Indexed",
  "displayName": "Subnets should have a Network Security Group",
  "description": "Deny creation/update of subnets without a Network Security Group unless explicitly excluded.",
  "metadata": {
    "version": "2.0.1",
    "category": "Network",
    "source": "https://github.com/Azure/Enterprise-Scale/",
    "alzCloudEnvironments": [
      "AzureCloud",
      "AzureChinaCloud",
      "AzureUSGovernment"
    ]
  },
  "parameters": {
    "effect": {
      "type": "String",
      "allowedValues": [
        "Audit",
        "Deny",
        "Disabled"
      ],
      "defaultValue": "Audit",
      "metadata": {
        "displayName": "Effect",
        "description": "Choose Audit (stage), Deny (enforce), or Disabled."
      }
    },
    "excludedSubnets": {
      "type": "Array",
      "metadata": {
        "displayName": "Excluded Subnets",
        "description": "Subnet names to exclude (e.g. gateway or firewall management)."
      },
      "defaultValue": [
        "GatewaySubnet",
        "AzureFirewallSubnet",
        "AzureFirewallManagementSubnet"
      ]
    }
  },
  "policyRule": {
    "if": {
      "anyOf": [
        {
          "allOf": [
            {
              "field": "type",
              "equals": "Microsoft.Network/virtualNetworks"
            },
            {
              "count": {
                "field": "Microsoft.Network/virtualNetworks/subnets[*]",
                "where": {
                  "allOf": [
                    {
                      "field": "Microsoft.Network/virtualNetworks/subnets[*].networkSecurityGroup.id",
                      "exists": false
                    },
                    {
                      "field": "Microsoft.Network/virtualNetworks/subnets[*].name",
                      "notIn": "[parameters('excludedSubnets')]"
                    }
                  ]
                }
              },
              "notEquals": 0
            }
          ]
        },
        {
          "allOf": [
            {
              "field": "type",
              "equals": "Microsoft.Network/virtualNetworks/subnets"
            },
            {
              "field": "name",
              "notIn": "[parameters('excludedSubnets')]"
            },
            {
              "field": "Microsoft.Network/virtualNetworks/subnets/networkSecurityGroup.id",
              "exists": false
            }
          ]
        }
      ]
    },
    "then": {
      "effect": "[parameters('effect')]"
    }
  }
}

3. サンプル Policy の再作成

修正された定義を利用して再度 Policy を作成します。設定内容は以下の通りです

項目 設定値
定義の場所 リソースグループが存在するサブスクリプションを指定
名前 [Test-Copilot]Deny-Subnet-Without-Nsg
カテゴリ Copilot-test

3-1. ポリシー定義の再作成

3-2. ポリシー名とカテゴリの修正

3-3. ポリシー定義の割り当て


4. 動作確認

本検証で作成したポリシー定義は NSGを適用していない場合はサブネットを作成することができない という内容のため実際にNSGを適用しない状態でサブネットを作成して動作確認を行います

4-1. 作業前提

  • リソースグループ(Policy-RG)と VNet(Policy-VNet)を作成済み
  • VNet(Policy-VNet)にはサブネットは1つも作成されていない

4-2. 動作確認

NSGを指定しない状態でサブネットを作成します


少し時間を置いてから、リソースグループのポリシー画面にて状態を確認します

ちゃんと検知しているようです😊

ChatGPT5 を利用した場合はどうなる?

同じプロンプトで ChatGPT5 に聞いてみました

コード自体の修正に加えて最初は Audit が推奨な旨を回答してくれていますが GitHub Copilot のように他の方法での展開(ARM/Bicep)やチェックリストに則ったチェックなどはもちろんしてくれません

ただ、コード修正という意味合いでは ChatGPT5 の利用でも全然問題ないと思いますので、絶対 GitHub Copilot が良いという意味ではないのでご注意ください


なお、1回目に提示されたコードではエラーとなりましたが、何回かやり取りすれば動くコードをちゃんと出してくれました

また、カスタムモード定義ファイルを ChatGPT5 に読み込ませて実行してみましたが GitHub Copilot のようには動きませんでした

まとめ

今回は、見つけたサンプルコードがうまく動作しない場合でも、AIを活用して修正の手間を減らす方法をまとめました。ChatGPT でもシステムプロンプトを工夫すれば似たことは可能かもしれませんが、GitHub Copilot の方がより手軽に実装できる印象です(VS Code と連携できる点も個人的には魅力だと感じています)

ライセンス費用も比較的抑えられていますので、コードを書く機会のあるインフラエンジニアの方は、一度 GitHub Copilot の利用を検討してみるのも良いかと思います

本記事が Azure Policy を作成する際に少しでもお役に立てば幸いです

Appendix

公式Docs
https://learn.microsoft.com/ja-jp/azure/governance/policy/overview

https://learn.microsoft.com/ja-jp/azure/governance/policy/policy-glossary

サンプルポリシー
https://learn.microsoft.com/ja-jp/azure/governance/policy/samples/built-in-policies

https://www.azadvertizer.net/index.html

Zennの記事
https://zenn.dev/yurio/articles/7b2082a0ab2ea8

https://zenn.dev/microsoft/articles/zenn-azure-policy

GitHub
https://github.com/takutsu001/github-chatmodes.git

Microsoft (有志)

Discussion