この記事は更新から24ヶ月以上経過しているため、最新の情報を別途確認することを推奨いたします。
こんにちはパーソルプロセス&テクノロジーの内田です。
Azure PolicyはAzureリソースに一定のガバナンスを効かせるためのサービスとなります。具体的にはリソースのデプロイ リージョンを日本のみに限定したり、コスト管理のためのタグ付けを強制したりといった内容となります。
新規にデプロイまたは更新しようとしているリソースが、JSON形式で定義したPolicyと乖離がある場合、それを検知し必要に応じて修正するという内容になります。
この特性を生かして、設定漏れのあるNSGリソースを検知するAzure Policyを今回は作成してみました。
次のようにAzure Portal上で準拠している/いないリソースを視覚的に確認することができます。
Azure PolicyのJSONファイルを作成する
公式ドキュメントに依れば、JSONには次の要素が含まれているようです。
- displayName (表示名)
- description (説明)
- mode (モード)
- metadata (メタデータ)
- parameters (パラメータ)
- policyRule (ポリシー規則)
- if (条件)
- then (効果)
参考:ポリシー定義の構造の詳細 – Azure Policy | Microsoft Docs
policyRuleのifで条件を指定し、真のときの効果をthenに指定するだけのようです。
今回は設定漏れを検知したいので、正しい値をparametersに指定しておきます。
"parameters": {
"reservedNsgRules": {
"type": "array",
"defaultValue": [
{
"destinationPortRange": "8080",
"destinationAddressPrefix": "*",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound",
"description": "Reserved rule"
},
{
"destinationPortRange": "8080",
"destinationAddressPrefix": "*",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Outbound",
"description": "Reserved rule"
}
]
}
}
上記は宛先ポート8080, Protocol Any, 優先度 100、説明欄にReserved ruleと記されたAllow送受信規則を定義しています。続いて、policyRuleのifキーで条件を指定していきます。allOfにて論理積を表現することができるので、非演算子に次を指定することにします。
- リソースの種類がNSGである
- NSGの規則に指定したものが含まれない
これは次のように書くことができます。
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/networkSecurityGroups"
},
{
"count": {
"value": "[parameters('reservedNsgRules')]",
"name": "reservedNsgRule",
"where": {
"count": {
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*]",
"where": {
"allOf": [
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].destinationPortRange",
"equals": "[current('reservedNsgRule').destinationPortRange]"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].destinationAddressPrefix",
"equals": "[current('reservedNsgRule').destinationAddressPrefix]"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].sourcePortRange",
"equals": "[current('reservedNsgRule').sourcePortRange]"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].sourceAddressPrefix",
"equals": "[current('reservedNsgRule').sourceAddressPrefix]"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].access",
"equals": "[current('reservedNsgRule').access]"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].priority",
"equals": "[current('reservedNsgRule').priority]"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].direction",
"equals": "[current('reservedNsgRule').direction]"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].description",
"equals": "[current('reservedNsgRule').description]"
}
]
}
},
"equals": 1
}
},
"notequals": "[length(parameters('reservedNsgRules'))]"
}
]
2つ目の非演算子内のcountは特定の条件を満たす配列要素の数をカウントするものです。これでNSGに特定の規則が含まれていないことを評価することが可能となりました。最後にthenキーにaudit(監査)を指定すれば完了です。
実際にできあがったjsonファイルは次のようになります。
{
"mode": "All",
"parameters": {
"reservedNsgRules": {
"type": "array",
"defaultValue": [
{
"destinationPortRange": "8080",
"destinationAddressPrefix": "*",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound",
"description": "Reserved rule"
},
{
"destinationPortRange": "8080",
"destinationAddressPrefix": "*",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Outbound",
"description": "Reserved rule"
}
]
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/networkSecurityGroups"
},
{
"count": {
"value": "[parameters('reservedNsgRules')]",
"name": "reservedNsgRule",
"where": {
"count": {
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*]",
"where": {
"allOf": [
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].destinationPortRange",
"equals": "[current('reservedNsgRule').destinationPortRange]"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].destinationAddressPrefix",
"equals": "[current('reservedNsgRule').destinationAddressPrefix]"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].sourcePortRange",
"equals": "[current('reservedNsgRule').sourcePortRange]"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].sourceAddressPrefix",
"equals": "[current('reservedNsgRule').sourceAddressPrefix]"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].access",
"equals": "[current('reservedNsgRule').access]"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].priority",
"equals": "[current('reservedNsgRule').priority]"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].direction",
"equals": "[current('reservedNsgRule').direction]"
},
{
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*].description",
"equals": "[current('reservedNsgRule').description]"
}
]
}
},
"equals": 1
}
},
"notequals": "[length(parameters('reservedNsgRules'))]"
}
]
},
"then": {
"effect": "audit"
}
}
}
Azure Policyを用いてメンテナンス負荷を削減することができそうですね。