Claude CodeでAzure Policyの非準拠を洗い、修復タスクの対象を決める
az policy state listで非準拠を集め、modifyとdeployIfNotExistsだけを修復タスクの候補に絞る手順です。remediation createは人が承認する権限設定も示します。
Azure Policyの非準拠リソースが数百件並んでも、修復タスクで直せるのは、効果(effect)がmodifyかdeployIfNotExistsのポリシーに引っかかったものだけです。Claude Codeにはaz policy state listで非準拠を集めて効果別に仕分けるところまでを任せ、az policy remediation createは人が承認する構成にすると、一覧づくりが速くなり、変更の判断は手元に残ります。この記事は、その権限設定、集め方、修復してよいかどうかの見分け方を順に示します。
Claude Codeに渡す権限は読み取りだけにする
調べる工程で使うコマンドは、どれもAzure側を変更しません。修復タスクの作成だけが変更を起こします。プロジェクトの.claude/settings.jsonでは、この境界をそのままルールにします。
{
"permissions": {
"allow": [
"Bash(az policy state list *)",
"Bash(az policy state summarize *)",
"Bash(az policy assignment show *)",
"Bash(az policy assignment list *)",
"Bash(az policy definition show *)",
"Bash(az policy remediation list *)"
],
"ask": [
"Bash(az policy state trigger-scan *)",
"Bash(az policy remediation create *)",
"Bash(az role assignment create *)"
]
}
}*はサブコマンドの後ろに置いています。Claude Codeはルールの最初の*より前を文面どおりに照合するため、Bash(az policy * list)のようにサブコマンドの位置へ置くと、意図しないコマンドまで通る恐れがあります。権限ドキュメントはこの形の許可ルールを、起動時の警告の対象にしています。
trigger-scanをaskに入れたのは、読み取りではなく評価スキャンの起動だからです。公式の説明では、Azure Policyは割り当て済みのポリシーを24時間ごとに再評価します。結果が古いと感じたときだけ、人が承認して走らせれば足ります。
複合コマンドにも注意が要ります。許可ルールは、&&や;で繋いだ各サブコマンドがそれぞれ一致して初めて効きます。一方でaskとdenyは、どれかのサブコマンドが一致すれば効きます。az policy state list ... && az policy remediation create ...と1行に書かれても、createの部分で確認が入ります。
文面一致は境界の全部ではない
Bashルールは、Claudeが書いたコマンドの文面を見ます。azを絶対パスで呼ぶ形やsh -c '...'の中身までは一致しないと、権限ドキュメントはcurlやrmの例で説明しています。az policy remediation createを止めたいなら、askだけに頼らず、Claude Codeに持たせるAzureの資格情報の側も絞ります。Azure RBACで閲覧系のロールだけを渡しておけば、文面をすり抜けた場合も変更は通りません。Azureをツール経由で操作させる構成はAzure MCPサーバーの記事にあります。
非準拠リソースをポリシー定義ごとに集める
集計の単位は、リソースではなく「どのポリシー定義に、いくつ引っかかっているか」にします。修復するかどうかはポリシーの性質で決まるので、定義ごとの件数が分かれば、判断の数がリソース数から定義数まで減ります。
まず、非準拠の状態レコードに絞って取り出します。出力に使う列は--selectで指定します。
az policy state list \
--filter "complianceState eq 'NonCompliant'" \
--select "policyAssignmentName, policyDefinitionName, \
policyDefinitionAction, resourceType, resourceId" \
--output json > policy-scan/noncompliant.jsonpolicyDefinitionActionは、そのレコードのポリシー定義が持つ効果(audit、deny、modify、deployIfNotExistsなど)を指します。公式のCLIリファレンスでは、--filterの例にpolicyDefinitionAction eq 'deny'が載っています。この列さえあれば、ポリシーの中身を開く前に、修復タスクの対象になり得るかどうかが振り分けられます。
出力をpolicy-scan/のようなワーキングディレクトリ内のファイルに書くのは、リダイレクト先がEditの許可ルールと作業ディレクトリの範囲で検査されるためです。範囲外や~始まりのパスへの出力は承認待ちになります。
サーバー側で集計したいときは、公式の例にある--applyのgroupbyが使えます。
az policy state list --apply \
"groupby((policyAssignmentId, policyDefinitionId), \
aggregate(\$count as numStates))"この形は、公式リファレンスのgroupby((policyAssignmentId, policySetDefinitionId, ...), aggregate($count as numStates))を基にしています。--filterと併用できるかは、リファレンスの例に載っていません。併用するなら、先に小さなスコープで--resource-groupを付けて試し、件数が想定と合うかを確かめてください。
件数の大きいテナントでは、--topで返す件数を絞れます。--allは「期間内の最新だけでなくすべての状態を返す」オプションなので、現在の非準拠を洗う目的には付けません。
効果別に仕分ける
noncompliant.jsonができたら、Claudeには次のような指示を出します。
policy-scan/noncompliant.json を policyDefinitionName 単位で集計して、
policyDefinitionAction ごとに件数の表を作ってください。
Azure の変更系コマンドは実行せず、表だけ返してください。返ってきた表を、効果の列で次の3つに分けます。
| policyDefinitionAction | 修復タスクで直せるか | 扱い |
|---|---|---|
modify | 修復タスクで直せるか直せる | 扱い次節で中身を確認 |
deployIfNotExists | 修復タスクで直せるか直せる | 扱い次節で中身を確認 |
audit / auditIfNotExists / deny ほか | 修復タスクで直せるか修復タスクの対象外 | 扱い手作業か例外の申請 |
公式ドキュメントは、修復タスクで準拠状態にできるのをdeployIfNotExistsとmodifyの効果を持つポリシーだけだと説明しています。audit系は検出するだけで、直す仕組みを持ちません。denyは新規・更新の要求を止めるための効果で、すでに存在する非準拠リソースはそのまま残ります。残ったリソースの設定を直すか、例外(exemption)を申請するかは、リソースの持ち主が決めます。
既存リソースは評価だけでは変わらない
modifyもdeployIfNotExistsも、評価サイクルの中では既存リソースに何もしません。公式の説明では、評価で条件に合うリソースは非準拠と記録されるだけで、変更は修復タスクが走って初めて起きます。新規作成や更新のときは効果がそのまま働くため、非準拠の山は、ポリシーを割り当てる前から存在していたリソースか、割り当て後に作成が通らなかった経路から生まれたものだと読めます。
修復タスクにしてよい定義を見分ける
modifyまたはdeployIfNotExistsと分かった定義も、全部を一括で修復タスクにはできません。定義と割り当てをshowで取り、次の4点をClaudeに読ませます。
修復タスクにする前の4点確認
- 1
roleDefinitionIdsの権限が最小か
両方の効果で
roleDefinitionIdsは必須の項目です。ここに広いロール(Contributorなど)が並んでいたら、修復の実行権限が大きすぎないかを人が見ます。公式も、権限は最小の集合に絞ることを求めています。 - 2
割り当てにマネージドIDとロールがあるか
修復はポリシー割り当てに紐づくマネージドIDで動きます。ポータルから割り当てると必要なロールが自動で付きますが、CLIやSDKでは自動付与されません。ロールが無ければ、修復のデプロイは失敗します。
- 3
何を変えるのかが読めるか
modifyはoperationsに、タグやプロパティのaddOrReplace・add・removeが書かれています。deployIfNotExistsはdeploymentにテンプレートが入っています。内容を読んで、再起動や公開範囲の変更のように、動いているサービスに影響するものを手作業側へ回します。 - 4
対象の範囲が割り当てスコープ内か
修復対象が割り当てスコープの外にある場合や、テンプレートがスコープ外のリソースを参照する場合は、マネージドIDに手動でロールを付ける必要があります。
3つ目の判断は、Claudeの読み取りに向いています。長いpolicyRuleのJSONからoperationsやdeploymentを抜き出し、変更される項目を一覧にするのは、機械的な作業だからです。ただし、その変更が許容できるかどうかは、ワークロードの事情を知る人にしか決められません。指示にも「許容できるかは判断せず、変更される項目を列挙するだけ」と書き添えます。
仕分けの結果は、次のような表にして返してもらうと、承認の材料にそのまま使えます。
| ポリシー定義 | 効果 | 非準拠件数 | 変更内容 | 区分 |
|---|---|---|---|---|
| タグの付与(例) | 効果modify | 非準拠件数120 | 変更内容tags['Dept']をaddOrReplace | 区分修復タスク候補 |
| 診断設定のデプロイ(例) | 効果deployIfNotExists | 非準拠件数38 | 変更内容診断設定のテンプレート | 区分修復タスク候補(テンプレート確認後) |
| 公開アクセスの禁止(例) | 効果deny | 非準拠件数15 | 変更内容なし(新規作成を拒否する効果) | 区分手作業 |
表の定義名と件数は書式の例です。自分のテナントで同じ形の表が出るかは、実際の出力で確かめてください。
修復タスクを作るのは人が承認する
候補が決まったら、az policy remediation createのコマンドをClaudeに組み立てさせ、承認画面で人が中身を見て実行します。
az policy remediation create \
--name fix-dept-tag \
--policy-assignment "/subscriptions/<subscriptionId>/providers/\
Microsoft.Authorization/policyAssignments/<assignmentName>"公式の手順では、1つの修復タスクで直せるのは、deployIfNotExistsまたはmodifyの1つのポリシーです。initiative(ポリシーセット)の割り当てなら、含まれるポリシーごとにタスクが要ります。
PowerShell版のStart-AzPolicyRemediationには、失敗率の閾値(-FailureThreshold、既定100%)、1回で直す件数(-ResourceCount、既定500、最大50,000)、同時デプロイ数(-ParallelDeploymentCount、既定10、指定できるのは1〜30)があります。CLIで同じ調整ができるかはaz policy remediation create --helpで確認してください。本番では、まず対象を1つのリソースグループに絞った小さいタスクで挙動を見てから、スコープを広げる進め方が安全です。
タスクを作った後の進み具合は、az policy remediation listで読み取れます。許可リストに入れてあるので、Claudeに状態の要約を頼んでも承認は要りません。
CLAUDE.mdに仕分けの規則を書いておく
毎回同じ指示を書かなくて済むよう、仕分けの規則をプロジェクトのCLAUDE.mdに置きます。
## Azure Policy の非準拠の扱い
- 調査は az policy state / assignment / definition の show・list だけで行う
- 非準拠は policyDefinitionName ごとに集計し、効果の列を必ず付ける
- 修復タスクの候補は modify と deployIfNotExists のみ。他の効果は手作業に分類する
- 候補ごとに roleDefinitionIds、operations または deployment の中身を列挙する
- remediation create は実行せず、コマンド案と対象スコープだけ提示するCLAUDE.mdの記述はClaudeの動きを方向づけますが、強制する仕組みではありません。強制が必要な操作は、冒頭の権限ルールで止めます。
つまずきやすい点
集計の結果が想定と食い違うときは、次の原因が多くなります。
- 評価が古い。ポリシーを割り当てた直後や定義を更新した直後は、評価が終わるまで件数が動きます。公式の説明では、新しい割り当ては適用まで約5分、その後に評価サイクルが始まります。大きなスコープでは、完了時刻の目安は示されていません。
Conflictが混ざる。同じリソースにmodifyのポリシーが複数当たり、競合時の動作(conflictEffect)がdenyのものが2つ以上あると、既存リソースの状態は非準拠ではなくConflictになります。NonCompliantで絞ると見落とします。- 定義を直しても割り当てが変わらない。公式の注記どおり、ポリシー定義を変更しても、割り当てと紐づくマネージドIDは自動では更新されません。
roleDefinitionIdsを編集したときは、ロールを手動で付け直します。 - 範囲が合わない。
az policy state listは既定で現在のサブスクリプションを見ます。管理グループ全体を洗うなら--management-groupを付けます。
AWSで同じ発想を使うなら、未使用リソースを洗い出す手順が参考になります。Bicepで修復後の構成をコード側に戻す場合は、what-ifを承認の境界に置く方法が使えます。
まとめ
非準拠の数字だけ見て修復を始めると、auditやdenyのポリシー分まで含めて途方に暮れます。効果の列で先に切り分ければ、人が見るのはmodifyとdeployIfNotExistsの定義数ぶんで済みます。そこでも、変更内容と権限を読んでから、人が承認してcreateを実行します。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。
- code.claude.com/docs/en/permissions
- learn.microsoft.com/en-us/azure/governance/policy/how-to/get-compliance-data
- learn.microsoft.com/en-us/azure/governance/policy/how-to/remediate-resources
- learn.microsoft.com/en-us/azure/governance/policy/concepts/effect-modify
- learn.microsoft.com/en-us/azure/governance/policy/concepts/effect-deploy-if-no…
- learn.microsoft.com/en-us/cli/azure/policy/state