[改良版]Azure Policyで 特定の VM イメージのみデプロイ許可する方法

この記事は  [Microsoft Azure Tech Advent Calendar 2024](https://qiita.com/advent-calendar/2024/microsoft-azure-tech) の **17日目の記事** です。

こんにちは、アーキテクトのやまぱんです。

補足コメントや質問、<font color="red">**いいね、拡散**</font>、是非お願いします🥺！
間違ってたら<font color="red">**優しく**</font>教えてください！


## モチベーション
以前[こんな記事](https://qiita.com/aktsmm/items/78a373b7572c35884dc7)を書きました

https://qiita.com/aktsmm/items/78a373b7572c35884dc7

今回はその改良版の紹介になります！

## [以前の記事](https://qiita.com/aktsmm/items/78a373b7572c35884dc7) の方法の問題点

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/da92bad8-0460-f455-324f-54649fd376fa.png)

:::note warn
発行元ID / ソースイメージ発行元(Publisher) でフィルターをかけていたので、Publisher がないイメージには適応することができなかった。
具体的には **カスタムイメージ (マイイメージ) には Publisher がないため対応していなかった**。
:::

+ 参考イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/65eece8f-c707-d886-6605-35e1fdbb573a.png)

## 作った Azure Policy 

とりあえず早速ですが今回作った Azure Policy です。
ポリシーの割り当ては[前回記事](https://qiita.com/aktsmm/items/78a373b7572c35884dc7#%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC%E3%81%AE%E5%89%B2%E3%82%8A%E5%BD%93%E3%81%A6)を参考にしてください

```json:いずれかの条件に合致した VM のデプロイのみを許可するカスタムポリシー
{
  "mode": "All",
  "policyRule": {
    "if": {
      "not": {
        "anyOf": [
          {
            "field": "Microsoft.Compute/virtualMachines/storageProfile.imageReference.publisher",
            "in": "[parameters('listOfAllowedImagePublishers')]"
          },
          {
            "allOf": [
              {
                "field": "type",
                "equals": "Microsoft.Compute/virtualMachines"
              },
              {
                "field": "Microsoft.Compute/virtualMachines/storageProfile.imageReference.id",
                "in": "[parameters('listOfAllowedImagesResourceIDs')]"
              }
            ]
          },
          {
            "field": "Microsoft.Compute/virtualMachines/storageProfile.imageReference.offer",
            "in": "[parameters('listOfAllowedImageOffers')]"
          }
        ]
      }
    },
    "then": {
      "effect": "deny"
    }
  },
  "parameters": {
    "listOfAllowedImagePublishers": {
      "type": "Array",
      "metadata": {
        "displayName": "Allowed Image Publishers",
        "description": "List of allowed image publishers."
      },
      "defaultValue": []
    },
    "listOfAllowedImageOffers": {
      "type": "Array",
      "metadata": {
        "displayName": "Allowed Image Offers",
        "description": "List of allowed image offers."
      },
      "defaultValue": []
    },
    "listOfAllowedImagesResourceIDs": {
      "type": "Array",
      "metadata": {
        "displayName": "Allowed Images Resource IDs",
        "description": "List of allowed image resource IDs."
      },
      "defaultValue": []
    }
  }
}
```



### ポリシーの動作
１．許可される条件以下のいずれかに合致する場合は許可される = 指定された条件を満たさない場合、作成は 拒否 (deny) されます。

+ 1.1 ```Allowed Image Publishers``` / 特定の発行元のイメージを使用している場合
> + 説明
> 許可されている仮想マシンイメージの発行元（Publisher）のリスト。 このリストに含まれるPublisherのイメージのみ使用可能。 許可されるイメージプロバイダーのリスト (例: Canonical, Microsoft, RedHat)。
>+ 今回の例: 
> ["RedHat"]
> Red Hat Enterprise Linux (RHEL) のイメージを許可

+ 1.2 ```Allowed Image Offers``` / 特定のイメージのオファーのイメージを使用している場合
> + 説明
> 許可されている仮想マシンイメージの「オファー」（Offer）のリスト。オファーは、Publisherが提供する具体的なイメージの種類（製品ライン）を指します。許可されるイメージオファーのリスト (例: UbuntuServer, WindowsServer)。
>+ 今回の例: 
> ["UbuntuServer","microsoftsqlserver"]
> Ubuntu Server 、SQL Server 用の Windows Serverイメージを許可

+ 1.3 ```Allowed Images Resource IDs``` / イメージが指定されたリソース ID のものである場合。
> + 説明
許可されているカスタムイメージのリソースIDのリスト。これにより、特定のカスタムイメージのみを使用可能にします。
>+ 今回の例: 
> ["/subscriptions/XXXXXXXXXXX/resourceGroups/rg-test/providers/Microsoft.Compute/images/image-from-vm"]
> リソース ID が "/subscriptions/XXXXXXXXXXX/resourceGroups/rg-test/providers/Microsoft.Compute/images/**image-from-vm**" にマッチ。

:::note 
+ Tips 
リソース ID は以前に書いた[こちらのAzureユーザーにオススメ拡張機能の紹介記事](https://qiita.com/aktsmm/items/b38fbaf86ec30bf8a8db#3azure-portal-plus
)で紹介している [Azure Portal Plus の拡張機能](https://chromewebstore.google.com/detail/azure-portal-plus/jkcphnjnffinkpflgnpcjagggmjmakdg) を入れると簡単に取得することができます

[参考画像]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/d2ea524f-c9e2-e755-ecc2-26f82c836eb3.png)

:::


２．拒否される条件
上記 3 つ(1.1-1.3)のいずれにも該当しないイメージはすべて拒否される。
例の場合だと、以下が例になる。
・発行元が RedHat 以外（例: Canonical, MicrosoftWindowsServerなど）。
・イメージのオファーが指定されていない（例: Debian, CentOS）。
・許可されていないカスタムイメージ


:::note 
以前の Azure Policy ではできなかった、「オファー(Allowed Image Offers)」や「リソースID(Allowed Images Resource IDs)」をもとにしたイメージの指定が可能になり、カスタムイメージ (マイイメージ や 共有イメージ)も指定できるようになりました！　
:::




## 参考画面ショット

### ポリシーの割当画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/c441e260-8f10-80d1-9d66-caa5a9550bdf.png)

:::note warn
パラメーターを必須項目にしないように ```"defaultValue": [] ``` を記述しているため、赤枠のチェックを外さないとパラメーターの入力フィールドが表示されない。
:::

例：） ポリシー割当の設定例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/81f3bd49-d735-94a6-322a-d7c002422567.png)

