JavaScriptを有効にしてください

Private Subnet を強制し隊

 ·   10 分で読めます  ·   Kento

今回は Private Subnet を強制する方法を Azure Policy で考えてみました

更新履歴

日付 内容
2023-12-29 Audit Policy について追記しました
2023-12-29 サブネットの委任ついて考慮しました

Private Subnet とは

Private Subnet の話をするためには規定の送信アクセスを理解する必要があります
興味がある人は以下を見てみてください

Private IP アドレスしか持たない端末がパブリックなインターネットに通信するためには Publc IP アドレスに NAT する必要があります
Azure では NAT ゲートウェイなどの明示的な NAT の設定を入れなくても、勝手に NAT をしてくれる機能があります
それが規定の送信アクセスです
Azure での既定の送信アクセス - Azure Virtual Network | Microsoft Learn

この規定の送信アクセスは2025/9/30 に廃止予定です

企業で Azure を利用する場合, 通信を管理するために Firewall や NVA を使うケースがあります
しかし, 規定の送信アクセスが働くことで Firewall や NVA を介さずにインターネットに通信できてしまいます

Private Subnet を有効化すると規定の送信アクセスを無効化することができます
よって, 上で書いたような “Firewall や NVA を介さずにインターネットに通信する” ことを防げます

Private Subnet の有効化

Private Subnet の有効化方法は以下の公開情報に記載されています

  • Azure portal で、Virtual Network の作成エクスペリエンスの一部としてサブネットを作成するときに、次に示すように、プライベート サブネットを有効にするオプションが選択されていることを確認します。
  • CLI を使用して、az network vnet subnet create でサブネットを作成する場合は、–default-outbound オプションを使用し、“false” を選択します
  • Azure Resource Manager テンプレートを使用して、defaultOutboundAccess パラメータの値を “false” に設定します

Azure での既定の送信アクセス - Azure Virtual Network | Microsoft Learn

これらの方法はサブネットを作成するユーザーが有効化するかどうかを決定できます
ユーザーに委任するのではなく Private Subnet を強制したいというのが今回の目的です

前提条件

  • この記事は 2023/12 時点の情報に基づいています
  • Private Subnet はプレビュー中なので使用する際は注意してください
  • 今回は Azure Portal を使ってデプロイする場合だけを対象にしています

サブネット作成の挙動

サブネット作成の挙動でハマった点が2つあります
実装方法だけ知りたい場合は読み飛ばして 実装イメージ から読んでください

Vnet のプロパティ? サブネットというリソース?

そのままなのですが, サブネットは作成するタイミングによって

  1. Vnet (Microsoft.Network/virtualNetworks) のプロパティと扱われる場合
  2. Subnet (Microsoft.Network/virtualNetworks/subnets) というリソースの種類として扱われる場合

があるようです

たとえば、
https://github.com/NakayamaKento/AzurePolicy/blob/main/CustomPolicy/DenydefaultSubnet.json
に記載したポリシーを適用してみます
ポリシー規則のところだけ書き出してみました

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
"policyRule": {
    "if": {
      "allOf": [
        {
          "field": "type",
          "equals": "Microsoft.Network/virtualNetworks/subnets"
        },
        {
          "field": "name",
          "equals": "default"
        }
      ]
    },
    "then": {
      "effect": "[parameters('effectType')]"
    }
}

想定する動作としては ‘default’ という名前のサブネットであれば作成を拒否するものです
対象となるリソースの種類をサブネット (Microsoft.Network/virtualNetworks/subnets) としています
実際に適用して、新規 Vnet を作成してみます

portal01
default という名前のサブネットを含む Vnet を新規作成:

このように作成前の検証が通り、実際に作成も成功します

一方、既存 Vnet に ‘default’ という名前のサブネットを追加してみます

portal02
default という名前のサブネットを既存の Vnet に追加:

今度はポリシーによって操作が拒否されました

このことから

  • Vnet を新規作成するとき (VM の新規作成の時と一緒に作るときも含める) は 1 に該当
    • Vnetのプロパティと扱われる
  • 既存の Vnet にサブネットを追加する場合は 2 に該当
    • Subnet というリソースの種類として扱われる

ということがわかりました

Azure Policy を適用する場合は “なんのリソースの種類” に対するポリシーなのかを定義する必要があります
そのため, 1 と 2 の場合でポリシーを分けて考える必要があります

Private Subnet のパラメータ (defaultOutboundAccess) が存在しない

Private Subnet の有効化 で記載した通り、Private Subnet を有効化するのは ARM template 的には defaultOutboundAccess というパラメータを使います
Vnet の新規作成画面で、サブネットを編集すると図のように Private Subnet のオプションが表示されています
ここのチェックの有無で defaultOutboundAccess が true (=既定の送信アクセスが有効) または false (=既定の送信アクセスが無効) になります

