Skip to content

Latest commit

 

History

History
259 lines (172 loc) · 11.5 KB

readme.md

File metadata and controls

259 lines (172 loc) · 11.5 KB

Azure Rego Policies

This repository contains some Rego policy files designed for Azure, both AzureRM and AzAPI. The policy files are structured as follows:

How to use it

To use these policies, you can use the Conftest tool. You can use the following command to run the policies against your Terraform plan:

conftest test --all-namespaces --update git::https://github.com/Azure/policy-library-avm.git//policy <path-to-tfplan>

To generate a Terraform plan file:

terraform plan -out=tfplan.binary && terraform show -json tfplan.binary > tfplan.json

Or you can use this library against the brown field infrastructure:

terraform show -json > state.json
conftest test --all-namespaces --update git::https://github.com/Azure/policy-library-avm.git//policy state.json

Supported Policies

  • Microsoft.Compute/virtualMachines

legacy_virtual_machine_not_allowed migrate_vm_using_availability_sets_to_vmss_flex mission_critical_virtual_machine_should_use_premium_or_ultra_disks mission_critical_virtual_machine_should_use_zone

  • Microsoft.ContainerService/managedClusters

configure_aks_default_node_pool_zones

  • Microsoft.DocumentDB/databaseAccounts

configure_cosmosdb_account_continuous_backup_mode

  • Microsoft.Network/applicationGateways

migrate_to_application_gateway_v2 deploy_application_gateway_in_a_zone_redundant_configuration

  • Microsoft.Network/loadBalancers

use_nat_gateway_instead_of_outbound_rules_for_production_load_lalancer use_resilient_load_lalancer_sku

  • Microsoft.Network/publicIPAddresses

public_ip_use_standard_sku_and_zone_redundant_ip

  • Microsoft.Network/virtualNetworkGateways

virtual_network_gateway_use_zone_redundant_sku

  • Microsoft.DBforMySQL/flexibleServers

mysql_flexible_server_high_availability_mode_zone_redundant mysql_flexible_server_geo_redundant_backup_enabled

  • Microsoft.DBforPostgreSQL/flexibleServers

postgresql_flexible_server_geo_redundant_backup_enabled postgresql_flexible_server_high_availability_mode_zone_redundant

  • Microsoft.Storage/storageAccounts

storage_accounts_are_zone_or_region_redundant

Apply(skip) policies

To apply a subset of policies, you can specify the policy folders you want to apply, e.g.:

conftest test --all-namespaces --update git::https://github.com/Azure/policy-library-avm.git//policy/Azure-Proactive-Resiliency-Library-v2 <path-to-tfplan>

This will only apply the policies under Azure-Proactive-Resiliency-Library-v2.

To skip a subset of policies, you can create an exception rego file, e.g.:

package Azure_Proactive_Resiliency_Library_v2

import rego.v1

exception contains rules if {
  rules = ["use_nat_gateway_instead_of_outbound_rules_for_production_load_lalancer", "storage_accounts_are_zone_or_region_redundant"]
}

Save it to exception.rego, then you can apply the exception file with the policies:

conftest test --all-namespaces --update git::https://github.com/Azure/policy-library-avm.git//policy/Azure-Proactive-Resiliency-Library-v2 -p policy -p exception.rego <path-to-tfplan>

Contribution

All contribution are welcome, please follow the structure below:

.
├── common
├── ruleset1
│       ├── provider1
│       └── provider2
└── ruleset2
    ├── provider1
    └── provider2

The policy files are grouped by ruleset, then provider. Now azurerm policies should be further grouped by service folder as terraform-provider-azurerm.

All shared util code MUST be stored in common folder.

Each rego file MUST has a corresponding xxx.mock.json file. The mock JSON file should contain a top-level key named "mock", which maps to a dictionary. This dictionary can have keys "valid" and "invalid", each mapping to another dictionary of test cases.

Example structure for mock JSON files:

{
  "mock": {
    "valid": {
      "case1": {...},
      "case2": {...}
    },
    "invalid": {
      "case1": {...},
      "case2": {...}
    }
  }
}

Alternatively, you can put all cases under the mock key directly:

{
  "mock": {
    "case1": {...},
    "invalid_case2": {...}
  }
}

