📘

Azure Policy でDenyが効かないパターン(前編)

6 min read

はじめに

Azure Policyではリソースの設定のチェックを行うことができ、セキュリティ的に脆弱ではないか、設計方針に違反していないかなどを監査したり、違反したリソースを作ろうとしたら作成に失敗させたり、設定を修復させたりすることができます。
なかでも、"Deny"という効果を使うと、「違反したリソースを作ろうとしたら作成に失敗」させることができるので、環境を強力に守ることができるのですが、今回はDenyが思った通り動かなかった話とその解決策を書いていきます。

困ったこと

ここでは、「Webアプリへの接続(通信)が暗号化されていること」というよくあるガイドラインを想定して、これをAzure Policyで守る場面を考えます。

Auditで守る

「下記設定が外れている場合に、Azure Policyが検知してしてくれる」というの目的に、次のPolicyを設定します。このポリシーは組み込みポリシーですので、Azure portalのポリシー管理画面で検索すれば誰でも使うことができます。

{
  "properties": {
    "displayName": "Web アプリケーションには HTTPS を介してのみアクセスできるようにする",
    "policyType": "BuiltIn",
    "mode": "Indexed",
    "description": "HTTPS を使用すると、サーバー/サービスの認証が確実に実行され、転送中のデータがネットワーク層の傍受攻撃から保護されるようになります。",
    "metadata": {
      "version": "1.0.0",
      "category": "App Service"
    },
    "parameters": {
      "effect": {
        "type": "String",
        "metadata": {
          "displayName": "エフェクト",
          "description": "ポリシーの実行を有効または無効にします"
        },
        "allowedValues": [
          "Audit",
          "Disabled"
        ],
        "defaultValue": "Audit"
      }
    },
    "policyRule": {
      "if": {
        "allOf": [
          {
            "field": "type",
            "equals": "Microsoft.Web/sites"
          },
          {
            "field": "kind",
            "like": "app*"
          },
          {
            "field": "Microsoft.Web/sites/httpsOnly",
            "equals": "false"
          }
        ]
      },
      "then": {
        "effect": "[parameters('effect')]"
      }
    }
  },
  "id": "/providers/Microsoft.Authorization/policyDefinitions/a4af4a39-4135-47fb-b175-47fbdf85311d",
  "type": "Microsoft.Authorization/policyDefinitions",
  "name": "a4af4a39-4135-47fb-b175-47fbdf85311d"
}

WebAppを作ってみる

Azure Portalから、WebAppを作ってみます。

画面をみると、今回設定したい「httpsonly」はAzure Portalから指定できないことがわかります。そして出来上がったリソースの「TLS/SSL の設定」をみると「HTTPS のみ」がオフとなっているため、非暗号化通信=HTTPで接続できる状態であることが確認できます。

Azure Policyの監査結果

ここでAzure Policy管理画面を見てみると、違反状態として報告されています。

期待通り動作しており、何も問題はありません。

Denyで守る

では一歩進んで、「当該設定が有効でない限り、リソースの作成に失敗する」というのを目的に、下記のポリシーを設定します。

{
  "properties": {
    "displayName": "Web アプリケーションには HTTPS を介してのみアクセスできるようにする",
    "policyType": "BuiltIn",
    "mode": "Indexed",
    "description": "HTTPS を使用すると、サーバー/サービスの認証が確実に実行され、転送中のデータがネットワーク層の傍受攻撃から保護されるようになります。",
    "metadata": {
      "version": "1.0.0",
      "category": "App Service"
    },
    "parameters": {
      "effect": {
        "type": "String",
        "metadata": {
          "displayName": "エフェクト"
          "description": "ポリシーの実行を有効または無効にします"
        },
        "allowedValues": [
          "Audit",
          "Disabled"
        ],
        "defaultValue": "Audit"
      }
    },
    "policyRule": {
      "if": {
        "allOf": [
          {
            "field": "type",
            "equals": "Microsoft.Web/sites"
          },
          {
            "field": "kind",
            "like": "app*"
          },
          {
            "field": "Microsoft.Web/sites/httpsOnly",
            "equals": "false"
          }
        ]
      },
      "then": {
        "effect": "[parameters('effect')]"
      }
    }
  },
  "id": "/providers/Microsoft.Authorization/policyDefinitions/a4af4a39-4135-47fb-b175-47fbdf85311d",
  "type": "Microsoft.Authorization/policyDefinitions",
  "name": "a4af4a39-4135-47fb-b175-47fbdf85311d"
}