portal03
Vnet の新規作成時の設定画面:

次に、既存の Vnet にサブネットを追加してみます
Azure Portal の画面は下記のとおり、Private Subnet に関する項目がありません

portal09
既存の Vnet にサブネットを追加:

その結果、そもそも Private Subnet を有効化することができません
ARM Template レベルで見ても defaultOutboundAccess のプロパティがそもそも存在していないことがわかります

portal08
Vnet の ARM template: defaultOutboundAccess のプロパティがない方があとから追加したサブネット

このことから

  • defaultOutboundAccess が存在する場合は false を強制 または true を拒否
  • defaultOutboundAccess が存在しない場合は、false としてプロパティごと追加

という処理のパターンを考える必要があります

実装イメージ

前述のとおりサブネットは作成のタイミングで挙動が異なります
そのため以下のように実装します

シナリオ リソースの種類 条件 効果
Vnet の新規作成 Vnet (Microsoft.Network/virtualNetworks) すべてのサブネットで defaultOutboundAccess: false が設定されていない 拒否(deny)
(2023/12 時点) 既存 Vnet へサブネットを追加 サブネット (Microsoft.Network/virtualNetworks/subnets) defaultOutboundAccess: false が設定されていない 追加 (append)
(将来的に) 既存 Vnet へサブネットを追加 サブネット (Microsoft.Network/virtualNetworks/subnets) defaultOutboundAccess: false が設定されていない 拒否(deny)
考慮漏れ対策 サブネット (Microsoft.Network/virtualNetworks/subnets) defaultOutboundAccess: false が設定されていない 監査 (Audit)

Azure Policy ではポリシーにどんな機能を持たせるかを定義することができます
これを公式では効果と呼んでいます
効果には Audit, Deny, Modify などがあります
今回は defaultOutboundAccess を false に強制したいので modify で修正させたいです
しかし AzurePolicy/CustomPolicy/ModifyPrivateSubnet.json をデプロイしよとすると以下のエラーが表示されました

New-AzPolicyDefinition: InvalidPolicyRuleModifyDetails : The policy definition ‘Modify not Private Subnet’ has operations referring to aliases that are not modifiable: ‘Microsoft.Network/virtualnetworks/subnets/defaultOutboundAccess’. CorrelationId: 4c8ba7e9-39e4-4c56-a77c-41b74f25ba25

おそらく defaultOutboundAccess が新しいため Modify が対応していないのが原因です
公開情報にも以下の記載があり, Modify がサポートされていないという状況は存在します
そこで, Modify を諦めて Deny を使うことに決めました
※Append はプロパティが競合してエラーになりました

ただし、マネージド ID を作成できない場合や、リソース プロパティのエイリアスが Modify でまだサポートされていない場合は、Append を使用することをお勧めします。

効果のしくみを理解する - Azure Policy | Microsoft Learn

実装

使用する Azure Policy をカスタムポリシーとして作成しました
ポリシー規則のところだけ書き出しておきます

シナリオ:Vnet の新規作成

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
"policyRule": {
  "if": {
    "allOf": [
      {
        "field": "type",
        "equals": "Microsoft.Network/virtualNetworks"
      },
      {
        "count": {
          "field": "Microsoft.Network/virtualnetworks/subnets[*]",
          "where": {
            "field": "Microsoft.Network/virtualnetworks/subnets[*].defaultOutboundAccess",
            "equals": "false"
          }
        },
        "notEquals": "[length(field('Microsoft.Network/virtualnetworks/subnets[*]'))]"
      }
    ]
  },
  "then": {
    "effect": "[parameters('effectType')]"
  }
}

AzurePolicy/CustomPolicy/DenyNotPrivateSubnet_NewVnet.json at main · NakayamaKento/AzurePolicy

シナリオ:(2023/12 時点) 既存 Vnet へサブネットを追加

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
"policyRule": {
  "if": {
      "allOf": [
          {
              "field": "type",
              "equals": "Microsoft.Network/virtualNetworks/subnets"
          },
          {
              "field": "Microsoft.Network/virtualnetworks/subnets/defaultOutboundAccess",
              "notEquals": "false"
          }
      ]
  },
  "then": {
      "effect": "[parameters('effectType')]",
      "details": [
          {
            "field": "Microsoft.Network/virtualnetworks/subnets/defaultOutboundAccess",
            "value": false
          }
        ]
  }
}

AzurePolicy/CustomPolicy/AppendPrivateSubnet.json at main · NakayamaKento/AzurePolicy