Any keys other than valid and invalid would be treated as a single case, any single cases without invalid prefix would be considered as a valid case.

To contribute a new policy, you MUST provide at least one valid case.

All policies MUST support both azurerm and azapi providers.

Use unique rule name as deny rule name

Please do:

deny_migrate_to_application_gateway_v2 contains reason if {
    resource := data.utils.resource(input, "azurerm_application_gateway")[_]
    not valid_azurerm_sku(resource)

    reason := sprintf("Azure-Proactive-Resiliency-Library-v2: '%s' `azurerm_application_gateway` must have 'sku.name' set to 'Standard_v2' or 'WAF_v2': https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/Network/applicationGateways/#migrate-to-application-gateway-v2", [resource.address])
}

Please DO NOT:

deny contains reason if {
    resource := data.utils.resource(input, "azurerm_application_gateway")[_]
    not valid_azurerm_sku(resource)

    reason := sprintf("Azure-Proactive-Resiliency-Library-v2: '%s' `azurerm_application_gateway` must have 'sku.name' set to 'Standard_v2' or 'WAF_v2': https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/Network/applicationGateways/#migrate-to-application-gateway-v2", [resource.address])
}

These rule names could be used in exceptions so users could skip the check for specific resources.

Use rule name as package name suffix

Please do:

package Azure_Proactive_Resiliency_Library_v2.configure_cosmosdb_account_continuous_backup_mode

import rego.v1

valid_azurerm_cosmosdb_account_backup_policy_type(resource) if {
    resource.values.backup[_].type == "Continuous"
}

deny_configure_cosmosdb_account_continuous_backup_mode contains reason if {
    resource := data.utils.resource(input, "azurerm_cosmosdb_account")[_]
    not valid_azurerm_cosmosdb_account_backup_policy_type(resource)

    reason := sprintf("Azure-Proactive-Resiliency-Library-v2: '%s' `azurerm_cosmosdb_account` must have backup type configured to 'Continuous': https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/DocumentDB/databaseAccounts/#configure-continuous-backup-mode", [resource.address])
}

Since we have rules for both azurerm and azapi providers, we need a predictable way to add a rule into exception list. Assuming we have the same rule for azapi resource:

package Azure_Proactive_Resiliency_Library_v2.configure_cosmosdb_account_continuous_backup_mode

import rego.v1

valid_azapi_cosmosdb_account_backup_policy_type(resource) if {
    resource.values.body.properties.backupPolicy.type == "Continuous"
}

deny_configure_cosmosdb_account_continuous_backup_mode contains reason if {
    resource := data.utils.resource(input, "azapi_resource")[_]
    data.utils.is_azure_type(resource.values, "Microsoft.DocumentDB/databaseAccounts")
    not valid_azapi_cosmosdb_account_backup_policy_type(resource)

    reason := sprintf("Azure-Proactive-Resiliency-Library-v2: '%s' `azapi_resource` must have backup type configured to 'Continuous': https://azure.github.io/Azure-Proactive-Resiliency-Library-v2/azure-resources/DocumentDB/databaseAccounts/#configure-continuous-backup-mode", [resource.address])
}

To ignore rule configure_cosmosdb_account_continuous_backup_mode, we need a new rego file:

package Azure_Proactive_Resiliency_Library_v2.configure_cosmosdb_account_continuous_backup_mode

import rego.v1

exception contains rules if {
    rules = ["configure_cosmosdb_account_continuous_backup_mode"]
}

Make your helper function name unique

As we are using rule name as package name suffix, we need to make sure the helper function name is unique. Please use the helper function name unique, the provider name could help here:

valid_azapi_cosmosdb_account_backup_policy_type(resource) if {
    resource.values.body.properties.backupPolicy.type == "Continuous"
}

Do not use input directly in your policy

According to the HashiCorp's OPA policies document:

The run data contains information like workspace details and the organization name. To access the properties from the Terraform plan data in your policies, use input.plan. To access properties from the Terraform run, use input.run.

Unlike Terraform plan file, the actual plan on HCP Terraform are wrapped in input.plan, so you MUST use resource := data.utils.resource(input, "azurerm_postgresql_flexible_server")[_] to get the actual plan object.

Don't forget to update the README

Please update the README file to include the new policy in #Supported Policies section.