From c417688cd2fb1a27d5bf5460cd6b3ab0fcaa1f64 Mon Sep 17 00:00:00 2001 From: hezijie Date: Mon, 10 Feb 2025 14:31:14 +0800 Subject: [PATCH 1/2] new rule for public ip resource --- ...rosoft_network_publicIPAddresses.mock.json | 131 +++++++++++++ .../microsoft_network_publicIPAddresses.rego | 16 ++ ...azurerm_public_ip_zone-redundant.mock.json | 183 ++++++++++++++++++ .../azurerm_public_ip_zone-redundant.rego | 15 ++ policy/common/avm.utils.rego | 17 -- policy/common/common.utils.rego | 4 + readme.md | 15 +- 7 files changed, 363 insertions(+), 18 deletions(-) create mode 100644 policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.mock.json create mode 100644 policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.rego create mode 100644 policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone-redundant.mock.json create mode 100644 policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone-redundant.rego delete mode 100644 policy/common/avm.utils.rego diff --git a/policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.mock.json b/policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.mock.json new file mode 100644 index 0000000..f47eeac --- /dev/null +++ b/policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.mock.json @@ -0,0 +1,131 @@ +{ + "mock": { + "default": { + "resource_changes": [ + { + "address": "azapi_resource.res", + "mode": "managed", + "type": "azapi_resource", + "name": "res", + "provider_name": "registry.terraform.io/azure/azapi", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "body": { + "sku": { + "name": "Standard", + "tier": "Regional" + }, + "zones": [ + "2", + "1" + ] + } + } + } + } + ] + }, + "invalid_basic": { + "resource_changes": [ + { + "address": "azapi_resource.res", + "mode": "managed", + "type": "azapi_resource", + "name": "res", + "provider_name": "registry.terraform.io/azure/azapi", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "body": { + "sku": { + "name": "Basic" + } + } + } + } + } + ] + }, + "invalid_no_zones": { + "resource_changes": [ + { + "address": "azapi_resource.res", + "mode": "managed", + "type": "azapi_resource", + "name": "res", + "provider_name": "registry.terraform.io/azure/azapi", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "body": { + "sku": { + "name": "Standard" + } + } + } + } + } + ] + }, + "invalid_empty_zones": { + "resource_changes": [ + { + "address": "azapi_resource.res", + "mode": "managed", + "type": "azapi_resource", + "name": "res", + "provider_name": "registry.terraform.io/azure/azapi", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "body": { + "sku": { + "name": "Standard" + }, + "zones": [] + } + } + } + } + ] + }, + "invalid_single_zone": { + "resource_changes": [ + { + "address": "azapi_resource.res", + "mode": "managed", + "type": "azapi_resource", + "name": "res", + "provider_name": "registry.terraform.io/azure/azapi", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "body": { + "sku": { + "name": "Standard" + }, + "zones": ["1"] + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.rego b/policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.rego new file mode 100644 index 0000000..b7ae556 --- /dev/null +++ b/policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.rego @@ -0,0 +1,16 @@ +package Azure_Proactive_Resiliency_Library_v2.Microsoft_Network_publicIPAddresses + +import rego.v1 + +valid(resource) if { + resource.values.body.sku.name == "Sandard" + count(resource.values.body.zones) >= 2 +} + +deny_use_resilient_load_lalancer_sku contains reason if { + resource := data.utils.resource(input, "azapi_resource")[_] + data.utils.is_azure_type(resource.values, "Microsoft.Network/publicIPAddresses") + not valid(resource) + + reason := sprintf("Azure-Proactive-Resiliency-Library-v2: '%s' `azapi_resource` must have configured `sku.name` to `\"Standard\"` and a `zones` that cotnains at least 2 zones: https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/Network/publicIPAddresses/#use-standard-sku-and-zone-redundant-ips-when-applicable", [resource.address]) +} \ No newline at end of file diff --git a/policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone-redundant.mock.json b/policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone-redundant.mock.json new file mode 100644 index 0000000..afae4fe --- /dev/null +++ b/policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone-redundant.mock.json @@ -0,0 +1,183 @@ +{ + "mock": { + "default": { + "resource_changes": [ + { + "address": "azurerm_public_ip.example", + "mode": "managed", + "type": "azurerm_public_ip", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/azurerm", + "change": { + "actions": [ + "create" + ], + "after": { + "sku": "Standard", + "sku_tier": "Regional", + "zones": [ + "1", + "2" + ] + } + } + } + ] + }, + "invalid_basic_sku": { + "resource_changes": [ + { + "address": "azurerm_public_ip.example", + "mode": "managed", + "type": "azurerm_public_ip", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/azurerm", + "change": { + "actions": [ + "create" + ], + "after": { + "sku": "Basic" + }, + "after_unknown": { + "fqdn": true, + "id": true, + "ip_address": true, + "resource_group_name": true, + "tags": {} + }, + "before_sensitive": false, + "after_sensitive": { + "tags": {} + } + } + } + ] + }, + "invalid_null_zones": { + "resource_changes": [ + { + "address": "azurerm_public_ip.example", + "mode": "managed", + "type": "azurerm_public_ip", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/azurerm", + "change": { + "actions": [ + "create" + ], + "after": { + "sku": "Standard", + "zones": null + }, + "after_unknown": { + "fqdn": true, + "id": true, + "ip_address": true, + "resource_group_name": true, + "tags": {} + }, + "before_sensitive": false, + "after_sensitive": { + "tags": {} + } + } + } + ] + }, + "invalid_no_zones": { + "resource_changes": [ + { + "address": "azurerm_public_ip.example", + "mode": "managed", + "type": "azurerm_public_ip", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/azurerm", + "change": { + "actions": [ + "create" + ], + "after": { + "sku": "Standard" + }, + "after_unknown": { + "fqdn": true, + "id": true, + "ip_address": true, + "resource_group_name": true, + "tags": {} + }, + "before_sensitive": false, + "after_sensitive": { + "tags": {} + } + } + } + ] + }, + "invalid_empty_zones": { + "resource_changes": [ + { + "address": "azurerm_public_ip.example", + "mode": "managed", + "type": "azurerm_public_ip", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/azurerm", + "change": { + "actions": [ + "create" + ], + "after": { + "sku": "Standard", + "zones": [] + }, + "after_unknown": { + "fqdn": true, + "id": true, + "ip_address": true, + "resource_group_name": true, + "tags": {} + }, + "before_sensitive": false, + "after_sensitive": { + "tags": {} + } + } + } + ] + }, + "invalid_single_zone": { + "resource_changes": [ + { + "address": "azurerm_public_ip.example", + "mode": "managed", + "type": "azurerm_public_ip", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/azurerm", + "change": { + "actions": [ + "create" + ], + "after": { + "sku": "Standard", + "zones": [ + "1" + ] + }, + "after_unknown": { + "fqdn": true, + "id": true, + "ip_address": true, + "resource_group_name": true, + "tags": {} + }, + "before_sensitive": false, + "after_sensitive": { + "tags": {} + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone-redundant.rego b/policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone-redundant.rego new file mode 100644 index 0000000..c36eeb4 --- /dev/null +++ b/policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone-redundant.rego @@ -0,0 +1,15 @@ +package Azure_Proactive_Resiliency_Library_v2.azurerm_public_ip + +import rego.v1 + +valid_ip(resource) if { + resource.values.sku == "Standard" + count(resource.values.zones) >= 2 +} + +deny_deploy_application_gateway_in_a_zone_redundant_configuration contains reason if { + resource := data.utils.resource(input, "azurerm_public_ip")[_] + not valid_ip(resource) + + reason := sprintf("Azure-Proactive-Resiliency-Library-v2: '%s' `azurerm_public_ip` must have configured `sku` to `\"Standard\"` and a `zones` that cotnains at least 2 zones: https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/Network/publicIPAddresses/#use-standard-sku-and-zone-redundant-ips-when-applicable", [resource.address]) +} \ No newline at end of file diff --git a/policy/common/avm.utils.rego b/policy/common/avm.utils.rego deleted file mode 100644 index 9694c90..0000000 --- a/policy/common/avm.utils.rego +++ /dev/null @@ -1,17 +0,0 @@ -package utils - -import rego.v1 - -tfplan(d) := output if { - d.plan.resource_changes - output := d.plan -} - -tfplan(d) := output if { - not d.plan.resource_changes - output := d -} - -is_azure_type(resource, azure_type) if { - regex.match(sprintf("^%s@", [azure_type]), resource.type) -} diff --git a/policy/common/common.utils.rego b/policy/common/common.utils.rego index 60925f3..c5d1a2c 100644 --- a/policy/common/common.utils.rego +++ b/policy/common/common.utils.rego @@ -2,6 +2,10 @@ package utils import rego.v1 +is_azure_type(resource, azure_type) if { + regex.match(sprintf("^%s@", [azure_type]), resource.type) +} + _resource(_input) := output if { _input.plan.resource_changes == _input.plan.resource_changes output := { diff --git a/readme.md b/readme.md index 9d71066..5c08d83 100644 --- a/readme.md +++ b/readme.md @@ -7,7 +7,20 @@ This repository contains some [Rego](https://www.openpolicyagent.org/) policy fi To use these policies, you can use the [Conftest](https://www.conftest.dev/) tool. You can use the following command to run the policies against your Terraform plan: ```bash -conftest test --all-namespaces -p /policy +conftest test --all-namespaces --update git::https://github.com/lonegunmanb/policy-library-avmrego.git//policy +``` + +To generate a Terraform plan file: + +```bash +terraform plan -out=tfplan.binary && terraform show -json tfplan.binary > tfplan.json +``` + +Or you can use this library against the brown field infrastructure: + +```bash +terraform show -json > state.json +conftest test --all-namespaces --update git::https://github.com/lonegunmanb/policy-library-avmrego.git//policy state.json ``` ## Supported Policies From 31e8a875bbcc4c3435876979e8fdc474147f1add Mon Sep 17 00:00:00 2001 From: hezijie Date: Mon, 10 Feb 2025 14:40:45 +0800 Subject: [PATCH 2/2] update readme and rule name, fix incorrect mock data --- .../microsoft_network_publicIPAddresses.mock.json | 12 ++++++++---- .../network/microsoft_network_publicIPAddresses.rego | 2 +- ...on => azurerm_public_ip_zone_redundant.mock.json} | 0 ...nt.rego => azurerm_public_ip_zone_redundant.rego} | 2 +- readme.md | 4 ++++ 5 files changed, 14 insertions(+), 6 deletions(-) rename policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/{azurerm_public_ip_zone-redundant.mock.json => azurerm_public_ip_zone_redundant.mock.json} (100%) rename policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/{azurerm_public_ip_zone-redundant.rego => azurerm_public_ip_zone_redundant.rego} (88%) diff --git a/policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.mock.json b/policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.mock.json index f47eeac..81e3133 100644 --- a/policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.mock.json +++ b/policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.mock.json @@ -47,7 +47,8 @@ "sku": { "name": "Basic" } - } + }, + "type": "Microsoft.Network/publicIPAddresses@2024-05-01" } } } @@ -71,7 +72,8 @@ "sku": { "name": "Standard" } - } + }, + "type": "Microsoft.Network/publicIPAddresses@2024-05-01" } } } @@ -96,7 +98,8 @@ "name": "Standard" }, "zones": [] - } + }, + "type": "Microsoft.Network/publicIPAddresses@2024-05-01" } } } @@ -121,7 +124,8 @@ "name": "Standard" }, "zones": ["1"] - } + }, + "type": "Microsoft.Network/publicIPAddresses@2024-05-01" } } } diff --git a/policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.rego b/policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.rego index b7ae556..6a9e15e 100644 --- a/policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.rego +++ b/policy/Azure-Proactive-Resiliency-Library-v2/azapi/network/microsoft_network_publicIPAddresses.rego @@ -7,7 +7,7 @@ valid(resource) if { count(resource.values.body.zones) >= 2 } -deny_use_resilient_load_lalancer_sku contains reason if { +deny_use_standard_sku_and_zone_redundant_ip contains reason if { resource := data.utils.resource(input, "azapi_resource")[_] data.utils.is_azure_type(resource.values, "Microsoft.Network/publicIPAddresses") not valid(resource) diff --git a/policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone-redundant.mock.json b/policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone_redundant.mock.json similarity index 100% rename from policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone-redundant.mock.json rename to policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone_redundant.mock.json diff --git a/policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone-redundant.rego b/policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone_redundant.rego similarity index 88% rename from policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone-redundant.rego rename to policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone_redundant.rego index c36eeb4..021003f 100644 --- a/policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone-redundant.rego +++ b/policy/Azure-Proactive-Resiliency-Library-v2/azurerm/network/azurerm_public_ip_zone_redundant.rego @@ -7,7 +7,7 @@ valid_ip(resource) if { count(resource.values.zones) >= 2 } -deny_deploy_application_gateway_in_a_zone_redundant_configuration contains reason if { +deny_use_standard_sku_and_zone_redundant_ip contains reason if { resource := data.utils.resource(input, "azurerm_public_ip")[_] not valid_ip(resource) diff --git a/readme.md b/readme.md index 5c08d83..8fad03a 100644 --- a/readme.md +++ b/readme.md @@ -45,6 +45,10 @@ conftest test --all-namespaces --update git::https://github.com/lonegunmanb/poli [`use_nat_gateway_instead_of_outbound_rules_for_production_load_lalancer`](https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/Network/loadBalancers/#use-nat-gateway-instead-of-outbound-rules-for-production-workloads) [`use_resilient_load_lalancer_sku`](https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/Network/loadBalancers/#use-standard-load-balancer-sku) +* `Microsoft.Network/publicIPAddresses` + +[`use_standard_sku_and_zone_redundant_ip`](https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/Network/publicIPAddresses/#use-standard-sku-and-zone-redundant-ips-when-applicable) + * `Microsoft.DBforMySQL/flexibleServers` [`mysql_flexible_server_high_availability_mode_zone_redundant`](https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/DBforMySQL/flexibleServers/#enable-ha-with-zone-redundancy)