シナリオ:(将来的に) 既存 Vnet へサブネットを追加

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
"policyRule": {
  "if": {
      "allOf": [
          {
              "field": "type",
              "equals": "Microsoft.Network/virtualNetworks/subnets"
          },
          {
              "field": "Microsoft.Network/virtualnetworks/subnets/defaultOutboundAccess",
              "notEquals": "false"
          }
      ]
  },
  "then": {
      "effect": "[parameters('effectType')]"
  }
}

AzurePolicy/CustomPolicy/DenyNotPrivateSubnet_ExitingVnet.json at main · NakayamaKento/AzurePolicy

シナリオ:考慮漏れ対策

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
"policyRule": {
    "if": {
        "allOf": [
            {
            "field": "type",
            "equals": "Microsoft.Network/virtualNetworks/subnets"
            },
            {
              "field": "Microsoft.Network/virtualnetworks/subnets/defaultOutboundAccess",
              "notEquals": "false"
            },
            {
              "field": "Microsoft.Network/virtualNetworks/subnets/delegations",
              "exists": false
            }
        ]
    },
    "then": {
        "effect": "[parameters('effectType')]"
    }
}

AzurePolicy/CustomPolicy/AuditNotPrivateSubnet.json at main · NakayamaKento/AzurePolicy

検証

実際に シナリオ:Vnet の新規作成シナリオ:(2023/12 時点) 既存 Vnet へサブネットを追加 を適用して Private Subnet が強制されるか確認してみます

Vnet の新規作成

新規 Vnet を作成するときに、1つだけサブネットを含むように作成しています

portal04
Vnet の新規作成: Private Subnet を有効化しなかった場合

Private Subnet を有効化していないので、作成前の検証でポリシーで弾かれています

portal05
Vnet の新規作成: Private Subnet を有効化した場合

Private Subnet を有効化すると検証は無事に通りました

次にサブネットを2個作成するようにします

portal06
Vnet の新規作成: Private Subnet を有効化していないのが1つでもある場合

1つでも Private Subnet が有効化していないものがあれば、ポリシーで弾かれています

portal07
Vnet の新規作成: すべてで Private Subnet を有効化している場合

すべてのサブネットで Private Subnet を有効化すると検証は通りました

既存 Vnet へサブネットを追加

既存 Vnet にサブネットを追加します
検証時は Private Subnet を有効化するメニューはないので、通常通り作成します

portal09
既存 Vnet へサブネットを追加:

作成後、ARM template を確認してみると defaultOutboundAccess:false が追加されていました

portal10
Vnet の ARM template: 緑色が追加したサブネット

(2023/12/29 追加) 既存 Vnet へサブネットを追加。サブネットの委任付き

Private Subnet が有効化されているとサブネットの委任ができないことがわかりました

portal11
Private Subnet を有効化したサブネットの委任:

そこで Azure Policy を修正してサブネットの委任が設定されていない場合にだけ Private Subnet を有効化するようにしました

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
"policyRule": {
    "if": {
        "allOf": [
            {
                "field": "type",
                "equals": "Microsoft.Network/virtualNetworks/subnets"
            },
            {
                "field": "Microsoft.Network/virtualnetworks/subnets/defaultOutboundAccess",
                "notEquals": "false"
            },
            {
                "field": "Microsoft.Network/virtualNetworks/subnets/delegations",
                "exists": false
            }
        ]
    },
    "then": {
        "effect": "[parameters('effectType')]",
        "details": [
            {
              "field": "Microsoft.Network/virtualnetworks/subnets/defaultOutboundAccess",
              "value": false
            }
          ]
    }
}

実際にサブネットの委任を設定してサブネットを追加すると、defaultOutboundAccess が追加されないようにできました

portal12
Vnet の ARM template: Private Subnet を有効化したサブネットの委任

インターネットに出れないことの確認

defaultOutboundAccess:false にさせることができたので、実際にインターネットに出れないことを確認します
検証した VM は以下の通りです

VM 名 属するサブネット サブネットの説明
VM1 default1 Vnet の新規作成時に GUI で Private Subnet を有効化
VM2 default2 Vnet の新規作成時に GUI で Private Subnet を有効化
VM3 default3 Vnet の作成後にサブネットを追加。ポリシーで defaultOutboundAccess:false を追加
vm
VM1:
vm
VM2:
vm
VM3:

すべての VM において次のことがわかりました

  • www.bing.com の名前解決はできているが、ブラウザでのアクセスができていない
  • タスクバー上のネットワーク接続状態インジケーター を見るとインターネットアクセスができていない

まとめ

Azure Policy を使って Private Subnet を強制させることができました
強制した Private Subnet からインターネットに出れないことも確認できました

はじめてカスタムの Azure Policy を作成したので、うまくできてよかったです

参考

共有

Kento
著者
Kento
2020年に新卒で IT 企業に入社. インフラエンジニア(主にクラウド)として活動中