Azure Portalからリソースを作成してみます。先ほどのWebAppから名前だけ変えて、testwa3を。
が、期待通り動作しません。そもそもポータルの画面上、当該設定を指定することができないので、デフォルト設定でリソース作成のリクエストが行われますが、出来上がったリソースは違反した状態になっています。しかし!ポリシーの画面を確認すると、このDenyのポリシーに違反しているリソースとして検出されています。

違反していると検出されるのに、リソースの作成が拒否されていない…なぜだ!?

Denyが効かないパターン

MSサポートに問い合わせてわかったこと

ということで問い合わせた結果、下記のようなことがわかりました。
・Deny効果のポリシーは、「リクエストペイロードに含まれているパラメータ」をチェックして、条件に当てはまる場合はリソース作成を拒否します。
・すなわち、リクエストに含まれていないパラメータで、Azure側(リソースプロバイダー?)が勝手に初期値として設定してくれてしまう値については、Deny効果で制御することはできません。
・Azure Portalからのリクエストの場合、この「リクエスト」はChromeの開発者モードでチェックすることができます。

Denyが効かない具体例を見てみる

上でDenyが効かなかった具体的なパターンで、開発者モードからリクエスト内容を見てみます。
↓の画面は、testwa3というWebAppを作成したところです。開発者モードのNetworkタブで、それらしいAPIの実行内容を確認します。HeadersタブのRequest Payloadの中にPropertiesやTemplateというパラメータが含まれていることがわかります。

よくよく見ると、Portalからリソースをデプロイする場合は、ARMテンプレートに相当する内容とそのパラメータがまるまる含まれているようです。
この内容をチェックしてみると…?期待ではここに「httpsonly」といったパラメータがあって、true/falseで送信されていて欲しいのですが、確かにこのパラメータは含まれていません。よって、ポリシーの判定条件をくぐり抜けてしまうわけです。
~~~~追記~~~~
Twitterで指摘いただきましたが、Portalからデプロイするときのリクエストには"Microsoft.Web/sites/httpsOnly"だけでなく、下記に相当するパラメータも含まれていません。ご注意ください!

          {
            "field": "kind",
            "like": "app*"
          },

~~~~~~~~~~
リソース作成時にはくぐり抜けるのですが、出来上がったリソースとしては当該パラメータがfalseの状態で作成されているので、Audit効果のポリシーとしては違反状態で警告することになります。(Deny効果のポリシーも、Audit効果を兼ねるので違反として警告が出ています)

Denyが間違ってないことを確認する

先ほど作成したtestwa3で、一度「HTTPSのみ」を有効化し、再度無効化しようとすると・・・↓のようにDeny効果のポリシーにより、ちゃんと拒否されています。やっぱりポリシーの定義は合ってます。

先ほどと同様にペイロードの内容をみると、今度はhttpsonlyがfalseで設定されようとしているのが見え、さらにこのリクエストが403で拒否されていることがわかります。(後から見たら403のリターンコードが映ってませんでした…)

まとめ

このように、リクエストペイロードに含まれない内容はDeny効果で制御することはできず、Auditで検知できるようにするしかできません。あるいは、AppendやDeployIfNotExists効果で強制的に設定を修正することが有効な対策になります。
ということで、Appendで守ったらどう動くのかということを次の記事でまとめたいと思います。

おわりに

今回はDeny効果のポリシーがうまく動かなかったことから調査した内容をメモに残しました。Deny効果はAuditに比べて強力な制御を行うことができますが、その分想定した通り動くかテストが重要です。このメモが、Policy使いこなせなくて困った人の助けになれば。。