Enterprise Azure Policy as Code (EPAC)

repository·main·Indexed 20 days ago

https://github.com/azure/enterprise-azure-policy-as-code

A GitOps solution for managing Azure Policy as code. EPAC enables the definition, versioning, and automated deployment of Azure Policy definitions, assignments, and exemptions within Git repositories. It includes support for multi-tenant deployments via epacCloudEnvironments, Azure Lighthouse cross-tenant role assignments, and programmatic exemption management using PowerShell cmdlets like Set-AzPolicyExemptionEpac and Get-AzExemptions.

Tokens
49.4K
Snippets
111
Records
178
Agent score
69%

What's inside Enterprise Azure Policy as Code (EPAC)

  1. What is Enterprise Azure Policy as Code (EPAC)?

    main
    Enterprise Azure Policy as Code (EPAC) is a solution designed to enable the management of Azure Policy using a GitOps approach. It allows you to define, version, and manage your Azure Policy definitions and assignments as code within a Git repository, facilitating automated deployment and governance workflows.
  2. Overview of Enterprise Azure Policy as Code (EPAC)

    main

    Enterprise Azure Policy as Code (EPAC) is a collection of PowerShell scripts designed for CI/CD-based or semi-automated deployment of Azure Policy resources. It enables managing Policies, Policy Sets (Initiatives), Policy Assignments, Policy Exemptions, and Role Assignments at scale.

    Key Capabilities:

    • Single and multi-tenant policy deployment.
    • Easy integration with any CI/CD tool.
    • Extraction of existing Policy resources from an environment into code.
    • Deployment sequencing based on resource dependencies.
    • Support for Azure Landing Zone (ALZ) recommended policies.
    • Desired state deployment (Note: EPAC will delete any Policy resources at the deploymentRootScope and its children that are not defined in the EPAC repository).
  3. Update policy default structure parameters

    main

    After generating the structure file, you must update it to match your environment. Key fields to modify include:

    • Parameters: Update values within the parameters object (e.g., dcrResourceId).
    • Management Group IDs: Update the value in the management section to your specific management group ID.
    • Enforcement Mode: Change enforcementMode to either Default or DoNotEnforce.

    Example JSON snippets:

    // Updating a parameter
    "ama_vm_insights_data_collection_rule_id": {
      "policy_assignment_name": [
        "Deploy-VM-Monitoring",
        "Deploy-VMSS-Monitoring",
        "Deploy-vmHybr-Monitoring"
      ],
      "description": "The data collection rule id that should be used for the VM Insights deployment.",
      "parameters": {
        "parameter_name": "dcrResourceId",
        "value": ""
      }
    }
    
    // Updating a management group ID
    "management": {
      "management_group_function": "Management",
      "value": "/providers/Microsoft.Management/managementGroups/management"
    }
    
    // Modifying enforcement mode
    "enforcementMode": "Default"
  4. Use CSV files for large Policy Set parameters and overrides

    main

    For large Policy Sets (e.g., Azure Security Benchmark, NIST 800-53), managing parameters, overrides, and nonComplianceMessages in JSON can become unmanageable. EPAC allows you to use a CSV spreadsheet to manage these values across multiple environments.

    EPAC uses the CSV to create:

    • parameters
    • overrides (if the effect is not a parameter in the Policy Set)
    • nonComplianceMessages (optional)

    Best Practice: Use this approach for large Policy Sets. For smaller Policy Sets, continue using standard JSON parameters, overrides, and nonComplianceMessages.

  5. Configure Metadata and the deployedBy field

    main

    The metadata section of a policy definition is used for organizational purposes.

    Metadata Fields:

    • category: Should be one of the standard categories used in built-in Azure Policies.
    • version: Should be a semantic version number.
    • deployedBy: EPAC automatically injects this string into the metadata section to identify the deployment source.

    Managing deployedBy:

    • Default Value: epac/$pacOwnerId/$pacSelector.
    • Global Override: You can override the default value for all definitions in global-settings.jsonc.
    • Local Override (Not Recommended): You can manually add deployedBy to a specific policy definition file to override the global/default value for that definition only.
  6. Choose the right scope exclusion method

    main

    When you need to exclude a scope from a policyAssignment, choose a method based on your specific requirement:

    • Periodic Review Required: Use Exemptions. This leverages Azure's native functionality to manage reviews and can include an ExpiresOn date.
    • Descope specific items within a policySetDefinition: Use NotScope within the policyAssignment. This allows you to change the effect for specific policy definitions inside a set (e.g., exempting one specific service from a larger security initiative).
    • Sweeping changes for all assignments: Use globalNotScopes in the Global Settings file. This is useful for blocking all inheritance for policies delivered by EPAC across a wide scope.
    • Exclude from Desired State Enforcement: Use Desired State Adjustments in the Global Settings file. This allows assignments to be deployed in a scope without being affected by the "desiredState":{"strategy":"full"} configuration.
    • Remove from EPAC management entirely: Define the scope in the Global Settings file to remove it from EPAC management.
  7. Understand how EPAC generates exemption names and display names

    main

    When defining exemptions using Option A (Policy Definition IDs/Names), Option C (Policy Set IDs/Names), or when using scopes, EPAC automatically generates unique name, displayName, and description values to ensure they are readable and unique across different assignments.

    Naming Logic

    • name: Generated by concatenating the provided name with a dash - and the Assignment name (the last part of the policyAssignmentId).
    • displayName and description: Generated by concatenating the provided displayName/description with a space-dash-space (-), followed by the last part of the scope or the human-readable name (if using the humanReadableName: prefix).

    Example: Using policyDefinitionId and scopes

    If you provide a definition file like this:

    {
        "exemptions": [
            {
                "name": "short-name",
                "displayName": "Descriptive name",
                "description": "More details",
                "exemptionCategory": "Waiver",
                "scopes": [
                    "/subscriptions/11111111-2222-3333-4444-555555555555",
                    "/subscriptions/11111111-2222-3333-4444-555555555556/resourceGroups/resourceGroupName1"
                ],
                "policyDefinitionId": "/providers/microsoft.authorization/policyDefinitions/00000000-0000-0000-0000-000000000000"
            }
        ]
    }

    EPAC generates the following for the resource group scope:

    • name: short-name-assignmentName
    • displayName: Descriptive name - resourceGroupName1 - assignmentName
    • description: More details - resourceGroupName1 - assignmentName
  8. Use Exemptions for periodic reviews

    main

    Exemptions are the preferred method when you need to review the validity of an exclusion periodically.

    Key Characteristics:

    • Location: Defined in the ./Definitions/policyExemptions/[pacSelectorName] directory using management files.
    • Format: JSON is recommended over CSV for easier reviews.
    • Granularity: Can be filtered within a policyAssignment to specific policyDefinitions within a policySetDefinition using policyDefinitionsReferenceIds.
    • Lifecycle: Supports the Azure native ExpiresOn property for automated periodic review requirements.
    • Reporting: Can be reported on as exceptions to the specific definitions they are tied to.
  9. Configure Metadata and deployedBy injection

    main

    The metadata section of a Policy Set should ideally include a category (matching standard built-in policy categories) and a version (semantic versioning).

    Automatic Injection: EPAC automatically injects a deployedBy string into the metadata section.

    • Default value: epac/$pacOwnerId/$pacSelector.
    • Customization: You can override the default value in global-settings.jsonc.

    Warning: Adding deployedBy manually to a Policy definition file will override the value provided by global-settings.jsonc or the default for that specific definition only.

  10. When to use Manual Configuration

    main

    Manual configuration is used when the EPAC Hydration Kit does not meet specific requirements. Use this approach for:

    • Complex multi-tenant scenarios
    • Custom folder structures or naming conventions
    • Advanced customization requirements
    • Specific compliance or organizational constraints

    Note: It is recommended to try the Hydration Kit first and customize the generated configuration before committing to a manual setup.

  11. How to use overrides for custom management group structures

    main

    In EPAC v11, if your environment does not follow the standard Azure Landing Zones (ALZ) management group structure, you can use the overrides key in your policy structure file to define custom archetypes and map them to your specific management groups.

    1. Define Custom Archetypes

    Use the overrides.archetypes.custom key. Set type to "new" to create entirely new archetypes. Each archetype defines a list of policy_assignments.

    2. Map Archetypes to Management Groups

    Use the managementGroupNameMappings key to map your custom archetype names to actual Azure Management Group resource IDs. The value can be a single string or an array of strings.

    3. Run the Sync

    When running the sync command, you must include the -EnableOverrides parameter.

    {
      "overrides":{
        "archetypes": {
          "custom": [
            {
              "name": "production",
              "type": "new",
              "policy_assignments": [
                "Audit-PeDnsZones",
                "Deny-HybridNetworking"
              ]
            }
          ]
        }
      },
      "managementGroupNameMappings": {
        "production": {
          "management_group_function": "Production",
          "value": "/providers/Microsoft.Management/managementGroups/prod"
        }
      }
    }
    Sync-ALZPolicyFromLibrary.ps1 -DefinitionsRootFolder .\Definitions\ -Type ALZ -PacEnvironmentSelector epac-dev -EnableOverrides
  12. Choose an Exemption Method (Options A, B, or C)

    main

    EPAC provides three ways to specify which policy or policy set to exempt. Choosing the right one depends on your goal.

    Best for new exemptions. It creates one exemption per Assignment containing the Policy definition.

    • Use policyDefinitionId for built-in definitions.
    • Use policyDefinitionName for custom definitions (In CSV, use policyDefinitions/{{policyDefinitionName}} in the assignmentReferenceId column).
    • Note: policyDefinitionReferenceIds must be empty/omitted.

    Option B: Policy Assignment ID

    The traditional method. Creates one exemption for a specific assignment.

    • Use policyAssignmentId (e.g., /providers/Microsoft.Management/managementGroups/.../providers/Microsoft.Authorization/policyAssignments/...).
    • For Policy Set Assignments, you can use policyDefinitionReferenceIds to exempt specific policies within that set.

    Option C: Policy Set Definition IDs or Names

    Useful for exempting multiple policies within a Policy Set using a single exemption.

    • Use policySetDefinitionId or policySetDefinitionName.
    • For custom sets in CSV, use policySetDefinitions/{{policySetDefinitionName}} in the assignmentReferenceId column.
    • Can be used with policyDefinitionReferenceIds to target a subset of the set.