## ポリシーの動作検証
スコープは Subscription に指定。
今回は以下のパラメーターで割当を実施
+ Allowed Image Publishers 
> ["RedHat"]
> Red Hat Enterprise Linux (RHEL) のイメージを許可

+ Allowed Image Offers
> ["UbuntuServer","microsoftsqlserver"]
> Ubuntu Server 、SQL Server 用の Windows Serverイメージを許可

+ Allowed Images Resource IDs
> ["/subscriptions/7XXXXXXXXXXXXXXXXX/resourceGroups/rg-test/providers/Microsoft.Compute/images/**image-from-vm**"]
> 上記のリソース ID を持つイメージを許可(カスタムイメージなど)

###  [エラーがでることを確認] いずれのパラメーターでも指定されていない Azure Market Place イメージ
+ Windows Server のイメージ
実行した Azure Market Place のイメージ
いずれの条件にも合致しないので拒否されるはず
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/cbad23c8-f852-887a-6ce7-efd33105ecec.png)

+ 以下のようにデプロイ前の確認画面で```Error Message```がでています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/0b5b85ba-b2c6-50e4-1e33-53f92c829f9c.png)
> Error Message : ```リソース 'Policy-test' はポリシーにより許可されませんでした。 (コード: RequestDisallowedByPolicy)```



###  [エラーがでることを確認] いずれのパラメーターでも指定されていないカスタムイメージ
以下の ```myCustomImageVMppg1``` を実行します。

+ カスタムイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/974c6878-d58f-dbc6-88a5-7e5fb7e35965.png)

+ 以下のようにデプロイ前の確認画面で ```Error Message```がでています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/3c2ba18a-5ff6-4f7c-8c17-11fdb6719955.png)
> Error Message : ```リソース 'Policy-test' はポリシーにより許可されませんでした。 (コード: RequestDisallowedByPolicy)```


###  [エラーがでないことを確認] Resource ID のパラメーターで指定し許可されているカスタムイメージ
+ カスタムイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/974c6878-d58f-dbc6-88a5-7e5fb7e35965.png)

+ 以下のようにデプロイ前の確認画面で ```Error Message```が**でていません！**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/1842ba0f-e6ad-dee2-986d-08805c71efed.png)

## まとめ
今回はAzure Policyを使って、特定のイメージだけを許可するカスタムポリシーの作り方を紹介しました。以前の記事で紹介した方法では対応できなかったカスタムイメージも、今回の改良版ポリシーではしっかりサポートできるようになりました。具体的には、リソースIDやイメージオファー、発行元のいずれかを指定することでガードレールを設置し、より柔軟に安全な環境を構築できるようになっています。

このポリシーを使うことで、組織内でのリソース管理が一層簡単かつ効率的になります。また、セキュリティの向上にも寄与するため、特定のイメージのみを許可することで、意図しないリソースの使用を防ぐことができます。ポリシーの設定や動作検証の際には、Azure Portal Plus の拡張機能を使うと便利です。リソース ID の取得などが簡単に行えるので、ぜひ試してみてください。

もしこの記事に関して質問やフィードバックがありましたら、気軽にコメントしてください。間違いがあれば優しく教えていただけると嬉しいです。また、この記事が役に立ったと思ったら、ぜひ「いいね」やシェアをお願いします！

みんなでAzureをもっと楽しみましょう！
Azureでの開発や運用が少しでも楽しく、スムーズになることを願っています。🚀🚀


## 追記
以下にさらに改良したバージョンを上げています。

https://github.com/aktsmm/Scripts/blob/main/AzPolicy/01_VMCreation/Allowed_Specific_VM.md

改良版では以下の条件でVMやVMSSデプロイを制御可能です。
+ VM : 許可されるイメージのパブリッシャーのリスト	
+ VM : 許可されるイメージオファーのリスト
+ VM : 許可されるカスタムイメージのリソースID
+ VM : 許可されるディスクIDに含まれる文字列パターン
+ VMSS : VMSSがイメージ制限をバイパスするために必要なタグ名