Azure PolicyのDeployIfNotExistsの挙動を整理する

Azure PolicyのDeployIfNotExistsの挙動を整理する

2025.08.06

はじめに

特定の管理グループ配下のサブスクリプションでDefender CSPMを自動で有効にしたいため、Azure Policyの一つであるMicrosoft Defender CSPM を有効にするように構成するを有効にしましたが、思ったように動作しませんでした。

具体的には、Microsoft Defender CSPM を有効にするように構成するを有効にすることで、現在Defender CSPMが無効になっているサブスクリプションに対して自動で有効になると思っていましたが、その通りにはいきませんでした。

イメージ(こうなると思ってた)
スクリーンショット 2025-08-05 23.52.06.png

この記事では、Azure Policyの効果 (effect) の一つである deployIfNotExists の挙動についてまとめるとともに、上記の原因を振り返ってみます。

Azure Policyとは

Azure Policyは、Azureリソースの統制・管理を行うサービスです。
Policyを管理グループ、サブスクリプション、リソースグループに適用することができ、その効果は下位の管理グループ、サブスクリプション、リソースグループに継承されます。

Azure Policyの効果 (effect) は下記の通りです。

今回私が有効にしたAzure PolicyであるMicrosoft Defender CSPM を有効にするように構成するのデフォルトの効果 (effect) はdeployIfNotExistsだったので、本記事では deployIfNotExists について深掘りしていきます。

「Microsoft Defender CSPM を有効にするように構成する」というAzure Policy

Microsoft Defender CSPM を有効にするように構成するの詳細は以下のJSON形式のポリシーで定義されています。

{
  "properties": {
    "displayName": "Microsoft Defender CSPM を有効にするように構成する",
    "policyType": "BuiltIn",
    "mode": "All",
    "description": "Defender クラウド セキュリティ態勢管理 (CSPM) は、強化されたセキュリティ態勢機能と新しいインテリジェントなクラウド セキュリティ グラフを提供し、リスクの特定、優先度付け、削減を支援します。Defender CSPM は、Defender for Cloud において既定で有効になる無料の基本的なセキュリティ態勢機能に加えて利用できます。",
    "metadata": {
      "version": "1.0.2",
      "category": "Security Center"
    },
    "version": "1.0.2",
    "parameters": {
      "effect": {
        "type": "String",
        "metadata": {
          "displayName": "効果",
          "description": "ポリシーの実行を有効または無効にします"
        },
        "allowedValues": [
          "DeployIfNotExists",
          "Disabled"
        ],
        "defaultValue": "DeployIfNotExists"
      }
    },
    "policyRule": {
      "if": {
        "field": "type",
        "equals": "Microsoft.Resources/subscriptions"
      },
      "then": {
        "effect": "[parameters('effect')]",
        "details": {
          "type": "Microsoft.Security/pricings",
          "name": "CloudPosture",
          "deploymentScope": "subscription",
          "existenceScope": "subscription",
          "roleDefinitionIds": [
            "/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635"
          ],
          "existenceCondition": {
            "field": "Microsoft.Security/pricings/pricingTier",
            "equals": "Standard"
          },
          "deployment": {
            "location": "westeurope",
            "properties": {
              "mode": "incremental",
              "parameters": {},
              "template": {
                "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
                "contentVersion": "1.0.0.0",
                "parameters": {},
                "variables": {},
                "resources": [
                  {
                    "type": "Microsoft.Security/pricings",
                    "apiVersion": "2023-01-01",
                    "name": "CloudPosture",
                    "properties": {
                      "pricingTier": "Standard"
                    }
                  }
                ],
                "outputs": {}
              }
            }
          }
        }
      }
    },
    "versions": [
      "1.0.2"
    ]
  },
  "id": "/providers/Microsoft.Authorization/policyDefinitions/689f7782-ef2c-4270-a6d0-7664869076bd",
  "type": "Microsoft.Authorization/policyDefinitions",
  "name": "689f7782-ef2c-4270-a6d0-7664869076bd"
}

リソースタイプがサブスクリプションで

      "if": {
        "field": "type",
        "equals": "Microsoft.Resources/subscriptions"
      },

プラン(pricingTier)が有償版(Standard)であるかを判断し

          "existenceCondition": {
            "field": "Microsoft.Security/pricings/pricingTier",
            "equals": "Standard"
          },

一致してない場合に以下のリソースをデプロイする(DeployIfNotExists)

          "deployment": {
            ## 中略
                "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
          }

と私は読み取りました。
ここまでは大きく間違っていませんでしたが、後述する deployIfNotExists の評価対象を勘違いしていたため思うような挙動になりませんでした。

DeployIfNotExists の効果(effect)

本記事の本題である、DeployIfNotExists の効果(effect)についてまとめます。
公式のドキュメントには以下の記載があります。

auditIfNotExists runs after a Resource Provider processed a create or update resource request and returned a success status code. The audit occurs if there are no related resources or if the resources defined by ExistenceCondition don't evaluate to true. For new and updated resources, Azure Policy adds a Microsoft.Authorization/policies/audit/action operation to the activity log and marks the resource as non-compliant. When triggered, the resource that satisfied the if condition is the resource that is marked as non-compliant.
auditIfNotExists は、リソース プロバイダーによってリソースの作成または更新要求が処理され、成功の状態コードが返された後に実行されます。 監査は、関連するリソースがない場合、または ExistenceCondition によって定義されたリソースが true と評価されない場合に発生します。 新規および更新されたリソースの場合、Azure Policy によってアクティビティ ログに Microsoft.Authorization/policies/audit/action 操作が追加され、リソースは非準拠とマークされます。 トリガーされた場合、if 条件を満たすリソースは、非準拠としてマークされているリソースです。

まとめると

  • 新規および更新されたリソースの場合は定義された修復アクションが実行される
  • それ以外の場合は非準拠リソースと評価される

ということだと読み取れます。

つまり、冒頭で私が検証していたMicrosoft Defender CSPM を有効にするように構成するを有効にした場合は、 既存のサブスクリプションのDefender CSPMは有効化されず、非準拠リソースとして評価される というのが正しい挙動のようです。

イメージ(こうだった)
スクリーンショット 2025-08-05 23.51.01.png

実際にはこのような表示になっています。
スクリーンショット 2025-08-05 23.55.09.png

補足:手動での修復

deployIfNotExists のようなポリシーで、自動で修復されなかったが非準拠と検出されているリソースについては、手動で修復作業を実行できます。
詳しくは以下のドキュメントを参照ください。
https://learn.microsoft.com/ja-jp/azure/governance/policy/how-to/remediate-resources?tabs=azure-portal

おわりに

この記事では、 deployIfNotExists の挙動についてまとめてながら私の失敗の原因について振り返ってみました。

Azureの経験が深い方であれば当たり前の知識かもしれませんが、どなたかの参考になれば幸いです。

この記事をシェアする

facebookのロゴhatenaのロゴtwitterのロゴ

© Classmethod, Inc. All rights reserved.