diff --git a/Docs/azure-monitor-dine-siem.vsdx b/Docs/Drawings/azure-monitor-dine-siem.vsdx similarity index 100% rename from Docs/azure-monitor-dine-siem.vsdx rename to Docs/Drawings/azure-monitor-dine-siem.vsdx diff --git a/Docs/azure-security-controls-process.vsdx b/Docs/Drawings/azure-security-controls-process.vsdx similarity index 100% rename from Docs/azure-security-controls-process.vsdx rename to Docs/Drawings/azure-security-controls-process.vsdx diff --git a/Docs/epac-explanations.vsdx b/Docs/Drawings/epac-explanations.vsdx similarity index 93% rename from Docs/epac-explanations.vsdx rename to Docs/Drawings/epac-explanations.vsdx index 5a38ffe2..70fa61b4 100644 Binary files a/Docs/epac-explanations.vsdx and b/Docs/Drawings/epac-explanations.vsdx differ diff --git a/Docs/epac-github-flow.drawio b/Docs/Drawings/epac-github-flow.drawio similarity index 69% rename from Docs/epac-github-flow.drawio rename to Docs/Drawings/epac-github-flow.drawio index 24fc40d4..608ad387 100644 --- a/Docs/epac-github-flow.drawio +++ b/Docs/Drawings/epac-github-flow.drawio @@ -1,209 +1,210 @@ - + - + - - + + - + - - + + - + - + - - - - - + + + + - + - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - - + + - - + + - - + + - + - + - + - + - + - + - - + + - - + + - - + + + + + + + - - + + - - + + - - + + - + - + - - + + - - + + @@ -211,49 +212,55 @@ - + - + - + - + - - + + - + - - + + - - + + - + - + - + + + + + + + diff --git a/Docs/EPAC-Presentation.pptx b/Docs/Drawings/epac-overview-presentation.pptx similarity index 100% rename from Docs/EPAC-Presentation.pptx rename to Docs/Drawings/epac-overview-presentation.pptx diff --git a/Docs/Drawings/epac-release-flow.drawio b/Docs/Drawings/epac-release-flow.drawio new file mode 100644 index 00000000..64ad1629 --- /dev/null +++ b/Docs/Drawings/epac-release-flow.drawio @@ -0,0 +1,268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Docs/Images/ci-cd-set-auto-complete.png b/Docs/Images/ci-cd-set-auto-complete.png new file mode 100644 index 00000000..4c08baf0 Binary files /dev/null and b/Docs/Images/ci-cd-set-auto-complete.png differ diff --git a/Docs/Images/epac-github-flow.png b/Docs/Images/epac-github-flow.png index 39ccf999..af3fba68 100644 Binary files a/Docs/Images/epac-github-flow.png and b/Docs/Images/epac-github-flow.png differ diff --git a/Docs/Images/epac-release-flow.png b/Docs/Images/epac-release-flow.png new file mode 100644 index 00000000..9754e6bc Binary files /dev/null and b/Docs/Images/epac-release-flow.png differ diff --git a/Docs/Images/shared-hierarchical.png b/Docs/Images/shared-hierarchical.png index 9d742c08..43c23035 100644 Binary files a/Docs/Images/shared-hierarchical.png and b/Docs/Images/shared-hierarchical.png differ diff --git a/Docs/changes.md b/Docs/changes.md new file mode 100644 index 00000000..48e3b9fd --- /dev/null +++ b/Docs/changes.md @@ -0,0 +1,159 @@ +# Changes in v10.0.0 + +> [!CAUTION] +> Read the [breaking changes](#breaking-changes-in-v1000) carefully and adjust your environment accordingly. + +## Breaking Changes in v10.0.0 + +### Changes in `globalSettings.jsonc` + +> [!CAUTION] +We heavily reworked the `globalSettings.jsonc` file. You will need to update the file. + +Deprecated top-level elements: + +- `globalNotScopes` is moved as an array into each `pacEnvironment`. If you used the `*` notation, copy the array into each `pacEnvironment`. +- `managedIdentityLocations` is moved as a string into each `pacEnvironment`. If you used the `*` notation, copy the string into each `pacEnvironment`. + +Per `pacEnvironment`: + +- New required `managedIdentityLocation` string. +- New optional `globalNotScopes` array. +- New optional `deployedBy` string. We recommend against using it and let EPAC [generate the default value](#metadata-deployedby-and-assignedby). +- `inheritedDefinitionsScopes` has been deprecated and removed. Please review the revised use case [Use Case 4: Multiple Teams in a Hierarchical Organization](settings-desired-state.md#use-case-4-multiple-teams-in-a-hierarchical-organization). +- `cloud` is now a required field. Previously, it was optional and defaulted to `AzureCloud`. +- `desiredState` is now a required field. + +`desiredState` has newly required fields: + +- `strategy`: was optional and defaulted to `full`. We recommend setting it to `full`, except during a short transition period to EPAC. This was changed to require an explicit decision. +- `keepDfcSecurityAssignments`: replaces `deleteDfcSecurityAssignments` which defaulted to `true`. We highly recommend setting it to `false` and assigning any desired Initiative at management groups. + +`desiredState` fields `deleteExpiredExemptions` and `deleteOrphanedExemptions` are deprecated and removed. Exemptions with an ``unknownOwner` are only deleted when `strategy` is `full`. + +The recommended `desiredState` settings are now as follows: + +```json +"desiredState": { + "strategy": "full", + "keepDfcSecurityAssignments": false +} +``` + +During a brief transition from a pre-EPAC to an EPAC usage, you can set `desiredState` to `ownedOnly` to keep existing Policy resources. This is not recommended for long-term use. + +```json +"desiredState": { + "strategy": "ownedOnly", + "keepDfcSecurityAssignments": false +} +``` + +### Desired State Handling for Policy Assignments + +Field `desiredState.includeResourceGroups` is deprecated/removed. This change removes all Policy Assignments in resource groups not defined in the Policy Assignment definition files. To keep the previous behavior, add a pattern `"/subscriptions/*/resourceGroups/*" to the `"excludedScopes"` array. + +Desired state handling for Policy Assignments related to Defender for Cloud (DfC) automatic Policy Assignments has been reworked. DfC creates two different types of Policy Assignments at the subscription level. + +- Security and Compliance Initiatives, such as, Microsoft cloud security benchmark, NIST SP 800-53, ... EPAC calls them DfC Security Policy Assignments. The PAC owner is listed as `managedByDfcSecurityPolicies` +- Initiatives assigned by DfC when enrolling a subscription in a DfC workload protection plan. These assignments contain Policies required by DfC for finding vulnerabilities and threats. EPAC calls them DfC Defender Plan Policy Assignments. The PAC owner is listed as `managedByDfcDefenderPlans`. + +Previously, the `desiredState.deleteDfcSecurityAssignments` field (default `true`) and was used to control the deletion of DfC both types of auto-assigned Policy Assignments at the subscription level when the `desiredState.strategy` was `"full"`. The new field is `keepDfcSecurityAssignments`. + +- This behavior is now independent of the `desiredState.strategy` field. Therefore it will delete DfC Security Policy Assignments at the subscription level, unless `desiredState.keepDfcSecurityAssignments` is set to `true`. +- Assignments created by DfC when enrolling a subscription in a DfC workload protection plan are **never** deleted starting with v10.0.0 + +### Build-PolicyDocumentation.ps1 ignores Policies with effect `Manual` + +- `Build-PolicyDocumentation.ps1` skips Policies with effect `Manual`. Using the switch parameter `-IncludeManualPolicies` overrides this behavior reverting to the previous behavior. + +### Deprecated Operational Scripts + +EPAC had multiple operational scripts which are not Policy as Code related. These scripts are now deprecated and will be removed in a future release. The scripts have been moved to a new folder `Scripts-Deprecated` and are not included in the PowerShell module. The scripts are: + +- `Get-AzMissingTags.ps1` +- `Get-AzResourceTags.ps1` +- `Get-AzStorageNetworkConfig.ps1` +- `Get-AzUserRoleAssignments.ps1` + +We recommend that you use [Azure Governance Visualizer (AzGovViz)](https://github.com/JulianHayward/Azure-MG-Sub-Governance-Reporting) for these tasks. + +## Enhancements planned for v10.1.0 + +- Script to update CSV effect/parameter files preserving extra columns: https://github.com/Azure/enterprise-azure-policy-as-code/issues/498. +- Automatically disable deprecated Policies: https://github.com/Azure/enterprise-azure-policy-as-code/issues/516. +- Cleanup/Improve `Export-PolicyResources` and `Build-PolicyDocumentation` scripts: https://github.com/Azure/enterprise-azure-policy-as-code/issues/517 and https://github.com/Azure/enterprise-azure-policy-as-code/issues/498. +- Simplify exemption creation by allowing lists of scopes and Policy definitions: https://github.com/Azure/enterprise-azure-policy-as-code/issues/518. +- Clarify SPNs, Least Privilege, and environments for CI/CD: https://github.com/Azure/enterprise-azure-policy-as-code/issues/519. + +## Enhancements in v10.0.0 + +### Support for Cloud environments with limited Support for Resource Graph Queries + +- US Government Cloud handling of Role Assignments +- China cloud (21v) handling for Role Assignments and Exemptions. + +### Cross-tenant (Lighthouse) support for Role Assignments. + +Cross-tenant Role Assignments are now supported. This is used if log collection is directed to a resource (Log Analytics, Event Hub. Storage) in a management tenant (e.g, Azure Lighthouse, and similar constructs) which requires you to use `additionalRoleAssignments` in the Policy Assignment file. + +### Simplified Exemption definitions + +Exemptions can be specified with a `policyDefinitionName` or `policyDefinitionId` instead of a `policyAssignmentId` and `policyDefinitionReferenceId`. EPAC creates as many Exemptions as needed to cover all Policy Assignments occurrences of the specified Policy +- Support for Microsoft release flow in addition to GitHub flow (documentation and starter kit) +- Schema updated to latest draft specification + +### Description field in Role Assignments + +The `description` field in Role Assignments is now populated with the Policy Assignment Id, reason and `deployedBy` value. This is useful for tracking the source of the Role Assignment. + +Reasons is one of: + +- `Role Assignment required by Policy` - Policy definition(s) specify the required Role Definition Ids. +- `additional Role Assignment` - from filed "additionalRoleAssignments" in the Policy Assignment file. +- `additional cross tenant Role Assignment` - from filed "additionalRoleAssignments" with `crossTenant` set to `$true` in the Policy Assignment file. + +### Metadata `deployedBy` and `assignedBy` + +`deployedBy` is a new field in the global settings per pacEnvironment. It is used to populate the `metadata` fields in the deployed resources. + +If not defined in global settings, EPAC generates it as `"epac/{{pacOwnerId}}/{{pacSelector}}"`. You can override this value in the Policy resource file by entering it directly to the respective `metadata` field. It is added to the deployed resources as follows: + +- Policy Definitions, Policy Set Definitions and Policy Exemptions - `metadata.deployedBy`. +- Policy Assignments - `metadata.assignedBy` since Azure Portal displays it as 'Assigned by'. +- Role Assignments - add the value to the [`description` field](#description-field-in-role-assignments). + +### Schema Updates + +Updating JSON schema to the latest [specification 2020-12](https://json-schema.org/specification). + +## Delayed to v10.1.0 + +- Script to update CSV effect/parameter files preserving extra columns. +- Automatically disable deprecated Policies. +- `Get-AzExemptions` and `Export-AzPolicyResources` scripts to generate the new simplified Exemptions format. + +### Documentation Updates + +Reorganized the documentation to make it easier to find information. Added a new section on how to use the starter kit and how to use the Microsoft release flow. + +### Code Cleanup + +Ongoing cleanup of code: Removed unused code and improved code quality. + +### Performance + +Multiple lengthy sections of the code have been converted to parallel execution to improve performance. The change maybe ineffective if you limit the CI/CD agent to a single vCore or use the Azure DevOps provided CI/CD agents. + +The scripts `Build-DeploymentPlan`, `Deploy-PolicyPlan`, and `Build-PolicyDocumentation` have a new parameter `VirtualCores` to control the number of parallel threads and allowing you to optimize your performance. The code applies the following formula to adjust the `For-Each -Parallel` throttle limits (threads) based on the number of VirtualCores. + +- Threads = 1 x VirtualCores for pre-processing (pure compute) Policy and Policy Set parameters during Policy Assignment plan calculations +- Threads = 2 x VirtualCores for Policy object deployment since it executes many REST calls to the Azure resource manager and therefore spends much of its time waiting on I/O. +- Threads = 4 (fixed) for reading and processing Policy resources; one each for + - Policy definitions + - Policy Set definitions + - Policy Assignments, Role Assignments, and Role Definitions + - Policy Exemptions + +Setting VirtualCores to zero (0) disables parallel processing. The default value is 4. EPAC also uses a minimum chunk size for deployments to avoid unnecessary overhead for small number of items. + diff --git a/Docs/ci-cd-ado-pipelines.md b/Docs/ci-cd-ado-pipelines.md index a6b582aa..7e43b7c3 100644 --- a/Docs/ci-cd-ado-pipelines.md +++ b/Docs/ci-cd-ado-pipelines.md @@ -1,8 +1,8 @@ # Azure DevOps Pipelines -This page covers the specifics for Azure DevOps (ADO) pipelines. It si based on a simplified GitHub Flow as documented in [CI/CD Overview](./ci-cd-overview.md) +This page covers the specifics for Azure DevOps (ADO) pipelines. It si based on a simplified GitHub Flow as documented in [CI/CD Overview](ci-cd-overview.md) -Previously [setup App Registrations](./ci-cd-app-registrations.md) are a pre-requisite. +Previously [setup App Registrations](ci-cd-app-registrations.md) are a pre-requisite. This repository contains starter pipelines @@ -12,13 +12,13 @@ This repository contains starter pipelines ## Service connections for Azure DevOps CI/CD -Create ADO service connections for each of the previously created [App Registrations](./ci-cd-app-registrations.md). You will need to retrieve the client id and create a client secret or authenticate with a X509 certificate configured for the SPN. +Create ADO service connections for each of the previously created [App Registrations](ci-cd-app-registrations.md). You will need to retrieve the client id and create a client secret or authenticate with a X509 certificate configured for the SPN. When creating a Service Connection in Azure DevOps you can set up the service connections on a Subscription or a Management Group scope level. If you are using subscriptions to simulate a hierarchy during EPAC development, configure the service connection(s) scope level as **Subscription**. When creating a Service Connections for management groups (any EPAC environments) Deployment and EPAC Role Assignment the service connection scope level is **Management Group**. Subscription scope level | Management Group scope level :-----------:|:----------------: -![image](./Images/azdoServiceConnectionSubConf.png) | ![image](./Images/azdoServiceConnectionMGConf.png) +![image](Images/azdoServiceConnectionSubConf.png) | ![image](Images/azdoServiceConnectionMGConf.png) ## Single Tenant Pipeline @@ -26,15 +26,15 @@ Subscription scope level | Management Group scope level | Stage | Purpose | Trigger | Scripts | |-------|---------|---------|---------| -| devStage | Feature branch DEV environment build, deploy and test | CI, Manual | Build-DeploymentPlans.ps1
Deploy-PolicyPlan.ps1
Deploy-RolesPlan.ps1 | -| tenantPlanFeatureStage | Feature branch based plan for prod deployment | CI, Manual | Build-DeploymentPlans.ps1 | -| tenantPlanMainStage | Main branch based plan for prod deployment | PR Merged, Manual | Build-DeploymentPlans.ps1 | -| tenantDeployStage | Deploy Policies defined by Main branch based plan | Prod stage approved | Deploy-PolicyPlan.ps1 | -| tenantRolesStage | Assign roles defined by Main branch based plan | Role stage approved | Deploy-RolesPlan.ps1 | +| devStage | Feature branch DEV environment build, deploy and test | CI, Manual | Build-DeploymentPlans
Deploy-PolicyPlan
Deploy-RolesPlan | +| tenantPlanFeatureStage | Feature branch based plan for prod deployment | CI, Manual | Build-DeploymentPlans | +| tenantPlanMainStage | Main branch based plan for prod deployment | PR Merged, Manual | Build-DeploymentPlans | +| tenantDeployStage | Deploy Policies defined by Main branch based plan | Prod stage approved | Deploy-PolicyPlan | +| tenantRolesStage | Assign roles defined by Main branch based plan | Role stage approved | Deploy-RolesPlan | ### Single Tenant Service Connections and Roles -Create Service Principals and associated service connections in Azure DevOps or the equivalent in your CI/CD tool. The SPNs require the following roles to adhere to the least privilege principle. If you have a single tenant, remove the last column and rows with connections ending in "-2". +Create Service Principals and associated service connections in Azure DevOps or the equivalent in your CI/CD tool. The SPNs require the following roles to adhere to the least privilege principle. If you have a single tenant, remove the last column and rows with connections ending in "-2". If a pacEnvironment in any of these stages is deploying to a lighthouse managed tenant and additionalRoleAssignemnts are to be used, ABAC assignments will need to be granted to the service principal at all remote scopes granting User Access Administrator for any roles that may need to be granted via additionalRoleAssignments. | Connection | Stages | MG: epac-dev-mg | MG: Tenant Root | | :--- | :--- | :--- | :--- | @@ -49,20 +49,20 @@ Create Service Principals and associated service connections in Azure DevOps or | Stage | Purpose | Trigger | Scripts | |-------|---------|---------|---------| -| devStage | Feature branch EPAC DEV environment build, deploy and test | CI, Manual | Build-DeploymentPlans.ps1
Deploy-PolicyPlan.ps1
Deploy-RolesPlan.ps1 | -| tenantPlanFeatureStage-1 | Feature branch based plan for prod deployment (tenant 1) | CI, Manual | Build-DeploymentPlans.ps1 | -| tenantPlanFeatureStage-2 | Feature branch based plan for prod deployment (tenant 2) | CI, Manual | Build-DeploymentPlans.ps1 | +| devStage | Feature branch EPAC DEV environment build, deploy and test | CI, Manual | Build-DeploymentPlans
Deploy-PolicyPlan
Deploy-RolesPlan | +| tenantPlanFeatureStage-1 | Feature branch based plan for prod deployment (tenant 1) | CI, Manual | Build-DeploymentPlans | +| tenantPlanFeatureStage-2 | Feature branch based plan for prod deployment (tenant 2) | CI, Manual | Build-DeploymentPlans | | completedFeature | Empty stage to complete feature branch | None | None | -| tenantPlanMainStage-1 | Main branch based plan for prod deployment (tenant 1) | PR Merged, Manual | Build-DeploymentPlans.ps1 | -| tenantDeployStage-1 | Deploy Policies defined by Main branch based plan (tenant 1) | Prod stage approved | Deploy-PolicyPlan.ps1 | -| tenantRolesStage-1 | Assign roles defined by Main branch based plan (tenant 1) | Role stage approved | Deploy-RolesPlan.ps1 | -| tenantPlanMainStage-2 | Main branch based plan for prod deployment (tenant 2) | PR Merged, Manual | Build-DeploymentPlans.ps1 | -| tenantDeployStage-2 | Deploy Policies defined by Main branch based plan (tenant 2) | Prod stage approved | Deploy-PolicyPlan.ps1 | -| tenantRolesStage-2 | Assign roles defined by Main branch based plan (tenant 2) | Role stage approved | Deploy-RolesPlan.ps1 | +| tenantPlanMainStage-1 | Main branch based plan for prod deployment (tenant 1) | PR Merged, Manual | Build-DeploymentPlans | +| tenantDeployStage-1 | Deploy Policies defined by Main branch based plan (tenant 1) | Prod stage approved | Deploy-PolicyPlan | +| tenantRolesStage-1 | Assign roles defined by Main branch based plan (tenant 1) | Role stage approved | Deploy-RolesPlan | +| tenantPlanMainStage-2 | Main branch based plan for prod deployment (tenant 2) | PR Merged, Manual | Build-DeploymentPlans | +| tenantDeployStage-2 | Deploy Policies defined by Main branch based plan (tenant 2) | Prod stage approved | Deploy-PolicyPlan | +| tenantRolesStage-2 | Assign roles defined by Main branch based plan (tenant 2) | Role stage approved | Deploy-RolesPlan | ### Multi Tenant Service Connections and Roles -Create Service Principals and associated service connections in Azure DevOps or the equivalent in your CI/CD tool. The SPNs require the following roles to adhere to the least privilege principle. If you have a single tenant, remove the last column and rows with connections ending in "-2". +Create Service Principals and associated service connections in Azure DevOps or the equivalent in your CI/CD tool. The SPNs require the following roles to adhere to the least privilege principle. If you have a single tenant, remove the last column and rows with connections ending in "-2". If a pacEnvironment in any of these stages is deploying to a lighthouse managed tenant and additionalRoleAssignemnts are to be used, ABAC assignments will need to be granted to the service principal at all remote scopes granting User Access Administrator for any roles that may need to be granted via additionalRoleAssignments. | Connection | Stages | MG: epac-dev-mg | MG: Tenant 1 Root | MG: Tenant 2 Root | | :--- | :--- | :--- | :--- | :--- | diff --git a/Docs/ci-cd-app-registrations.md b/Docs/ci-cd-app-registrations.md index 12fa64b1..a0ccfd6f 100644 --- a/Docs/ci-cd-app-registrations.md +++ b/Docs/ci-cd-app-registrations.md @@ -8,7 +8,7 @@ The following screenshot shows the Management Group hierarchy that used for the ## Custom `EPAC Resource Policy Reader Role` -EPAC uses a set of Entra ID App Registrations (Service Principals). To build the deployment plan and adhere to the least-privilege-principle, a Resource Policy Reader role is required. This role is not built-in. EPAC contains script `New-AzPolicyReaderRole.ps1` to create this role or you can use the below JSON in Azure Portal. +EPAC uses a set of Entra ID App Registrations (Service Principals). To build the deployment plan and adhere to the least-privilege-principle, a Resource Policy Reader role is required. This role is not built-in. EPAC contains script `New-AzPolicyReaderRole` to create this role or you can use the below JSON in Azure Portal. ```json { diff --git a/Docs/ci-cd-github-actions.md b/Docs/ci-cd-github-actions.md index 7698ea86..63fa3685 100644 --- a/Docs/ci-cd-github-actions.md +++ b/Docs/ci-cd-github-actions.md @@ -12,7 +12,7 @@ The previous version is still available in the starter kit in folder `Legacy` an You will need one [GitHub deployment environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment) for the `epac-dev` workflow and three environments each for your epac-prod or tenant workflows. This documentation assumes the include starter kit pipelines. -| Environment | Purpose | [App Registration](./ci-cd-app-registrations.md) (SPN) | +| Environment | Purpose | [App Registration](ci-cd-app-registrations.md) (SPN) | |---|---|---| | EPAC-DEV | Plan and deploy to `epac-dev` | ci-cd-epac-dev-owner | | TENANT-PLAN | Build deployment plan for `tenant` | ci-cd-root-policy-reader | @@ -28,22 +28,6 @@ For each environment, [add to the environment secrets](https://docs.github.com/e * [Restrict branch](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-branches-and-tags) to `main` branch for TENANT-DEPLOY-POLICY and TENANT-DEPLOY-ROLES environments. * Do not [allow administrators to bypass configured protection rules](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#allow-administrators-to-bypass-configured-protection-rules) for TENANT-DEPLOY-POLICY and TENANT-DEPLOY-ROLES environments. -## New GitHub Workflows - -Each of the workflows has three (3) jobs: -* `Build` - Builds the deployment plan -* `Deploy Policy` - Deploys the policy plan -* `Deploy Roles` - Deploys the role plan - -The starter kit contains the following workflows: - -* `epac-dev.yaml` is the workflow for the `epac-dev` environment. It is triggered on push to any `feature/**` branch. -* `tenant.yaml` is the workflow for the `epac-prod` or `tenant` environments. It is triggered on PR closed to the `main` branch. - -## Testing your Workflows - -To test the actions make a change to a file in the definitions folder. - ## Previous CI/CD Workflow -- Legacy This section is retained from the previous documentation to enable you to continue using the previous approach. It is recommended that you migrate to the new approach as soon as possible. @@ -62,8 +46,8 @@ This section is retained from the previous documentation to enable you to contin 8. For role changes when the PR is approved again the same action runs - this time using the `Deploy-RolesPlan` for deployment. 9. When complete the PR is closed and the branch containing the plan is deleted. -!!! note - This is a sample method of deploying policy and role changes - feel free to modify it to suit your environment and contribute to this project if you want to share an update. +> [!NOTE] +> This is a sample method of deploying policy and role changes - feel free to modify it to suit your environment and contribute to this project if you want to share an update. ### Setup in GitHub -- Legacy diff --git a/Docs/ci-cd-overview.md b/Docs/ci-cd-overview.md index a541ad88..24e5f305 100644 --- a/Docs/ci-cd-overview.md +++ b/Docs/ci-cd-overview.md @@ -1,60 +1,144 @@ # CI/CD Overview -This page covers the general CI/CD documentation. -This repository contains starter pipelines +Since EPAC is based on PowerShell scripts, any CI/CD tool with the ability to execute scripts can be used. The starter kits currently include pipeline definitions for Azure DevOps and GitHub Actions. Additional starter kits are being implemented and will be added in future releases. -* [Azure DevOps Pipelines](./ci-cd-ado-pipelines.md) -* [GitHub Actions](./github-actions.md) +The authors are interested in supporting other deployment pipelines. If you have developed pipelines for other technologies, such as GitLab, Jenkins, etc., please contribute them to the project as additional starter kits. +This repository contains starter pipelines and instructions for can be found here: -The authors are interested in supporting other deployment pipelines. If you have developed pipelines for other technologies, such as GitLab, Jenkins, etc., please contribute them to the project as additional starter kits. +- [Azure DevOps Pipelines](ci-cd-ado-pipelines.md) +- [GitHub Actions](ci-cd-github-actions.md) + +## Create Azure DevOps Pipelines or GitHub Workflows + +The scripts `New-PipelinesFromStarterKit` create [Azure DevOps Pipelines or GitHub Workflows from the starter kit](operational-scripts-hydration-kit.md#create-azure-devops-pipeline-or-github-workflow). You select the type of pipeline to create, the branching flow to implement, and the type of script to use. + +### Azure DevOps Pipelines + +The following commands create Azure DevOps Pipelines from the starter kit; use one of the commands: + +```ps1 +New-PipelinesFromStarterKit -StarterKitFolder .\StarterKit -PipelinesFolder .\pipelines -PipelineType AzureDevOps -BranchingFlow GitHub -ScriptType script +New-PipelinesFromStarterKit -StarterKitFolder .\StarterKit -PipelinesFolder .\pipelines -PipelineType AzureDevOps -BranchingFlow Release -ScriptType script +New-PipelinesFromStarterKit -StarterKitFolder .\StarterKit -PipelinesFolder .\pipelines -PipelineType AzureDevOps -BranchingFlow GitHub -ScriptType module +New-PipelinesFromStarterKit -StarterKitFolder .\StarterKit -PipelinesFolder .\pipelines -PipelineType AzureDevOps -BranchingFlow Release -ScriptType module +``` + +### GitHub Workflows + +The following commands create GitHub Workflows from the starter kit; use one of the commands: + +```ps1 +New-PipelinesFromStarterKit -StarterKitFolder .\StarterKit -PipelinesFolder .\.github/workflows -PipelineType GitHubActions -BranchingFlow GitHub -ScriptType script +New-PipelinesFromStarterKit -StarterKitFolder .\StarterKit -PipelinesFolder .\.github/workflows -PipelineType GitHubActions -BranchingFlow Release -ScriptType script +New-PipelinesFromStarterKit -StarterKitFolder .\StarterKit -PipelinesFolder .\.github/workflows -PipelineType GitHubActions -BranchingFlow GitHub -ScriptType module +New-PipelinesFromStarterKit -StarterKitFolder .\StarterKit -PipelinesFolder .\.github/workflows -PipelineType GitHubActions -BranchingFlow Release -ScriptType module +``` + + + +## Developing Policy Resources in a Feature Branch + +Developing Policy resources is the dame for `GitHub Flow` and `Release Flow`. The following steps are recommended: + +1. Developers create feature branches from `main` branch with a name `feature/*user-id*/*feature-name*`. +2. Developers create or update Policy definitions, Policy Set definitions, Policy Assignment, amd Policy Exemptions files in the `Definitions` folder. Developers push changes to the feature branch. +3. The CI/CD pipeline/action is triggered from the push to the feature branch. We recommend to use a single App Registration (SPN) to execute pipeline/action during development. The SPN must have `Owner` rights to the `epac-dev` Management Group and the Microsoft Graph permissions described below. The steps are: + - Build-DeploymentPlans.ps1 to calculate the deployment plan + - Deploy-PolicyPlan.ps1 to deploy the plan's Policy Resources + - Deploy-RolesPlan.ps1 to create the role assignments for the Managed Identities required for `DeployIfNotExists` and `Modify` Policies. + - The starter pipelines calculate the Plans for tenant(s). The Plans are stored in the `Output` folder. +4. When the feature is ready, the developer creates a Pull Request (PR) to merge the feature branch into the `main` branch. +5. Set the pull request to be auto-completed. Ensure that you select `Delete feature/*user-id*/*feature-name* after merging`. + +![image.png](Images/ci-cd-set-auto-complete.png) + +6. After the merge completes, cleanup your local clone by: + - Switching the branch to main + - Pull the latest changes from main + - Delete the feature branch + - Run `git remote prune origin` to remove the remote tracking branch. + +Steps 1 to 3 are repeated during the development process. + +The resulting pipeline CI/CD trigger depends on the type of flow used. The following sections describe the simplified `GitHub Flow` and the more advanced `Release Flow`. + +## General Hardening Guidelines + +- **Least Privilege**: Use the least privilege principle when assigning roles to the SPNs used in the CI/CD pipeline. The roles should be assigned at the root or pseudo-root management group level. +- Require a Pull Request for changes to the `main` branch. This ensures that changes are reviewed before deployment. +- Require additional reviewers for yml pipeline and script changes. +- Require branches to be in a folder `feature` to prevent accidental deployment of branches. +- Require an approval step between the Plan stage/job and the Deploy stage/job. This ensures that the changes are reviewed before deployment. +- [Optional] Require an approval step between the Deploy stage/job and the Role Assignments stage/job. This ensures that the role assignments are reviewed before deployment. +- For `Release Flow` only: allow only privileged users to create `releases-prod` and `releases-exemptions-only` branches and require those branches to be created from the main branch only. ## Simplified `GitHub Flow` for Policy as Code -The diagram below shows the use of GitHub Flow in Policy as Code. The diagram uses GitHub workflow terminology; however, the concepts apply equally to other CI/CD technologies. Detailed instructions for [Azure DevOps Pipelines](./ci-cd-ado-pipelines.md) and [GitHub Actions](./github-actions.md) are provided. - -The flow shown in the diagram contains the following steps: - -1. Developers create feature branches from `main` branch. -2. Developers create or update Policy definitions, Policy Set definitions, and Policy Assignment files in the `Definitions` folder. Developers push changes to the feature branch. -3. The CI/CD pipeline/action is triggered from the push to the feature branch. We recommend to use a single App Registration (SPN) to execute pipeline/action. The SPN must have `Owner` rights to the `epac-dev` Management Group and the Microsoft Graph permissions described below. The steps are: - * Build-DeploymentPlans.ps1 to calculate the deployment plan - * Deploy-PolicyPlan.ps1 to deploy the plan's Policy Resources - * Deploy-RolesPlan.ps1 to create the role assignments for the Managed Identities required for `DeployIfNotExists` and `Modify` Policies. -* Steps 1 to 3 are repeated during the development process. -4. When the feature is ready, the developer creates a Pull Request (PR) to merge the feature branch into the `main` branch. The merge of the PR into the `main` branch triggers the CI/CD pipeline/action (step 5) to deploy the changes to the `prod` environment. -5. Since these deployments are most often deployed at the pseudo root of the tenant, we recommend creating a separate App Registration (SPN) for each of the 3 steps with roles assigned in line with the least privilege principle. The steps are: - * Build-DeploymentPlans.ps1 to calculate the deployment plan. SPN must have `EPAC Resource Policy Reader` custom role on the root or pseudo-root management group and the Microsoft Graph permissions described below. - * Approval gate for Policy resources deployment. - * Deploy-PolicyPlan.ps1 to deploy the plan's Policy Resources. SPN must have `Resource Policy Contributor` built-in role on the root or pseudo-root management group. Microsoft Graph permissions are not required. - * Approval gate for Role assignments deployment. - * Deploy-RolesPlan.ps1 to create the role assignments for the Managed Identities required for `DeployIfNotExists` and `Modify` Policies. SPN must have `User Access Administrator` built-in role on the root or pseudo-root management group and the Microsoft Graph permissions described below. -* Action through 3 within step 8 above are repeated for additional tenants in a multi-tenant scenario. +The diagram below shows the use of GitHub Flow in Policy as Code. The diagram uses GitHub workflow terminology; however, the concepts apply equally to other CI/CD technologies. + +The merge of the PR into the `main` branch triggers the CI/CD pipeline/action to deploy the changes to the `tenant` environment. + +Since these deployments are most often deployed at the pseudo root of the tenant, we recommend creating a separate App Registration (SPN) for each of the 3 steps with roles assigned in line with the least privilege principle. The steps are: + +- Build-DeploymentPlans.ps1 to calculate the deployment plan. SPN must have `EPAC Resource Policy Reader` custom role on the root or pseudo-root management group and the Microsoft Graph permissions described below. +- Approval gate for Policy resources deployment. +- Deploy-PolicyPlan.ps1 to deploy the plan's Policy Resources. SPN must have `Resource Policy Contributor` built-in role on the root or pseudo-root management group. Microsoft Graph permissions are not required. +- Approval gate for Role assignments deployment. +- Deploy-RolesPlan.ps1 to create the role assignments for the Managed Identities required for `DeployIfNotExists` and `Modify` Policies. SPN must have `User Access Administrator` built-in role on the root or pseudo-root management group and the Microsoft Graph permissions described below. ![image.png](Images/epac-github-flow.png) -## `GitHub` Flow Variations +### `GitHub Flow` Variations + +EPAC can handle any flow you like. For `GitHub Flow`, the following variations are possible. + +- Adding a deployment plan from the feature branch to the production environment in step 3 above during the development process (see steps 1 through 3 in the diagram above) by adding a step using Build-DeploymentPlans.ps1. This is useful to test the deployment plan in the production environment before creating a PR. We recommend using a separate SPN for this step (job). +- PR creation trigger for a CI/CD pipeline/action deploying the changes to an `epac-test` environment with the same steps as the deployment to `epac-dev` environment in steps 3 above. + +## Advanced CI/CD with Release Flow -EPAC can handle any flow you like. For `GitHub Flow`, the following variations are possible. WE do not recommend this approach since the additional calculations rarely yield any insights.: +Testing the Policy changes against the IaC `nonprod` environment is often desirable to prevent surprises when deploying against the IaC `prod` environment. IaC environments can either be separate tenants or management groups within a single tenant (recommended). -* Adding a deployment plan from the feature branch to the production environment in step 3 above during the development process (see steps 1 through 3 in the diagram above) by adding a step using Build-DeploymentPlans.ps1. This is useful to test the deployment plan in the production environment before creating a PR. We recommend using a separate SPN for this step (job). -* PR creation trigger for a CI/CD pipeline/action deploy the changes to an `epac-test` environment with the same steps as the deployment to `epac-dev` environment in steps 3 above. +[Release Flow](https://devblogs.microsoft.com/devops/release-flow-how-we-do-branching-on-the-vsts-team/) is a more advanced CI/CD process that allows for testing the Policy changes against the IaC `nonprod` environment before deploying to the IaC `prod` environment as shown in the diagram below. +- The merge of the PR into the `main` branch triggers the CI/CD pipeline/action to deploy the changes to the IaC `nonprod` environment. +- Wait a few days to verify that the Policies in the IaC `nonprod` environment are working as expected. + - Creating a `releases-prod` branch triggers a pipeline deploying Policy resources to the IaC `prod` environment. + - Keep n-1 `releases-prod` branches to allow for quick rollback in case of issues. +- Sometimes, Exemptions need to be granted while keeping a regular lifecycle for Definitions and Assignments. The script `Build-DeploymentPlans` has a parameter `BuildExemptionsOnly` to deploy only Exemptions. + - Creating a `releases-exemptions-only` branch triggers a pipeline deploying Exemptions only to the IaC `prod` environment. + - Keep n-1 `releases-exemptions-only` branches to allow for quick rollback in case of issues. + +If necessary, you can also branch of the `releases-prod` branch to create a `hotfix` branch to fix issues in the `prod` environment. Similar to the development process, the `hotfix` branch is merged into the `releases-prod` branch with a Pull request. + +![image.png](Images/epac-release-flow.png) + +### `Release Flow` Variations + +EPAC can handle any flow you like. For `Release Flow`, the following variations are possible. + +- Adding a deployment plan from the feature branch to the production environment in step 3 above during the development process (see steps 1 through 3 in the diagram above) by adding a step using Build-DeploymentPlans.ps1. This is useful to test the deployment plan in the production environment before creating a PR. We recommend using a separate SPN for this step (job). +- PR creation trigger for a CI/CD pipeline/action deploying the changes to an `epac-test` environment with the same steps as the deployment to `epac-dev` environment in steps 3 above. + +## Multiple Tenants + +For multiple tenants simply apply each of the flows (except for the `feature` branch) above to each tenant's IaC environments. This works for both simplified GitHub flow and Microsoft Release flow. ## Deployment Scripts -While this script intended to be used in CI/CD, they can be run manually to create a semi-automated EPAC solution. This is useful: +While the scripts are intended to be used in CI/CD, they can be run manually to create a semi-automated EPAC solution. This is useful: -* CI/CD environment is not yet available. -* Debugging the scripts from Visual Studio Code. +- CI/CD environment is not yet available. +- Debugging the scripts from Visual Studio Code. -Deployment scripts require permissions to the Azure environment and Microsoft Graph API. In a CI/CD scenario, App Registration (SPNs) are used to execute the scripts. These identities must be granted the necessay permissions as documented in [App Registrations Setup](./ci-cd-app-registrations.md). In a semi-automated scenario, the user executing the scripts must have the necessary permissions. The scripts will prompt for the necessary permissions. +Deployment scripts require permissions to the Azure environment and Microsoft Graph API. In a CI/CD scenario, App Registration (SPNs) are used to execute the scripts. These identities must be granted the necessay permissions as documented in [App Registrations Setup](ci-cd-app-registrations.md). In a semi-automated scenario, the user executing the scripts must have the necessary permissions. The scripts will prompt for the necessary permissions. The image below shows the scripts and the roles required for their execution. -* `Build-DeploymentPlans.ps1` requires `EPAC Resource Policy Reader` custom role on the root or pseudo-root management group and the Microsoft Graph permissions described below. -* `Deploy-PolicyPlan.ps1` requires `Resource Policy Contributor` built-in role on the root or pseudo-root management group. Microsoft Graph permissions are not required. -* `Deploy-RolesPlan.ps1` requires `User Access Administrator` built-in role on the root or pseudo-root management group and the Microsoft Graph permissions described below. +- `Build-DeploymentPlans.ps1` requires `EPAC Resource Policy Reader` custom role on the root or pseudo-root management group and the Microsoft Graph permissions described below. +- `Deploy-PolicyPlan.ps1` requires `Resource Policy Contributor` built-in role on the root or pseudo-root management group. Microsoft Graph permissions are not required. +- `Deploy-RolesPlan.ps1` requires `User Access Administrator` built-in role on the root or pseudo-root management group and the Microsoft Graph permissions described below. Furthermore, it shows the consumption of the `Definitions` files by script Build-DeploymentPlans.ps1 and output of two plan files (Policy and Roles). The plan files are subsequently used by the deployment scripts `Deploy-PolicyPlan.ps1` and `Deploy-RolesPlan.ps1`. @@ -72,12 +156,12 @@ Furthermore, it shows the consumption of the `Definitions` files by script Build Analyzes changes in Policy definition, Policy Set definition, and Policy Assignment files. It calculates a plan to apply deltas. The deployment scripts are **declarative** and **idempotent**: this means, that regardless how many times they are run, they always push all changes that were implemented in the JSON files to the Azure environment, i.e. if a JSON file is newly created/updated/deleted, the pipeline will create/update/delete the Policy and/or Policy Set and/or Policy Assignments definition in Azure. If there are no changes, the pipeline can be run any number of times, as it won't make any changes to Azure. -In addition to the [common parameters](#common-script-parameters), these parameters are defined: - |Parameter | Explanation | |----------|-------------| | `OutputFolder` | Output folder path for plan files. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER` or `./Output`. | | `DevOpsType` | If set, outputs variables consumable by conditions in a DevOps pipeline. Default: not set. | +| `BuildExemptionsOnly` | If set, only builds the Exemptions plan. This useful to fast-track Exemption when utilizing [Microsoft Release Flow](#advanced-cicd-with-microsoft-release-flow) Default: not set. | +| `VirtualCores` | Number of (virtual) cores available to calculate the deployment plan. Defaults to 4. | ### Deploy-PolicyPlan.ps1 @@ -86,6 +170,7 @@ Deploys Policies, Policy Sets, Policy Assignments, and Policy Exemptions at thei |Parameter | Explanation | |----------|-------------| | `InputFolder` | Input folder path for plan files. Defaults to environment variable `$env:PAC_INPUT_FOLDER`, `$env:PAC_OUTPUT_FOLDER` or `./Output`. | +| `VirtualCores` | Number of (virtual) cores available to deploy Policy objects in parallel. Defaults to 4. | ### Deploy-RolesPlan.ps1 diff --git a/Docs/code-promotion-module-release-process.md b/Docs/code-promotion-module-release-process.md deleted file mode 100644 index 54014ad3..00000000 --- a/Docs/code-promotion-module-release-process.md +++ /dev/null @@ -1,64 +0,0 @@ -# EPAC Development to Production Promotion Process - -A guide for maintainers on how to move internal EPAC development (ADO) to production (GitHub). - -Assumption: You have completed PR in for EPAC Development in ADO ([https://secinfra.visualstudio.com/\_git/epac-development](https://secinfra.visualstudio.com/_git/epac-development)) and are ready to release to public GitHub EPAC project. - -You are using known local path names for EPAC Development repo and GitHub repo, for example: - -EPAC Development local repo: `C:\GitRepoClones\epac-development` -EPAC GitHub local repo: `C:\GitRepoClones\enterprise-azure-policy-as-code` - -## Code Promotion Process - -1. Create a branch in GitHub ([https://github.com/Azure/enterprise-azure-policy-as-code](https://github.com/Azure/enterprise-azure-policy-as-code)). - -2. Update local production repo with content from local development repo. In local VS code repo for EPAC GitHub, open terminal: - `PS C:\GitRepoClones\enterprise-azure-policy-as-code> .\Sync-ToGH.ps1`. - -3. Commit changes and sync. - -4. Go to [https://github.com/Azure/enterprise-azure-policy-as-code](https://github.com/Azure/enterprise-azure-policy-as-code), go to `Compare and Pull Request` - -5. Add PR title and create PR. - -6. Complete GitHub Review and merge PR process. - -7. Delete branch from GitHub. - -8. Go to VSCode for EPAC Release (GitHub) (ex `C:\GitRepoClones\enterprise-azure-policy-as-code`) In Source Control, select main branch. Move to Remotes and fetch, then sync changes. - -9. Move to branches, delete local branch (force delete may be required). - -10. Open terminal, type `git remote prune origin` - -# Module Release Process - -This is a guide on how to release a new version of the project - including automated PowerShell module publish. It is used by the EPAC maintainers only. - -## GitHub Release Process - -1. Navigate to https://github.com/Azure/enterprise-azure-policy-as-code/releases -2. Click on **Draft a new release** -3. Click on **Choose a tag** and enter in the new release version - it should be in the format "v(major).(minor).(build)" i.e. v7.3.4 **Don't forget the v** -4. When prompted click on **Create new tag: vX.X.X on publish** -5. Add a release title - you can just use the new version number. -6. Click on **Generate release notes** to pull all the notes in from related PRs. Update if necessary. -7. Click **Publish Release** - -Now just verify the module publish action has run - -## Verify Action - -1. Click on **Actions** -2. Verify that a workflow run has started with the same name as the release. - -It should finish successfully - if there is a failure review the build logs. - -# Documentation Release Process - -A guide for maintainers on how to update documentation.. - -1. Modify files in the Docs folder following the format of other files. For a list of acceptable admonitions please see [here](https://squidfunk.github.io/mkdocs-material/reference/admonitions/#supported-types) -2. If you are adding a new file ensure it is added to the `mkdocs.yml` file in the appropriate section. Use the built site to determine where a new document should be placed. -3. Create a PR and merge - the actions will commence automatically. There are two actions which run in the background to update the GitHub Pages site. diff --git a/Docs/create-az-remediation-tasks.md b/Docs/create-az-remediation-tasks.md deleted file mode 100644 index baa0ac96..00000000 --- a/Docs/create-az-remediation-tasks.md +++ /dev/null @@ -1,50 +0,0 @@ -# Batch Creation of Remediation Tasks - -The script `Create-AzRemediationTasks.ps1` creates remediation tasks for all non-compliant resources for EPAC environments in the `global-settings.jsonc` file. - -This script executes all remediation tasks in a Policy as Code environment specified with parameter `PacEnvironmentSelector`. The script will interactively prompt for the value if the parameter is not supplied. The script will recurse the Management Group structure and subscriptions from the defined starting point. - -* Find all Policy assignments with potential remediation capable resources -* Query Policy Insights for non-complaint resources -* Start remediation task for each Policy with non-compliant resources - -## Script Parameters - -| Parameter | Description | -| --- | --- | -| `PacEnvironmentSelector` | Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc`. | -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER or './Definitions'`. | -| `Interactive` | Set to false if used non-interactive | -| `OnlyCheckManagedAssignments` | Include non-compliance data only for Policy assignments owned by this Policy as Code repo | -| `PolicyDefinitionFilter` | Filter by Policy definition names (array) or ids (array). | -| `PolicySetDefinitionFilter` | Filter by Policy Set definition names (array) or ids (array). | -| `PolicyAssignmentFilter` | Filter by Policy Assignment names (array) or ids (array). | -| `PolicyEffectFilter` | Filter by Policy effect (array). | - - -## Examples - -```ps1 -Create-AzRemediationTasks -PacEnvironmentSelector "dev" -``` - -```ps1 -Create-AzRemediationTasks -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\git\policy-as-code\Definitions" -``` - -```ps1 -Create-AzRemediationTasks -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\git\policy-as-code\Definitions" -Interactive $false -``` - -```ps1 -Create-AzRemediationTasks -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\git\policy-as-code\Definitions" -OnlyCheckManagedAssignments -``` - -```ps1 -Create-AzRemediationTasks -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\git\policy-as-code\Definitions" -PolicyDefinitionFilter "Require tag 'Owner' on resource groups" -PolicySetDefinitionFilter "Require tag 'Owner' on resource groups" -PolicyAssignmentFilter "Require tag 'Owner' on resource groups" -``` - -## Links - -- [Remediate non-compliant resources with Azure Policy](https://learn.microsoft.com/en-us/azure/governance/policy/how-to/remediate-resources?tabs=azure-portal) -- [Start-AzPolicyRemediation](https://learn.microsoft.com/en-us/powershell/module/az.policyinsights/start-azpolicyremediation?view=azps-10.1.0) diff --git a/Docs/create-policy-reader-role.md b/Docs/create-policy-reader-role.md deleted file mode 100644 index bebc0419..00000000 --- a/Docs/create-policy-reader-role.md +++ /dev/null @@ -1,39 +0,0 @@ -# Create Policy Reader Role - -Creates a custom role `EPAC Resource Policy Reader` with `Id` `2baa1a7c-6807-46af-8b16-5e9d03fba029`. It provides read access to all Policy resources for the purpose of planning the EPAC deployments at the scope selected with `PacEnvironmentSelector`. The permissions granted are: - -* `Microsoft.Authorization/policyassignments/read` -* `Microsoft.Authorization/policydefinitions/read` -* `Microsoft.Authorization/policyexemptions/read` -* `Microsoft.Authorization/policysetdefinitions/read` -* `Microsoft.Authorization/roleAssignments/read` -* `Microsoft.PolicyInsights/*` -* `Microsoft.Management/register/action` -* `Microsoft.Management/managementGroups/read` - - -## Script Parameters - -| Parameter | Description | -| --- | --- | -| `PacEnvironmentSelector` | Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc`. | -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER or './Definitions'`. It contains `global-settings.jsonc`. | -| `Interactive` | Script is being run interactively and can request az login. Defaults to $false if PacEnvironmentSelector parameter provided and $true otherwise. | - -## Examples - -```ps1 -.\New-AzPolicyReaderRole.ps1 -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\Src\Definitions" -Interactive $true -``` - -```ps1 -.\New-AzPolicyReaderRole.ps1 -Interactive $true -``` - -```ps1 -.\New-AzPolicyReaderRole.ps1 -Interactive $true -DefinitionsRootFolder "C:\Src\Definitions" -``` - -```ps1 -.\New-AzPolicyReaderRole.ps1 -Interactive $true -DefinitionsRootFolder "C:\Src\Definitions" -PacEnvironmentSelector "dev" -``` diff --git a/Docs/definitions-and-global-settings.md b/Docs/definitions-and-global-settings.md deleted file mode 100644 index 68dd3768..00000000 --- a/Docs/definitions-and-global-settings.md +++ /dev/null @@ -1,132 +0,0 @@ -# Definitions and Global Settings - -## Folders - -This `Definitions` folder and subfolders contains all your definitions. The `Sync-Repo.ps1` script does not copy this folder. - -1. Define the Azure environment(s) in file **[global-settings.jsonc](#global-settings)** -1. Create custom Policies (optional) in folder **[policyDefinitions](policy-definitions.md)** -1. Create custom Policy Sets (optional) in folder **[policySetDefinitions](policy-set-definitions.md)** -1. Define the Policy Assignments in folder **[policyAssignments](policy-assignments.md)** -1. Define the Policy Exemptions (optional) in folder **[policyExemptions](policy-exemptions.md)** -1. Define Documentation in folder **[policyDocumentations](documenting-assignments-and-policy-sets.md)** - -## Global Settings - -`global-settings.jsonc` has following sections explained below: - -- `telemetryOptOut` if set to true disables the collection of usage date for the EPAC repo. The default is false. See [Usage Tracking](usage-tracking.md) for more information. -- `pacOwnerId` uniquely identifies deployments from a specific repo. We recommend using a GUID. -- `pacEnvironments` defines the EPAC environments. -- `managedIdentityLocations` is used in Policy Assignments as the location of the created Managed Identities. -- `globalNotScopes` defines scopes not subject to the Policy Assignments. - -### JSON Schema - -The GitHub repo contains a JSON schema which can be used in tools such as [VS Code](https://code.visualstudio.com/Docs/languages/json#_json-schemas-and-settings) to provide code completion. - -To utilize the schema add a ```$schema``` tag to the JSON file. - -``` -{ - "$schema": "https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/main/Schemas/global-settings-schema.json" -} -``` - -This schema is new in v7.4.x and may not be complete. Please let us know if we missed anything. - -### Opt out of telemetry data collection `telemetryOptOut` - -Starting with v8.0.0, Enterprise Policy as Code (EPAC) is tracking the usage using Customer Usage Attribution (PID). See [Usage Tracking](usage-tracking.md) for more information on opt out. Default is false. - -```json -"telemetryOptOut": true, -``` - -### Uniquely identify deployments `pacOwnerId` - -`pacOwnerId` is required for [desired state handling](desired-state-strategy.md) to distinguish Policy resources deployed via this EPAC repo, legacy technology, another EPAC repo, or another Policy as Code solution. - -### Define EPAC Environments in `pacEnvironments` - -EPAC has a concept of an environment identified by a string (unique per repository) called `pacSelector` as defined in `pacEnvironments`. An environment associates the following with the `pacSelector`: - -- `cloud` - to select sovereign cloud environments. -- `tenantId` - enables multi-tenant scenarios. -- `rootDefinitionScope` - the deployment scope for the Policies and Policy Sets to be used in assignments later. - - Policy Assignments can only defined at this scope and child scopes (recursive). - - Operational tasks, such as `Create-AzRemediationTasks.ps1`, must use the same `rootDefinitionScope` or they will fail. -- Optional: define `desiredState` strategy. This element is documented in two places: - - [Desired State Strategy](desired-state-strategy.md). and - - [Managing Defender for Cloud Assignments](dfc-assignments.md). - -Like any other software or IaC solution, EPAC needs areas for developing and testing new Policies, Policy Sets and Policy Assignments before any deployment to EPAC prod environments. In most cases you will need one management group hierarchy to simulate EPAC production management groups for development and testing of Policies. EPAC's prod environment will govern all other IaC environments (e.g., sandbox, development, integration, test/qa, pre-prod, prod, ...) and tenants. This can be confusing. We will use EPAC environment(s) and IaC environments to disambiguate the environments. - -In a centralized single tenant scenario, you will define two EPAC environments: epac-dev and tenant. In a multi-tenant scenario, you will add an additional EPAC environment per additional tenant. - -The `pacSelector` is just a name. We highly recommend to call the Policy development environment `epac-dev`, you can name the EPAC prod environments in a way which makes sense to you in your environment. We use `tenant`, `tenant1`, etc in our samples and documentation. These names are used and therefore must match: - -- Defining the association (`pacEnvironments`) of an EPAC environment, `managedIdentityLocation` and `globalNotScopes` in `global-settings.jsonc` -- Script parameter when executing different deployment stages in a CI/CD pipeline or semi-automated deployment targeting a specific EPAC environments. -- `scopes`, `notScopes`, `additionalRoleAssignments`, `managedIdentityLocations`, and `userAssignedIdentity` definitions in Policy Assignment JSON files. - -```json -"pacEnvironments": [ - { - "pacSelector": "epac-dev", - "cloud": "AzureCloud", - "tenantId": "70238025-b3dc-40a5-bea1-314973cea2db", - "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/PAC-Heinrich-Dev" - }, - { - "pacSelector": "tenant", - "cloud": "AzureCloud", - "tenantId": "70238025-b3dc-40a5-bea1-314973cea2db", - "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/Contoso-Root", - "inheritedDefinitionsScopes": [], // optional for desired state coexistence scenarios - "desiredState": { // optional for desired state coexistence scenarios - } - } -], -``` - -### DeployIfNotExists and Modify Policy Assignments need `managedIdentityLocation` - -Policies with `Modify` and `DeployIfNotExists` effects require a Managed Identity for the remediation task. This section defines the location of the managed identity. It is often created in the tenant's primary location. This location can be overridden in the Policy Assignment files. The star in the example matches all `pacEnvironmentSelector` values. - -```json - "managedIdentityLocation": { - "*": "eastus2" - }, -``` - -### Excluding scopes for all Assignments with `globalNotScopes` - -Resource Group patterns allow us to exclude "special" managed Resource Groups. The exclusion is not dynamic. It is calculated when the deployment scripts execute. - -The arrays can have the following entries: - -| Scope type | Example | -|------------|---------| -| `managementGroups` | "/providers/Microsoft.Management/managementGroups/myManagementGroupId" | -| `subscriptions` | "/subscriptions/00000000-0000-0000-000000000000" | -| `resourceGroups` | "/subscriptions/00000000-0000-0000-000000000000/resourceGroups/myResourceGroup" | -| `resourceGroupPatterns` | No wild card or single \* wild card at beginning or end of name or both; wild cards in the middle are invalid:
"/resourceGroupPatterns/name"
"/resourceGroupPatterns/name\*"
"/resourceGroupPatterns/\*name"
"/resourceGroupPatterns/\*name\*"
- -```json - "globalNotScopes": { - "*": [ - "/resourceGroupPatterns/synapseworkspace-managedrg-*", - "/resourceGroupPatterns/managed-rg-*", - "/resourceGroupPatterns/databricks-*", - "/resourceGroupPatterns/DefaultResourceGroup*", - "/resourceGroupPatterns/NetworkWatcherRG", - "/resourceGroupPatterns/LogAnalyticsDefault*", - "/resourceGroupPatterns/cloud-shell-storage*" - ], - "tenant": [ - "/providers/Microsoft.Management/managementGroups/mg-personal-subscriptions", - "/providers/Microsoft.Management/managementGroups/mg-policy-as-code" - ] - }, -``` diff --git a/Docs/dfc-assignments.md b/Docs/dfc-assignments.md deleted file mode 100644 index 3f52fb2d..00000000 --- a/Docs/dfc-assignments.md +++ /dev/null @@ -1,38 +0,0 @@ -# Managing Defender for Cloud Assignments - -Defender for Cloud (DFC) is a suite of Azure Security Center (ASC) capabilities that helps you prevent, detect, and respond to threats. It provides you with integration of Microsoft's threat protection technology and expertise. For more information, see [Azure Defender for Cloud](https://docs.microsoft.com/en-us/azure/security-center/defender-for-cloud). - -## Behavior of EPAC Prior to v9.0.0 - -Defender for Cloud uses Azure Policy Assignments to enable and configure the various capabilities. These assignments are created at the subscription level. - -* Policy Assignments required for [Defender plans](#defender-for-cloud-settings-for-defender-plans) (e.g., SQL, App Service, ...) -* Policy Assignments required for [Security policies](#defender-for-cloud-settings-for-security-policy-sets) (e.g., Microsoft Cloud Security Benchmark, NIST 800-53 Rev 5, NIST 800-171, ...) - -Prior to v9.0.0 of EPAC, Defender for Cloud Assignments were removed by EPAC. This was a problem for Microsoft's customers, especially for Defender Plans. - -## Revised behavior of EPAC Starting with v9.0.0: - -* EPAC **no longer manages (removes)** `Defender for Cloud`'s Policy Assignments required for enabled Defender Plans. -* EPAC behavior for Security Policy **is controlled by** the `keepDfcSecurityAssignments` in `desiredState` setting per `pacEnvironment` in `global-settings.jsonc`. - * If set to `true` or `strategy` is `ownedOnly`, EPAC will **not** remove Security Policy assignments created by Defender for Cloud. - * If **omitted** or **set to `false`** and `strategy` is `full`, EPAC will remove Security Policy Set Assignments created by Defender for Cloud. - - ```json - "desiredState": { - "strategy": "full", - "keepDfcSecurityAssignments": true - } - ``` - -**Security Policies should be manged by EPAC at the Management Group level**; this is the recommended approach for managing Security Policies instead of relying on the auto-assignments. - -## Defender for Cloud Settings - -### Defender for Cloud settings for Defender Plans - -![image.png](Images/dfc-defender-plans-settings.png) - -### Defender for Cloud settings for Security Policy Sets - -![image.png](Images/dfc-security-policy-sets-settings.png) diff --git a/Docs/epac-extracting-policy-resources.md b/Docs/epac-extracting-policy-resources.md new file mode 100644 index 00000000..b7ce2165 --- /dev/null +++ b/Docs/epac-extracting-policy-resources.md @@ -0,0 +1,62 @@ +# Extract Policy Resources + +Script `Export-AzPolicyResources` (Operations) extracts existing Policies, Policy Sets, and Policy Assignments and Exemptions outputing them in EPAC format into subfolders in folder `$outputFolders/Definitions`. The subfolders are `policyDefinitions`, `policySetDefinitions`, `policyAssignments` and `policyExemptions`. + +> [!TIP] +> In a new EPAC instance these subfolders can be directly copied to the `Definitions` folder enabling an initial transition from a pre-EPAC to EPAC environment. + +> [!NOTE] +> The script collects information on ownership of the Policy resources into a CSV file. You can analyze this file to assist in the transition to EPAC. + +The scripts creates a `Definitions` folder in the `OutputFolder` with the subfolders for `policyDefinitions`, `policySetDefinitions`, `policyAssignments` and `policyExemptions`. To use the generated files copy them to your `Definitions` folder. + +* `policyDefinitions`, `policySetDefinitions` have a subfolder based on `metadata.category`. If the definition has no `category` `metadata` they are put in a subfolder labeled `Unknown Category`. Duplicates when including child scopes are sorted into the `Duplicates` folder. Creates one file per Policy and Policy Set. +* `policyAssignments` creates one file per unique assigned Policy or Policy Set spanning multiple Assignments. +* `policyExemptions` creates one subfolder per EPAC environment + +> [!WARNING] +> The script deletes the `$outputFolders/Definitions` folder before creating a new set of files. In interactive mode it will ask for confirmation before deleting the directory. + +## Use case 1: Interactive or non-interactive single tenant + +`-Mode 'export'` is used to collect the Policy resources and generate the definitions file. This works for `-Interactive $true` (the default) to extract Policy resources in single tenant or multi-tenant scenario, prompting the user to logon to each new tenant in turn. + +It also works for a single tenant scenario for an automated collection, assuming that the Service Principal has read permissions for every EPAC Environment in `global-settings.jsonc`. + +```ps1 +Export-AzPolicyResources +``` + +The parameter `-InputPacSelector` can be used to only extract Policy resources for one of the EPAC environments. + +## Use case 2: Non-interactive multi-tenant + +While this pattern can be used for interactive users too, it is most often used for multi-tenant non-interactive usage since an SPN is bound to a tenant and the script cannot prompt for new credentials. + +The solution is a multi-step process: + +Collect the raw information for very EPAC environment after logging into each EPAC environment (tenant): + +```ps1 +Connect-AzAccount -Environment $cloud -Tenant $tenantIdForDev +Export-AzPolicyResources -Interactive $false -Mode collectRawFile -InputPacSelector 'epac-dev' + +Connect-AzAccount -Environment $cloud -Tenant $tenantId1 +Export-AzPolicyResources -Interactive $false -Mode collectRawFile -InputPacSelector 'tenant1' + +Connect-AzAccount -Environment $cloud -Tenant $tenantId2 +Export-AzPolicyResources -Interactive $false -Mode collectRawFile -InputPacSelector 'tenant2' +``` + +Next, the collected raw files are used to generate the same output: + +```ps1 +Export-AzPolicyResources -Interactive $false -Mode exportFromRawFiles +``` + +## Caveats + +The extractions are subject to the following assumptions and caveats: + +* Assumes Policies and Policy Sets with the same name define the same properties independent of scope and EPAC environment. +* Ignores Assignments auto-assigned by Defender for Cloud. This behavior can be overridden with the switch parameter `-IncludeAutoAssigned`. diff --git a/Docs/clone-github.md b/Docs/epac-forking-github-repo.md similarity index 98% rename from Docs/clone-github.md rename to Docs/epac-forking-github-repo.md index f02347b1..21ea3f4b 100644 --- a/Docs/clone-github.md +++ b/Docs/epac-forking-github-repo.md @@ -1,4 +1,4 @@ -# Alternate Script Installation cloning the GitHub Repository +# Forking the GitHub Repo - an Alternate Installation Method Instead of installing `EnterprisePolicyAsCode` from the PowerShell Gallery, you can clone the GitHub repository and use the scripts described below to install the script source code. This is useful, if your organization has overly restrictive policies on installing PowerShell modules from the PowerShell Gallery. It can also be usefule if you want to contribute EPAC source code to the project. @@ -15,7 +15,7 @@ Instead of installing `EnterprisePolicyAsCode` from the PowerShell Gallery, you 1. Use only folders `Definitions` and `Pipeline`, except when working on fixes to be contributed back to GitHub. 1. Review the [`Sync-Repo.ps1`](#sync-repops1) documentation for additional information on the folders which are destroyed and recreated as part of the version upgrade process for additional insight on this topic. -![image](./Images/Sync-Repo.png) +![image](Images/Sync-Repo.png) ## Syncing latest Version from GitHub repo diff --git a/Docs/epac-implementing.md b/Docs/epac-implementing.md new file mode 100644 index 00000000..b063a724 --- /dev/null +++ b/Docs/epac-implementing.md @@ -0,0 +1,179 @@ +# Implementing Enterprise Policy as Code + +> [!CAUTION] +> EPAC is a true desired state deployment technology. It takes possession of all Policy Resources at the `deploymentRootScope` and its children. It will **delete any Policy resources not defined in the EPAC repo**. This behavior can be modified as documented in the [desired state strategy](desired-state-strategy.md) page. + +## Getting Started + +The following steps are required to implement Enterprise Policy as Code (EPAC) in your environment: + +1. Understand [concepts and environments](#epac-concepts-and-environments). +2. Determine [desired state strategy](settings-desired-state.md). +3. How to handle [Defender for Cloud Policy Assignments](settings-dfc-assignments.md). +7. Design your [CI/CD process](ci-cd-overview.md). +4. Install [Powershell and EPAC](#install-powershell-and-epac). +5. Create your [`Definitions` folder and subfolders](#create-the-definitions-folder). +6. Populate `global-settings.jsonc` with your [environment settings](settings-global-setting-file.md) and [desired state strategy](settings-dfc-assignments.md). +7. Populate your Definitions folder with Policy resources. + - [Option A:] [Extract existing Policy resources](epac-extracting-policy-resources.md) from your Azure environment. + - [Option B:] [Integrate Azure Landing Zones (ALZ)](integrating-with-alz.md). + - [Option C:] Utilize the [hydration kit](operational-scripts-hydration-kit.md) and `StarterKit` content. + - [Optional] Create custom [Policy definitions](policy-definitions.md). + - [Optional] Create custom [Policy Set definitions](policy-set-definitions.md). + - Create your [Policy Assignments](policy-assignments.md). + - [Optional] Manage [Policy Exemptions](policy-exemptions.md). +8. Implement your [CI/CD pipelines](ci-cd-overview.md). +8. Operate your environment with the provided [operational scripts](operational-scripts.md). + +## EPAC Concepts and Environments + +> [!IMPORTANT] +> Understanding the concepts and environments is crucial. Do **not** proceed until you completely understand this section. + +### EPAC Concepts + +Like any other code development project (including Infrastructure as Code - IaC), developing Policy requires a development area to test and validate the Policy resources before deploying them to production. EPAC is no different. + +- EPAC's nonprod environment is used to develop and test Policy resources. In most cases you will need one management group hierarchy to simulate EPAC production tenants and management groups for development and testing of Policy definitions and Policy Assignments. +- EPAC's prod environment will govern all other IaC environments (e.g., sandbox, development, integration, test/qa, pre-prod, prod, ...) and tenants. This can be confusing. We will use **EPAC environments** and **IaC environments** to disambiguate the environments. + +### Defining EPAC Environments + +EPAC defines environments identified by a string (unique per repository) called `pacSelector`. `pacEnvironments` in `global-settings.jsonc` environment map a `pacSelector` to the following settings: + +- `cloud` - to select commercial or sovereign cloud environments. +- `tenantId` - enables multi-tenant scenarios. +- `rootDefinitionScope` - scope for custom Policy and Policy Set definition deployment. +- [Optional] Define the following items: + - `globalNotScopes` - used to exclude scopes from Policy Assignments. + - `managedIdentityLocations` - used for the location for created Managed Identities. + - `desiredState` - desired state strategy and details for Policy resources. + - `managedTenant` - used for environments that are in a lighthouse managed tenant. + +These associations are stored in [global-settings.jsonc](settings-global-setting-file.md) in an element called `pacEnvironments`. + +### Multi-Tenant Support + +EPAC supports single and multi-tenant deployments from a single source. In most cases you should have a fully or partially isolated area for Policy development and testing, such as a Management Group. An entire tenant can be used; however, it is not necessary since EPAC has sophisticated partitioning capabilities. EPAC also supports deployments to managed (Lighthouse) tenants and is able to deploy cross tenant role assignments to projected subscriptions in order to facilitate writing data back to the managing tenant (e.g. diagnostic settings). + +> [!IMPORTANT] +> In some multi-tenant implementations, not all policies, policy sets, and/or assignments will function in all tenants, usually due to either built-in policies that don't exist in some tenant types or unavailable resource providers. In order to facilitate multi-tenant deployments in these scenarios, utilize the `epacCloudEnvironments` property to specify which cloud type a specific file should be considered in. For example in order to have a policy definition deployed only to epacEnvironments that are China cloud tenants, add a metadata property like this to that definition (or definitionSet) file: + +```json +"metadata": { + "epacCloudEnvironments": [ + "AzureChinaCloud" + ] +}, +``` + +For assignment files, this is a top level property on the assignment's root node: + +```json +"nodeName": "/root", +"epacCloudEnvironments": [ + "AzureChinaCloud" +], +``` + +### Example Management Group Structure and EPAC Environments + +Assuming that you have a single tenant with a management group hierarchy as follows (with additional levels of management groups not shown for brevity): + +- Root tenant (always present) + - mg-Enterprise (pseudo root) + - mg-Identity + - mg-NonProd + - mg-Dev + - mg-Sandbox + - ... + - mg-Prod + - mg-LandingZones + - mg-PCI + - mg-EpacDev (EPAC development) + +You should create a development testing structure for EPAC in `mg-EpacDev`. We have found little need for a separate management group for EPAC testing, but you can create one mirroring the structure of `mg-EpacDev`. + +- Root tenant (always present) + - mg-Enterprise (pseudo root) :arrow_right: **EPAC environment `"tenant"`** + - mg-Identity + - mg-NonProd + - mg-Sandbox + - mg-Prod + - mg-PCI + - mg-EpacDev (EPAC development) :arrow_right: **EPAC environment `"epac-dev"`** + - mg-EpacDev-Identity + - mg-EpacDev-NonProd + - mg-EpacDev-Dev + - mg-EpacDev-Sandbox + - mg-EpacDev-Prod + - mg-EpacDev-LandingZones + - mg-EpacDev-PCI + +The simplest `global-settings.jsonc` for the above structure is: + +```json +{ + "$schema": "https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/main/Schemas/global-settings-schema.json", + "pacOwnerId": "{{guid}}", + "pacEnvironments": [ + { + "pacSelector": "epac-dev", + "cloud": "AzureCloud", + "tenantId": "{{tenant-id}}", + "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/mg-Epac-Dev" + }, + { + "pacSelector": "tenant", + "cloud": "AzureCloud", + "tenantId": "{{tenant-id}}", + "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/mg-Enterprise" + } + ] +} +``` + +## Install Powershell and EPAC + +EPAC can be installed in two ways: + +- Install the `EnterprisePolicyAsCode` module from the [PowerShell marketplace](https://www.powershellgallery.com/packages/EnterprisePolicyAsCode). This is the recommended approach documented here. +- Copy the source code from an [EPAC GitHub repository fork](https://github.com/Azure/enterprise-azure-policy-as-code). The process is described in [Forking the GitHub Repo - an Alternate Installation Method](fork-github.md) page. + +### Installation Steps + +1. [Install PowerShell 7.4 or later](https://github.com/PowerShell/PowerShell/releases). +2. Install the Az PowerShell modules and Enterprise Policy as Code module. +```ps1 + Install-Module Az -Scope CurrentUser + Install-Module EnterprisePolicyAsCode -Scope CurrentUser +``` + +Many scripts use parameters for input and output folders. They default to the current directory. We recommend that you do one of the following approaches instead of accepting the default to prevent your files being created in the wrong location: + - [Preferred] Set the environment variables `PAC_DEFINITIONS_FOLDER`, `PAC_OUTPUT_FOLDER`, and `PAC_INPUT_FOLDER`. + - [Alternative] Use the script parameters `-DefinitionsRootFolder`, `-OutputFolder`, and `-InputFolder`. + +### `Definitions` Folder Structure + +- Define the Azure environment(s) in file `global-settings.jsonc` +- Create custom Policies (optional) in folder `policyDefinitions` +- Create custom Policy Sets (optional) in folder `policySetDefinitions` +- efine the Policy Assignments in folder `policyAssignments` +- Define the Policy Exemptions (optional) in folder `policyExemptions` +- Define Documentation in folder `policyDocumentations]` + +### Create the Definitions folder + +Create a new EPAC `Definitions` folder with a number of subfolder and a `global-settings.jsonc` file + +```ps1 +New-EPACDefinitionFolder -DefinitionsRootFolder Definitions +``` + +## Debug EPAC issues + +Should you encounter issues with the expected behavior of EPAC, try the following: + +* Run the scripts interactively. +* [Debug the scripts in VS Code](https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/vscode/using-vscode?view=powershell-7.3). +* Ask for help by raising a [GitHub Issue](https://github.com/Azure/enterprise-azure-policy-as-code/issues/new) diff --git a/Docs/epac-overview.md b/Docs/epac-overview.md new file mode 100644 index 00000000..b5588499 --- /dev/null +++ b/Docs/epac-overview.md @@ -0,0 +1,118 @@ +# Enterprise Azure Policy as Code Overview + +Enterprise Azure Policy as Code (EPAC for short) is a number of PowerShell scripts which can be used in CI/CD based system or a semi-automated use to deploy Policies, Policy Sets, Policy Assignments, Policy Exemptions and Role Assignments. It also contains operational scripts to simplify operational tasks. + +> [!CAUTION] +> v10.0.0 has breaking changes. Please review the [Changes](changes.md) document. + +> [!IMPORTANT] +> Starting with v8.0.0, Enterprise Policy as Code (EPAC) is tracking the usage using [Customer Usage Attribution](https://learn.microsoft.com/en-us/partner-center/marketplace/azure-partner-customer-usage-attribution). In accordance with Microsoft's privacy policies, you have the right to **opt-out** of this tracking. Please review [Telemetry below](#telemetry-tracking-using-customer-usage-attribution-pid) and [Microsoft Privacy](https://privacy.microsoft.com/en-US/) for more information. + +## Benefits of EPAC + +- Single and multi-tenant policy deployment +- Easy CI/CD Integration with any CI/CD tool +- Extract existing Policy resources from an environment +- PowerShell Module or consume source code from GitHub +- Deployment scripts to deploy Policy resources and Role Assignments +- Deployments are sequenced based on the dependencies between the different Policy resources +- Operational scripts to simplify operational tasks +- Integration with Azure Landing Zone recommended policies +- Starter Kit with examples + +> [!CAUTION] +> EPAC is a true desired state deployment technology. It takes possession of all Policy Resources at the `deploymentRootScope` and its children. It will **delete any Policy resources not defined in the EPAC repo**. This behavior can be modified as documented in the [desired state strategy](settings-desired-state.md) page. + +## Who Should use EPAC? + +EPAC is designed for medium and large organizations with a larger number of Policies, Policy Sets and Assignments and/or complex deployment scenarios, such as, multiple tenants, multiple teams managing Policies. + +> [!TIP] +> EPAC provides a mature [integration with Azure Landing Zones](integrating-with-alz.md). Utilizing [Azure Landing Zones](https://aka.ms/alz/aac) together with EPAC is highly recommended. + +### Smaller Organizations + +- While designed for medium and large Enterprises, EPAC can and should be used by small organizations implementing fully-automated DevOps deployments of every Azure resource (known as Infrastructure as Code). Your DevOps maturity level will be well suited for EPAC. +- If your DevOps (CI/CD) maturity is lower, [Azure Landing Zones direct implementation of Policies](https://aka.ms/alz/aac) might be a better choice. +- For extremely small Azure customers with one or two subscriptions Microsoft Defender for Cloud automated Policy Assignments for built-in Policies is sufficient. + +## Project Links + +- [GitHub Repo](https://github.com/Azure/enterprise-azure-policy-as-code) +- [GitHub Issues](https://github.com/Azure/enterprise-azure-policy-as-code/issues) +- [Starter Kit](https://github.com/Azure/enterprise-azure-policy-as-code/tree/main/StarterKit) +- [Enterprise Policy as Code PowerShell Module](https://www.powershellgallery.com/packages/EnterprisePolicyAsCode) +- [Azure Enterprise Policy as Code – A New Approach](https://techcommunity.microsoft.com/t5/core-infrastructure-and-security/azure-enterprise-policy-as-code-a-new-approach/ba-p/3607843) +- [Azure Enterprise Policy as Code – Azure Landing Zones Integration](https://techcommunity.microsoft.com/t5/core-infrastructure-and-security/azure-enterprise-policy-as-code-azure-landing-zones-integration/ba-p/3642784) + +## Deployment Scripts + +Three deployment scripts plan a deployment, deploy Policy resources, and Role Assignments respectively as shown in the following diagram. The solution consumes definition files (JSON and/or CSV files). The planning script (`Build-DeploymentPlan`) creates plan files (`policy-plan.json` and `roles-plan.json`) to be consumed by the two deployment scripts (`Deploy-PolicyPlan` and `Deploy-RolesPlan`). The scripts require `Reader`, `Contributor` and `User Access Administrator` privileges respectively as indicated in blue text in the diagram. The diagram also shows the usual approval gates after each step/script for prod deployments. + +![image.png](Images/epac-deployment-scripts.png) + +
+ +## Operational Scripts + +The solution contains [operational scripts](operational-scripts.md) to manage Policy operations. + +## Enterprise Policy as Code, AzAdvertizer and AzGovViz + +Enterprise Policy-as-Code (EPAC), AzAdvertizer and Azure Governance Visualizer (AzGovViz) are three distinct open source projects or tools internally developed and maintained by Microsoft employees, each helping address different needs in enterprise scale management and governance of Azure environments. + +- [AzAdvertizer](https://www.azadvertizer.net/) - AzAdvertizer is a publicly accessible web service that provides continually up-to-date insights on new releases and changes/updates for different Azure Governance capabilities such as Azure Policy's built-in policy and initiative (policy set) definitions, Azure aliases, Azure security & regulatory compliance controls, Azure RBAC built-in role definitions and Azure resource provider operations. + +- [Azure Governance Visualizer (AzGovViz)](https://github.com/JulianHayward/Azure-MG-Sub-Governance-Reporting) - AzGovViz is an open source community project that provides visualization and reporting solution for any customer Azure environments, delivering a rich set of detailed insights covering tenant management group hierarchies, RBAC assignments, Azure policy assignments, Blueprints, Azure network topology and much more. AzGovViz is listed as recommended tool in use for both Microsoft Cloud Adoption Framework (CAF) and Microsoft Well Architected Framework (WAF). + +- [Enterprise Policy-as-Code (EPAC)](https://github.com/Azure/enterprise-azure-policy-as-code) - EPAC is an open source community project that provides a CI/CD automation solution for the development, deployment, management and reporting of Azure policy at scale. EPAC can maintain a policy "desired state" to provide a high level of assurance in highly controlled and sensitive environments, and a means of managing policy exemptions. While it uses standard JSON file structure for its repositories, operation and maintenance of policy and policy sets can actually be done via CSV files, reducing the skill expertise needed to operate the solution once implemented. + +## Telemetry Tracking Using Customer Usage Attribution (PID) + +Microsoft can identify the deployments of the Azure Resource Manager with the deployed Azure resources. Microsoft can correlate these resources used to support the deployments. Microsoft collects this information to provide the best experiences with their products and to operate their business. The telemetry is collected through [customer usage attribution](https://learn.microsoft.com/azure/marketplace/azure-partner-customer-usage-attribution). The data is collected and governed by Microsoft's privacy policies; for details see [Privacy at Microsoft](https://privacy.microsoft.com/en-US/). + +### Opt out of telemetry data collection `telemetryOptOut` + +To opt-out of this tracking, we have included a settings in `global-settings.jsonc` called `telemetryOptOut`. If you would like to disable this tracking, then simply [set this value](settings-global-setting-file.md/#opt-out-of-telemetry-data-collection-telemetryoptout) to `true` (default is `false`). + +If you are happy with leaving telemetry tracking enabled, no changes are required. + +### Module PID Value Mapping + +The following is the unique IDs (also known as PIDs) used in each of the modules: + +| Function Name | PID | +|:------------|:----| +| `Deploy-PolicyPlan` | `3c88f740-55a8-4a96-9fba-30a81b52151a` | +| `Deploy-PolicyPlan` | `fe9ff1e8-5521-4b9d-ab1d-84e15447565e` | +| `Deploy-RolesPlan` | `cf031290-b7d4-48ef-9ff5-4dcd7bff8c6c` | +| `Build-PolicyDocumentation` | `2dc29bae-2448-4d7f-b911-418421e83900` | +| `Create-AzRemediationTasks` | `6f4dcbef-f6e2-4c29-ba2a-eef748d88157` | +| `Export-AzPolicyResources` | `dc5b73fd-e93c-40ca-8fef-976762d1d30` | +| `Export-NonComplianceReports` | `f464b017-898b-4156-9da5-af932831fa2f` | +| `Get-AzExemptions` | `3f02e7d5-1cf5-490a-a95c-3d49f0673093` | +| `New-AzPolicyReaderRole` | `f4b5b7ac-70b4-40fc-836f-585791aa83e7` | + +## Support + +Please raise issues via the [GitHub](https://github.com/Azure/enterprise-azure-policy-as-code/issues) repository. + +## Contributing + +This project welcomes contributions and suggestions. Contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit . + +When you submit a pull request, a CLA bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +## Trademarks + +This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow +[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). +Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to the third-party's policies. diff --git a/Docs/export-non-compliance.md b/Docs/export-non-compliance.md deleted file mode 100644 index f6996b4b..00000000 --- a/Docs/export-non-compliance.md +++ /dev/null @@ -1,72 +0,0 @@ -# Exporting Non-Compliance Reports - -The script `Export-NonComplianceReports` exports non-compliance reports for EPAC environments in the `global-settings.jsonc` file. It outputs the reports in the `$outputFolders/non-compliance-reports` folder: - -- `summary-by-policy.csv` contains the summary of the non-compliant resources by Policy definition. The columns contain the resource counts. -- `summary-by-resource.csv` contains the summary of the non-compliant resources. The columns contain the number of Policies causing the non-compliance. -- `details-by-policy.csv` contains the details of the non-compliant resources by Policy definition including the non-compliant resource ids. Assignments are combined by Policy definition. -- `details-by-resource.csv` contains the details of the non-compliant resources sorted by Resource id. Assignments are combined by Resource id. -- `full-details-by-assignment.csv` contains the details of the non-compliant resources sorted by Policy Assignment id. -- `full-details-by-resource.csv` contains the details of the non-compliant resources sorted by Resource id including the Policy Assignment details. - -## Script parameters - -| Parameter | Explanation | -| --- | --- | -| `PacEnvironmentSelector` | Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc`. | -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER` or `./Definitions`. | -| `OutputFolder` | Output Folder. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER` or `./Outputs`. | -| `WindowsNewLineCells` | Formats CSV multi-object cells to use new lines and saves it as UTF-8 with BOM - works only for Excel in Windows. Default uses commas to separate array elements within a cell | -| `Interactive` | Set to false if used non-interactive | -| `OnlyCheckManagedAssignments` | Include non-compliance data only for Policy assignments owned by this Policy as Code repo | -| `PolicyDefinitionFilter` | Filter by Policy definition names (array) or ids (array). | -| `PolicySetDefinitionFilter` | Filter by Policy Set definition names (array) or ids (array). Can only be used when PolicyAssignmentFilter is not used. | -| `PolicyAssignmentFilter` | Filter by Policy Assignment names (array) or ids (array). Can only be used when PolicySetDefinitionFilter is not used. | -| `PolicyEffectFilter` | Filter by Policy effect (array). | -| `RemediationOnly` | Filter by Policy Effect "deployifnotexists" and "modify" and compliance status "NonCompliant" - -## Examples - -```ps1 -Export-NonComplianceReports -PacEnvironmentSelector "dev" -``` - -```ps1 -Export-NonComplianceReports -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\MyPacRepo\Definitions" -OutputFolder "C:\MyPacRepo\Outputs" -``` - -```ps1 -Export-NonComplianceReports -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\MyPacRepo\Definitions" -OutputFolder "C:\MyPacRepo\Outputs" -WindowsNewLineCells -``` - -```ps1 -Export-NonComplianceReports -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\MyPacRepo\Definitions" -OutputFolder "C:\MyPacRepo\Outputs" -OnlyCheckManagedAssignments -``` - -```ps1 -Export-NonComplianceReports -PolicySetDefinitionFilter "org-sec-initiative", "/providers/Microsoft.Authorization/policySetDefinitions/11111111-1111-1111-1111-111111111111" -``` - -```ps1 -Export-NonComplianceReports -PolicyAssignmentFilter "/providers/microsoft.management/managementgroups/11111111-1111-1111-1111-111111111111/providers/microsoft.authorization/policyassignments/taginh-env", "prod-asb" -``` - -## Sample Output - -### `summary-by-policy.csv` - -| Category | Policy Name | Policy Id | Non Compliant | Unknown | Not Started | Exempt | Conflicting | Error | Assignment Ids | Group Names | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| General | Audit usage of custom RBAC roles | /providers/microsoft.authorization/policydefinitions/a451c1ef-c6ca-483d-87ed-f49761e3ffb5 | 9 | 0 | 0 | 0 | 0 | 0 | /providers/microsoft.management/managementgroups/pac-heinrich-dev-dev/providers/microsoft.authorization/policyassignments/dev-nist-800-53-r5,/providers/microsoft.management/managementgroups/pac-heinrich-dev-dev/providers/microsoft.authorization/policyassignments/dev-asb | azure_security_benchmark_v3.0_pa-7,nist_sp_800-53_r5_ac-6(7),nist_sp_800-53_r5_ac-2(7),nist_sp_800-53_r5_ac-6,nist_sp_800-53_r5_ac-2 | -| Regulatory Compliance | Control use of portable storage devices | /providers/microsoft.authorization/policydefinitions/0a8a1a7d-16d3-4d8e-9f2c-6b8d9e1c7c1d | 0 | 0 | 0 | 0 | 0 | 0 | /providers/microsoft.management/managementgroups/pac-heinrich-dev-dev/providers/microsoft.authorization/policyassignments/dev-nist-800-53-r5,/providers/microsoft.management/managementgroups/pac-heinrich-dev-dev/providers/microsoft.authorization/policyassignments/dev-asb | azure_security_benchmark_v3.0_pa-7,nist_sp_800-53_r5_ac-6(7),nist_sp_800-53_r5_ac-2(7),nist_sp_800-53_r5_ac-6,nist_sp_800-53_r5_ac-2 | -| Regulatory Compliance | Deploy Azure Policy to audit Windows VMs that do not use managed disks | /providers/microsoft.authorization/policydefinitions/0b2b84f2-eb8a-4f0a-8a1c-0c0d6e4cdeea | 0 | 0 | 0 | 0 | 0 | 0 | /providers/microsoft.management/managementgroups/pac-heinrich-dev-dev/providers/microsoft.authorization/policyassignments/dev-nist-800-53-r5,/providers/microsoft.management/managementgroups/pac-heinrich-dev-dev/providers/microsoft.authorization/policyassignments/dev-asb | azure_security_benchmark_v3.0_pa-7,nist_sp_800-53_r5_ac-6(7),nist_sp_800-53_r5_ac-2(7),nist_sp_800-53_r5_ac-6,nist_sp_800-53_r5_ac-2 | -| Regulatory Compliance | Deploy Azure Policy to audit Windows VMs that do not use managed disks | /providers/microsoft.authorization/policydefinitions/0b2b84f2-eb8a-4f0a-8a1c-0c0d6e4cdeea | 0 | 0 | 0 | 0 | 0 | 0 | /providers/microsoft.management/managementgroups/pac-heinrich-dev-dev/providers/microsoft.authorization/policyassignments/dev-nist-800-53-r5,/providers/microsoft.management/managementgroups/pac-heinrich-dev-dev/providers/microsoft.authorization/policyassignments/dev-asb | azure_security_benchmark_v3.0_pa-7,nist_sp_800-53_r5_ac-6(7),nist_sp_800-53_r5_ac-2(7),nist_sp_800-53_r5_ac-6,nist_sp_800-53_r5_ac-2 | - -### `summary-by-resource.csv` - -| Resource Id | Subscription Id | Subscription Name | Resource Group | Resource Type | Resource Name | Resource Qualifier | Non Compliant | Unknown | Not Started | Exempt | Conflicting | Error | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| /subscriptions/******************************** | ******************************** | PAC-DEV-001 | | subscriptions | | | 25 | 481 | 0 | 0 | 0 | 0 | -| /subscriptions/********************************/providers/microsoft.authorization/roledefinitions/0b00bc79-2207-410c-b9d5-d5d182ad514f | ******************************** | PAC-DEV-001 | | microsoft.authorization/roledefinitions | 0b00bc79-2207-410c-b9d5-d5d182ad514f | | 0 | 0 | 0 | 0 | 0 | 0 | -| /subscriptions/********************************/providers/microsoft.authorization/roledefinitions/0b00bc79-2207-410c-b9d5-d5d182ad514f | ******************************** | PAC-DEV-001 | | microsoft.authorization/roledefinitions | 0b00bc79-2207-410c-b9d5-d5d182ad514f | | 0 | 0 | 0 | 0 | 0 | 0 | -| /subscriptions/********************************/providers/microsoft.authorization/roledefinitions/0b00bc79-2207-410c-b9d5-d5d182ad514f | ******************************** | PAC-DEV-001 | | microsoft.authorization/roledefinitions | 0b00bc79-2207-410c-b9d5-d5d182ad514f | | 0 | 0 | 0 | 0 | 0 | 0 | diff --git a/Docs/export-policy-exemptions.md b/Docs/export-policy-exemptions.md deleted file mode 100644 index c68e3c73..00000000 --- a/Docs/export-policy-exemptions.md +++ /dev/null @@ -1,45 +0,0 @@ -# Exporting Policy Exemptions - -The script `Get-AzExemptions.ps1` retrieves Policy Exemptions from an EPAC environment and saves them to files in JSON and CSV format. These files can be used as starting points for creating new exemptions. - - -## Script Parameters - -| Parameter | Description | -| --- | --- | -| `PacEnvironmentSelector` | Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc`. | -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER or './Definitions'`. | -| `OutputFolder` | Output Folder. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER or './Outputs'`. | -| `Interactive` | Set to false if used non-interactive | -| `FileExtension` | File extension type for the output files. Valid values are json and jsonc. Defaults to json. | - -## Examples - -```ps1 -.\Get-AzExemptions.ps1 -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\Src\Definitions" -OutputFolder "C:\Src\Outputs" -Interactive $true -FileExtension "jsonc" -``` - -```ps1 -.\Get-AzExemptions.ps1 -Interactive $true -``` - -```ps1 -.\Get-AzExemptions.ps1 -Interactive $true -FileExtension "jsonc" -``` - -```ps1 -.\Get-AzExemptions.ps1 -Interactive $true -FileExtension "json" -``` - -```ps1 -.\Get-AzExemptions.ps1 -Interactive $true -FileExtension "csv" -``` - -```ps1 -.\Get-AzExemptions.ps1 -Interactive $true -FileExtension "csv" -OutputFolder "C:\Src\Outputs" -``` - -## Links - -- [Policy Exemptions](https://azure.github.io/enterprise-azure-policy-as-code/policy-exemptions/) - diff --git a/Docs/extract-existing-policy-resources.md b/Docs/extract-existing-policy-resources.md deleted file mode 100644 index 053ce560..00000000 --- a/Docs/extract-existing-policy-resources.md +++ /dev/null @@ -1,75 +0,0 @@ -# Extract existing Policy Resources from an Environment in EPAC Format - -Script `Export-AzPolicyResources.ps1` (Operations) extracts existing Policies, Policy Sets, and Policy Assignments and Exemptions outputing them in EPAC format into subfolders in folder `$outputFolders/Definitions`. The subfolders are `policyDefinitions`, `policySetDefinitions`, `policyAssignments` and `policyExemptions`. In a new EPAC instance these subfolders can be directly copied to the `Definitions` folder enabling an initial transition from a pre-EPAC to EPAC environment. - -The scripts creates a `Definitions` folder in the `outputFolder` and subfolders for `policyDefinitions`, `policySetDefinitions` and `policyAssignments`. To use the generated files copy them to your `Definitions` folder. - -* `policyDefinitions`, `policySetDefinitions` have a subfolder based on `metadata.category`. If the definition has no `category` `metadata` they are put in a subfolder labeled `Unknown Category`. Duplicates when including child scopes are sorted into the `Duplicates` folder. Creates one file per Policy and Policy Set. -* `policyAssignments` creates one file per unique assigned Policy or Policy Set spanning multiple Assignments. -* `policyExemptions` creates one subfolder per EPAC environment - -The script works for two principal use cases indicated by three modes: - -## Use case 1: Interactive or non-interactive single tenant - -`-Mode 'export'` is used to collect the Policy resources and generate the definitions file. This works for `-Interactive $true` (the default) to extract Policy resources in single tenant or multi-tenant scenario, prompting the user to logon to each new tenant in turn. - -It also works for a single tenant scenario for an automated collection, assuming that the Service Principal has read permissions for every EPAC Environment in `global-settings.jsonc`. - -```ps1 -Export-AzPolicyResources -``` - -The parameter `-InputPacSelector` can be used to only extract Policy resources for one of the EPAC environments. - -!!! warning - The script deletes the `$outputFolders/Definitions` folder before creating a new set of files. In interactive mode it will ask for confirmation before deleting the directory. - -## Use case 2: Non-interactive multi-tenant - -While this pattern can be used for interactive users too, it is most often used for multi-tenant non-interactive usage since an SPN is bound to a tenant and the script cannot prompt for new credentials. - -The solution is a multi-step process: - -Collect the raw information for very EPAC environment after logging into each EPAC environment (tenant): - -```ps1 -Connect-AzAccount -Environment $cloud -Tenant $tenantIdForDev -Export-AzPolicyResources -Interactive $false -Mode collectRawFile -InputPacSelector 'epac-dev' - -Connect-AzAccount -Environment $cloud -Tenant $tenantId1 -Export-AzPolicyResources -Interactive $false -Mode collectRawFile -InputPacSelector 'tenant1' - -Connect-AzAccount -Environment $cloud -Tenant $tenantId2 -Export-AzPolicyResources -Interactive $false -Mode collectRawFile -InputPacSelector 'tenant2' -``` - -Next, the collected raw files are used to generate the same output: - -```ps1 -Export-AzPolicyResources -Interactive $false -Mode exportFromRawFiles -``` - -!!! warning - This last script deletes the `$outputFolders/Definitions` folder before creating a new set of files. - -## Caveats - -The extractions are subject to the following assumptions and caveats: - -* Assumes Policies and Policy Sets with the same name define the same properties independent of scope and EPAC environment. -* Ignores Assignments auto-assigned by Defender for Cloud. This behavior can be overridden with the switch parameter `-IncludeAutoAssigned`. - -## Script parameters - -|Parameter | Explanation | -|----------|-------------| -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER` or `./Definitions`. It contains `global-settings.jsonc`. -| `OutputFolder` | Output Folder. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER` or `./Outputs`. -| `Interactive` | Script is being run interactively and can request az login. It will also prompt for each file to process or skip. Defaults to $true. | -| `IncludeChildScopes` | Switch parameter to include Policies and Policy Sets in child scopes; child scopes are normally ignored for definitions. This does not impact Policy Assignments. | -| `IncludeAutoAssigned` | Switch parameter to include Assignments auto-assigned by Defender for Cloud. | -| `ExemptionFiles` | Create Exemption files (none=suppress, csv=as a csv file, json=as a json or jsonc file). Defaults to 'csv'. | -| `FileExtension` | Controls the output files extension. Default is `jsonc` but `json` is also accepted | -| `Mode` | a) `export` exports EPAC environments, must be used with -Interactive in a multi-tenant scenario
b) `collectRawFile` exports the raw data only; used with `InputPacSelector` when running non-Interactive in a multi-tenant scenario to collect the raw data once per tenant
c) `exportFromRawFiles` reads the files generated with one or more runs of b) and outputs the files like the normal 'export' without re-reading the environment. | -| `InputPacSelector` | Limits the collection to one EPAC environment, useful for non-Interactive use in a multi-tenant scenario, especially with -Mode 'collectRawFile'. Default is `'*'` which will execute all EPAC environments. This can be used in other scenarios.| diff --git a/Docs/index.md b/Docs/index.md deleted file mode 100644 index bea5d06b..00000000 --- a/Docs/index.md +++ /dev/null @@ -1,188 +0,0 @@ -# Enterprise Azure Policy as Code (EPAC) -## Overview - -Enterprise Azure Policy as Code or EPAC for short comprises a number of scripts which can be used in CI/CD based system or a semi-automated use to deploy Policies, Policy Sets, Assignments, Policy Exemptions and Role Assignments. - -Main features include: - -- Multi-tenant/environment policy deployment -- Easy CI/CD Integration -- Extract existing policy objects from an environment -- Support JSON and CSV inputs for large complex policies -- PowerShell Module -- Integration with Azure Landing Zone recommended policies -- Starter Kit with examples -- Schema to provide Intellisense for VS Code development - -## Who Should use EPAC? - -EPAC is designed for organizations with a large number of Policies, Policy Sets and Assignments. It is also designed for organizations with multiple tenants and/or environments. You can also combine ALZ and EPAC through the provided ["Integration of EPAC with Azure Landing Zones"](integrating-with-alz.md). - -EPAC can be used by small organizations with a small number of Policies, Policy Sets and Assignments. Depending on their DevSecOps maturity, [Azure Landing Zones direct implementation of Policies](https://aka.ms/alz/aac) might be a better choice. - -For extremely small Azure customers with one or two subscriptions Microsoft Defender for Cloud automated Policy Assignments for built-in Policies is sufficient. - -## Tracking EPAC Usage - -Starting with v8.0.0, Enterprise Policy as Code (EPAC) is tracking the usage using [Customer Usage Attribution](https://learn.microsoft.com/en-us/partner-center/marketplace/azure-partner-customer-usage-attribution) EPAC is in the role of a partner as defined in the linked documentation. We use this data to justify the investment in EPAC and to prioritize features. - -You have the right and means to **opt-out**; see [Usage Tracking](usage-tracking.md). - -## Project Links - -- [GitHub Repo](https://github.com/Azure/enterprise-azure-policy-as-code) -- [GitHub Issues](https://github.com/Azure/enterprise-azure-policy-as-code/issues) -- [Starter Kit](https://github.com/Azure/enterprise-azure-policy-as-code/tree/main/StarterKit) -- [Enterprise Policy as Code PowerShell Module](https://www.powershellgallery.com/packages/EnterprisePolicyAsCode) -- [Azure Enterprise Policy as Code – A New Approach](https://techcommunity.microsoft.com/t5/core-infrastructure-and-security/azure-enterprise-policy-as-code-a-new-approach/ba-p/3607843) -- [Azure Enterprise Policy as Code – Azure Landing Zones Integration](https://techcommunity.microsoft.com/t5/core-infrastructure-and-security/azure-enterprise-policy-as-code-azure-landing-zones-integration/ba-p/3642784) - -## EPAC and Defender for Cloud Assignments - -Defender for Cloud uses Azure Policy Assignments to enable and configure the various capabilities. Prior to v9.0.0 EPAC removed these subscription-level assignments. - -* Policy Assignments required for Defender plans (e.g., SQL, App Service, ...). These is no longer managed (removed) by EPAC v9.0.0 and later. -* Policy Assignments required for Security policies (e.g., Microsoft Cloud Security Benchmark, NIST 800-53 Rev 5, NIST 800-171, ...). The default `desiredState` behavior is to manage (remove) these assignments. Setting `keepDfcSecurityAssignments` to `true` disables the management (removal) by EPAC. - -Carefully review [Managing Defender for Cloud Assignments](dfc-assignments.md) . - -## Terminology - -| Full name | Simplified use in this documentation | -| :------------------------------------------------------------------------ | :----------------------------------- | -| Policy definition(s) | Policy, Policies | -| Initiative definition(s) or Policy Set definition(s) | Policy Set(s) | -| Policy Assignment(s) of a Policy or Policy Set | Assignment(s) | -| Policy Assignment(s) of a Policy Set | Policy Set Assignment | -| Policy Exemption(s) | Exemption(s) | -| Role Assignment(s)s for Managed Identities required by Policy Assignments | Role Assignment(s) | -| Policies, Policy Sets, Assignments **and** Exemptions | Policy resources | - -## Deployment Scripts - -Three deployment scripts plan a deployment, deploy Policy resources, and Role Assignments respectively as shown in the following diagram. The solution consumes definition files (JSON and/or CSV files). The planning script (`Build-DeploymentPlan`) creates plan files (`policy-plan.json` and `roles-plan.json`) to be consumed by the two deployment steps (`Deploy-PolicyPlan` and `Deploy-RolesPlan`). The scripts require `Reader`, `Contributor` and `User Access Administrator` privileges respectively as indicated in blue text in the diagram. The diagram also shows the usual approval gates after each step/script for prod deployments. - -![image.png](Images/epac-deployment-scripts.png) - -
- -## CI/CD Tool Compatibility - -Since EPAC is based on PowerShell scripts, any CI/CD tool with the ability to execute scripts can be used. The starter kits currently include pipeline definitions for Azure DevOps and GitHub Actions. Additional starter kits are being implemented and will be added in future releases. - -## Multi-Tenant Support - -EPAC supports single and multi-tenant deployments from a single source. In most cases you should have a fully or partially isolated area for Policy development and testing, such as a Management Group. An entire tenant can be used; however, it is not necessary since EPAC has sophisticated partitioning capabilities. - -In some multi-tenant implementations, not all policies, policy sets, and/or assignments will function in all tenants, usually due to either built-in policies that don't exist in some tenant types or unavailable resource providers. In order to facilitate multi-tenant deployments in these scenarios, utilize the " epacCloudEnvironments" property to specify which cloud type a specific file should be considered in. For example in order to have a policy definition deployed only to epacEnvironments that are China cloud tenants, add a metadata property like this to that definition (or definitionSet) file: - -```json -"metadata": { - "epacCloudEnvironments": [ - "AzureChinaCloud" - ] -}, -``` - -For assignment files, this is a top level property on the assignment's root node: - -```json -"nodeName": "/root", -"epacCloudEnvironments": [ - "AzureChinaCloud" -], -``` - -## Operational Scripts - -Scripts to simplify [operational task](operational-scripts.md) are provided. Examples are: - -- `Build-PolicyDocumentation` generates [documentation in markdown and csv formats for Policy Sets and Assignments.](documenting-assignments-and-policy-sets.md) -- `Create-AzRemediationTasks` to bulk remediate non-compliant resources for Policies with `DeployIfNotExists` or `Modify` effects. - -## Understanding EPAC Environments and the pacSelector - -!!! note -Understanding of this concept is crucial. Do **not** proceed until you completely understand the implications. - -EPAC has a concept of an environment identified by a string (unique per repository) called `pacSelector`. An environment associates the following with the `pacSelector`: - -- `cloud` - to select commercial or sovereign cloud environments. -- `tenantId` - enables multi-tenant scenarios. -- `rootDefinitionScope` - scope for custom Policy and Policy Set definition deployment. -- Optional: define `desiredState` - -!!! note -Policy Assignments can only defined at `rootDefinitionScope` and child scopes (recursive). - -These associations are stored in [global-settings.jsonc](definitions-and-global-settings.md) in an element called `pacEnvironments`. - -Like any other software or IaC solution, EPAC needs areas for developing and testing new Policies, Policy Sets and Assignments before any deployment to EPAC prod environments. In most cases you will need one management group hierarchy to simulate EPAC production management groups for development and testing of Policies. EPAC's prod environment will govern all other IaC environments (e.g., sandbox, development, integration, test/qa, pre-prod, prod, ...) and tenants. This can be confusing. We will use EPAC environment(s) and IaC environment(s) to disambiguate the environments. - -In a centralized single tenant scenario, you will define two EPAC environments: epac-dev and tenant. In a multi-tenant scenario, you will add an additional EPAC environment per additional tenant. - -The `pacSelector` is just a name. We highly recommend to call the Policy development environment `epac-dev`, you can name the EPAC prod environments in a way which makes sense to you in your environment. We use `tenant`, `tenant1`, etc in our samples and documentation. These names are used and therefore must match: - -- Defining the association (`pacEnvironments`) of an EPAC environment, `managedIdentityLocation` and `globalNotScopes` in `global-settings.jsonc` -- Script parameter when executing different deployment stages in a CI/CD pipeline or semi-automated deployment targeting a specific EPAC environments. -- `scopes`, `notScopes`, `additionalRoleAssignments`, `managedIdentityLocations`, and `userAssignedIdentity` definitions in Policy Assignment JSON files. - -## Coexistence and Desired State Strategy - -EPAC is a desired state system. It will remove Policy resources in an environment which are not defined in the definition files. To facilitate transition from previous Policy implementations and coexistence of multiple EPAC and third party Policy as Code systems, a granular way to control such coexistence is implemented. Specifically, EPAC supports: - -- **Centralized**: One centralized team manages all Policy resources in the Azure organization, at all levels (Management Group, Subscription, Resource Group). This is the default setup. -- **Distributed**: Multiple teams manage Policy resources in a distributed manner. Distributed is also useful during a brownfield deployment scenario to allow for an orderly transition from pre-EPAC to EPAC. - -Desired state strategy documentation can be found [here.](desired-state-strategy.md). The short version: - -- `full` deletes any Policies, Policy Sets, Assignments, and Exemptions not deployed by this EPAC solution or another EPAC solution.\* -- `ownedOnly` deletes only Policies with this repos’s pacOwnerId. This allows for a gradual transition from your existing Policy management to Enterprise Policy as Code.\* -- Policy resources with another `pacOwnerId` `metadata` field are never deleted. - -!!! warning -If you have a existing Policies, Policy Sets, Assignments, and Exemptions in your environment, you have not transferred to EPAC, do not forget to _include_ the new `desiredState` element with a `strategy` of `ownedOnly`. This is the equivalent of the deprecated "brownfield" variable in the pipeline. The default `strategy` is `full`. - -## Understanding differences between usage of EPAC, AzAdvertizer and AzGovViz - -Enterprise Policy-as-Code (EPAC), AzAdvertizer and Azure Governance Visualizer (AzGovViz) are three distinct open source projects or tools internally developed and maintained by Microsoft employees, each helping address different needs in enterprise scale management and governance of Azure environments. - -- [AzAdvertizer](https://www.azadvertizer.net/) - AzAdvertizer is a publicly accessible web service that provides continually up-to-date insights on new releases and changes/updates for different Azure Governance capabilities such as Azure Policy's built-in policy and initiative (policy set) definitions, Azure aliases, Azure security & regulatory compliance controls, Azure RBAC built-in role definitions and Azure resource provider operations. - -- [Azure Governance Visualizer (aka AzGovViz)](https://github.com/JulianHayward/Azure-MG-Sub-Governance-Reporting) - AzGovViz is an open source community project that provides visualization and reporting solution for any customer Azure environment or estate, delivering a rich set of detailed insights covering tenant management group hierarchies, RBAC assignments, Azure policy assignments, Blueprints, Azure network topology and much more. AzGovViz is listed as recommended tool in use for both Microsoft Cloud Adoption Framework (CAF) and Microsoft Well Architected Framework (WAF). - -- [Enterprise Policy-as-Code (aka EPAC)](https://github.com/Azure/enterprise-azure-policy-as-code) - EPAC is an open source community project that provides a CI/CD automation solution for the development, deployment, management and reporting of Azure policy at scale. EPAC can maintain a policy "desired state" to provide a high level of assurance in highly controlled and sensitive environments, and a means of managing policy exemptions. While it uses standard JSON file structure for its repositories, operation and maintenance of policy and policy sets can actually be done via CSV files, reducing the skill expertise needed to operate the solution once implemented. - - - -The table below provides a summary functions/features comparison between the three solutions/tools. - -| Function/Feature | AzAdvertizer | AzGovViz | EPAC | -| ---------------- | -------------|--------- | ---- | -| Purpose | Detailed insight tool on released Azure public cloud governance features like current built-in polices and initiatives | Azure environment governance reporting and monitoring solution exposing tenant config/deployment detail of tenant hierarchies, RBAC assignments, policies, blueprints | Azure environment automated policy governance deployment, management and reporting solution | -| Implementation | hosted web service | customer deployment, interactive Azure governance management and security reporting tool | customer deployment, deployment automation and reporting tool | -| Requirements | browser | PowerShell 7.0.3 | PowerShell 7.3.1 | - -## Support - -Please raise issues via the [GitHub](https://github.com/Azure/enterprise-azure-policy-as-code/issues) repository. - -## Contributing - -This project welcomes contributions and suggestions. Most contributions require you to agree to a -Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us -the rights to use your contribution. For details, visit . - -When you submit a pull request, a CLA bot will automatically determine whether you need to provide -a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions -provided by the bot. You will only need to do this once across all repos using our CLA. - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or -contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. - -## Trademarks - -This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow -[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). -Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies. diff --git a/Docs/integrating-with-alz.md b/Docs/integrating-with-alz.md index 1d096bf4..eaf0f759 100644 --- a/Docs/integrating-with-alz.md +++ b/Docs/integrating-with-alz.md @@ -182,8 +182,8 @@ To deploy the ALZ policies using EPAC follow the steps below. 7. Follow the normal steps to deploy the solution to the environment. -!!! tip - Searching for comments in the assignment JSON files will show which values need to be updated. +> [!TIP] +> Searching for comments in the assignment JSON files will show which values need to be updated. ## Keeping up to date with changes manually @@ -197,14 +197,14 @@ Sync-ALZPolicies -DefinitionsRootFolder .\Definitions -CloudEnvironment AzureClo Carefully review the proposed changes before deploying them. It is best to make sure you're project is stored in source control so you can easily see which files have changed before deployment. -!!! warning - If you have follow Scenario 1 above, the first time you run the `Sync-ALZPolicies` there will be many changes recorded due to formatting. Review the files completely before deploying. +> [!WARNING] +> If you have follow Scenario 1 above, the first time you run the `Sync-ALZPolicies` there will be many changes recorded due to formatting. Review the files completely before deploying. -!!! note - Assignments deployed via the ALZ accelerators are kept in sync with the EnterprisePolicyAsCode module so ensure you have the latest PowerShell module installed before running `Sync-ALZPolicies` +> [!WARNING] +> Assignments deployed via the ALZ accelerators are kept in sync with the EnterprisePolicyAsCode module so ensure you have the latest PowerShell module installed before running `Sync-ALZPolicies` -!!! tip - Rename or copy the default ALZ assignment files - when you do a sync it makes it easier to compare changes. +> [!TIP] +> Rename or copy the default ALZ assignment files - when you do a sync it makes it easier to compare changes. ## Keeping up to date with GitHub Actions diff --git a/Docs/operating-environment.md b/Docs/operating-environment.md deleted file mode 100644 index 109e4e2e..00000000 --- a/Docs/operating-environment.md +++ /dev/null @@ -1,42 +0,0 @@ -# Operating Environment - -## EPAC Software Requirements - -Your operating environment will include two repos, a runner, and at least one developer machine. The following software is required on the runners and any developer workstation. - -* PowerShell 7.3.1 or later, 7.3.4 (latest) recommended -* PowerShell Modules - * Az required 9.3.0 or later - **9.2.x has a bug which causes EPAC to fail** - * ImportExcel (required only if using Excel functionality) -* Git latest version - -### Pipeline Runner or Agent - -OS: Any that Support PowerShell versions above. - -* Linux and Windows are fully supported by EPAC -* Mac OS might work; however, we have not tested this scenario. - -Software: Must Meet [EPAC Software Requirements](#epac-software-requirements). - -### Developer Workstation - -* Software: Must meet [EPAC Software Requirements](#epac-software-requirements). -* Software Recommendations: Visual Studio Code 1.74.3 or later (may work with older versions) - -## Required Management Groups and Subscriptions - -This solution requires EPAC environments for development, (optional) integration, and production per Azure tenant. These EPAC environments are not the same as the standard Azure environments for applications or solutions - do not confuse them; EPAC non-prod environment are only for development and integration of Azure Policy. The standard Azure Sandbox, DEV, DEVINT, TEST/QA and PROD app solution environments are managed with Policy deployed from the EPAC PROD environment. - -* Build a management group dedicated to Policy as Code (PaC) -- `mg-epac-dev`
-* Create management groups or subscriptions to simulate your EPAC production environments. - -## Security Considerations for DevOps CI/CD Runners/Agents - -Agents (also called runners) are often hosted in VMs within Azure itself. It is therefore essential to manage them as highly privileged devices. - -* Utilize hardened images. -* Be managed as high-privilege assets to minimize the risk of compromise. -* Only used for a single purpose. -* Hosted in PROD tenant in multi-tenant scenarios. -* Hosted in the hub VNET or a shared services VNET. diff --git a/Docs/documenting-assignments-and-policy-sets.md b/Docs/operational-scripts-documenting-policy.md similarity index 97% rename from Docs/documenting-assignments-and-policy-sets.md rename to Docs/operational-scripts-documenting-policy.md index 1908611f..9c5adda4 100644 --- a/Docs/documenting-assignments-and-policy-sets.md +++ b/Docs/operational-scripts-documenting-policy.md @@ -2,7 +2,7 @@ ## Overview -The Documentation feature provides reports on Policy Assignments deployed within an environment, and comparisons of Policy Assignments and Sets of Policy Set definitions for considering differences in policies and effects. Output is generated as Markdown (`.md`), and Excel (`.csv`) files. with script [`./Scripts/Operations/Build-PolicyDocumentation.ps1`](operational-scripts.md#Build-PolicyDocumentation.ps1) It retrieves its instruction from the JSON files in this folder; the names of the definition JSON files don't matter as the script reads any file in the folder with a `.json` and `.jsonc` extension. +The Documentation feature provides reports on Policy Assignments deployed within an environment, and comparisons of Policy Assignments and Sets of Policy Set definitions for considering differences in policies and effects. Output is generated as Markdown (`.md`), and Excel (`.csv`) files. with script [`./Scripts/Operations/Build-PolicyDocumentation`](operational-scripts.md#Build-PolicyDocumentation) It retrieves its instruction from the JSON files in this folder; the names of the definition JSON files don't matter as the script reads any file in the folder with a `.json` and `.jsonc` extension. * Read and process Policy Assignments which are representative of an environment category, such as prod, test, dev, and sandbox. It generates Markdown (`.md`), and Excel (`.csv`) files. * Read and process Policy Sets to compare them for Policy and effect overlap. It generates Markdown (`.md`), Excel (`.csv`) files, and JSON file (`.jsonc`). diff --git a/Docs/operational-scripts-hydration-kit.md b/Docs/operational-scripts-hydration-kit.md new file mode 100644 index 00000000..b15872f2 --- /dev/null +++ b/Docs/operational-scripts-hydration-kit.md @@ -0,0 +1,29 @@ +# Hydration Kit + +## Create Policy Reader Role + +`New-AzPolicyReaderRole` creates a custom role EPAC Resource Policy Reader with Id `2baa1a7c-6807-46af-8b16-5e9d03fba029`. It provides read access to all Policy resources for the purpose of planning the EPAC deployments at the scope selected with PacEnvironmentSelector. The permissions granted are: + +- Microsoft.Authorization/policyassignments/read +- Microsoft.Authorization/policydefinitions/read +- Microsoft.Authorization/policyexemptions/read +- Microsoft.Authorization/policysetdefinitions/read +- Microsoft.Authorization/roleAssignments/read +- Microsoft.PolicyInsights/* +- Microsoft.Management/register/action +- Microsoft.Management/managementGroups/read + +## Create Azure DevOps Pipeline or GitHub Workflow + +`New-PipelinesFromStarterKit` creates a new Azure DevOps Pipeline or GitHub Workflow from the starter kit. This script copies pipelines and templates from the starter kit to a new folder. The script assembles the pipelines/workflows based on the type of pipeline to create, the branching flow to implement, and the type of script to use. + +`-StarterKitFolder ` + +`-PipelinesFolder ` + +`-PipelineType ` - AzureDevOps or GitHubActions; default is AzureDevOps + +`-BranchingFlow ` - Release or GitHub (flow); default is Release + +`-ScriptType ` - scripts (in your repo) or module (from PowerShell gallery); default is module + diff --git a/Docs/operational-scripts-reference.md b/Docs/operational-scripts-reference.md new file mode 100644 index 00000000..ee344820 --- /dev/null +++ b/Docs/operational-scripts-reference.md @@ -0,0 +1,472 @@ +# Scripts References + +## Script `Build-PolicyDocumentation` + +Builds documentation from instructions in policyDocumentations folder reading the delployed Policy Resources from the EPAC envioronment. + +```ps1 +Build-PolicyDocumentation [[-DefinitionsRootFolder] ] [[-OutputFolder] ] [-WindowsNewLineCells] [[-Interactive] ] [-SuppressConfirmation] [-IncludeManualPolicies] [[-VirtualCores] ] [] +``` + +### Parameters + +#### `-DefinitionsRootFolder ` + +Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER or './Definitions'. + +#### `-OutputFolder ` + + +Output Folder. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER or './Outputs'. + +#### `-WindowsNewLineCells []` + +Formats CSV multi-object cells to use new lines and saves it as UTF-8 with BOM - works only fro Excel in Windows. Default uses commas to separate array elements within a cell + +#### `-Interactive ` + +Set to false if used non-interactive + +#### `-SuppressConfirmation []` + +Suppresses prompt for confirmation to delete existing file in interactive mode + +#### `-IncludeManualPolicies []` + +Include Policies with effect Manual. Default: do not include Polcies with effect Manual. + +#### `-VirtualCores ` + +Number of virtual cores to use for the operation. Default is 4. + +## Script `Create-AzRemediationTasks` + +The Create-AzRemediationTasks PowerShell creates remediation tasks for all non-compliant resources in the current AAD tenant. If one or multiple remediation tasks fail, their respective objects are added to a PowerShell variable that is outputted for later use in the Azure DevOps Pipeline. + +```ps1 +Create-AzRemediationTasks [[-PacEnvironmentSelector] ] [-DefinitionsRootFolder ] [-Interactive ] [-OnlyCheckManagedAssignments] [-PolicyDefinitionFilter ] [-PolicySetDefinitionFilter ] [-PolicyAssignmentFilter ] [-PolicyEffectFilter ] [-NoWait] [-WhatIf] [-Confirm] [] +``` + +### Parameters + +#### `-PacEnvironmentSelector ` + +Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc. + +#### ` -DefinitionsRootFolder ` + +Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER or './Definitions'. + +#### `-Interactive ` + +Set to false if used non-interactive + +#### `-OnlyCheckManagedAssignments []` + +Include non-compliance data only for Policy assignments owned by this Policy as Code repo + +#### `-PolicyDefinitionFilter ` + +Filter by Policy definition names (array) or ids (array). + +#### `-PolicySetDefinitionFilter ` + +Filter by Policy Set definition names (array) or ids (array). + +#### `-PolicyAssignmentFilter ` + +Filter by Policy Assignment names (array) or ids (array). + +#### `-PolicyEffectFilter ` + +Filter by Policy effect (array). + +#### `-NoWait []` + + +#### `-WhatIf []` + + +#### `-Confirm []` + +## Script `Create-AzureDevOpsBug` + +Creates a Bug on the current Iteration of a team when one or multiple Remediation Tasks failed. The Bug is formatted as an HTML table and contains information on the name and Url properties. As a result, the team can easily locate and resolve the Remediation Tasks that failed. + +```ps1 +Create-AzureDevOpsBug [-FailedPolicyRemediationTasksJsonString] [-ModuleName] [-OrganizationName] [-ProjectName] [-PersonalAccessToken] [-TeamName] [] +``` + +### Parameters + +#### `-FailedPolicyRemediationTasksJsonString ` + +Specifies the JSON string that contains the objects of one or multiple failed Remediation Tasks. + +#### `-ModuleName ` + +Specifies the name of the PowerShell module installed at the beginning of the PowerShell script. By default, this is the VSTeam PowerShell Module. + +#### `-OrganizationName ` + +Specifies the name of the Azure DevOps Organization. + +#### `-ProjectName ` + +Specifies the name of the Azure DevOps Project. + +#### `-PersonalAccessToken ` + +Specifies the Personal Access Token that is used for authentication purposes. Make sure that you use the AzureKeyVault@2 task (link below) for this purpose. + +#### `-TeamName ` + +Specifies the name of the Azure DevOps team. + +## Script `Create-GitHubIssue` + +Creates an Issue in a GitHub Repository that is located under a GitHub Organization when one or multiple Remediation Tasks failed. The Bug is formatted as an HTML table and contains information on the name and Url properties. As a result, the team can easily locate and resolve the Remediation Tasks that failed. + +```ps1 +Create-GitHubIssue [-FailedPolicyRemediationTasksJsonString] [-OrganizationName] [-RepositoryName] [-PersonalAccessToken] [] +``` + +### Parameters + +#### `-FailedPolicyRemediationTasksJsonString ` + +Specifies the JSON string that contains the objects of one or multiple failed Remediation Tasks. + +#### `-OrganizationName ` + +Specifies the name of the GitHub Organization. + +#### `-RepositoryName ` + +Specifies the name of the GitHub Repository. + +#### `-PersonalAccessToken ` + + +## Script `Export-AzPolicyResources` + +Exports Azure Policy resources in EPAC format or raw format. It also generates documentation for the exported resources (can be suppressed with `-SuppressDocumentation`). + +```ps1 +Export-AzPolicyResources [[-DefinitionsRootFolder] ] [[-OutputFolder] ] [[-Interactive] ] [-IncludeChildScopes] [-IncludeAutoAssigned] [[-ExemptionFiles] ] [[-FileExtension] ] [[-Mode] ] [[-InputPacSelector] ] [-SuppressDocumentation] [-SuppressEpacOutput] [-PSRuleIgnoreFullScope] [] +``` + +### Parameters + +#### ` -DefinitionsRootFolder ` + + Definitions folder path. Defaults to environment variable $env:PAC_DEFINITIONS_FOLDER or './Definitions'. + +#### `-OutputFolder ` + +Output Folder. Defaults to environment variable $env:PAC_OUTPUT_FOLDER or './Outputs'. + +#### `-Interactive ` + +Set to false if used non-interactive. Defaults to $true. + +#### `-IncludeChildScopes []` + +Switch parameter to include Policies and Policy Sets definitions in child scopes + +#### `-IncludeAutoAssigned []` + +Switch parameter to include Assignments auto-assigned by Defender for Cloud + +#### `-ExemptionFiles ` + +Create Exemption files (none=suppress, csv=as a csv file, json=as a json or jsonc file). Defaults to 'csv'. + +#### `-FileExtension ` + +File extension type for the output files. Defaults to '.jsonc'. + +#### `-Mode ` + +Operating mode: + +- `export` exports EPAC environments in EPAC format, should be used with -Interactive $true in a multi-tenant scenario, or use with an inputPacSelector to limit the scope to one EPAC environment. +- `collectRawFile` exports the raw data only; Often used with 'inputPacSelector' when running non-interactive in a multi-tenant scenario to collect the raw data once per tenant into a file named after the EPAC environment +- `exportFromRawFiles` reads the files generated with one or more runs of b) and outputs the files the same as normal 'export'. +- `exportRawToPipeline` exports EPAC environments in EPAC format, should be used with `-Interactive` $true in a multi-tenant scenario, or use with an inputPacSelector to limit the scope to one EPAC environment. +- `psrule` exports EPAC environment into a file which can be used to create policy rules for PSRule for Azure + +#### `-InputPacSelector ` + +Limits the collection to one EPAC environment, useful for non-interactive use in a multi-tenant scenario, especially with -Mode 'collectRawFile'. + The default is '*' which will execute all EPAC-Environments. + +#### `-SuppressDocumentation []` + +Suppress documentation generation. + +#### `-SuppressEpacOutput []` + +Suppress output generation in EPAC format. + +#### `-PSRuleIgnoreFullScope []` + +Ignore full scope for PsRule Extraction +## Script `Export-NonComplianceReports` + +Exports Non-Compliance Reports in CSV format + +```ps1 +Export-NonComplianceReports [[-PacEnvironmentSelector] ] [-DefinitionsRootFolder ] [-OutputFolder ] [-WindowsNewLineCells] [-Interactive ] [-OnlyCheckManagedAssignments] [-PolicyDefinitionFilter ] [-PolicySetDefinitionFilter ] [-PolicyAssignmentFilter ] [-PolicyEffectFilter ] [-ExcludeManualPolicyEffect] [-RemediationOnly] [] +``` + +### Parameters + +#### `-PacEnvironmentSelector ` + +Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc. + +#### ` -DefinitionsRootFolder ` + + Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER or './Definitions'. + +#### `-OutputFolder ` + +Output Folder. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER or './Outputs'. + +#### `-WindowsNewLineCells []` + +Formats CSV multi-object cells to use new lines and saves it as UTF-8 with BOM - works only fro Excel in Windows. Default uses commas to separate array elements within a cell + +#### `-Interactive ` + +Set to false if used non-interactive + +#### `-OnlyCheckManagedAssignments []` + +Include non-compliance data only for Policy assignments owned by this Policy as Code repo + +#### `-PolicyDefinitionFilter ` + +Filter by Policy definition names (array) or ids (array). + +#### `-PolicySetDefinitionFilter ` + +Filter by Policy Set definition names (array) or ids (array). + +#### `-PolicyAssignmentFilter ` + +Filter by Policy Assignment names (array) or ids (array). + +#### `-PolicyEffectFilter ` + +Filter by Policy Effect (array). + +#### `-ExcludeManualPolicyEffect []` + +Switch parameter to filter out Policy Effect Manual + +#### `-RemediationOnly []` + +Filter by Policy Effect "deployifnotexists" and "modify" and compliance status "NonCompliant" + +## Script `Get-AzExemptions` + +Retrieves Policy Exemptions from an EPAC environment and saves them to files. + +```ps1 +Get-AzExemptions [[-PacEnvironmentSelector] ] [-DefinitionsRootFolder ] [-OutputFolder ] [-Interactive ] [-FileExtension ] [-ActiveExemptionsOnly] [] +``` + +### Parameters + +#### `-PacEnvironmentSelector ` + +Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc. + +#### ` -DefinitionsRootFolder ` + +Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER or './Definitions'. + +#### `-OutputFolder ` + +Output Folder. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER or './Outputs'. + +#### `-Interactive ` + +Set to false if used non-interactive + +#### `-FileExtension ` + +File extension type for the output files. Valid values are json and jsonc. Defaults to json. + +#### `-ActiveExemptionsOnly []` + +Set to true to only generate files for active (not expired and not orphaned) exemptions. Defaults to false. + +## Script `Get-AzMissingTags` + +Gets all resources that are missing tags in the current subscription. + +```ps1 +Get-AzMissingTags [[-PacEnvironmentSelector] ] [-DefinitionsRootFolder ] [-OutputFileName ] [-Interactive ] [] +``` + +### Parameters + +#### `-PacEnvironmentSelector ` + +Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc. + +#### ` -DefinitionsRootFolder ` + +Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER or './Definitions'. + +#### `-OutputFileName ` + +Output file name. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER/Tags/missing-tags-results.csv or './Outputs/Tags/missing-tags-results.csv'. + +#### `-Interactive ` + +Set to false if used non-interactive + +## Script `Get-AzPolicyAliasOutputCSV` + +Gets all aliases and outputs them to a CSV file. + +```ps1 +Get-AzPolicyAliasOutputCSV [] +``` + +## Script `New-AzPolicyReaderRole` + +Creates a custom role 'Policy Reader' that provides read access to all Policy resources for the purpose of planning the EPAC deployments. + +```ps1 +New-AzPolicyReaderRole [[-PacEnvironmentSelector] ] [-DefinitionsRootFolder ] [-Interactive ] [] +``` + +### Parameters + +#### `-PacEnvironmentSelector ` + +Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc. + +#### ` -DefinitionsRootFolder ` + + Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER or './Definitions'. + +#### `-Interactive ` + +Set to false if used non-interactive + +## Script `New-EPACDefinitionFolder` + +Creates a definitions folder with the correct folder structure and blank global settings file. + +```ps1 +New-EPACDefinitionFolder [[-DefinitionsRootFolder] ] [] +``` + +### Description + +Creates a definitions folder with the correct folder structure and blank global settings file. + + +### Parameters + +#### ` -DefinitionsRootFolder ` + +The folder path to create the definitions root folder (./Definitions) + +## Script `New-EPACGlobalSettings` + +Creates a global-settings.jsonc file with a new guid, managed identity location and tenant information + +```ps1 +New-EPACGlobalSettings [-ManagedIdentityLocation] [-TenantId] [-DefinitionsRootFolder] [-DeploymentRootScope] [] +``` + +### Parameters + +#### `-ManagedIdentityLocation ` + +The Azure location to store the managed identities (Get-AzLocation|Select Location) + +#### `-TenantId ` + +The Azure tenant id + +#### ` -DefinitionsRootFolder ` + +The folder path to where the New-EPACDefinitionsFolder command created the definitions root folder (C:\definitions\) + +#### `-DeploymentRootScope ` + +The root management group to export definitions and assignments (/providers/Microsoft.Management/managementGroups/) + +## Script `New-EPACPolicyAssignmentDefinition` + +Exports a policy assignment from Azure to a local file in the EPAC format. + +```ps1 +New-EPACPolicyAssignmentDefinition [-PolicyAssignmentId] [[-OutputFolder] ] [] +``` + +### Parameters + +#### `-PolicyAssignmentId ` + +The policy assignment id + +#### `-OutputFolder ` + +The folder path for the Policy Assignment. + +## Script `New-EPACPolicyDefinition` + +Exports a Policy definition from Azure to a local file in the EPAC format + +```ps1 +New-EPACPolicyDefinition [-PolicyDefinitionId] [[-OutputFolder] ] [] +``` + +### Parameters + +#### `-PolicyDefinitionId ` + +The Policy definition id. + +#### `-OutputFolder ` + +The folder path for the Policy Definition. + +## Script `New-PipelineFromStarterKit` + +This script copies pipelines and templates from the starter kit to a new folder. The script assembles the pipelines/workflows based on the type of pipeline to create, the branching flow to implement, and the type of script to use. + +```ps1 +New-PipelineFromStarterKit [[-StarterKitFolder] ] [[-PipelinesFolder] ] [[-PipelineType] ] [[-BranchingFlow] ] [[-ScriptType] ] [] +``` + +### Parameters + +#### `-StarterKitFolder ` + +Starter kit folder + +#### `-PipelinesFolder ` + +New pipeline folder + +#### `-PipelineType ` + +Type of DevOps pipeline to create AzureDevOps or GitHubActions? + +#### `-BranchingFlow ` + +Implementing branching flow Release or GitHub + +#### `-ScriptType ` + +Using Powershell module or script? diff --git a/Docs/operational-scripts.md b/Docs/operational-scripts.md index 6f7b9bce..6d6d6fe1 100644 --- a/Docs/operational-scripts.md +++ b/Docs/operational-scripts.md @@ -1,330 +1,69 @@ # Operational Scripts -## Build-DefinitionsFolder.ps1 +The scripts are detailed in the [reference page](operational-scripts-reference.md) including syntax, descriptions and parameters. -This script has been replaced by `Export-AzPolicyResources.ps1`. See [Extract existing Policy Resources from an Environment](extract-existing-policy-resources.md). +## Batch Creation of Remediation Tasks -## Build-PolicyDocumentation.ps1 +The script `Create-AzRemediationTasks` creates remediation tasks for all non-compliant resources for EPAC environments in the `global-settings.jsonc` file. -Builds documentation from instructions in policyDocumentations folder reading the deployed Policy Resources from the EPAC environment. +This script executes all remediation tasks in a Policy as Code environment specified with parameter `PacEnvironmentSelector`. The script will interactively prompt for the value if the parameter is not supplied. The script will recurse the Management Group structure and subscriptions from the defined starting point. -| Parameter | Explanation | -| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `DefinitionsRootFolder` | Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc`. | -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER` or `./Definitions`. It contains `global-settings.jsonc`. | -| `OutputFileName` | Output file name. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER/Tags/missing-tags-results.csv` or `./Outputs/Tags/missing-tags-results.csv`. | -| `Interactive` | Script is being run interactively and can request az login. Defaults to $false if PacEnvironmentSelector parameter provided and $true otherwise. | +* Find all Policy assignments with potential remediation capable resources +* Query Policy Insights for non-complaint resources +* Start remediation task for each Policy with non-compliant resources +* Switch parameter `-OnlyCheckManagedAssignments` includes non-compliance data only for Policy assignments owned by this Policy as Code repo. -## Create-AzRemediationTasks.ps1 +#### Links -This PowerShell script creates remediation tasks for all non-compliant resources in the current Azure Active Directory (AAD) tenant. If one or multiple remediation tasks fail, their respective objects are added to a PowerShell variable that is outputted for later use in the Azure DevOps Pipeline. +- [Remediate non-compliant resources with Azure Policy](https://learn.microsoft.com/en-us/azure/governance/policy/how-to/remediate-resources?tabs=azure-portal) +- [Start-AzPolicyRemediation](https://learn.microsoft.com/en-us/powershell/module/az.policyinsights/start-azpolicyremediation?view=azps-10.1.0) -| Parameter | Explanation | -| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `PacEnvironmentSelector` | Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc`. | -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER` or `./Definitions`. | -| `Interactive` | Set to false if used non-interactive. | -| `OnlyCheckManagedAssignments` | Include non-compliance data only for Policy assignments owned by this Policy as Code repo. | -| `PolicyDefinitionFilter` | Filter by Policy definition names (array) or ids (array). | -| `PolicySetDefinitionFilter` | Filter by Policy Set definition names (array) or ids (array). | -| `PolicyAssignmentFilter` | Filter by Policy Assignment names (array) or ids (array). | -| `PolicyEffectFilter` | Filter by Policy effect (array). | +## Policy Resources Exports -### Examples +- `Export-AzPolicyResources` exports Azure Policy resources in EPAC. It also generates documentation for the exported resources (can be suppressed with `-SuppressDocumentation`). See usage documentation in [Extract existing Policy Resources](epac-extracting-policy-resources.md). +- `Get-AzExemptions` retrieves Policy Exemptions from an EPAC environment and saves them to files. +- `Get-AzPolicyAliasOutputCSV` exports Policy Aliases to CSV format. -1. `Create-AzRemediationTasks.ps1 -PacEnvironmentSelector "dev"` +## Hydration Kit -2. `Create-AzRemediationTasks.ps1 -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\git\policy-as-code\Definitions"` +The Hydration Kit is a set of scripts that can be used to deploy an EPAC environment from scratch. The scripts are documented in the [Hydration Kit](operational-scripts-hydration-kit.md) page. -3. `Create-AzRemediationTasks.ps1 -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\git\policy-as-code\Definitions" -Interactive $false` +## CI/CD Helpers -4. `Create-AzRemediationTasks.ps1 -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\git\policy-as-code\Definitions" -OnlyCheckManagedAssignments` +The scripts `Create-AzureDevOpsBug` and `Create-GitHubIssue` create a Bug or Issue when there are one or multiple failed Remediation Tasks. -5. `Create-AzRemediationTasks.ps1 -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\git\policy-as-code\Definitions" -PolicyDefinitionFilter "Require tag 'Owner' on resource groups" -PolicySetDefinitionFilter "Require tag 'Owner' on resource groups" -PolicyAssignmentFilter "Require tag 'Owner' on resource groups"` +## Documenting Policy -### Inputs +`Build-PolicyDocumentation` builds documentation from instructions in the `policyDocumentations` folder reading the deployed Policy Resources from the EPAC environment. It is also used to generate parameter/effect CSV files for Policy Assignment files. -None. +See usage documentation in [Documenting Policy](operational-scripts-documenting-policy.md). -### Outputs +## Non-compliance Reports -The Create-AzRemediationTasks.ps1 PowerShell script outputs multiple string values for logging purposes, a JSON string containing all the failed Remediation Tasks and a boolean value, both of which are used in a later stage of the Azure DevOps Pipeline. +`Export-NonComplianceReports` exports non-compliance reports for EPAC environments . It outputs the reports in the `$OutputFolders/non-compliance-reports` folder. -## Create-AzureDevOpsBug.ps1 +- `summary-by-policy.csv` contains the summary of the non-compliant resources by Policy definition. The columns contain the resource counts. +- `summary-by-resource.csv` contains the summary of the non-compliant resources. The columns contain the number of Policies causing the non-compliance. +- `details-by-policy.csv` contains the details of the non-compliant resources by Policy definition including the non-compliant resource ids. Assignments are combined by Policy definition. +- `details-by-resource.csv` contains the details of the non-compliant resources sorted by Resource id. Assignments are combined by Resource id. +- `full-details-by-assignment.csv` contains the details of the non-compliant resources sorted by Policy Assignment id. +- `full-details-by-resource.csv` contains the details of the non-compliant resources sorted by Resource id including the Policy Assignment details. -This PowerShell script creates a Bug when there are one or multiple failed Remediation Tasks. +
+Sample Output -The Create-AzureDevOpsBug.ps1 PowerShell script creates a Bug on the current Iteration of a team when one or multiple Remediation Tasks failed. The Bug is formatted as an HTML table and contains information on the name and Url properties. As a result, the team can easily locate and resolve the Remediation Tasks that failed. +### Sample `summary-by-policy.csv` -| Parameter | Explanation | -| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -| `FailedPolicyRemediationTasksJsonString` | Specifies the JSON string that contains the objects of one or multiple failed Remediation Tasks. | -| `ModuleName` | Specifies the name of the PowerShell module installed at the beginning of the PowerShell script. By default, this is the VSTeam PowerShell Module. | -| `OrganizationName` | Specifies the name of the Azure DevOps Organization. | -| `ProjectName` | Specifies the name of the Azure DevOps Project. | -| `PersonalAccessToken` | Specifies the Personal Access Token that is used for authentication purposes. Make sure that you use the AzureKeyVault@2 task for this purpose. | -| `TeamName` | Specifies the name of the Azure DevOps team. | +| Category | Policy Name | Policy Id | Non Compliant | Unknown | Not Started | Exempt | Conflicting | Error | Assignment Ids | Group Names | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| General | Audit usage of custom RBAC roles | /providers/microsoft.authorization/policydefinitions/a451c1ef-c6ca-483d-87ed-f49761e3ffb5 | 9 | 0 | 0 | 0 | 0 | 0 | /providers/microsoft.management/managementgroups/pac-heinrich-dev-dev/providers/microsoft.authorization/policyassignments/dev-nist-800-53-r5,/providers/microsoft.management/managementgroups/pac-heinrich-dev-dev/providers/microsoft.authorization/policyassignments/dev-asb | azure_security_benchmark_v3.0_pa-7,nist_sp_800-53_r5_ac-6(7),nist_sp_800-53_r5_ac-2(7),nist_sp_800-53_r5_ac-6,nist_sp_800-53_r5_ac-2 | +| Regulatory Compliance | Control use of portable storage devices | /providers/microsoft.authorization/policydefinitions/0a8a1a7d-16d3-4d8e-9f2c-6b8d9e1c7c1d | 0 | 0 | 0 | 0 | 0 | 0 | /providers/microsoft.management/managementgroups/pac-heinrich-dev-dev/providers/microsoft.authorization/policyassignments/dev-nist-800-53-r5,/providers/microsoft.management/managementgroups/pac-heinrich-dev-dev/providers/microsoft.authorization/policyassignments/dev-asb | azure_security_benchmark_v3.0_pa-7,nist_sp_800-53_r5_ac-6(7),nist_sp_800-53_r5_ac-2(7),nist_sp_800-53_r5_ac-6,nist_sp_800-53_r5_ac-2 | -### Example +### Sample `summary-by-resource.csv` -`Create-AzureDevOpsBug.ps1 - -FailedPolicyRemediationTasksJsonString '' --ModuleName 'VSTeam' -OrganizationName 'bavanben' --ProjectName 'Contoso' -PersonalAccessToken '' --TeamName 'Contoso Team'` +| Resource Id | Subscription Id | Subscription Name | Resource Group | Resource Type | Resource Name | Resource Qualifier | Non Compliant | Unknown | Not Started | Exempt | Conflicting | Error | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| /subscriptions/******************************** | ******************************** | PAC-DEV-001 | | subscriptions | | | 25 | 481 | 0 | 0 | 0 | 0 | +| /subscriptions/********************************/providers/microsoft.authorization/roledefinitions/0b00bc79-2207-410c-b9d5-d5d182ad514f | ******************************** | PAC-DEV-001 | | microsoft.authorization/roledefinitions | 0b00bc79-2207-410c-b9d5-d5d182ad514f | | 0 | 0 | 0 | 0 | 0 | 0 | -## Create-GitHubIssue.ps1 - -This PowerShell script creates an Issue when there are one or multiple failed Remediation Tasks. - -The Create-GitHubIssue.ps1 PowerShell script creates an Issue in a GitHub Repository that is located under a GitHub Organization when one or multiple Remediation Tasks failed. The Bug is formatted as an HTML table and contains information on the name and Url properties. As a result, the team can easily locate and resolve the Remediation Tasks that failed. - -| Parameter | Explanation | -| ---------------------------------------- | ------------------------------------------------------------------------------------------------ | -| `FailedPolicyRemediationTasksJsonString` | Specifies the JSON string that contains the objects of one or multiple failed Remediation Tasks. | -| `OrganizationName` | Specifies the name of the GitHub Organization. | -| `RepositoryName` | Specifies the name of the GitHub Repository. | -| `PersonalAccessToken` | Specifies the Personal Access Token that is used for authentication purposes. | - -### Example - -`Create-GitHubIssue.ps1 - -FailedPolicyRemediationTasksJsonString '' --OrganizationName 'basvanbennekommsft' -RepositoryName 'Blog-Posts' --PersonalAccessToken ''` - -## Export-AzPolicyResources.ps1 - -Exports Azure Policy resources in EPAC format or raw format. It has 4 operating modes - see -Mode parameter for details. It also generates documentation for the exported resources (can be suppressed with -SuppressDocumentation). To just generate EPAC formatted Definitions without generating documentation files, use -supressEpacOutput. - -| Parameter | Explanation | -| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER` or `./Definitions`. | -| `OutputFolder` | Output Folder. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER` or `./Outputs`. | -| `Interactive` | Set to false if used non-interactive. Defaults to `$true`. | -| `IncludeChildScopes` | Switch parameter to include Policies and Policy Sets definitions in child scopes | -| `IncludeAutoAssigned` | Switch parameter to include Assignments auto-assigned by Defender for Cloud | -| `ExemptionFiles` | Create Exemption files (none=suppress, csv=as a csv file, json=as a json or jsonc file). Defaults to 'csv'. | -| `FileExtension` | File extension type for the output files. Defaults to '.jsonc'. | -| `Mode` | Operating mode: 'export', 'collectRawFile', 'exportFromRawFiles', 'exportRawToPipeline', 'psrule' | -| `InputPacSelector` | Limits the collection to one EPAC environment, useful for non-interactive use in a multi-tenant scenario, especially with -Mode 'collectRawFile'. The default is '\*' which will execute all EPAC-Environments. | -| `SuppressDocumentation` | Suppress documentation generation. | -| `SuppressEpacOutput` | Suppress output generation in EPAC format. | -| `PSRuleIgnoreFullScope` | Ignore full scope for PsRule Extraction | - -### Example - -`Export-AzPolicyResources -DefinitionsRootFolder ./Definitions -OutputFolder ./Outputs -Interactive $true -IncludeChildScopes -IncludeAutoAssigned -ExemptionFiles csv -FileExtension jsonc -Mode export -InputPacSelector '\*'` - -## Export-NonComplianceReports.ps1 - -Exports Non-Compliance Reports in CSV format. - -| Parameter | Explanation | -| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `PacEnvironmentSelector` | Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc`. | -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER` or `./Definitions`. | -| `OutputFolder` | Output Folder. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER` or `./Outputs`. | -| `WindowsNewLineCells` | Formats CSV multi-object cells to use new lines and saves it as UTF-8 with BOM - works only for Excel in Windows. Default uses commas to separate array elements within a cell. | -| `Interactive` | Set to false if used non-interactive. | -| `OnlyCheckManagedAssignments` | Include non-compliance data only for Policy assignments owned by this Policy as Code repo. | -| `PolicyDefinitionFilter` | Filter by Policy definition names (array) or ids (array). | -| `PolicySetDefinitionFilter` | Filter by Policy Set definition names (array) or ids (array). | -| `PolicyAssignmentFilter` | Filter by Policy Assignment names (array) or ids (array). | -| `PolicyEffectFilter` | Filter by Policy Effect (array). | -| `ExcludeManualPolicyEffect` | Switch parameter to filter out Policy Effect Manual. | -| `RemediationOnly` | Filter by Policy Effect "deployifnotexists" and "modify" and compliance status "NonCompliant". | - -### Examples - -1. `Export-NonComplianceReports -PacEnvironmentSelector "dev"` - -2. `Export-NonComplianceReports -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\MyPacRepo\Definitions" -OutputFolder "C:\MyPacRepo\Outputs"` - -3. `Export-NonComplianceReports -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\MyPacRepo\Definitions" -OutputFolder "C:\MyPacRepo\Outputs" -WindowsNewLineCells` - -4. `Export-NonComplianceReports -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\MyPacRepo\Definitions" -OutputFolder "C:\MyPacRepo\Outputs" -OnlyCheckManagedAssignments` - -5. `Export-NonComplianceReports -PolicySetDefinitionFilter "org-sec-initiative", "/providers/Microsoft.Authorization/policySetDefinitions/11111111-1111-1111-1111-111111111111"` - -6. `Export-NonComplianceReports -PolicyAssignmentFilter "/providers/microsoft.management/managementgroups/11111111-1111-1111-1111-111111111111/providers/microsoft.authorization/policyassignments/taginh-env", "prod-asb"` - -7. `Export-NonComplianceReports -PolicyEffectFilter "deny"` - -8. `Export-NonComplianceReports -PolicyEffectFilter "deny", "audit"` - -9. `Export-NonComplianceReports -ExcludeManualPolicyEffect` - -## Format-PolicyName.ps1 - -Formats a given display name into a scrubbed string that can be used as a policy name. - -| Parameter | Explanation | -| ------------- | --------------------------------- | -| `DisplayName` | The display name to be formatted. | - -### Example - -`Format-PolicyName.ps1 -DisplayName "My Policy Name"` - -## Get-AzExemptions.ps1 - -Retrieves Policy Exemptions from an EPAC environment and saves them to files. - -| Parameter | Explanation | -| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `PacEnvironmentSelector` | Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc`. | -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER` or `./Definitions`. | -| `OutputFolder` | Output Folder. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER` or `./Outputs`. | -| `Interactive` | Set to false if used non-interactive. | -| `FileExtension` | File extension type for the output files. Valid values are json and jsonc. Defaults to json. | -| `ActiveExemptionsOnly` | Set to true to only generate files for active (not expired and not orphaned) exemptions. Defaults to false. | - -### Examples - -`Get-AzExemptions.ps1 -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\Src\Definitions" -OutputFolder "C:\Src\Outputs" -Interactive $true -FileExtension "jsonc"` - -`Get-AzExemptions.ps1 -Interactive $true` - -## Get-AzMissingTags.ps1 - -Lists missing tags based on non-compliant Resource Groups. - -| Parameter | Explanation | -| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `PacEnvironmentSelector` | Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc`. | -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER` or `./Definitions`. It contains `global-settings.jsonc`. | -| `OutputFileName` | Output file name. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER/Tags/missing-tags-results.csv` or `./Outputs/Tags/missing-tags-results.csv`. | -| `Interactive` | Script is being run interactively and can request az login. Defaults to $false if PacEnvironmentSelector parameter provided and $true otherwise. | - -### Example - -`Get-AzMissingTags.ps1 -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\Src\Definitions" -OutputFileName "missing-tags-results.csv" -Interactive $true` - -## Get-AzPolicyAliasOutputCSV.ps1 - -Pull all policy aliases into a CSV file. This is helpful for Azure Policy development. - -| Parameter | Explanation | -| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `NamespaceMatch` | Use this to cut out unnecessary aliases by specifying your desired namespace. More documentation here: | -| `ResourceTypeMatch` | Resource type match can also be used to filter out unnecessary aliases. More documentation here: | - -### Example - -`Get-AzPolicyAliasOutputCSV.ps1 -OutputFileName "PolicyAliases.csv"` - -## Get-AzResourceTags.ps1 - -Lists all resource tags in tenant. - -| Parameter | Explanation | -| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `PacEnvironmentSelector` | Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc`. | -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER` or `./Definitions`. It contains `global-settings.jsonc`. | -| `OutputFileName` | Output file name. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER/Tags/all-tags.csv` or `./Outputs/Tags/all-tags.csv`. | -| `Interactive` | Script is being run interactively and can request az login. Defaults to $false if PacEnvironmentSelector parameter provided and $true otherwise. | - -### Example - -`Get-AzResourceTags.ps1 -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\Src\Definitions" -OutputFileName "resource-tags-results.csv" -Interactive $true` - -## Get-AzStorageNetworkConfig.ps1 - -Lists Storage Account network configurations. - -| Parameter | Explanation | -| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `PacEnvironmentSelector` | Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc`. | -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER` or `./Definitions`. It contains `global-settings.jsonc`. | -| `OutputFileName` | Output file name. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER/Storage/StorageNetwork.csv` or `./Outputs/Storage/StorageNetwork.csv` | -| `Interactive` | Script is being run interactively and can request az login. Defaults to $false if PacEnvironmentSelector parameter provided and $true otherwise. | - -### Example - -`Get-AzStorageNetworkConfig.ps1 -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\Src\Definitions" -OutputFileName "StorageNetwork.csv" -Interactive $true` - -## Get-AzUserRoleAssignments.ps1 - -Lists Role assignments per user. - -| Parameter | Explanation | -| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `PacEnvironmentSelector` | Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc`. | -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER` or `./Definitions`. It contains `global-settings.jsonc`. | -| `OutputFileName` | Output file name. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER/Users/RoleAssignments.csv` or `./Outputs/Users/RoleAssignments.csv` | -| `Interactive` | Script is being run interactively and can request az login. Defaults to $false if PacEnvironmentSelector parameter provided and $true otherwise. | - -### Example - -`Get-AzUserRoleAssignments.ps1 -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\Src\Definitions" -OutputFileName "RoleAssignments.csv" -Interactive $true` - -## New-AzPolicyReaderRole.ps1 - -Creates a custom role 'Policy Reader' that provides read access to all Policy resources for the purpose of planning the EPAC deployments. - -| Parameter | Explanation | -| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `PacEnvironmentSelector` | Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc`. | -| `DefinitionsRootFolder` | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER` or `./Definitions`. | -| `Interactive` | Set to false if used non-interactive. | - -### Examples - -`New-AzPolicyReaderRole.ps1 -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\Src\Definitions" -Interactive $true` - -`New-AzPolicyReaderRole.ps1 -Interactive $true` - -## New-EPACDefinitionFolder.ps1 - -Creates a new EPAC definition folder. - -| Parameter | Explanation | -| ----------------------- | ---------------------------------------------------------------- | -| `DefinitionFolderName` | The name of the new definition folder. | -| `DefinitionsRootFolder` | The root folder where the new definition folder will be created. | - -### Example - -`New-EPACDefinitionFolder.ps1 -DefinitionFolderName "MyNewDefinition" -DefinitionsRootFolder "C:\Src\Definitions"` - -## New-EPACGlobalSettings.ps1 - -Creates a global-settings.jsonc file with a new guid, managed identity location and tenant information. - -| Parameter | Explanation | -| ------------------------- | --------------------------------------------------------------------------------------------------- | -| `ManagedIdentityLocation` | The Azure location to store the managed identities. | -| `TenantId` | The Azure tenant ID for the solution. | -| `DefinitionsRootFolder` | The folder path to where the New-EPACDefinitionsFolder command created the definitions root folder. | -| `DeploymentRootScope` | The root management group to export definitions and assignments. | - -### Example - -`New-EPACGlobalSettings.ps1 -ManagedIdentityLocation NorthCentralUS -TenantId 00000000-0000-0000-0000-000000000000 -DefinitionsRootFolder C:\definitions\ -DeploymentRootScope /providers/Microsoft.Management/managementGroups/mgroup1` - -## New-EPACPolicyAssignmentDefinition.ps1 - -Exports a policy assignment from Azure to a local file in the EPAC format. Provides a base template only - you may have to manipulate the file to fit in to your current assignment structure - -| Parameter | Required | Explanation | -| -------------------- | -------- | -------------------------------------------------------------------------------------- | -| `PolicyAssignmentId` | Required | Resource ID in Azure for the policy assignment you want to export | -| `OutputFolder` | Optional | Output folder for the exported policy assignment - - default is JSON output to console | - -### Example - -`New-EPACPolicyAssignmentDefinition.ps1 -PolicyAssignmentId "/providers/Microsoft.Authorization/policyAssignments/assignment1" -OutputFolder "C:\Src\Definitions\Assignments"` - -## New-EPACPolicyDefinition.ps1 - -Exports a Policy definition from Azure to a local file in the EPAC format. - -| Parameter | Explanation | -| -------------------- | -------------------------------------------------------------- | -| `PolicyDefinitionId` | The ID of the Policy definition to export. | -| `OutputFolder` | The folder where the exported Policy definition will be saved. | - -### Example - -`New-EPACPolicyDefinition.ps1 -PolicyDefinitionId "/providers/Microsoft.Management/managementGroups/epac/providers/Microsoft.Authorization/policyDefinitions/Append-KV-SoftDelete" -OutputFolder` +
diff --git a/Docs/policy-assignments-csv-parameters.md b/Docs/policy-assignments-csv-parameters.md new file mode 100644 index 00000000..101f8faf --- /dev/null +++ b/Docs/policy-assignments-csv-parameters.md @@ -0,0 +1,135 @@ + +# Policy Assignment Parameters from a CSV File + +Assigning single or multiple security and compliance focused Policy Sets (Initiatives), such as Microsoft cloud security benchmark, NIST 800-53 R5, PCI, NIST 800-171, etc, with just JSON parameters becomes very complex fast. Add to this the complexity of overriding the effect if it is not surfaced as a parameter in the `Policy Set`. Finally, adding the optional `nonComplianceMessages` further increases the complexity. + +To address the problem of reading and maintaining hundreds or thousands of JSON lines, EPAC can use the content of a spreadsheet (CSV) to create `parameters`, `overrides` and optionally `nonComplianceMessages` for a single Policy assignment `definitionEntry` or multiple Policy definitions (`definitionEntryList`). + +> [!TIP] +> This approach is best for large Policy Sets such as Azure Security Benchmark, NIST 800-53, etc. Smaller Policy Sets should still be handled with JSON `parameters`, `overrides` and `nonComplianceMessages`. + +## Generate the CSV File + +### From a list of Policy Sets + +[Generating documentation for one or more Policy Sets](operational-scripts-documenting-policy.md#policy-set-documentation), then modify the effect and parameter columns for each type of environment types you will use. + +### From a list of deployed Policy Assignments + +If you want to switch from JSON to CSV or start EPAC from an existing deployment, [generate this CSV file frm your already deployed Assignment(s)](operational-scripts-documenting-policy.md#assignment-documentation). + +## CSV File + +In the example header below the infrastructure environments prod, test, dev, and sandbox are used as prefixes to the columns for Effect and Parameters respectively. Optionally you can add a column for `nonComplianceMessages` + +The CSV file generated contains the following headers/columns: + +* `name` is the name of the policyDefinition referenced by the Policy Sets being assigned. +* `referencePath` is only used if the Policy is used more than once in at least one of the Policy Sets to disambiguate them. The format is `//`. +* `policyType`,`category`,`displayName`,`description`,`groupNames`,`policySets`,`allowedEffects` are optional and not used for deployment planning. They assist you in filling out the `Effect` columns. The CSV file is sorted alphabetically by `category` and `displayName`. +* `Effect` columns must contain one of the allowedValues or allowedOverrides values. You define which scopes define each type of environment and what short name you give the environment type to use as a column prefix. +* `Parameters` can contain additional parameters. You can also specify such parameters in JSON. EPAC will use the union of all parameters. +* `nonComplianceMessages` column is optional. The documentation script does not generate this columns. + +> [!NOTE] +> Additional columns are allowed and ignored by EPAC. + +EPAC will find the effect parameter name for each Policy in each Policy Set and use them. If no effect parameter is defined by the Policy Set, EPAC will use `overrides` to set the effect. EPAC will generate the `policyDefinitionReferenceId` for `nonComplianceMessages`. + +After building the spreadsheet, you must reference the CSV file and the column prefix in each tree branch. `parameterFile` must occur once per tree branch. Define it adjacent to the `'definitionEntry` or `definitionEntryList` to improve readability. + +```json +"parameterFile": "security-baseline-parameters.csv", +"definitionEntryList": [ + { + "policySetName": "1f3afdf9-d0c9-4c3d-847f-89da613e70a8", + "displayName": "Azure Security Benchmark", + "assignment": { + "append": true, + "name": "asb", + "displayName": "Azure Security Benchmark", + "description": "Azure Security Benchmark Initiative. " + } + }, + { + "policySetName": "179d1daa-458f-4e47-8086-2a68d0d6c38f", + "displayName": "NIST SP 800-53 Rev. 5", + "assignment": { + "append": true, + "name": "nist-800-53-r5", + "displayName": "NIST SP 800-53 Rev. 5", + "description": "NIST SP 800-53 Rev. 5 Initiative." + } + } +], +``` + +In the child nodes specifying the scope(s) specify which column prefix to use for selecting the CSV columns with `parameterSelector`. The actual prefix names have no meaning; they only need to match between the JSON below and the CSV file. + +```json +{ + "nodeName": "Prod/", + "assignment": { + "name": "pr-", + "displayName": "Prod ", + "description": "Prod Environment controls enforcement with initiative " + }, + "parameterSelector": "prod", + "scope": { + "epac-dev": [ + "/providers/Microsoft.Management/managementGroups/Epac-Mg-Prod" + ], + "tenant": [ + "/providers/Microsoft.Management/managementGroups/Contoso-Prod" + ] + } +}, +``` + +The element `nonComplianceMessageColumn` may appear anywhere in the tree. Definitions at a child override the previous setting. If no `nonComplianceMessageColumn` is specified, the spreadsheet is not used for the (optional) `nonComplianceMessages`. + +```json +{ + "nodeName": "Prod/", + "assignment": { + "name": "pr-", + "displayName": "Prod ", + "description": "Prod Environment controls enforcement with initiative " + }, + "parameterSelector": "prod", + "nonComplianceMessageColumn": "nonComplianceMessages" + "scope": { + "epac-dev": [ + "/providers/Microsoft.Management/managementGroups/Epac-Mg-Prod" + ], + "tenant": [ + "/providers/Microsoft.Management/managementGroups/Contoso-Prod" + ] + } +}, +``` + +## Effects for `definitionEntryList` Policy Sets with Overlapping Policies + +Policy Set definitions often have a large overlap. In CSV files the Policy only shows up once. When EPAC processes the CSV file, it will use the effect from the first Policy Set definition in the `definitionEntryList` that contains the Policy. + +For the next Policy Set in the `definitionEntryList` that contains the same Policy, EPAC will adjust the effect: +- `Append`, `Modify` and `Deny` will be adjusted to `Audit` +- `DeployIfNotExists` will be adjusted to `AuditIfNotExists` + +## Updating the CSV File + +Policy Set definitions for builtin or custom Policy Sets are sometimes updated. When this happens, the CSV file must be updated to reflect the changes. EPAC display a Warning when this happens. + +### Policy Removed (Policy from Row in the CSV File is not used in any Policy Set) + +If a Policy is removed from every Policy Sets, remove the row from the spreadsheet or regenerate the CSV file from the deployed Policy Assignments. + +### Policy Added (Policy Entry is missing in the CSV file) + +If a Policy is added to a Policy Set, add the row manually to the CSV file. The Policy will be assigned with the default effect. + +Better, [regenerate the CSV file from the deployed Policy Assignments](operational-scripts-documenting-policy.md#assignment-documentation). This will ensure that all Policies are included in the CSV file. However, this does not generate the `nonComplianceMessages` column or any additional columns you added. + +> [!NOTE] +> We have planned to add a feature to generate the CSV file from the Policy Assignments and merge them with your existing CSV File to preserve extra columns. \ No newline at end of file diff --git a/Docs/policy-assignments.md b/Docs/policy-assignments.md index c3498b99..da813ef7 100644 --- a/Docs/policy-assignments.md +++ b/Docs/policy-assignments.md @@ -1,11 +1,11 @@ # Policy Assignments -This chapter describes how **Policy Assignments** are handled by EPAC. To learn about how custom Policy and Policy Set definitions are managed, see the [Policies](policy-definitions.md) and [Policy Set Definitions](policy-set-definitions.md). +This chapter describes how **Policy Assignments** are handled by EPAC. Policy Assignments are the actual assignments of Policies and Policy Sets to scopes in Azure ## Assignment JSON structure -Assignment JSON is hierarchical for efficient definitions, avoiding duplication (copy/paste) of JSON. Each branch of the tree is cumulative. Each tree node must include a `nodeName` - an arbitrary string exclusively used by EPAC to display an error location. EPAC concatenates a leading `/` and the nodeName entries encountered in the tree to create a "breadcrumbs" trail; therefore, we recommend that you use `/` to help separate the concatenated `nodeName`. The following (partial and invalid) assignment tree would create this error message. +Assignment JSON is hierarchical for efficient definitions, avoiding duplication (copy/paste) of JSON. Each branch of the tree is cumulative. Each tree node must include a `nodeName` - an arbitrary string exclusively used by EPAC to display an error location. EPAC concatenates a leading `/` and the nodeName entries encountered in the tree to create a "breadcrumbs" trail; therefore, we recommend that you use `/` to help separate the concatenated `nodeName`. The following partial and invalid assignment tree would create this error message. ```json { @@ -24,6 +24,8 @@ Assignment JSON is hierarchical for efficient definitions, avoiding duplication } ``` +![Assignment File Overview Diagram](Images/PaC-Assignment-Structure.png) + ### JSON Schema The GitHub repo contains a JSON schema which can be used in tools such as [VS Code](https://code.visualstudio.com/Docs/languages/json#_json-schemas-and-settings) to provide code completion. @@ -36,23 +38,19 @@ To utilize the schema add a ```$schema``` tag to the JSON file. } ``` -This schema is new in v7.4.x and may not be complete. Please let us know if we missed anything. +## Key Points -### Key Points +- Every tree branch must accumulate a `definitionEntry` (or `definitionEntryList`), Assignment naming (`name` and `displayName`) and `scope` element. +- The elements `parameters`, `overrides`, `resourceSelectors`, `notScope`, `enforcementMode`, `metadata`, `userAssignedIdentity`, `managedIdentityLocations`,`additionalRoleAssignments`and`nonComplianceMessages` are optional. +- For Policy Sets with large numbers of included Policies you should use a spreadsheet (CSV file) to manage **effects** (parameterized or effect `overrides`), `parameters` and optional `nonComplianceMessages`. We recommend the CSV approach for Policy Sets with more than 10 included Policies. +- EPAC continues to support deprecated elements `initiativeId`, `initiativeName` and `ignoreBranch`, Consider using their replacements `policySetId`, `policySetName` and `enforcementMode` instead. +- Role Assignments for user-assigned Managed Identities (UAMI) are not managed by EPAC, and will not generate a `roles-plan.json` file. +- `additionalRoleAssignments` are used when a resource required is not in the current scope. For example, a Policy Assignment that requires a Event Hub to be managed in a subscription not contained in the current management group. -* Every tree branch must accumulate a `definitionEntry` (or `definitionEntryList`), Assignment naming (`name` and `displayName`) and `scope` element. -* The elements `parameters`, `overrides`, `resourceSelectors`, `notScope`, `enforcementMode`, `metadata`, `userAssignedIdentity`, `managedIdentityLocations`,`additionalRoleAssignments`and`nonComplianceMessages` are optional. -* For Policy Sets with large numbers of included Policies you should use a spreadsheet (CSV file) to manage **effects** (parameterized or effect `overrides`), `parameters` and optional `nonComplianceMessages`. We recommend the CSV approach for Policy Sets with more than 10 included Policies. -* EPAC continues to support deprecated elements `initiativeId`, `initiativeName` and `ignoreBranch`, Consider using their replacements `policySetId`, `policySetName` and `enforcementMode` instead. +> [!TIP] +> The tree is not required to be balanced. The number of levels is not restricted; however, anything beyond 3 levels is unnecessary in real scenarios and would be difficult to read and manage as the depth increases. -!!! note - The tree is not required to be balanced. The number of levels is not restricted; however, anything beyond 3 levels is unnecessary in real scenarios and would be difficult to read and manage as the depth increases. - -### Tree Structure - -![Assignment File Overview Diagram](Images/PaC-Assignment-Structure.png) - -## Assignment Naming Element +## Assignment Element and Metadata Each Assignment is required to have a `name` which is used in it's resource id. EPAC also requires a `displayName`. The `description` is optional. For the allowed location assignment you specify the component with: @@ -66,17 +64,48 @@ Each Assignment is required to have a `name` which is used in it's resource id. Multiple `assignment` naming components in a tree branch are string concatenated for each of the three fields. -!!! warning - Azure has a limit of 24 characters for the concatenated `name` string. EPAC displays an error if this limit is exceeded. +> [!WARNING] +> Azure has a limit of 24 characters for the concatenated `name` string. EPAC displays an error if this limit is exceeded. + +### Defining `metadata` + +`metadata` is sometimes used to assign categories for changes. Do NOT specify EPAC-reserved elements `roles` and `pacOwnerId`. For the final `metadata` EPAC creates the union of instances in the entire tree branch. + +```json +"metadata": { + "category": "Security" +} +``` + +**Not recommended**: Adding `assignedBy` to the `metadata` overrides the `deployedBy` value from the `global-settings.jsonc` file normally used for `assignedBy`. It defaults to `"epac/$pacOwnerId/$pacSelector"`. + +```json +"metadata": { + "category": "Security", + "assignedBy": "security-team@epac/epac/00000000-0000-0000-0000-000000000000/tenant" +} +``` + +### Metadata for Role Assignments + +Role assignments do not contain a `metadata` field. Instead, the `description` field is used to populate the `deployedBy` value. The `description` field is populated with the Policy Assignment Id, reason and `deployedBy` value. This is useful for tracking the source of the Role Assignment. + +Reasons is one of: + +- `Role Assignment required by Policy` - Policy definition(s) specify the required Role Definition Ids. +- `additional Role Assignment` - from filed "additionalRoleAssignments" in the Policy Assignment file. +- `additional cross tenant Role Assignment` - from filed "additionalRoleAssignments" with `crossTenant` set to `$true` in the Policy Assignment file. ## Assigning Policy Sets or Policies +### Assigning a single Policy or Policy Set + Each assignment assigns either a Policy or Policy Set. In EPAC this is done with a `definitionEntry` or a `definitionEntryList`. Exactly one occurrence must exist in any collated tree branch. For each entry, you need to specify one of the following: -* `policyName` - custom Policy managed by EPAC. Specifying just the name allows EPAC to inject the correct definition scope. -* `policySetName` - custom Policy Set managed by EPAC. -* `policyId` - resource id for builtin Policy. -* `policySetId` - resource id for builtin Policy Set. +- `policyName` - custom Policy. Specifying just the name allows EPAC to inject the correct definition scope. +- `policySetName` - custom Policy Set. Specifying just the name allows EPAC to inject the correct definition scope +- `policyId` - resource id for builtin Policy. +- `policySetId` - resource id for builtin Policy Set. `displayName` is an optional field to document the entry if the Policy name is a GUID. Builtin Policies and Policy Sets use a GUID. @@ -87,6 +116,8 @@ Each assignment assigns either a Policy or Policy Set. In EPAC this is done with }, ``` +### Assigning multiple Policies or Policy Sets + Using `definitionEntryList` allows you to save on copy/paste tree branches. Without it, the number of branches would need to be duplicated as many times as the list has entries. Each entry in the list creates an Assignment at each leaf of the tree. Since assignments must have unique names at a specific scope, the Assignment naming component must be amended for each list entry. In this sub-component you can decide if you want to concatenate the string by appending or prepending them by specifying `append` boolean value. @@ -128,18 +159,18 @@ In the above example one of the children (leaf node) has the following Assignmen This example generates two assignments at the "prod" leaf per scope: -* /providers/Microsoft.Management/managementGroups/***Contoso-Prod***/providers/Microsoft.Authorization/policyAssignments/**pr-asb** - * `displayName` = "Prod Azure Security Benchmark" - * `description` = "Prod Environment controls enforcement with Azure Security Benchmark Initiative." -* /providers/Microsoft.Management/managementGroups/***Contoso-Prod***/providers/Microsoft.Authorization/policyAssignments/**pr-nist-800-53-r5** - * `displayName` = "Prod NIST SP 800-53 Rev. 5" - * `description` = "Prod Environment controls enforcement with NIST SP 800-53 Rev. 5 Initiative." +- /providers/Microsoft.Management/managementGroups/***Contoso-Prod***/providers/Microsoft.Authorization/policyAssignments/**pr-asb** + - `displayName` = "Prod Azure Security Benchmark" + - `description` = "Prod Environment controls enforcement with Azure Security Benchmark Initiative." +- /providers/Microsoft.Management/managementGroups/***Contoso-Prod***/providers/Microsoft.Authorization/policyAssignments/**pr-nist-800-53-r5** + - `displayName` = "Prod NIST SP 800-53 Rev. 5" + - `description` = "Prod Environment controls enforcement with NIST SP 800-53 Rev. 5 Initiative." ## Assignment scopes and excluded scopes `scope` is required exactly once in each tree branch. Excluded scopes (`notScope`) are cumulative from `global-settings.json` and the entire tree branch; however, once a scope is defined `notScope` may not be defined at any child node. -Both `scope` and `notScope` are specific to an [EPAC Environment using the pacSelector name](index.md#understanding-epac-environments-and-the-pacselector), e.g., `epac-dev` and `tenant`. +Both `scope` and `notScope` are specific to an [EPAC Environment using the pacSelector name](epac-implementing.md#epac-concepts-and-environments), e.g., `epac-dev` and `tenant`. ```json "scope": { @@ -153,16 +184,15 @@ Both `scope` and `notScope` are specific to an [EPAC Environment using the pacSe } ``` -`notScope` works the same. In addition `"*"` means all EPAC Environments which is most often used for `resourceGroupPatterns`. +`notScope` works the same. In addition `"*"` means all EPAC Environments. ```json "notScope": { "*": [ - "/resourceGroupPatterns/excluded-rg*" + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-pattern*" ], "tenant": [ - "/providers/Microsoft.Management/managementGroups/Epac", - "/providers/Microsoft.Management/managementGroups/" + "/providers/Microsoft.Management/managementGroups/" ] } ``` @@ -184,7 +214,9 @@ You can specify them in `global-settings.jsonc` or at any node in the tree. The ### Defining optional `additionalRoleAssignments` -In some scenarios you will need `additionalRoleAssignments`; e.g., for diagnostics settings to Event Hubs, the target resource might be in a different Management Group and therefore the Managed Identity requires additional role assignments. You must specify the `additionalRoleAssignments` based on EPAC Environment or use `"*"`to use the same `additionalRoleAssignments`for all of the EPAC Environments. +In some scenarios you will need `additionalRoleAssignments`; e.g., for diagnostics settings to Event Hubs, the target resource might be in a different Management Group and therefore the Managed Identity requires additional role assignments. You must specify the `additionalRoleAssignments` based on EPAC Environment or use `"*"`to use the same `additionalRoleAssignments`for all of the EPAC Environments. If the pacEnvironment under deployment is specified in the additionalRoleAssignments, the `"*"` assignments will be ignored. + +If the additional assignment is to made to a managing tenant in the sceenario where the pacEnvironment under deployment is a manganged (lighthouse) tenant, you must specify `""crossTenant": true"` for that assignment. Ensure all necessary ABAC permissions are in place for the executing SPN. ```json "additionalRoleAssignments": { @@ -193,13 +225,26 @@ In some scenarios you will need `additionalRoleAssignments`; e.g., for diagnosti "roleDefinitionId": "/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c", "scope": "/subscriptions//resourceGroups/" } + ], + "prod": [ + { + "roleDefinitionId": "/providers/microsoft.authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635", + "scope": "/subscriptions//resourceGroups/" + } + ], + "lighthouse": [ + { + "roleDefinitionId": "/providers/microsoft.authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7", + "scope": "/subscriptions/945a01ac-ae61-41da-81b4-640a8441da7b", + "crossTenant": true + } ] -}, + }, ``` ### User-assigned Managed Identities -Azure Policy can use a user-defined Managed Identity and EPAC allows you to use this functionality (new in version 7.0). You must specify the user-defined Managed Identity based on EPAC Environment or use `"*"` to use the same identity for all of the EPAC Environments (only possible in single tenant scenarios). Within each EPAC Environment entry, you can specify just the URI string indicating to use the same identity even if we are using a `definitionEntryList`, or in the case of a `definitionEntryList` can assign a different identity based on the definitionEntryList by specifying a matching `policyName`, `policyId`, `policySetName` or `policySetId`. +Azure Policy can use a user-defined Managed Identity and EPAC allows you to use this functionality. You must specify the user-defined Managed Identity based on EPAC Environment or use `"*"` to use the same identity for all of the EPAC Environments (only possible in single tenant scenarios). Within each EPAC Environment entry, you can specify just the URI string indicating to use the same identity even if we are using a `definitionEntryList`, or in the case of a `definitionEntryList` can assign a different identity based on the definitionEntryList by specifying a matching `policyName`, `policyId`, `policySetName` or `policySetId`. ```json "userAssignedIdentity": { @@ -219,12 +264,30 @@ Azure Policy can use a user-defined Managed Identity and EPAC allows you to use } ``` -!!! note - The rest (below) of the node components are optional. +
+ +## Defining `parameters`, `overrides` and `nonComplianceMessages` + +### Utilizing a CSV File to define `parameters`, `overrides` and `nonComplianceMessages` + +Assigning single or multiple security and compliance focused Policy Sets (Initiatives), such as Microsoft cloud security benchmark, NIST 800-53 R5, PCI, NIST 800-171, etc, with just JSON parameters becomes very complex fast. Add to this the complexity of overriding the effect if it is not surfaced as a parameter in the `Policy Set`. Finally, adding the optional `nonComplianceMessages` further increases the complexity. + +To address the problem of reading and maintaining hundreds or thousands of JSON lines, EPAC can use the content of a spreadsheet (CSV) to create `parameters`, `overrides` and optionally `nonComplianceMessages` for a single Policy assignment `definitionEntry` or multiple Policy definitions (`definitionEntryList`). + +> [!TIP] +> This approach is best for large Policy Sets such as Azure Security Benchmark, NIST 800-53, etc. Smaller Policy Sets should still be handled with JSON `parameters`, `overrides` and `nonComplianceMessages`. -## Defining `parameters` with JSON +Implement these steps as documented in [Managing Policy Assignment Parameters with a CSV file](policy-assignments-csv-parameters.md). -`parameters` have a simple JSON structure. You do not need the additional `value` indirection Azure requests (EPAC will inject that indirection). +- Generate the CSV file form your already deployed Assignment(s) or Policy Set(s). +- Modify the effect and parameter columns for each type of environment types you will use. +- Modify the Policy Assignment file to reference the CSV file and the column prefix. +- Update the CSV file with the new effect and parameter values. + +### Defining `parameters` with JSON + +> [!WARNING] +> `parameters` have a simplified JSON structure. You do not need the additional `value` indirection Azure requests (EPAC will inject that indirection). ```json "parameters": { @@ -240,9 +303,12 @@ Azure Policy can use a user-defined Managed Identity and EPAC allows you to use }, ``` -Too enable `definitionEntryList`, parameters not present in the Policy or Policy Set definition are quietly ignored. +> [!NOTE] +> Too enable `definitionEntryList`, parameters not present in the Policy or Policy Set definition are quietly ignored. -## Defining `overrides` with JSON +## Advanced Elements + +### Defining `overrides` with JSON `overrides` are in the same [format as documented by Azure](https://learn.microsoft.com/en-us/azure/governance/policy/concepts/assignment-structure#overrides-preview). They are cumulative in each tree branch. The `selectors` element is only used for Assignments of Policy Sets. They are not valid for Assignments of a single Policy. @@ -281,13 +347,13 @@ If using `definitionEntryList`, you must add the `policyName`, `policyId`, `poli ], ``` -## Defining `nonComplianceMessages` with JSON +### Defining `nonComplianceMessages` with JSON Assign a non-compliance message to the assignment, or individual non-compliance messages if the assignment is for an Policy Set. This value is an array of objects - each containing a message, and in the case of an initiative a policyDefinitionReferenceId. See [this link](https://learn.microsoft.com/en-us/azure/governance/policy/concepts/assignment-structure#non-compliance-messages) for details. If you use single `definitionEntry`, place them normally. If you use a `definitionEntryList` place them in the respective list entry. -```json +```jsonc "nonComplianceMessages": [ { "message": "Update main message" @@ -301,106 +367,7 @@ If you use single `definitionEntry`, place them normally. If you use a `definiti ], ``` -## Defining `parameters`, `overrides` and `nonComplianceMessages` with a CSV file - -Assigning single or multiple security and compliance focused Policy Sets (Initiatives), such as Azure Security Benchmark, NIST 800-53 r5, PCI, NIST 800-171, etc, with just JSON parameters becomes very complex fast. Add to this the complexity of overriding the effect if it is not surfaced as a parameter in the Policy Set using `overrides`. Finally, adding the optional `nonComplianceMessages` further increases the complexity. - -To address the problem of reading and maintaining hundreds or thousands of JSON lines, EPAC can use the content of a spreadsheet (CSV) to create `parameters`, `overrides` and optionally `nonComplianceMessages` for a single Policy assignment `definitionEntry` or multiple Policy definitions (`definitionEntryList`). - -!!! note - This approach is best for very large Policy Sets such as Azure Security Benchmark, NIST 800-53, etc. Smaller Policy Sets should still be handled with JSON `parameters`, `overrides` and `nonComplianceMessages`. - -Start by [generating documentation for one or more of those Policy Sets](documenting-assignments-and-policy-sets.md#policy-set-documentation), then modify the effect and parameter columns for each type of environment types you will use. In the example header below the infrastructure environments prod, test, dev, and sandbox are used as prefixes to the columns for Effect and Parameters respectively. Optionally you can add a column for `nonComplianceMessages`. If you want to switch from JSON to CSV, you can [generate this CSV file frm your already deployed Assignment(s)](documenting-assignments-and-policy-sets.md#assignment-documentation). - -The CSV file generated contains the following headers/columns: - -`name,referencePath,policyType,category,displayName,description,groupNames,policySets,allowedEffects,allowedOverrides,prodEffect,testEffect,devEffect,sandboxEffect,prodParameters,testParameters,devParameters,sandboxParameters,nonComplianceMessages` - -Column explanations: - -* `name` is the name of the policyDefinition referenced by the Policy Sets being assigned. -* `referencePath` is only used if the Policy is used more than once in at least one of the Policy Sets to disambiguate them. The format is `//`. -* `policyType`,`category`,`displayName`,`description`,`groupNames`,`policySets`,`allowedEffects` are optional and not used for deployment planning. They assist you in filling out the `Effect` columns. -* `Effect` columns must contain one of the allowedValues or allowedOverrides values. You define which scopes define each type of environment and what short name you give the environment type to use as a column prefix. -* `Parameters` can contain additional parameters. You can also specify such parameters in JSON. EPAC will use the union of all parameters. -* `nonComplianceMessages` column is optional. The documentation script does not generate this columns. - -EPAC will find the effect parameter name for each Policy in each Policy Set and use them. If no effect parameter is defined by the Policy Set, EPAC will use `overrides` to set the effect. EPAC will generate the `policyDefinitionReferenceId` for `nonComplianceMessages`. - -After building the spreadsheet, you must reference the CSV file and the column prefix in each tree branch. `parameterFile` can be overridden in a child node; however, it is often used once per tree branch and defined adjacent to the `'definitionEntry` or `definitionEntryList`. - -```json -"parameterFile": "security-baseline-parameters.csv", -"definitionEntryList": [ - { - "policySetName": "1f3afdf9-d0c9-4c3d-847f-89da613e70a8", - "displayName": "Azure Security Benchmark", - "assignment": { - "append": true, - "name": "asb", - "displayName": "Azure Security Benchmark", - "description": "Azure Security Benchmark Initiative. " - } - }, - { - "policySetName": "179d1daa-458f-4e47-8086-2a68d0d6c38f", - "displayName": "NIST SP 800-53 Rev. 5", - "assignment": { - "append": true, - "name": "nist-800-53-r5", - "displayName": "NIST SP 800-53 Rev. 5", - "description": "NIST SP 800-53 Rev. 5 Initiative." - } - } -], -``` - -In the child nodes specifying the scope(s) specify which column prefix to use for selecting the CSV columns with `parameterSelector`. The actual prefix names have no meaning; they only need to match between the JSON below and the CSV file. - -```json -{ - "nodeName": "Prod/", - "assignment": { - "name": "pr-", - "displayName": "Prod ", - "description": "Prod Environment controls enforcement with initiative " - }, - "parameterSelector": "prod", - "scope": { - "epac-dev": [ - "/providers/Microsoft.Management/managementGroups/Epac-Mg-Prod" - ], - "tenant": [ - "/providers/Microsoft.Management/managementGroups/Contoso-Prod" - ] - } -}, -``` - -The element `nonComplianceMessageColumn` may appear anywhere in the tree. Definitions at a child override the previous setting. If no `nonComplianceMessageColumn` is specified, the spreadsheet is not used for the (optional) `nonComplianceMessages`. - -```json -{ - "nodeName": "Prod/", - "assignment": { - "name": "pr-", - "displayName": "Prod ", - "description": "Prod Environment controls enforcement with initiative " - }, - "parameterSelector": "prod", - "nonComplianceMessageColumn": "nonComplianceMessages" - "scope": { - "epac-dev": [ - "/providers/Microsoft.Management/managementGroups/Epac-Mg-Prod" - ], - "tenant": [ - "/providers/Microsoft.Management/managementGroups/Contoso-Prod" - ] - } -}, -``` - -## Defining `resourceSelectors` +### Defining `resourceSelectors` `resourceSelectors` may appear anywhere in the tree and are cumulative in any branch. [They follow the standard Azure Format](https://learn.microsoft.com/en-us/azure/governance/policy/concepts/assignment-structure#resource-selectors-preview). @@ -418,17 +385,7 @@ The element `nonComplianceMessageColumn` may appear anywhere in the tree. Defini ] ``` -## Defining `metadata` - -`metadata` is sometimes used to track tickets for changes. Do NOT specify EPAC-reserved elements `roles` and `pacOwnerId`. For the final `metadata` EPAC creates the union of instances in the entire tree branch. - -```json -"metadata": { - "someItem": "Lorem Ipsum" -} -``` - -## Defining `enforcementMode` +### Defining `enforcementMode` `enforcementMode` is similar to the deprecated `ignoreBranch`; it deploys the assignment and sets the assignment to `Default` or `DoNotEnforce`. `DoNotEnforce` allows a what-if analysis. `enforcementMode` may appear anywhere in the tree. Definitions at a child override the previous setting. @@ -440,7 +397,12 @@ The element `nonComplianceMessageColumn` may appear anywhere in the tree. Defini ### Simple Policy Assignment (Allowed Locations) -In the simple case an assignment is a single assignment or with no difference in `assignment`, `parameters`, and `definitionEntry` across multiple scopes. In many scenarios "Allowed Locations" is such a simple Assignment. Such Assignments do not have child nodes, just the root node. +In the simple case an assignment is a single node with no difference in `assignment`, `parameters`, and `definitionEntry` across multiple scopes. In many scenarios "Allowed Locations" is such a simple Assignment. Such Assignments do not have child nodes, just the root node. +Example + + +
+Example ```json { @@ -475,18 +437,23 @@ In the simple case an assignment is a single assignment or with no difference in } ``` -* `nodeName` is required for error messages; it's value is immaterial. EPAC concatenates them in the current tree branch. -* `definitionEntry` specifies that the custom Policy Set `general-allowed-locations-policy-set` from our starter kit. `displayName` has no meaning - it is for readability and in this instance is superfluous. -* `assignment` fields `name`, `displayName` and `description` are used when creating the assignment. -* This assignment has no `metadata`. You don't need an empty collection. EPAC will add `pacOwnerId` and `roles` `metadata`. Do not add them manually. -* enforcementMode is set to default - it is superfluous. -* `parameters` are obvious. Note: you don't add the `value` layer Azure inserts - EPAC takes care of that. -* `scope`: - * During Policy resource development (called `epac-dev`) the Assignment is deployed to an EPAC development Management Group `Epac-Mg-1`. - * During Policy prod deployments (`tenant`-wide), it is deployed to the tenant Management Group `Epac-Mg-1`. -* No `notScope` entries are specified. - +- `nodeName` is required for error messages; it's value is immaterial. EPAC concatenates them in the current tree branch. +- `definitionEntry` specifies that the custom Policy Set `general-allowed-locations-policy-set` from our starter kit. `displayName` has no meaning - it is for readability and in this instance is superfluous. +- `assignment` fields `name`, `displayName` and `description` are used when creating the assignment. +- This assignment has no `metadata`. You don't need an empty collection. EPAC will add `pacOwnerId` and `roles` `metadata`. Do not add them manually. +- enforcementMode is set to default - it is superfluous. +- `parameters` are obvious. Note: you don't add the `value` layer Azure inserts - EPAC takes care of that. +- `scope`: + - During Policy resource development (called `epac-dev`) the Assignment is deployed to an EPAC development Management Group `Epac-Mg-1`. + - During Policy prod deployments (`tenant`-wide), it is deployed to the tenant Management Group `Epac-Mg-1`. +- No `notScope` entries are specified. + +
+ +
+ If we remove the empty and superfluous entries, we arrive at: + ```json { @@ -518,12 +485,17 @@ If we remove the empty and superfluous entries, we arrive at: } ``` +
+ ### Security-Focused Policy Assignment with JSON parameters -* In the following example we named our root node (`nodeName`) `/security/`. Since it is only used in case of error messages produced by EPAC during planning it's actual value doesn't matter as long as it's unique. -* We use a `definitionEntryList` to create two assignments at every leaf (six assignments total). -* For `assignment` string concatenation we append the strings in the `definitionEntryList` to the strings in the child nodes. You can see this best when you look at the `description` string in the child nodes. It will form a sentence when concatenated by `append`ing the `definitionEntryList` `assignment` field `description`. -* The `parameters` specified in the children are specific to the IaC environment types and their `scope`. Note: a real assignment would define many more parameters. The set here is abbreviated since the actual set could easily exceed a hundred entries for each of the IaC environments. We'll see in the next example how to simplify large Policy Set parameters with a CSV file. +- In the following example we named our root node (`nodeName`) `/security/`. Since it is only used in case of error messages produced by EPAC during planning it's actual value doesn't matter as long as it's unique. +- We use a `definitionEntryList` to create two assignments at every leaf (six assignments total). +- For `assignment` string concatenation we append the strings in the `definitionEntryList` to the strings in the child nodes. You can see this best when you look at the `description` string in the child nodes. It will form a sentence when concatenated by `append`ing the `definitionEntryList` `assignment` field `description`. +- The `parameters` specified in the children are specific to the IaC environment types and their `scope`. Note: a real assignment would define many more parameters. The set here is abbreviated since the actual set could easily exceed a hundred entries for each of the IaC environments. We'll see in the next example how to simplify large Policy Set parameters with a CSV file. + +
+Example ```json { @@ -628,114 +600,19 @@ If we remove the empty and superfluous entries, we arrive at: } ``` -### Security-Focused Policy Assignment with CSV file parameters - -This example is the same as the previous, except we replaced inline JSON parameters with a CSV file and use the column prefixes in the CSV file to select which parameter values we use by: - -* Setting the file name at the root node with - - ```json - "parameterFile": "security-baseline-parameters.csv", - ``` - -* Setting the column prefix with `parameterSelector` to `prod`, `nonprod` and `sandbox`. For example: - - ```json - "parameterSelector": "prod", - ``` - -The CSV file is explained [above](#define-assignment-parameters-with-a-csv-file). The entire file is: - -```json -{ - "nodeName": "/Security/", - "parameterFile": "security-baseline-parameters.csv", - "definitionEntryList": [ - { - "policySetId": "/providers/Microsoft.Authorization/policySetDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8", - "displayName": "Azure Security Benchmark", - "assignment": { - "append": true, - "name": "asb", - "displayName": "Azure Security Benchmark", - "description": "Azure Security Benchmark Initiative." - } - }, - { - "policySetId": "/providers/Microsoft.Authorization/policySetDefinitions/179d1daa-458f-4e47-8086-2a68d0d6c38f", - "displayName": "NIST SP 800-53 Rev. 5", - "assignment": { - "append": true, - "name": "nist-800-53-r5", - "displayName": "NIST SP 800-53 Rev. 5", - "description": "NIST SP 800-53 Rev. 5 Initiative." - } - } - ], - "children": [ - { - "nodeName": "Prod/", - "parameterSelector": "prod", - "assignment": { - "name": "pr-", - "displayName": "Prod ", - "description": "Prod Environment controls enforcement with " - }, - "scope": { - "epac-dev": [ - "/providers/Microsoft.Management/managementGroups/epac-dev-prod" - ], - "tenant": [ - "/providers/Microsoft.Management/managementGroups/Contoso-Prod" - ] - } - }, - { - "nodeName": "NonProd/", - "parameterSelector": "nonprod", - "assignment": { - "name": "np-", - "displayName": "NonProd ", - "description": "Non Prod Environment controls enforcement with " - }, - "scope": { - "epac-dev": [ - "/providers/Microsoft.Management/managementGroups/epac-dev-nonprod" - ], - "tenant": [ - "/providers/Microsoft.Management/managementGroups/Contoso-nonprod" - ] - } - }, - { - "nodeName": "Sandbox/", - "parameterSelector": "sandbox", - "assignment": { - "name": "sbx-", - "displayName": "Sandbox ", - "description": "Sandbox Environment controls enforcement with " - }, - "scope": { - "epac-dev": [ - "/providers/Microsoft.Management/managementGroups/epac-dev-sandbox" - ], - "tenant": [ - "/providers/Microsoft.Management/managementGroups/Contoso-Sandbox" - ] - } - } - ] -} -``` +
### Inverted Policy Assignment (Tag Inheritance and Required Tags) As mentioned above sometimes it is advantageous (to reduce the number of repetitions) to turn a definition on its head: -* **Common** `parameters`, `scope`, `definitionEntryList` (with two Policies) at the root (`nodeName` is `/Tags/`). -* Start of the `assignment` strings (`append` is defaulted to `false`). Again look at description which will be a concatenated sentence. -* The children define the `tagName` parameter and the second part of the strings for `assignment`. The set of `parameters` is the union of the root node and the child node. -* This creates six Assignments (number of Policies assigned times number of children). +- **Common** `parameters`, `scope`, `definitionEntryList` (with two Policies) at the root (`nodeName` is `/Tags/`). +- Start of the `assignment` strings (`append` is defaulted to `false`). Again look at description which will be a concatenated sentence. +- The children define the `tagName` parameter and the second part of the strings for `assignment`. The set of `parameters` is the union of the root node and the child node. +- This creates six Assignments (number of Policies assigned times number of children). + +
+Example ```json { @@ -812,10 +689,14 @@ As mentioned above sometimes it is advantageous (to reduce the number of repetit ] } ``` +
### Non-Compliance Messages in a Policy Definition Assignment -An example of a policy assignment for a single policy definition with a default non-compliance message. + + +
+An example of a policy assignment for a single policy definition with a default non-compliance message. ```json { @@ -842,9 +723,14 @@ An example of a policy assignment for a single policy definition with a default } ``` +
+ ### Non-Compliance Messages in a Policy Set Definition Assignment +
+ An example of a policy assignment for a policy set definition with a default non-compliance message and a policy specific non-compliance message. + ```json { @@ -875,9 +761,14 @@ An example of a policy assignment for a policy set definition with a default non } ``` +
+ ### Non-Compliance Messages in a Policy Set Definition Assignment with a `definitionEntryList` +
+ An example of how to use a non-compliance message when using a `definitionEntryList` list in the assignment. + ```json { @@ -919,3 +810,5 @@ An example of how to use a non-compliance message when using a `definitionEntryL } } ``` + +
diff --git a/Docs/policy-definitions.md b/Docs/policy-definitions.md index 60972198..c46cc1b1 100644 --- a/Docs/policy-definitions.md +++ b/Docs/policy-definitions.md @@ -1,11 +1,11 @@ -# Policies +# Policy Definitions ## Policy Definition Files Policy definition files are managed within the folder `policyDefinitions` under `Definitions`. The Policy definition files are structured based on the official [Azure Policy definition structure](https://docs.microsoft.com/en-us/azure/governance/policy/concepts/definition-structure) published by Microsoft. There are numerous definition samples available on Microsoft's [GitHub repository for azure-policy](https://github.com/Azure/azure-policy). -!!! note - When authoring Policy and Policy definitions, check out the [Maximum count of Azure Policy objects](https://docs.microsoft.com/en-us/azure/governance/policy/overview#maximum-count-of-azure-policy-objects) +> [!TIP] +> When authoring Policy and Policy definitions, check out the [Maximum count of Azure Policy objects](https://docs.microsoft.com/en-us/azure/governance/policy/overview#maximum-count-of-azure-policy-objects) The names of the definition JSON files don't matter, the Policy and Policy Set definitions are registered based on the `name` attribute. The solution also allows the use of JSON with comments by using `.jsonc` instead of `.json` for the file extension. @@ -32,6 +32,14 @@ This schema is new in v7.4.x and may not be complete. Please let us know if we m * Whenever feasible, provide a `defaultValue` for parameters, especially for the `effect` parameter. * Policy aliases are used by Azure Policy to refer to resource type properties in the `if` condition and in `existenceCondition`: . +## Metadata + +It is customary to include a `category` and a `version` in the `metadata` section. The `category` should be one of the standard ones defined in built-in Policies. The `version` should be a semantic version number. + +EPAC injects `deployedBy` into the `metadata` section. This is a string that identifies the deployment source. It defaults to `epac/$pacOwnerId/$pacSelector`. You can override this value in `global-settings.jsonc` + +**Not recommended:** Adding `deployedBy` to the `metadata` section in the Policy definition file will override the value for this definition only from `global-settings.jsonc` or default value. + ## Example ```json @@ -47,6 +55,19 @@ This schema is new in v7.4.x and may not be complete. Please let us know if we m "category": "Your Category" }, "parameters": { + "effect": { + "type": "String", + "metadata": { + "displayName": "Effect", + "description": "Enable or disable the execution of the policy", + }, + "allowedValues": [ + "Audit", + "Deny", + "Disabled" + ], + "defaultValue": "Audit" + }, "YourParameter": { "type": "String", "metadata": { @@ -60,11 +81,7 @@ This schema is new in v7.4.x and may not be complete. Please let us know if we m "Insert Logic Here" }, "then": { - "effect": "Audit, Deny, Modify, etc.", - "details": { - "roleDefinitionIds": [], - "operations": [] - } + "effect": "[parameters('effect')]", } } } diff --git a/Docs/policy-exemptions.md b/Docs/policy-exemptions.md index 14ba9fce..691d82c8 100644 --- a/Docs/policy-exemptions.md +++ b/Docs/policy-exemptions.md @@ -1,19 +1,10 @@ # Exemptions -## Exemption Files +## Exemption Folder Structure Exemptions can be defined as JSON or CSV files (we recommend that you use CSV files). The names of the definition files don't matter. If multiple files exists in a folder, the lists from all the files are added together. -The pacEnvironment (see global-settings.jsonc) is represented with a folder structure under the folder policyExemptions, such as epac-dev, tenant, ... A missing folder indicates that the pacEnvironment's Exemptions are not managed by this solution. To extract existing exemptions, the operations script Get-AzExemptions.ps1 can be used to generate JSON and CSV files. The output may be used to start the Exemption definitions. This same output is also created when [Extract existing Policy Resources from an Environment](extract-existing-policy-resources.md). - - -The `desiredState` in global-settings.json allows for some modifications to the behavior of exemptions at deployment. - -`deleteExpiredExemptions` - Default is true. When set to false, EPAC will not delete expired, owned exemptions. This is primarily used to prevent errors in EPAC deployments for organizations that choose to apply delete locks. - -`deleteOrphanedExemptions` - Default is true. When set to false, EPAC will not delete orphaned, owned exemptions. This is primarily used to prevent errors in EPAC deployments for organizations that choose to apply delete locks. - -EPAC will ignore all exemptions not owned by the executing pacOwnerId. +The pacEnvironment (see global-settings.jsonc) is represented with a folder structure under the folder policyExemptions, such as epac-dev, tenant, ... A missing folder indicates that the pacEnvironment's Exemptions are not managed by this solution. To extract existing exemptions, the operations script Get-AzExemptions.ps1 can be used to generate JSON and CSV files. The output may be used to start the Exemption definitions. This same output is also created when [Extract existing Policy Resources from an Environment](epac-extracting-policy-resources.md). A typical folder structure might look like this: @@ -26,22 +17,6 @@ Definitions .csv of .json ``` -## CSV Format - -We recommend that you use spreadsheets (`.csv`). The columns must have the following headers: - -* `name` - unique name. -* `displayName` - descriptive name displayed on portal. -* `exemptionCategory` - `waiver` or `mitigated`. -* `expiresOn` - empty or expiry date. -* `scope` - Management Group, subscription, Resource Group or resource. -* `policyAssignmentId` - fully qualified assignment id. -* `policyDefinitionReferenceIds` use comma separated list within each cell. -* `metadata` - valid JSON (see JSON format below) -* Optional - * `assignmentScopeValidation` - `Default` or `DoNotValidate` - * `resourceSelectors` - valid JSON (see JSON format below) - ## JSON Schema The GitHub repo contains a JSON schema which can be used in tools such as [VS Code](https://code.visualstudio.com/Docs/languages/json#_json-schemas-and-settings) to provide code completion. @@ -54,31 +29,156 @@ To utilize the schema add a ```$schema``` tag to the JSON file. } ``` -This schema is new in v7.4.x and may not be complete. Please let us know if we missed anything. +## Defining Exemptions + +> [!TIP] +> In v10.0.0, exemptions can be defined by specifying the Policy definition Ids or Names instead of Policy Assignment Ids. This significantly reduces the complexity of defining exemptions for Policy Sets with overlapping Policy definitions. **We recommend using Policy definition Ids or Names for new exemptions.** + +Each exemption must define the following properties: +- `name` - unique name, we recommend a GUID. +- `displayName` - descriptive name displayed on portal. +- `exemptionCategory` - `Waiver` or `Mitigated`. +- Policy or Policies to be exempted +- `scope` - Management Group, subscription, Resource Group or resource. +- `metadata` - valid JSON (see JSON format below) +- Optional + - `expiresOn` - empty or expiry date. + - `assignmentScopeValidation` - `Default` or `DoNotValidate` + - `resourceSelectors` - valid JSON (see JSON format below) + +### Specifying Policy or Policies to be Exempted + +The following properties can be used to specify the Policy or Policies to be exempted: + +- Option **A**: Policy definition Ids or Names (**recommended**) +- Option **B**: Policy Assignment Id and for Policy Sets a list of Policy definition Ids or Names, or policyDefinitionReferenceIds (**legacy - no longer recommended**) +- Option **C**: Policy Set definition Ids or Names and a list of Policy definition Ids or Names, or policyDefinitionReferenceIds (**included for completeness, do not use**) + +## Metadata + +You can use `metadata` for additional information. + +EPAC injects `deployedBy` into the `metadata` section. This is a string that identifies the deployment source. It defaults to `epac/$pacOwnerId/$pacSelector`. You can override this value in `global-settings.jsonc` + +**Not recommended:** Adding `deployedBy` to the `metadata` section in the Policy definition file will override the value for this Exemption only from `global-settings.jsonc` or default value. + +### CSV Format + +The columns must have the headers as described above. The order of the columns is not important. + +#### Regular Columns + +- `name` - unique name, we recommend a GUID. +- `displayName` - descriptive name displayed on portal. +- `exemptionCategory` - `Waiver` or `Mitigated`. +- `scope` - Management Group, subscription, Resource Group or resource. +- `metadata` - valid JSON (see JSON format below) +- Optional + - `expiresOn` - empty or expiry date. + - `assignmentScopeValidation` - `Default` or `DoNotValidate` + - `resourceSelectors` - valid JSON (see JSON format below) + +#### Option A: Policy definition Ids or Names -## JSON Format +- Column `assignmentReferenceId` must be formatted: + - For Built-in Policy definition: `/providers/Microsoft.Authorization/policyDefinitions/00000000-0000-0000-0000-000000000000` + - For Custom Policy definition: `policyDefinitions/{{policyDefinitionName}}` +- Column `policyDefinitionReferenceIds` must be empty -`name`, `displayName`, `exemptionCategory`, `scope` and `policyAssignmentId` are required fields. The others are optional. +#### Option B: Policy Assignment Id + +- Column `assignmentReferenceId` must be a Policy Assignment Id: + - `/providers/Microsoft.Management/managementGroups/{{managementGroupId}}/providers/Microsoft.Authorization/policyAssignments/{{policyAssignmentName}}` +- Column `policyDefinitionReferenceIds` must be a comma separated list containing any of the following: + - Empty for Policy Assignment of a single Policy, or to exempt the scope from every Policy in the assigned Policy Set + - policyDefinitionReferenceId from the assigned Policy Set definition + - For Built-in Policy definition: `/providers/Microsoft.Authorization/policyDefinitions/00000000-0000-0000-0000-000000000000` + - For Custom Policy definition: `policyDefinitions/{{policyDefinitionName}}` + +#### Option C: Policy Set definition Ids or Names + +- Column `assignmentReferenceId` must be a Policy Set definition Id or Name: + - For Built-in Policy Set definition: `/providers/Microsoft.Authorization/policySetDefinitions/00000000-0000-0000-0000-000000000000` + - For Custom Policy Set definition: `policySetDefinitions/{{policySetDefinitionName}}` +- Column `policyDefinitionReferenceIds` must be a comma separated list containing any of the following: + - Empty for Policy Assignment of a single Policy, or to exempt the scope from every Policy in the assigned Policy Set + - policyDefinitionReferenceId from the assigned Policy Set definition + - For Built-in Policy definition: `/providers/Microsoft.Authorization/policyDefinitions/00000000-0000-0000-0000-000000000000` + - For Custom Policy definition: `policyDefinitions/{{policyDefinitionName}}` + +### JSON Format + +The fields are the same as the CSV format: + +- `name` - unique name, we recommend a GUID. +- `displayName` - descriptive name displayed on portal. +- `exemptionCategory` - `Waiver` or `Mitigated`. +- `scope` - Management Group, subscription, Resource Group or resource. +- `metadata` - valid JSON (see JSON format below) +- Optional + - `expiresOn` - empty or expiry date. + - `assignmentScopeValidation` - `Default` or `DoNotValidate` + - `resourceSelectors` - valid JSON (see JSON format below) + +#### Option A: Policy definition Ids or Names + +- For built-in Policy definitions: `policyDefinitionId` +- For custom Policy definitions: `policyDefinitionName` +- Omit `policyDefinitionReferenceIds`. + +#### Option B: Policy Assignment Id + +- `policyAssignmentId` - Policy Assignment Id +- Omit `"policyDefinitionReferenceIds": [ ... ]` for Policy Assignment of a single Policy, or to exempt the scope from every Policy in the assigned Policy Set +- For Policy Set Assignments only: `"policyDefinitionReferenceIds": [ ... ]` containing an array following: + - policyDefinitionReferenceId from the assigned Policy Set definition + - For Built-in Policy definition: `"/providers/Microsoft.Authorization/policyDefinitions/00000000-0000-0000-0000-000000000000"` + - For Custom Policy definition: `"policySetDefinitions/{{policySetDefinitionName}}"` + +#### Option C: Policy Set definition Ids or Names + +- For built-in Policy Set definitions: `policySetDefinitionId` +- For custom Policy Set definitions: `policySetDefinitionName` +- Omit `"policyDefinitionReferenceIds": [ ... ]` to exempt the scope from every Policy in the assigned Policy Set +- To select the Policies within the Policy set to exempt `"policyDefinitionReferenceIds": [ ... ]` containing an array following: + - policyDefinitionReferenceId from the assigned Policy Set definition + - For Built-in Policy definition: `"/providers/Microsoft.Authorization/policyDefinitions/00000000-0000-0000-0000-000000000000"` + - For Custom Policy definition: `"policySetDefinitions/{{policySetDefinitionName}}"` + +#### Example ```json { "exemptions": [ { - "name": "Unique name", + "name": "00000000-0000-0000-0000-000000000000", + "displayName": "Descriptive name displayed on portal", + "description": "More details", + "exemptionCategory": "Waiver", + "scope": "/subscriptions/11111111-2222-3333-4444-555555555555", + "policyDefinitionId": "/providers/microsoft.authorization/policyDefinitions/00000000-0000-0000-0000-000000000000", + }, + { + "name": "00000000-0000-0000-0000-000000000001", + "displayName": "Descriptive name displayed on portal", + "description": "More details", + "exemptionCategory": "Mitigated", + "scope": "/subscriptions/11111111-2222-3333-4444-555555555555", + "policyDefinitionName": "policyDefinitionName", + "expiresOn": "2022-12-31T23:59:59Z", + "assignmentScopeValidation": "DoNotValidate", + }, + { + "name": "00000000-0000-0000-0000-000000000002", "displayName": "Descriptive name displayed on portal", "description": "More details", - "exemptionCategory": "waiver", + "exemptionCategory": "Mitigated", "scope": "/subscriptions/11111111-2222-3333-4444-555555555555", - "policyAssignmentId": "/providers/microsoft.management/managementgroups/contoso-prod/providers/microsoft.authorization/policyassignments/prod-asb", + "policyAssignmentId": "/providers/microsoft.authorization/policyAssignments/{{assignmentName}}}}", "policyDefinitionReferenceIds": [ - "webApplicationFirewallShouldBeEnabledForApplicationGatewayMonitoringEffect" - ], - "metadata": { - "custom": "value" - }, - "assignmentScopeValidation": "Default", - "resourceSelectors": [ - // see Microsoft documentation for details + "/providers/microsoft.authorization/policyDefinitions/00000000-0000-0000-0000-000000000000", + "policyDefinitions/{{policyDefinitionName}}", + "{{policyReferenceId}}" ] } ] diff --git a/Docs/policy-set-definitions.md b/Docs/policy-set-definitions.md index 0a41d243..caf24bab 100644 --- a/Docs/policy-set-definitions.md +++ b/Docs/policy-set-definitions.md @@ -4,32 +4,25 @@ Policy Set definition files are managed within the folder `policySetDefinitions` under `Definitions`. The definition files are structured based on the official [Azure Initiative definition structure](https://docs.microsoft.com/en-us/azure/governance/policy/concepts/initiative-definition-structure) published by Microsoft. There are numerous definition samples available on Microsoft's [GitHub repository for azure-policy](https://github.com/Azure/azure-policy/tree/master/built-in-policies/policySetDefinitions). -!!! note - When authoring Policy or Policy Set definitions, check out the [Maximum count of Azure Policy objects](https://docs.microsoft.com/en-us/azure/governance/policy/overview#maximum-count-of-azure-policy-objects) +> [!TIP] +> When authoring Policy or Policy Set definitions, check out the [Maximum count of Azure Policy objects](https://docs.microsoft.com/en-us/azure/governance/policy/overview#maximum-count-of-azure-policy-objects) The names of the definition JSON files don't matter, the Policy Sets are registered based on the `name` attribute. The solution also allows the use of JSON with comments by using `.jsonc` instead of `.json` for the file extension. +### Policy Definition Groups + **Optional:** Policy definition groups allow custom Policy Sets to map to different regulatory compliance requirements. These will show up in the regulatory compliance blade in Azure Security Center as if they were built-in. In order to use this, the custom Policy Sets must have both policy definition groups and group names defined. -* Policy definition groups must be pulled from a built-in Policy Sets such as the Azure Security Benchmark initiative ([Azure Initiative definition structure](https://docs.microsoft.com/en-us/azure/governance/policy/concepts/initiative-definition-structure) published by Microsoft). There are numerous definition samples available on Microsoft's [GitHub Azure Security Benchmark Code](https://github.com/Azure/azure-policy/blob/master/built-in-policies/policySetDefinitions/Security%20Center/AzureSecurityCenter.json). -* Policy definition groups can be imported by using `importPolicyDefinitionGroups`. The following imports the groups from Azure Security Benchmark. +- Policy definition groups must be pulled from a built-in Policy Sets, such as, the [`Microsoft cloud security benchmark` Policy Set](https://github.com/Azure/azure-policy/blob/master/built-in-policies/policySetDefinitions/Security%20Center/AzureSecurityCenter.json). +- Policy definition groups can be imported by using `importPolicyDefinitionGroups`. The following imports the groups from Azure Security Benchmark. -```json - "importPolicyDefinitionGroups": [ - // built-in Policy Set definition (ASB v3) - "/providers/Microsoft.Authorization/policySetDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8" - ], +```jsonc +"importPolicyDefinitionGroups": [ + // built-in Policy Set definition "Microsoft cloud security benchmark" + "/providers/Microsoft.Authorization/policySetDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8" +], ``` -## Recommendations - -* `"name"` is required and should be unique. It can be a GUID or a unique short name. -* `"category"` should be one of the standard ones defined in built-in Policies. -* Custom Policies: use `policyDefinitionName`. The solution constructs the `policyDefinitionId` based on the `deploymentRootScope` in `global-settings.jsonc`. -* Builtin Policies: use `policyDefinitionId`. The solution can constructs the `policyDefinitionId` from `policyDefinitionName` for builtin Policies; however using `policyDefinitionId` is more explicit/cleaner. -* Do **not** specify an `id`. The solution will ignore it. -* Make the `effects` parameterized - ## JSON Schema The GitHub repo contains a JSON schema which can be used in tools such as [VS Code](https://code.visualstudio.com/Docs/languages/json#_json-schemas-and-settings) to provide code completion. @@ -42,7 +35,22 @@ To utilize the schema add a ```$schema``` tag to the JSON file. } ``` -This schema is new in v7.4.x and may not be complete. Please let us know if we missed anything. +## Recommendations + +* `"name"` is required and should be unique. It can be a GUID or a unique short name. +* `"category"` should be one of the standard ones defined in built-in Policies. +* Custom Policies: must use `policyDefinitionName`. The solution constructs the `policyDefinitionId` based on the `deploymentRootScope` in `global-settings.jsonc`. +* Builtin Policies: must use `policyDefinitionId`. +* Do **not** specify an `id`. The solution will ignore it. +* Make the `effects` parameterized + +## Metadata + +It is customary to include a `category` and a `version` in the `metadata` section. The `category` should be one of the standard ones defined in built-in Policy Sets. The `version` should be a semantic version number. + +EPAC injects `deployedBy` into the `metadata` section. This is a string that identifies the deployment source. It defaults to `epac/$pacOwnerId/$pacSelector`. You can override this value in `global-settings.jsonc` + +**Not recommended:** Adding `deployedBy` to the `metadata` section in the Policy definition file will override the value for this definition only from `global-settings.jsonc` or default value. ## Example diff --git a/Docs/quick-start.md b/Docs/quick-start.md deleted file mode 100644 index c374a0df..00000000 --- a/Docs/quick-start.md +++ /dev/null @@ -1,110 +0,0 @@ -# Getting Started - -EPAC scripts can be installed in the following ways: - -* Install the `EnterprisePolicyAsCode` module from the [PowerShell marketplace](https://www.powershellgallery.com/packages/EnterprisePolicyAsCode). This is the recommended approach documented in step 3 below. -* Copy the source code from the [EPAC GitHub repository](https://github.com/Azure/enterprise-azure-policy-as-code). The process is described in [Alternate Script Installation](clone-github.md) page. That process replaces step 4 below. - -## EPAC Quick Start - -In this quick start you can get set up with EPAC and use it to extract the policies and assignments in your own environment. From that point you can either choose to let EPAC manage the policies or look at some of the more advanced features allowing you to complete a gradual rollout. - -For this example all you need is ```Reader``` permission in your Azure environment and to follow the steps below. - -1. [Install PowerShell 7](https://github.com/PowerShell/PowerShell/releases). -2. Install the Az PowerShell modules and connect to Azure. -```ps1 - Install-Module Az -Scope CurrentUser - Connect-AzAccount -``` -3. Install the Enterprise Policy as Code module. -```ps1 - Install-Module EnterprisePolicyAsCode -Scope CurrentUser -``` -4. Many scripts use parameters for input and output folders. They default to the current directory. We recommend that you do one of the following approaches instead of accepting the default to prevent your files being created in the wrong location: - - Set the environment variables `PAC_DEFINITIONS_FOLDER`, `PAC_OUTPUT_FOLDER`, and `PAC_INPUT_FOLDER`. - - Use the script parameters `-DefinitionsRootFolder`, `-OutputFolder`, and `-InputFolder`. - -5. Create a new EPAC definitions folder to hold policy objects. -```ps1 - New-EPACDefinitionFolder -DefinitionsRootFolder Definitions -``` -6. This will create a folder called ```Definitions``` with a number of subfolder and a ```global-settings.jsonc``` file where the environment is defined. -7. Edit the ```global-settings.jsonc``` file by copying the sample below. Modify the commented sections as appropriate. -```json - { - "$schema": "https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/main/Schemas/global-settings-schema.json", - "pacOwnerId": "f2ce1aea-944e-4517-94fb-edada00633ae", // Generate a guid using New-Guid and place it here - "managedIdentityLocations": { - "*": "australiaeast" // Update the default location for managed identities - }, - "globalNotScopes": { - "*": [ - "/resourceGroupPatterns/excluded-rg*" - ] - }, - "pacEnvironments": [ - { - "pacSelector": "quick-start", - "cloud": "AzureCloud", - "tenantId": "bdb8ea1c-17da-4423-8895-6b79af002b4e", // Replace this with your tenant Id - "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/root" // Replace this with a management group that represents the functional root in your environment. - } - ] - } -``` -8. Extract all the existing policies and assignments at the scope indicated above by running the script below. -```ps1 - Export-AzPolicyResources -DefinitionsRootFolder .\Definitions -OutputFolder Output -``` - -In the ```Output``` folder you should now find all the custom policy definitions and assignments which have been deployed in your environment. From this point you can make some choices about how to best utilize EPAC to handle Azure Policy in your environment including:- - -- Copy the Output files into the appropriate folders in your ```Definitions``` folder and use the ```Build-DeploymentPlans``` command to generate a plan for policy deployment. Once the plan is generated you can use the ```Deploy-PolicyPlan``` and ```Deploy-RolesPlan``` commands to start managing deployed policies with EPAC. -- Read up on [Desired State Strategy](desired-state-strategy.md) and plan a gradual rollout of policy using EPAC. -- Use the artifacts in the [Starter Kit](https://github.com/Azure/enterprise-azure-policy-as-code/tree/main/StarterKit) for some in-depth examples and sample pipelines for CI/CD integration. -- Review the rest of this documentation to examine some of the more complex EPAC features. - -If there are any issue please raise them in the (GitHub Repository)[https://github.com/Azure/enterprise-azure-policy-as-code/issues]. - -## Create your environment - -* [Setup DevOps Environment](operating-environment.md) for your developers (on their workstations) and your CI/CD pipeline runners/agents (on a VM or set of VMs) to facilitate correct implementations.
**Operating Environment Prerequisites:** The EPAC Deployment process is designed for DevOps CI/CD. It requires the installation of several tools to facilitate effective development, testing, and deployment during the course of a successful implementation. -* Acquire the PowerShell scripts (options) - * [Import Azure PowerShell Module](powershell-module.md) - * [Create a source repository and import the source code](clone-github.md) from this repository. - -## Define your deployment scenarios - -* [Select the desired state strategy](desired-state-strategy.md). -* [Define your deployment environment](definitions-and-global-settings.md) in `global-settings.jsonc`. - -## Create the CI/CD (skip if using the semi-automated approach) - -* Copy starter kit pipeline definition and definition folder to your folders. -* [Build your CI/CD pipeline](ci-cd-pipeline.md) using a starter kit. - -## Build your definitions and assignments - -* Generate a starting point for the `Definitions` subfolders: - * [Extract existing Policy resources from an environment](extract-existing-policy-resources.md). - * [Import Policies from the Cloud Adoption Framework](integrating-with-alz.md). - * Use the sample Policy resource definitions in the starter kit. - * Start from scratch. -* [Add custom Policies](policy-definitions.md). -* [Add custom Policy Sets](policy-set-definitions.md). -* [Create Policy Assignments](policy-assignments.md). - -## Manage your Policy environment - -* [Manage Policy Exemptions](policy-exemptions.md). -* [Document your deployments](documenting-assignments-and-policy-sets.md). -* [Execute operational tasks](operational-scripts.md). - -## Debug EPAC issues - -Should you encounter issues with the expected behavior of EPAC, try the following: - -* Run the scripts interactively. -* [Debug the scripts in VS Code](https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/vscode/using-vscode?view=powershell-7.3). -* Ask for help by raising a [GitHub Issue](https://github.com/Azure/enterprise-azure-policy-as-code/issues/new) diff --git a/Docs/desired-state-strategy.md b/Docs/settings-desired-state.md similarity index 52% rename from Docs/desired-state-strategy.md rename to Docs/settings-desired-state.md index 91138bbe..6dfd1879 100644 --- a/Docs/desired-state-strategy.md +++ b/Docs/settings-desired-state.md @@ -1,83 +1,122 @@ -# Desired State Strategy +# Desired State Management -Desired State strategy enables shared responsibility scenarios. the following documents the archetypical use cases. For complex scenarios it is possible to combine multiple use cases. +> [!CAUTION] +> EPAC is a true desired state deployment technology. It takes possession of all Policy Resources at the `deploymentRootScope` and its children. It will delete any Policy resources not defined in the EPAC repo. -## Use Case 1: Centralized Team +Desired State strategy enables you to adjust the default behavior to fit more complex scenarios, including shared responsibility scenarios. The use cases below show the archetypical use cases. For complex scenarios it is possible to combine multiple use cases. -This original (previously the only) use case assumes one team/repo manages all Policies in a tenant or multiple tenants. `global-settings.jsonc` must ***not*** contain the following entries: +## The `desiredState` Element -* `inheritedDefinitionsScopes` -* `desiredState` +`pacEnvironments` must contain a `desiredState` element. -## Use case 2: Manage Policy Definitions, Assignments, or Exemptions differently +- Required: + - `strategy`: The strategy to use for managing Policy resources. The following values are supported: + - `full`: EPAC manages all Policy resources in the `deploymentRootScope` and its children. EPAC deletes any Policy resources not defined in the EPAC repo. + - `ownedOnly`: EPAC manages only Policy resources defined in the EPAC repo. EPAC does not delete any Policy resources not defined in the EPAC repo. + - `keepDfcSecurityAssignments`: It is recommended that Security and Compliance Initiatives are managed at management group levels with EPAC. Please read [Managing Defender for Cloud Assignments](settings-dfc-assignments.md). +- Optional: + - `excludedScopes`: An array of scopes to exclude from management by EPAC. The default is an empty array. Wild cards are supported. + - `excludedPolicyDefinitions`: An array of Policy Definitions to exclude from management by EPAC. The default is an empty array. Wild cards are supported. + - `excludedPolicySetDefinitions`: An array of Policy Set Definitions to exclude from management by EPAC. The default is an empty array. Wild cards are supported. + - `excludedPolicyAssignments`: An array of Policy Assignments to exclude from management by EPAC. The default is an empty array. Wild cards are supported. -In some organizations the lifecycle of different parts may be managed separately. For example, you may have one repo to manage Definitions and Assignments separately from Exemptions. Since the ownership of Exemptions is managed from the Assignment `pacOwnerId`, changing it is not effective. +The following example shows the `desiredState` element with all properties set: -EPAC only manages items with a directory in the `Definitions` folder. Therefore, you can use the same `pacOwnerId` from two repos and remove the folders to separate them. In this example: +```json +"desiredState": { + "strategy": "full", + "keepDfcSecurityAssignments": false, + "excludedScopes": [], + "excludedPolicyDefinitions": [], + "excludedPolicySetDefinitions": [], + "excludedPolicyAssignments": [] +} +``` -* Repo1: `Definitions` contains `policyDefinitions`, `policySetDefinitions` and `policyAssignments` folders. -* Repo2: `Definitions` contains `policyExemptions` folder. +## Transitioning to EPAC -Policy resource that would be defined in the folder. It is important to remove the folders. GitHub repos remove empty folder automatically. +While transitioning to EPAC, existing Policy resources may need to be kept. Setting `desiredState` to `ownedOnly` allows EPAC to remove its own resources while preserving instances requiring (temporary) preservation. -If you have an empty folder or a folder with a file extension not recognized by EPAC, EPAC will delete any item which the folder could define from your environment. -## Use case 3: Include Resource Groups +```json +"desiredState": { + "strategy": "ownedOnly", + "keepDfcSecurityAssignments": false +} +``` -By default, Policy Assignments at resource groups are not managed by EPAC. Prior to v6.0, managing resource groups was to expensive. **Breaking change:** If you used the `-IncludeResourceGroup` switch in prior versions, set `includeResourceGroups` to `true` to achieve the same effect. We also recommend this for new installations. +After short transitioning period (weeks), it is recommended to set `desiredState` to `full` to allow EPAC to manage all Policy resources. ```json "desiredState": { "strategy": "full", - "includeResourceGroups": true + "keepDfcSecurityAssignments": false } ``` -## Use Case 4: Multiple Teams with Shared Responsibility - -In a shared responsibility model multiple teams manage the same tenant(s) at the same scope. Additionally, a variant of this use case is well suited to what previously was called `brownfield` which needs to preserve Policy resources deployed prior to EPAC. The following diagram shows two EPAC solutions managing the same root (tenant). Other Policy as Code solutions can also participate if the solution sets `metadata.pacOwnerId`. - -![image.png](Images/shared-responsibility.png) +## Exclude Resource Groups -For standard behavior where each repo manages, no additional entries in `global-settings.jsonc` are necessary since the default strategy `full` is the default. `full` deletes any Policy resources without a `pacOwnerId`; however, id does not delete Policy resources with a different `pacOwnerId`. +> [!CAUTION] +> **Breaking change in v10.0.0:** Starting in v10.0.0 Policy Assignments at resource groups are **managed** by EPAC. The elemenent `includeResourceGroups` has been deprecated and removed. -You may add the following JSON for clarity/documentation of the default behavior. +To exclude resource groups from management by EPAC, add an `excludedScopes` array element with a wild card for the subscription and resourceGroups to `desiredState`. ```json "desiredState": { - "strategy": "full" + "excludedScopes": [ + "/subscriptions/*/resourceGroups/*" + ] } ``` -## Use Case 5: Multiple Teams in a Hierarchical Organization +## Use Case 1: Centralized Team -The hierarchical model allows a central team to manage the commonality while giving parts of the organization a capability to further restrict resources with Policies. This is a common scenario in multi-national corporations with additional jurisdictional requirements (e.g., data sovereignty, local regulations, ...). +This original (previously the only) use case assumes one team/repo manages all Policies in a tenant or multiple tenants. Omit `desiredState` and `inheritedDefinitionsScopes`. -Additionally, it is possible for a solution at a child scope to inherit Policy definitions. +## Use case 2: Manage Policy Definitions, Assignments, or Exemptions differently -![image.png](Images/shared-hierarchical.png) +In some organizations the lifecycle of different parts may be managed separately. For example, you may want to manage Definitions and Assignments separately from Exemptions. -Repo A is managed the same as in use cases 1, 2 and 2a. Repo C sets sets the same as repo B in use case 2 or 2a. If inheriting Policy definitions from the parent EPAC solution, add `inheritedDefinitionsScopes` to `global-settings.jsonc`. Inherited definition scopes used but not managed by this repository, scopes must be visible from `deploymentRootScope`. +### Using Advanced CI/CD Pipelines (Recommended) -```json -"inheritedDefinitionsScopes": [], -"desiredState": { - "strategy": "full" -} -``` +[Advanced CI/CD Pipelines with Release Flow](ci-cd-overview.md#advanced-cicd-with-release-flow) can be used to fast-track Exemptions while keeping a regular lifecycle for Definitions and Assignments. Script `Build-DeploymentPlans` has a parameter `BuildExemptionsOnly` to deploy only Exemptions. -## Use Case 6: Transitioning to EPAC +### Using separate Repos -While transitioning to EPAC, existing Policy resources may need to be kept. Setting `desiredState` to `ownedOnly` allows EPAC to remove its own resources while preserving instances requiring (temporary) preservation. +In some organizations the lifecycle of different parts may be managed separately. For example, you may have one repo to manage Definitions and Assignments separately from Exemptions. Changing `pacOwnerId` is not effective. +EPAC only manages items with a directory in the `Definitions` folder. Therefore, you can use the same `pacOwnerId` from two repos and remove the folders to separate them. In this example: -```json -"desiredState": { - "strategy": "ownedOnly" -} -``` +* Repo1: `Definitions` contains `policyDefinitions`, `policySetDefinitions` and `policyAssignments` folders. +* Repo2: `Definitions` contains `policyExemptions` folder. + +Policy resource that would be defined in the folder. It is important to remove the folders. GitHub repos remove empty folder automatically. -## Use Case 7: Exclude some Scopes and Policy Resources +If you have an empty folder or a folder with a file extension not recognized by EPAC, EPAC will delete any item which the folder could define from your environment. + +## Use Case 3: Multiple Teams with Shared Responsibility + +In a shared responsibility model multiple teams manage the same tenant(s) at the same scope. Additionally, a variant of this use case is well suited to what previously was called `brownfield` which needs to preserve Policy resources deployed prior to EPAC. The following diagram shows two EPAC solutions managing the same root (tenant). Other Policy as Code solutions can also participate if the solution sets `metadata.pacOwnerId`. + +![image.png](Images/shared-responsibility.png) + +For standard behavior where each repo manages, no additional entries in `global-settings.jsonc` are necessary since the default strategy `full` is the default. `full` deletes any Policy resources without a `pacOwnerId`; however, id does not delete Policy resources with a different `pacOwnerId`. +[test](settings-desired-state.md#use-case-4-multiple-teams-in-a-hierarchical-organization) + +## Use Case 4: Multiple Teams in a Hierarchical Organization + +The hierarchical model allows a central team to manage the commonality while giving parts of the organization a capability to further restrict resources with Policies. This is a common scenario in multi-national corporations with additional jurisdictional requirements (e.g., data sovereignty, local regulations, ...). + +This is managed identical to use case 3. + +> [!WARNING] +> Previously, it was possible for a solution at a child scope to inherit Policy definitions form EPAC-A. This feature has been removed in v10.0.0 since it was not possible to manage the dependencies between Policy and Policy Set definitions and Policy Assignments correctly. +> +> To replicate the previous functionality, copy/replicate the custom Policy and Policy Set definitions files from EPAC-A repo to EPAC-C repo. + +![image.png](Images/shared-hierarchical.png) + +## Use Case 5: Exclude some Scopes and Policy Resources In rare cases you may need to exclude individual child scopes, or Policy resources from management by an EPAC solution. @@ -85,7 +124,7 @@ In rare cases you may need to exclude individual child scopes, or Policy resourc Child scope is managed by some other means. The use of a EPAC development Management Group under the same root is such an example. Another example is a child scope managed by a different organization not subject to the root scope Policies. -You use `globalNotScopes` to exclude a child scope from management by EPAC. The following example excludes the `childScope` from management by EPAC. See also [Definitions and Global Settings](definitions-and-global-settings.md#global-settings) +You use `globalNotScopes` to exclude a child scope from management by EPAC. The following example excludes the `childScope` from management by EPAC. See also [Global Settings](settings-global-setting-file.md) ```json "globalNotScopes": { @@ -106,8 +145,6 @@ This happens when EPAC `strategy` is `full` and some child scopes contain Policy You can exclude any combination of `excludedScopes`, `excludedPolicyDefinitions`, `excludedPolicySetDefinitions` and `excludedPolicyAssignments`. Any of the strings can contain simple wild cards. -Examples - ```json "desiredState": { "strategy": "full", @@ -128,4 +165,3 @@ Examples ``` ![image.png](Images/shared-excluded.png) - diff --git a/Docs/settings-dfc-assignments.md b/Docs/settings-dfc-assignments.md new file mode 100644 index 00000000..f8826ea7 --- /dev/null +++ b/Docs/settings-dfc-assignments.md @@ -0,0 +1,30 @@ +# Managing Defender for Cloud Assignments + +Defender for Cloud (DFC) is a suite of Azure Security Center (ASC) capabilities that helps you prevent, detect, and respond to threats. It provides you with integration of Microsoft's threat protection technology and expertise. For more information, see [Azure Defender for Cloud](https://docs.microsoft.com/en-us/azure/security-center/defender-for-cloud). + +## Defender for Cloud Assignments for Defender Plans + +> [!NOTE] +> DfC manages the Policy Assignments for Defender Plans when a plan is enabled. EPAC v9.0.0 and later **never** manage these Policy Assignments. + +![image.png](Images/dfc-defender-plans-settings.png) + +## Defender for Cloud Security Policy Assignments + +DfC automatically assigns `Microsoft cloud security benchmark` to each new subscription enrolled in Defender for Cloud. It also adds compliance Assignments when a Compliance framework is enabled, such as NIST 800-53 Rev 5, NIST 800-171, etc. + +These Assignments are enabled/created at the subscription level or at management group level. Since these Policies are set to to `Audit` and you will want to set many of them to `Deny`, it is recommended that EPAC manages them at the management group level. This is the default behavior. + +> [!WARNING] +> EPAC behavior for Security Policy **is controlled by** the `keepDfcSecurityAssignments` in `desiredState`. + +- If set to `true` or `strategy` is `ownedOnly`, EPAC will **not** remove "DfC Security Policy Assignments" created by Defender for Cloud. +- If **omitted** or **set to `false`** and `strategy` is `full`, EPAC will remove "DfC Security Policy Assignments" created by Defender for Cloud. + +```json +"desiredState": { + "keepDfcSecurityAssignments": true +} +``` + +![image.png](Images/dfc-security-policy-sets-settings.png) diff --git a/Docs/settings-global-setting-file.md b/Docs/settings-global-setting-file.md new file mode 100644 index 00000000..18333bf8 --- /dev/null +++ b/Docs/settings-global-setting-file.md @@ -0,0 +1,183 @@ +# Global Settings + +## Overview + +`global-settings.jsonc` has following sections explained below: + +- `telemetryOptOut` if set to true disables the collection of usage date for the EPAC repo. The default is false. See [Usage Tracking](usage-tracking.md) for more information. +- `pacOwnerId` uniquely identifies deployments from a specific repo. We recommend using a GUID. +- `pacEnvironments` defines the EPAC environments. + +### Example with Required Elements + +```json +{ + "$schema": "https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/main/Schemas/global-settings-schema.json", + "pacOwnerId": "00000000-0000-0000-0000-000000000000", + "pacEnvironments": [ + { + "pacSelector": "epac-dev", + "cloud": "AzureCloud", + "tenantId": "00000000-0000-0000-0000-000000000000", + "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/mg-Epac-Dev", + "desiredState": { + "strategy": "full", + "keepDfcSecurityAssignments": false + }, + "managedIdentityLocation": "eastus2" + }, + { + "pacSelector": "tenant", + "cloud": "AzureCloud", + "tenantId": "00000000-0000-0000-0000-000000000000", + "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/mg-Enterprise", + "desiredState": { + "strategy": "full", + "keepDfcSecurityAssignments": false + }, + "managedIdentityLocation": "eastus2", + "globalNotScopes": [ + "/providers/Microsoft.Management/managementGroups/mg-Epac-Dev" + ] + } + ] +} +``` + +## JSON Schema + +The GitHub repo contains a JSON schema which can be used in tools such as [VS Code](https://code.visualstudio.com/Docs/languages/json#_json-schemas-and-settings) to provide code completion. + +To utilize the schema add a ```$schema``` tag to the JSON file. + +``` +{ + "$schema": "https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/main/Schemas/global-settings-schema.json" +} +``` + +## Opt out of telemetry data collection `telemetryOptOut` + +Starting with v8.0.0, Enterprise Policy as Code (EPAC) is tracking the usage using Customer Usage Attribution (PID). See [Usage Tracking](epac-overview.md#telemetry-tracking-using-customer-usage-attribution-pid) for more information on opt out. Default is false. + +```json +"telemetryOptOut": true, +``` + +## Uniquely identify deployments with `pacOwnerId` + +`pacOwnerId` is required for [desired state handling](settings-desired-state.md) to distinguish Policy resources deployed via this EPAC repo, legacy technology, another EPAC repo, or another Policy as Code solution. + +## Define EPAC Environments in `pacEnvironments` + +EPAC has a concept of an environment identified by a string (unique per repository) called `pacSelector`. The `pacSelector` is just a name. We highly recommend to call the Policy development environment `epac-dev`, you can name the EPAC prod environments in a way which makes sense to you in your environment. We use `tenant`, in our samples and documentation. These names are used and therefore must match: + +- Defining the association (`pacEnvironments`) of an EPAC environment. +- Script parameter when executing different deployment stages in a CI/CD pipeline or semi-automated deployment targeting a specific EPAC environments. +- `scopes`, `notScopes`, `additionalRoleAssignments`, `managedIdentityLocations`, and `userAssignedIdentity` definitions in Policy Assignment JSON files. + +`pacEnvironments` entries associate: + +- Required: + - `pacSelector`: the logical name of the EPAC environment. + - `cloud`: select cloud environments. + - `tenantId`: enables multi-tenant scenarios. + - `deploymentRootScope`: the deployment scope for Policy and Policy Set definitions. Policy Assignments can only defined at this scope and child scopes (recursive). + - `desiredState`: defines the desired state strategy. + - `strategy`: see [Desired State Strategy](settings-desired-state.md). + - `keepDfcSecurityAssignments`: see [Managing Defender for Cloud Policy Assignments](settings-dfc-assignments.md). + - `managedIdentityLocation`: see [DeployIfNotExists and Modify Policy Assignments need `managedIdentityLocation`](settings-global-setting-file.md#deployifnotexists-and-modify-policy) +- Optional: + - `globalNotScopes`: see [Excluding scopes for all Assignments with `globalNotScopes`](settings-global-setting-file.md#excluding-scopes-for-all-assignments-with-globalnotscopes). + - `deployedBy`: populates the `metadata` fields. It defaults to `epac/$pacOwnerId/$pacSelector`. We recommend to use the default. + - Policy Definitions, Policy Set Definitions and Policy Exemptions - `metadata.deployedBy`. + - Policy Assignments - `metadata.assignedBy` since Azure Portal displays it as 'Assigned by'. + - Role Assignments - add the value to the `description` field since Role assignments do not contain `metadata`. + - `managedTenant`: Used when the `pacEnvironment` is in a lighthouse managed tenant, [see this example](#example-for-lighthouse-manged-tenant) It must contain: + - `managingTenantId` - The tenantId of the managing tenant. + - `managingTenantRootScope` - An array of all subscriptions that will need `additionalRoleAssignments` deployed to them. + +### DeployIfNotExists and Modify Policy Assignments need `managedIdentityLocation` + +Policies with `Modify` and `DeployIfNotExists` effects require a Managed Identity for the remediation task. This section defines the location of the managed identity. It is often created in the tenant's primary location. This location can be overridden in the Policy Assignment files. The star in the example matches all `pacEnvironmentSelector` values. + +```json + "managedIdentityLocation": { + "*": "eastus2" + }, +``` + +### Excluding scopes for all Assignments with `globalNotScopes` + +The arrays can have the following entries: + +| Scope type | Example | +|------------|---------| +| `managementGroups` | `"/providers/Microsoft.Management/managementGroups/myManagementGroupId"` | +| `subscriptions` | `"/subscriptions/00000000-0000-0000-000000000000"` | +| `resourceGroups` | `"/subscriptions/00000000-0000-0000-000000000000/resourceGroups/myResourceGroup"` | +| Resource group pattern | `"/subscriptions/*/resourceGroups/myResourceGroupPattern*"` | + +Resource Group patterns allow us to exclude "special" managed Resource Groups. The exclusion is not dynamic. It is calculated when the deployment scripts execute. + +```json +"globalNotScopes": [ + "/subscriptions/*/resourceGroups/synapseworkspace-managedrg-*", + "/subscriptions/*/resourceGroups/managed-rg-*", + "/providers/Microsoft.Management/managementGroups/mg-personal-subscriptions", + "/providers/Microsoft.Management/managementGroups/mg-policy-as-code" +] +``` + +### Example for Lighthouse Manged Tenant + +```json +{ + "pacOwnerId": "00000000-0000-0000-0000-000000000000", + "pacEnvironments": [ + { + "pacSelector": "epac-dev", + "cloud": "AzureCloud", + "tenantId": "11000000-0000-0000-0000-000000000000", + "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/PAC-Heinrich-Dev", + "desiredState": { + "strategy": "full", + "keepDfcSecurityAssignments": false + }, + "mangedIdentityLocation": "eastus2" + }, + { + "pacSelector": "tenant", + "cloud": "AzureCloud", + "tenantId": "11000000-0000-0000-0000-000000000000", + "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/Contoso-Root", + "desiredState": { + "strategy": "full", + "keepDfcSecurityAssignments": false + }, + "globalNotScopes": [ + "/providers/Microsoft.Management/managementGroups/PAC-Heinrich-Dev" + ], + "managedIdentityLocation": "eastus2" + }, + { + "pacSelector": "lightHouseTenant", + "cloud": "AzureCloud", + "tenantId": "22000000-0000-0000-0000-000000000000", + "managingTenant": { + "managingTenantId": "11000000-0000-0000-0000-000000000000", + "managingTenantRootScope": [ + "/subscriptions/00000000-0000-0000-0000-000000000000", + "/subscriptions/00000000-0000-0000-0000-000000000000" + ] + }, + "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/Contoso-Root", + "desiredState": { + "strategy": "full", + "keepDfcSecurityAssignments": false + }, + "managedIdentityLocation": "eastus2" + } + ] +} +``` diff --git a/Docs/tips.md b/Docs/tips.md deleted file mode 100644 index 71c74904..00000000 --- a/Docs/tips.md +++ /dev/null @@ -1,22 +0,0 @@ -# Tips - -Miscellaneous explanation to get the most from EPAC. - -## Export-AzPolicyResources - -If the `global-settings.jsonc` contains `managedIdentityLocations` or `globalNotScopes` any matching `managedIdentityLocations` and `notScopes` are not emitted as part of the assignment files. - -## Parameter CSV Files - -If an `effect` parameter is not specified in the CSV file, the default value from the definition is used. - -If an `effect` for a Policy is not surfaced as a parameter at the Policy Set, EPAC will use the Policy Assignment `overrides` feature to set the desired value. Conversely, if an `effect` for a Policy is surfaced as a parameter at the Policy Set, EPAC will not use the Policy Assignment `overrides` feature to set the desired value. - -Build-PolicyDocumentation.ps1 will include the `overrides` in the effective `effect` value. - - -## Role Assignments - -`Build-DeploymentPlan.ps1` will not calculate Role Assignments for user-assigned Managed Identities (UAMI) and will not generate a `roles-plan.json` file. - -`additionalRoleAssignments` are used when a resource required is not in the current scope. For example, a Policy Assignment that requires a Event Hub to be managed in a subscription not contained in the current management group. \ No newline at end of file diff --git a/Docs/usage-tracking.md b/Docs/usage-tracking.md deleted file mode 100644 index aaa39d2c..00000000 --- a/Docs/usage-tracking.md +++ /dev/null @@ -1,27 +0,0 @@ -# Usage Tracking - -Starting with v8.0.0, Enterprise Policy as Code (EPAC) is tracking the usage using Customer Usage Attribution (PID). - -## Telemetry Tracking Using Customer Usage Attribution (PID) - -Microsoft can identify the deployments of the Azure Resource Manager with the deployed Azure resources. Microsoft can correlate these resources used to support the deployments. Microsoft collects this information to provide the best experiences with their products and to operate their business. The telemetry is collected through [customer usage attribution](https://learn.microsoft.com/azure/marketplace/azure-partner-customer-usage-attribution). The data is collected and governed by Microsoft's privacy policies, located at the [trust center](https://www.microsoft.com/trustcenter). - -To opt-out of this tracking, we have included a settings in `global-settings.jsonc` called `telemetryOptOut`. If you would like to disable this tracking, then simply [set this value](definitions-and-global-settings.md#opt-out-of-telemetry-data-collection-telemetryoptout) to `true` (default is `false`). - -If you are happy with leaving telemetry tracking enabled, no changes are required. - -## Module PID Value Mapping - -The following is the unique IDs (also known as PIDs) used in each of the modules: - -| Function Name | PID | -|:------------|:----| -| `Deploy-PolicyPlan` | `3c88f740-55a8-4a96-9fba-30a81b52151a` | -| `Deploy-PolicyPlan` | `fe9ff1e8-5521-4b9d-ab1d-84e15447565e` | -| `Deploy-RolesPlan` | `cf031290-b7d4-48ef-9ff5-4dcd7bff8c6c` | -| `Build-PolicyDocumentation` | `2dc29bae-2448-4d7f-b911-418421e83900` | -| `Create-AzRemediationTasks` | `6f4dcbef-f6e2-4c29-ba2a-eef748d88157` | -| `Export-AzPolicyResources` | `dc5b73fd-e93c-40ca-8fef-976762d1d30` | -| `Export-NonComplianceReports` | `f464b017-898b-4156-9da5-af932831fa2f` | -| `Get-AzExemptions` | `3f02e7d5-1cf5-490a-a95c-3d49f0673093` | -| `New-AzPolicyReaderRole` | `f4b5b7ac-70b4-40fc-836f-585791aa83e7` | \ No newline at end of file diff --git a/README.md b/README.md index bd423e10..461a953e 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,10 @@ # Enterprise Azure Policy as Code -## Breaking changes in V6.0 and v7.0 - -Substantial feature enhancements required [breaking changes in v6.0 and to a lesser extend in v7.0](Docs/breaking-changes.md). - -## Az PowerShell Module 9.2.x issue - -**Az PowerShell Module 9.2.x has a known issue (bug).** This bug causes multiple failures of EPAC and any other Policy as Code solution depending on Az Module. **Az PowerShell Module 9.3.0 fixed this issue.** - -## Documentation - -In v7.0, the documentation source has moved to the [file './Docs/index.md'](Docs/index.md). - -The current release documentation is hosted on [https://azure.github.io/enterprise-azure-policy-as-code/](https://azure.github.io/enterprise-azure-policy-as-code/). +This repository contains the source code for the Enterprise Azure Policy as Code (EPAC) solution. EPAC is a solution that allows you to manage Azure Policy as code in a git repository. For an overview see the [EPAC documentation](https://aka.ms/epac). ## Contributing -This project welcomes contributions and suggestions. Most contributions require you to agree to a +This project welcomes contributions and suggestions. Contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit . diff --git a/Schemas/global-settings-schema.json b/Schemas/global-settings-schema.json index 9d58ea60..73386bcb 100644 --- a/Schemas/global-settings-schema.json +++ b/Schemas/global-settings-schema.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "pacOwnerId": { @@ -23,10 +23,32 @@ "tenantId": { "type": "string" }, + "deployedBy": { + "type": "string" + }, + "managedIdentityLocation": { + "type": "string" + }, + "managingTenant": { + "type": "array", + "item": [ + { + "managingTenantId": "string" + }, + { + "managingTenantRootScopes": "array" + } + ], + "additionalProperties": false, + "required": [ + "managingTenantId", + "managingTenantRootScopes" + ] + }, "deploymentRootScope": { "type": "string" }, - "inheritedDefinitionsScopes": { + "globalNotScopes": { "type": "array", "items": [ { @@ -44,9 +66,6 @@ "ownedOnly" ] }, - "includeResourceGroups": { - "type": "boolean" - }, "keepDfcSecurityAssignments": { "type": "boolean" }, @@ -81,17 +100,12 @@ "type": "string" } ] - }, - "deleteExpiredExemptions": { - "type": "boolean" - }, - "deleteOrphanedExemptions": { - "type": "boolean" } }, "additionalProperties": false, "required": [ - "strategy" + "strategy", + "keepDfcSecurityAssignments" ] } }, @@ -100,31 +114,12 @@ "pacSelector", "cloud", "tenantId", - "deploymentRootScope" + "deploymentRootScope", + "managedIdentityLocation", + "desiredState" ] } ] - }, - "managedIdentityLocations": { - "type": "object", - "patternProperties": { - "^*$": { - "type": "string" - } - } - }, - "globalNotScopes": { - "type": "object", - "patternProperties": { - "^*$": { - "type": "array", - "items": [ - { - "type": "string" - } - ] - } - } } }, "additionalProperties": false, diff --git a/Schemas/policy-assignment-schema.json b/Schemas/policy-assignment-schema.json index a01fccd6..50b3644f 100644 --- a/Schemas/policy-assignment-schema.json +++ b/Schemas/policy-assignment-schema.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "nodeName": { diff --git a/Schemas/policy-definition-schema.json b/Schemas/policy-definition-schema.json index 47cb784f..9cd508da 100644 --- a/Schemas/policy-definition-schema.json +++ b/Schemas/policy-definition-schema.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "name": { diff --git a/Schemas/policy-documentation-schema.json b/Schemas/policy-documentation-schema.json index fbee1e06..f790d3eb 100644 --- a/Schemas/policy-documentation-schema.json +++ b/Schemas/policy-documentation-schema.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "documentAssignments": { diff --git a/Schemas/policy-exemption-schema.json b/Schemas/policy-exemption-schema.json index 421046c8..31b89736 100644 --- a/Schemas/policy-exemption-schema.json +++ b/Schemas/policy-exemption-schema.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "exemptions": { @@ -32,6 +32,18 @@ "policyDefinitionReferenceIds": { "type": "array" }, + "policyId": { + "type": "string" + }, + "policyName": { + "type": "string" + }, + "policySetId": { + "type": "string" + }, + "policySetName": { + "type": "string" + }, "resourceSelectors": { "type": "array" }, @@ -43,12 +55,38 @@ } }, "additionalProperties": false, + "oneOf": [ + { + "required": [ + "policyAssignmentId" + ] + }, + { + "required": [ + "policyId" + ] + }, + { + "required": [ + "policyName" + ] + }, + { + "required": [ + "policySetId" + ] + }, + { + "required": [ + "policySetName" + ] + } + ], "required": [ "name", "displayName", "exemptionCategory", - "scope", - "policyAssignmentId" + "scope" ] } ] diff --git a/Schemas/policy-set-definition-schema.json b/Schemas/policy-set-definition-schema.json index e1ac9ee1..cda1e221 100644 --- a/Schemas/policy-set-definition-schema.json +++ b/Schemas/policy-set-definition-schema.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "name": { diff --git a/Scripts/Operations/Get-AzMissingTags.ps1 b/Scripts-Deprecated/Get-AzMissingTags.ps1 similarity index 100% rename from Scripts/Operations/Get-AzMissingTags.ps1 rename to Scripts-Deprecated/Get-AzMissingTags.ps1 diff --git a/Scripts/Operations/Get-AzResourceTags.ps1 b/Scripts-Deprecated/Get-AzResourceTags.ps1 similarity index 100% rename from Scripts/Operations/Get-AzResourceTags.ps1 rename to Scripts-Deprecated/Get-AzResourceTags.ps1 diff --git a/Scripts/Operations/Get-AzStorageNetworkConfig.ps1 b/Scripts-Deprecated/Get-AzStorageNetworkConfig.ps1 similarity index 100% rename from Scripts/Operations/Get-AzStorageNetworkConfig.ps1 rename to Scripts-Deprecated/Get-AzStorageNetworkConfig.ps1 diff --git a/Scripts/Operations/Get-AzUserRoleAssignments.ps1 b/Scripts-Deprecated/Get-AzUserRoleAssignments.ps1 similarity index 100% rename from Scripts/Operations/Get-AzUserRoleAssignments.ps1 rename to Scripts-Deprecated/Get-AzUserRoleAssignments.ps1 diff --git a/Scripts/CloudAdoptionFramework/policyAssignments/ALZ-Corp-Default.jsonc b/Scripts/CloudAdoptionFramework/policyAssignments/ALZ-Corp-Default.jsonc index e5277897..5b645957 100644 --- a/Scripts/CloudAdoptionFramework/policyAssignments/ALZ-Corp-Default.jsonc +++ b/Scripts/CloudAdoptionFramework/policyAssignments/ALZ-Corp-Default.jsonc @@ -105,7 +105,6 @@ "additionalRoleAssignments": { "*": [ { - "roleDisplayName": "Network Contributor", "roleDefinitionId": "/providers/microsoft.authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7", "scope": "/subscriptions/connectivity--subscription--id" // Replace with your connectivity subscription Id } @@ -242,4 +241,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/Scripts/Deploy/Build-DeploymentPlans.ps1 b/Scripts/Deploy/Build-DeploymentPlans.ps1 index 2d14ec56..e123799f 100644 --- a/Scripts/Deploy/Build-DeploymentPlans.ps1 +++ b/Scripts/Deploy/Build-DeploymentPlans.ps1 @@ -4,7 +4,7 @@ .SYNOPSIS Builds the deployment plans for the Policy as Code (PAC) environment. -.PARAMETER PacEnvironmentSelectorepac +.PARAMETER PacEnvironmentSelector Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc. .PARAMETER DefinitionsRootFolder @@ -19,6 +19,9 @@ .PARAMETER DevOpsType If set, outputs variables consumable by conditions in a DevOps pipeline. Valid values are '', 'ado' and 'gitlab'. +.PARAMETER VirtualCores + Number of virtual cores available to calculate the deployment plan. Defaults to 4. + .EXAMPLE .\Build-DeploymentPlans.ps1 -PacEnvironmentSelector "dev" @@ -37,7 +40,7 @@ [CmdletBinding()] param ( [parameter(HelpMessage = "Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc.", Position = 0)] - [string] $PacEnvironmentSelector, + [string] $PacEnvironmentSelector = "", [Parameter(HelpMessage = "Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER or './Definitions'.")] [string]$DefinitionsRootFolder, @@ -45,6 +48,9 @@ param ( [Parameter(HelpMessage = "Output folder path for plan files. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER or './Output'.")] [string]$OutputFolder, + [Parameter(HelpMessage = "If set, only build the exemptions plan.")] + [switch] $BuildExemptionsOnly, + [Parameter(HelpMessage = "Script is used interactively. Script can prompt the interactive user for input.")] [switch] $Interactive, @@ -52,8 +58,9 @@ param ( [ValidateSet("ado", "gitlab", "")] [string] $DevOpsType = "", - [Parameter(HelpMessage = "Ignore scope tree errors")] - [switch] $IgnoreScopeTreeErrors + [Parameter(HelpMessage = "Number of virtual cores available to calculate the deployment plan. Defaults to 4. A value of 0 disables parallel processing.")] + [Int16] $VirtualCores = 4 + ) $PSDefaultParameterValues = @{ @@ -81,32 +88,14 @@ else { } Write-Information "" -# Getting existing Policy resources -$exemptionsAreNotManagedMessage = "" -$policyExemptionsFolder = $pacEnvironment.policyExemptionsFolder - -$exemptionsFolderForPacEnvironment = "$($policyExemptionsFolder)/$($pacEnvironment.pacSelector)" -$exemptionsAreNotManaged = $false -if (!(Test-Path $policyExemptionsFolder -PathType Container)) { - $exemptionsAreNotManagedMessage = "Policy Exemptions folder 'policyExemptions' not found. Exemptions not managed by this EPAC instance." - $exemptionsAreNotManaged = $true -} -elseif (!(Test-Path $exemptionsFolderForPacEnvironment -PathType Container)) { - $exemptionsAreNotManagedMessage = "Policy Exemptions are not managed by this EPAC instance's PaC environment $($pacEnvironment.pacSelector)!" - $exemptionsAreNotManaged = $true -} - -if ($IgnoreScopeTreeErrors) { - Write-Warning "Ignoring scope tree errors" - $scopeTable = Get-AzScopeTree -PacEnvironment $pacEnvironment -IgnoreScopeTreeErrors +#region plan data structures +$buildSelections = @{ + buildAny = $false + buildPolicyDefinitions = $false + buildPolicySetDefinitions = $false + buildPolicyAssignments = $false + buildPolicyExemptions = $false } -else { - $scopeTable = Get-AzScopeTree -PacEnvironment $pacEnvironment -} - -$deployedPolicyResources = Get-AzPolicyResources -PacEnvironment $pacEnvironment -ScopeTable $scopeTable -SkipExemptions:$exemptionsAreNotManaged - -# Process Policies $policyDefinitions = @{ new = @{} update = @{} @@ -121,17 +110,6 @@ $allDefinitions = @{ policysetdefinitions = @{} } $replaceDefinitions = @{} - -Build-PolicyPlan ` - -DefinitionsRootFolder $pacEnvironment.policyDefinitionsFolder ` - -PacEnvironment $pacEnvironment ` - -DeployedDefinitions $deployedPolicyResources.policydefinitions ` - -Definitions $policyDefinitions ` - -AllDefinitions $allDefinitions ` - -ReplaceDefinitions $replaceDefinitions ` - -PolicyRoleIds $policyRoleIds - -# Process Policy Sets $policySetDefinitions = @{ new = @{} update = @{} @@ -140,17 +118,6 @@ $policySetDefinitions = @{ numberOfChanges = 0 numberUnchanged = 0 } - -Build-PolicySetPlan ` - -DefinitionsRootFolder $pacEnvironment.policySetDefinitionsFolder ` - -PacEnvironment $pacEnvironment ` - -DeployedDefinitions $deployedPolicyResources.policysetdefinitions ` - -Definitions $policySetDefinitions ` - -AllDefinitions $allDefinitions ` - -ReplaceDefinitions $replaceDefinitions ` - -PolicyRoleIds $policyRoleIds - -# Process Assignment JSON files $assignments = @{ new = @{} update = @{} @@ -161,23 +128,11 @@ $assignments = @{ } $roleAssignments = @{ numberOfChanges = 0 - added = @() - removed = @() + added = [System.Collections.ArrayList]::new() + updated = [System.Collections.ArrayList]::new() + removed = [System.Collections.ArrayList]::new() } $allAssignments = @{} - -Build-AssignmentPlan ` - -AssignmentsRootFolder $pacEnvironment.policyAssignmentsFolder ` - -PacEnvironment $pacEnvironment ` - -ScopeTable $scopeTable ` - -DeployedPolicyResources $deployedPolicyResources ` - -Assignments $assignments ` - -RoleAssignments $roleAssignments ` - -AllDefinitions $allDefinitions ` - -AllAssignments $allAssignments ` - -ReplaceDefinitions $replaceDefinitions ` - -PolicyRoleIds $policyRoleIds - $exemptions = @{ new = @{} update = @{} @@ -188,18 +143,6 @@ $exemptions = @{ numberOfChanges = 0 numberUnchanged = 0 } - -# Process exemption JSON files -Build-ExemptionsPlan ` - -ExemptionsRootFolder $exemptionsFolderForPacEnvironment ` - -ExemptionsAreNotManagedMessage $exemptionsAreNotManagedMessage ` - -PacEnvironment $pacEnvironment ` - -AllAssignments $allAssignments ` - -Assignments $assignments ` - -DeployedExemptions $deployedPolicyResources.policyExemptions ` - -Exemptions $exemptions - -# Output Plan $pacOwnerId = $pacEnvironment.pacOwnerId $timestamp = Get-Date -AsUTC -Format "u" $policyPlan = @{ @@ -215,97 +158,281 @@ $rolesPlan = @{ pacOwnerId = $pacOwnerId roleAssignments = $roleAssignments } +$policyDefinitionsFolder = $pacEnvironment.policyDefinitionsFolder +$policySetDefinitionsFolder = $pacEnvironment.policySetDefinitionsFolder +$policyAssignmentsFolder = $pacEnvironment.policyAssignmentsFolder +$policyExemptionsFolder = $pacEnvironment.policyExemptionsFolder +$policyExemptionsFolderForPacEnvironment = "$($policyExemptionsFolder)/$($pacEnvironment.pacSelector)" +#endregion plan data structures -Write-Information "===================================================================================================" -Write-Information "Summary" -Write-Information "===================================================================================================" - -if ($null -ne $pacEnvironment.policyDefinitionsFolder) { - Write-Information "Policy counts:" - Write-Information " $($policyDefinitions.numberUnchanged) unchanged" - if ($policyDefinitions.numberOfChanges -eq 0) { - Write-Information " $($policyDefinitions.numberOfChanges) changes" +#region calculate which plans need to be built +$warningMessages = [System.Collections.ArrayList]::new() +$exemptionsAreNotManagedMessage = $null +$exemptionsAreManaged = $true +if (!(Test-Path $policyExemptionsFolder -PathType Container)) { + $exemptionsAreNotManagedMessage = "Policy Exemptions folder '$policyExemptionsFolder not found. Exemptions not managed by this EPAC instance." + $exemptionsAreManaged = $false +} +elseif (!(Test-Path $policyExemptionsFolderForPacEnvironment -PathType Container)) { + $exemptionsAreNotManagedMessage = "Policy Exemptions folder '$policyExemptionsFolderForPacEnvironment' for PaC environment $($pacEnvironment.pacSelector) not found. Exemptions not managed by this EPAC instance." + $exemptionsAreManaged = $false +} +if ($BuildExemptionsOnly) { + $null = $warningMessages.Add("Building only the Exemptions plan. Policy, Policy Set, and Assignment plans will not be built.") + if ($exemptionsAreManaged) { + $buildSelections.buildPolicyExemptions = $true + $buildSelections.buildAny = $true } else { - Write-Information " $($policyDefinitions.numberOfChanges) changes:" - Write-Information " new = $($policyDefinitions.new.psbase.Count)" - Write-Information " update = $($policyDefinitions.update.psbase.Count)" - Write-Information " replace = $($policyDefinitions.replace.psbase.Count)" - Write-Information " delete = $($policyDefinitions.delete.psbase.Count)" + $null = $warningMessages.Add($exemptionsAreNotManagedMessage) + $null = $warningMessages.Add("Policy Exemptions plan will not be built. Exiting...") } + $buildSelections.buildPolicyDefinitions = $false + $buildSelections.buildPolicySetDefinitions = $false + $buildSelections.buildPolicyAssignments = $false } else { - Write-Information "Policy definitions not managed by EPAC." -} - -if ($null -ne $pacEnvironment.policySetDefinitionsFolder) { - Write-Information "Policy Set counts:" - Write-Information " $($policySetDefinitions.numberUnchanged) unchanged" - if ($policySetDefinitions.numberOfChanges -eq 0) { - Write-Information " $($policySetDefinitions.numberOfChanges) changes" + if (!(Test-Path $policyDefinitionsFolder -PathType Container)) { + $null = $warningMessages.Add("Policy definitions '$policyDefinitionsFolder' folder not found. Policy definitions not managed by this EPAC instance.") } else { - Write-Information " $($policySetDefinitions.numberOfChanges) changes:" - Write-Information " new = $($policySetDefinitions.new.psbase.Count)" - Write-Information " update = $($policySetDefinitions.update.psbase.Count)" - Write-Information " replace = $($policySetDefinitions.replace.psbase.Count)" - Write-Information " delete = $($policySetDefinitions.delete.psbase.Count)" + $buildSelections.buildPolicyDefinitions = $true + $buildSelections.buildAny = $true } -} -else { - Write-Information "Policy Set definitions not managed by EPAC." -} - -if ($null -ne $pacEnvironment.policyAssignmentsFolder) { - Write-Information "Policy Assignment counts:" - Write-Information " $($assignments.numberUnchanged) unchanged" - if ($assignments.numberOfChanges -eq 0) { - Write-Information " $($assignments.numberOfChanges) changes" + if (!(Test-Path $policySetDefinitionsFolder -PathType Container)) { + $null = $warningMessages.Add("Policy Set definitions '$policySetDefinitionsFolder' folder not found. Policy Set definitions not managed by this EPAC instance.") } else { - Write-Information " $($assignments.numberOfChanges) changes:" - Write-Information " new = $($assignments.new.psbase.Count)" - Write-Information " update = $($assignments.update.psbase.Count)" - Write-Information " replace = $($assignments.replace.psbase.Count)" - Write-Information " delete = $($assignments.delete.psbase.Count)" + $buildSelections.buildPolicySetDefinitions = $true + $buildSelections.buildAny = $true } - Write-Information "Role Assignment counts:" - if ($roleAssignments.numberOfChanges -eq 0) { - Write-Information " $($roleAssignments.numberOfChanges) changes" + if (!(Test-Path $policyAssignmentsFolder -PathType Container)) { + $null = $warningMessages.Add("Policy Assignments '$policyAssignmentsFolder' folder not found. Policy Assignments not managed by this EPAC instance.") } else { - Write-Information " $($roleAssignments.numberOfChanges) changes:" - Write-Information " add = $($roleAssignments.added.psbase.Count)" - Write-Information " remove = $($roleAssignments.removed.psbase.Count)" + $buildSelections.buildPolicyAssignments = $true + $buildSelections.buildAny = $true + } + if ($exemptionsAreManaged) { + $buildSelections.buildPolicyExemptions = $true + $buildSelections.buildAny = $true + } + else { + $null = $warningMessages.Add($exemptionsAreNotManagedMessage) + } + if (-not $buildSelections.buildAny) { + $null = $warningMessages.Add("No Policies, Policy Set, Assignment, or Exemptions managed by this EPAC instance found. No plans will be built. Exiting...") } } -else { - Write-Information "Policy definitions not managed by EPAC." +if ($warningMessages.Count -gt 0) { + foreach ($warningMessage in $warningMessages) { + Write-Warning $warningMessage + } } +#endregion calculate which plans need to be built + +if ($buildSelections.buildAny) { + + # get the scope table for the deployment root scope amd the resources + $scopeTable = Build-ScopeTableForDeploymentRootScope -PacEnvironment $pacEnvironment + $skipExemptions = -not $buildSelections.buildPolicyExemptions + $skipRoleAssignments = -not $buildSelections.buildPolicyAssignments + $NoParallelProcessing = $VirtualCores -eq 0 + # $NoParallelProcessing = $true # for debugging, disable parallel processing + $deployedPolicyResources = Get-AzPolicyResources ` + -PacEnvironment $pacEnvironment ` + -ScopeTable $scopeTable ` + -SkipExemptions:$skipExemptions ` + -SkipRoleAssignments:$skipRoleAssignments ` + -NoParallelProcessing:$NoParallelProcessing + + # Calculate roleDefinitionIds for built-in and inherited Policies + $readOnlyPolicyDefinitions = $deployedPolicyResources.policydefinitions.readOnly + foreach ($id in $readOnlyPolicyDefinitions.Keys) { + $deployedDefinitionProperties = Get-PolicyResourceProperties -PolicyResource $readOnlyPolicyDefinitions.$id + if ($deployedDefinitionProperties.policyRule.then.details -and $deployedDefinitionProperties.policyRule.then.details.roleDefinitionIds) { + $roleIds = $deployedDefinitionProperties.policyRule.then.details.roleDefinitionIds + $null = $policyRoleIds.Add($id, $roleIds) + } + } -if ($exemptionsAreNotManaged) { - Write-Warning $exemptionsAreNotManagedMessage -} -else { - Write-Information "Policy Exemption counts:" - Write-Information " $($exemptions.numberUnchanged) unchanged" - Write-Information " $($exemptions.numberOfOrphans) orphaned" - Write-Information " $($exemptions.numberOfExpired) expired" - if ($exemptions.numberOfChanges -eq 0) { - Write-Information " $($exemptions.numberOfChanges) changes" + # Populate allDefinitions.policydefinitions with all deployed definitions + $allDeployedDefinitions = $deployedPolicyResources.policydefinitions.all + foreach ($id in $allDeployedDefinitions.Keys) { + $allDefinitions.policydefinitions[$id] = $allDeployedDefinitions.$id } - else { - Write-Information " $($exemptions.numberOfChanges) changes:" - Write-Information " new = $($exemptions.new.psbase.Count)" - Write-Information " update = $($exemptions.update.psbase.Count)" - Write-Information " replace = $($exemptions.replace.psbase.Count)" - Write-Information " delete = $($exemptions.delete.psbase.Count)" + + if ($buildSelections.buildPolicyDefinitions) { + # Process Policies + Build-PolicyPlan ` + -DefinitionsRootFolder $policyDefinitionsFolder ` + -PacEnvironment $pacEnvironment ` + -DeployedDefinitions $deployedPolicyResources.policydefinitions ` + -Definitions $policyDefinitions ` + -AllDefinitions $allDefinitions ` + -ReplaceDefinitions $replaceDefinitions ` + -PolicyRoleIds $policyRoleIds + } + + # Calculate roleDefinitionIds for built-in and inherited PolicySets + $readOnlyPolicySetDefinitions = $deployedPolicyResources.policysetdefinitions.readOnly + foreach ($id in $readOnlyPolicySetDefinitions.Keys) { + $policySetProperties = Get-PolicyResourceProperties -PolicyResource $readOnlyPolicySetDefinitions.$id + $roleIds = @{} + foreach ($policyDefinition in $policySetProperties.policyDefinitions) { + $policyId = $policyDefinition.policyDefinitionId + if ($policyRoleIds.ContainsKey($policyId)) { + $addRoleDefinitionIds = $PolicyRoleIds.$policyId + foreach ($roleDefinitionId in $addRoleDefinitionIds) { + $roleIds[$roleDefinitionId] = "added" + } + } + } + if ($roleIds.psbase.Count -gt 0) { + $null = $policyRoleIds.Add($id, $roleIds.Keys) + } + } + + # Populate allDefinitions.policysetdefinitions with deployed definitions + $allDeployedDefinitions = $deployedPolicyResources.policysetdefinitions.all + foreach ($id in $allDeployedDefinitions.Keys) { + $allDefinitions.policysetdefinitions[$id] = $allDeployedDefinitions.$id + } + + if ($buildSelections.buildPolicySetDefinitions) { + # Process Policy Sets + Build-PolicySetPlan ` + -DefinitionsRootFolder $policySetDefinitionsFolder ` + -PacEnvironment $pacEnvironment ` + -DeployedDefinitions $deployedPolicyResources.policysetdefinitions ` + -Definitions $policySetDefinitions ` + -AllDefinitions $allDefinitions ` + -ReplaceDefinitions $replaceDefinitions ` + -PolicyRoleIds $policyRoleIds } -} + # Convert Policy and PolicySetDefinition to detailed Info + $combinedPolicyDetails = Convert-PolicyResourcesToDetails ` + -AllPolicyDefinitions $allDefinitions.policydefinitions ` + -AllPolicySetDefinitions $allDefinitions.policysetdefinitions ` + -VirtualCores $VirtualCores + + # Populate allAssignments + $deployedPolicyAssignments = $deployedPolicyResources.policyassignments.managed + foreach ($id in $deployedPolicyAssignments.Keys) { + $allAssignments[$id] = $deployedPolicyAssignments.$id + } + + if ($buildSelections.buildPolicyAssignments) { + # Process Assignment JSON files + Build-AssignmentPlan ` + -AssignmentsRootFolder $policyAssignmentsFolder ` + -PacEnvironment $pacEnvironment ` + -ScopeTable $scopeTable ` + -DeployedPolicyResources $deployedPolicyResources ` + -Assignments $assignments ` + -RoleAssignments $roleAssignments ` + -AllAssignments $allAssignments ` + -ReplaceDefinitions $replaceDefinitions ` + -PolicyRoleIds $policyRoleIds ` + -CombinedPolicyDetails $combinedPolicyDetails + } + + if ($buildSelections.buildPolicyExemptions) { + # Process Exemption JSON files + Build-ExemptionsPlan ` + -ExemptionsRootFolder $policyExemptionsFolderForPacEnvironment ` + -ExemptionsAreNotManagedMessage $exemptionsAreNotManagedMessage ` + -PacEnvironment $pacEnvironment ` + -ScopeTable $scopeTable ` + -AllDefinitions $allDefinitions ` + -AllAssignments $allAssignments ` + -CombinedPolicyDetails $combinedPolicyDetails ` + -Assignments $assignments ` + -DeployedExemptions $deployedPolicyResources.policyExemptions ` + -Exemptions $exemptions + } + + Write-Information "===================================================================================================" + Write-Information "Summary" + Write-Information "===================================================================================================" + + if ($buildSelections.buildPolicyDefinitions) { + Write-Information "Policy counts:" + Write-Information " $($policyDefinitions.numberUnchanged) unchanged" + if ($policyDefinitions.numberOfChanges -eq 0) { + Write-Information " $($policyDefinitions.numberOfChanges) changes" + } + else { + Write-Information " $($policyDefinitions.numberOfChanges) changes:" + Write-Information " new = $($policyDefinitions.new.psbase.Count)" + Write-Information " update = $($policyDefinitions.update.psbase.Count)" + Write-Information " replace = $($policyDefinitions.replace.psbase.Count)" + Write-Information " delete = $($policyDefinitions.delete.psbase.Count)" + } + } + + if ($buildSelections.buildPolicySetDefinitions) { + Write-Information "Policy Set counts:" + Write-Information " $($policySetDefinitions.numberUnchanged) unchanged" + if ($policySetDefinitions.numberOfChanges -eq 0) { + Write-Information " $($policySetDefinitions.numberOfChanges) changes" + } + else { + Write-Information " $($policySetDefinitions.numberOfChanges) changes:" + Write-Information " new = $($policySetDefinitions.new.psbase.Count)" + Write-Information " update = $($policySetDefinitions.update.psbase.Count)" + Write-Information " replace = $($policySetDefinitions.replace.psbase.Count)" + Write-Information " delete = $($policySetDefinitions.delete.psbase.Count)" + } + } + + if ($buildSelections.buildPolicyAssignments) { + Write-Information "Policy Assignment counts:" + Write-Information " $($assignments.numberUnchanged) unchanged" + if ($assignments.numberOfChanges -eq 0) { + Write-Information " $($assignments.numberOfChanges) changes" + } + else { + Write-Information " $($assignments.numberOfChanges) changes:" + Write-Information " new = $($assignments.new.psbase.Count)" + Write-Information " update = $($assignments.update.psbase.Count)" + Write-Information " replace = $($assignments.replace.psbase.Count)" + Write-Information " delete = $($assignments.delete.psbase.Count)" + } + Write-Information "Role Assignment counts:" + if ($roleAssignments.numberOfChanges -eq 0) { + Write-Information " $($roleAssignments.numberOfChanges) changes" + } + else { + Write-Information " $($roleAssignments.numberOfChanges) changes:" + Write-Information " add = $($roleAssignments.added.psbase.Count)" + Write-Information " update = $($roleAssignments.updated.psbase.Count)" + Write-Information " remove = $($roleAssignments.removed.psbase.Count)" + } + } + + if ($buildSelections.buildPolicyExemptions) { + Write-Information "Policy Exemption counts:" + Write-Information " $($exemptions.numberUnchanged) unchanged" + Write-Information " $($exemptions.numberOfOrphans) orphaned" + Write-Information " $($exemptions.numberOfExpired) expired" + if ($exemptions.numberOfChanges -eq 0) { + Write-Information " $($exemptions.numberOfChanges) changes" + } + else { + Write-Information " $($exemptions.numberOfChanges) changes:" + Write-Information " new = $($exemptions.new.psbase.Count)" + Write-Information " update = $($exemptions.update.psbase.Count)" + Write-Information " replace = $($exemptions.replace.psbase.Count)" + Write-Information " delete = $($exemptions.delete.psbase.Count)" + } + } + +} Write-Information "---------------------------------------------------------------------------------------------------" -Write-Information "Output plan(s)" +Write-Information "Output plan(s); if any, will be written to the following file(s):" $policyResourceChanges = $policyDefinitions.numberOfChanges $policyResourceChanges += $policySetDefinitions.numberOfChanges $policyResourceChanges += $assignments.numberOfChanges diff --git a/Scripts/Deploy/Deploy-PolicyPlan.ps1 b/Scripts/Deploy/Deploy-PolicyPlan.ps1 index 1d4e990b..424cdeb1 100644 --- a/Scripts/Deploy/Deploy-PolicyPlan.ps1 +++ b/Scripts/Deploy/Deploy-PolicyPlan.ps1 @@ -16,8 +16,8 @@ .PARAMETER Interactive Use switch to indicate interactive use -.PARAMETER IgnoreScopeLockedErrors - Ignore errors raised by locked scopes +.PARAMETER VirtualCores + Number of virtual cores available to deploy Policy objects in parallel. Defaults to 4. .EXAMPLE Deploy-PolicyPlan.ps1 -PacEnvironmentSelector "dev" -DefinitionsRootFolder "C:\git\policy-as-code\Definitions" -InputFolder "C:\git\policy-as-code\Output" -Interactive @@ -49,8 +49,8 @@ param ( [Parameter(HelpMessage = "Use switch to indicate interactive use")] [switch] $Interactive, - [Parameter(HelpMessage = "Ignore errors raised by locked scopes")] - [switch] $IgnoreScopeLockedErrors + [Parameter(HelpMessage = "Number of virtual cores available to deploy Policy objects in parallel. Defaults to 4.")] + [Int16] $VirtualCores = 4 ) $PSDefaultParameterValues = @{ @@ -65,6 +65,7 @@ Clear-Variable -Name epacInfoStream -Scope global -Force -ErrorAction SilentlyCo $InformationPreference = "Continue" $pacEnvironment = Select-PacEnvironment $PacEnvironmentSelector -DefinitionsRootFolder $DefinitionsRootFolder -InputFolder $InputFolder -Interactive $Interactive $null = Set-AzCloudTenantSubscription -Cloud $pacEnvironment.cloud -TenantId $pacEnvironment.tenantId -Interactive $pacEnvironment.interactive +$throttleLimit = $VirtualCores * 2 # Telemetry if ($pacEnvironment.telemetryEnabled) { @@ -80,7 +81,7 @@ $planFile = $pacEnvironment.policyPlanInputFile $plan = Get-DeploymentPlan -PlanFile $planFile if ($null -eq $plan) { Write-Warning "***************************************************************************************************" - Write-Warning "Plan does not exist, skipping Policy resource deployment." + Write-Warning "Plan file '$planFile' does not exist, skipping Policy resource deployment." Write-Warning "***************************************************************************************************" Write-Warning "" } @@ -91,293 +92,302 @@ else { Write-Information "Plan created on $($plan.createdOn)." Write-Information "***************************************************************************************************" - [hashtable] $newAssignments = ConvertTo-HashTable $plan.assignments.new - [hashtable] $replaceAssignments = ConvertTo-HashTable $plan.assignments.replace - [hashtable] $updateAssignments = ConvertTo-HashTable $plan.assignments.update - #region delete exemptions, assignment, definitions - $exemptions = ConvertTo-HashTable $plan.exemptions.delete - if ($exemptions.psbase.Count -gt 0) { + $table = ConvertTo-HashTable $plan.exemptions.delete + $table += ConvertTo-HashTable $plan.exemptions.replace + if ($table.psbase.Count -gt 0) { Write-Information "" Write-Information "===================================================================================================" - Write-Information "Delete orphaned, deleted, and expired Exemptions ($($exemptions.psbase.Count))" + Write-Information "Delete orphaned, deleted, expired and replaced Exemptions ($($table.psbase.Count))" Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($id in $exemptions.Keys) { - $exemption = $exemptions[$id] - Write-Information $exemption.displayName - try { - $null = Remove-AzPolicyExemption -Id $id -Force -ErrorAction Stop + $chunks = Split-HashtableIntoChunks -Table $table -NumberOfChunks $throttleLimit -MinChunkingSize 10 + if ($chunks.psbase.Count -eq 1) { + $chunk = $chunks[0] + foreach ($id in $chunk.Keys) { + $entry = $chunk.$id + Write-Information "$($entry.displayName) - $($id)" + Remove-AzResourceByIdRestMethod -Id $id -ApiVersion $pacEnvironment.apiVersions.policyExemptions } - catch { - if ($IgnoreScopeLockedErrors -and $_.Exception.Message -match "^ScopeLocked") { - Write-Warning "Scope is locked - error output: $($_.Exception.Message)" + } + else { + $funcRemoveAzResourceByIdRestMethod = ${function:Remove-AzResourceByIdRestMethod}.ToString() + $chunks | ForEach-Object -ThrottleLimit $throttleLimit -Parallel { + if ($null -eq ${function:Remove-AzResourceByIdRestMethod}) { + ${function:Remove-AzResourceByIdRestMethod} = $using:funcRemoveAzResourceByIdRestMethod } - else { - throw $_ + $pacEnvironment = $using:pacEnvironment + foreach ($id in $_.Keys) { + $entry = $_.$id + Write-Information "$($entry.displayName) - $($id)" + Remove-AzResourceByIdRestMethod -Id $id -ApiVersion $pacEnvironment.apiVersions.policyExemptions } } } } - $exemptions = ConvertTo-HashTable $plan.exemptions.replace - if ($exemptions.psbase.Count -gt 0) { + $table = ConvertTo-HashTable $plan.assignments.delete + $table += ConvertTo-HashTable $plan.assignments.replace + if ($table.psbase.Count -gt 0) { Write-Information "" Write-Information "===================================================================================================" - Write-Information "Delete replaced Exemptions ($($exemptions.psbase.Count))" + Write-Information "Delete removed and replaced Assignments ($($table.psbase.Count))" Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($id in $exemptions.Keys) { - $exemption = $exemptions[$id] - Write-Information $exemption.displayName - try { - $null = Remove-AzPolicyExemption -Id $id -Force -ErrorAction Stop + $chunks = Split-HashtableIntoChunks -Table $table -NumberOfChunks $throttleLimit -MinChunkingSize 10 + if ($chunks.psbase.Count -eq 1) { + $chunk = $chunks[0] + foreach ($id in $chunk.Keys) { + $entry = $chunk.$id + Write-Information "$($entry.displayName) - $($id)" + Remove-AzResourceByIdRestMethod -Id $id -ApiVersion $pacEnvironment.apiVersions.policyAssignments } - catch { - if ($IgnoreScopeLockedErrors -and $_.Exception.Message -match "^ScopeLocked") { - Write-Warning "Scope is locked - error output: $($_.Exception.Message)" + } + else { + $funcRemoveAzResourceByIdRestMethod = ${function:Remove-AzResourceByIdRestMethod}.ToString() + $chunks | ForEach-Object -ThrottleLimit $throttleLimit -Parallel { + if ($null -eq ${function:Remove-AzResourceByIdRestMethod}) { + ${function:Remove-AzResourceByIdRestMethod} = $using:funcRemoveAzResourceByIdRestMethod } - else { - throw $_ + $pacEnvironment = $using:pacEnvironment + foreach ($id in $_.Keys) { + $entry = $_.$id + Write-Information "$($entry.displayName) - $($id)" + Remove-AzResourceByIdRestMethod -Id $id -ApiVersion $pacEnvironment.apiVersions.policyAssignments } } } } - $assignments = ConvertTo-HashTable $plan.assignments.delete - if ($assignments.psbase.Count -gt 0) { - Write-Information "" - Write-Information "===================================================================================================" - Write-Information "Delete removed Assignments ($($assignments.psbase.Count))" - Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($id in $assignments.Keys) { - $assignment = $assignments[$id] - Write-Information $assignment.displayName - $null = Remove-AzPolicyAssignment -Id $id - } - } - - $assignments = $replaceAssignments - if ($assignments.psbase.Count -gt 0) { + $table = ConvertTo-HashTable $plan.policySetDefinitions.delete + $table += ConvertTo-HashTable $plan.policySetDefinitions.replace + if ($table.psbase.Count -gt 0) { Write-Information "" Write-Information "===================================================================================================" - Write-Information "Delete replaced Assignments ($($assignments.psbase.Count))" + Write-Information "Delete removed and replaced Policy Sets ($($table.psbase.Count))" Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($id in $assignments.Keys) { - $assignment = $assignments[$id] - Write-Information $assignment.displayName - $null = Remove-AzPolicyAssignment -Id $id + $chunks = Split-HashtableIntoChunks -Table $table -NumberOfChunks $throttleLimit -MinChunkingSize 10 + if ($chunks.psbase.Count -eq 1) { + $chunk = $chunks[0] + foreach ($id in $chunk.Keys) { + $entry = $chunk.$id + Write-Information "$($entry.displayName) - $($id)" + Remove-AzResourceByIdRestMethod -Id $id -ApiVersion $pacEnvironment.apiVersions.policySetDefinitions + } } - } - - $policySetDefinitions = ConvertTo-HashTable $plan.policySetDefinitions.delete - if ($policySetDefinitions.psbase.Count -gt 0) { - Write-Information "" - Write-Information "===================================================================================================" - Write-Information "Delete removed Policy Sets ($($policySetDefinitions.psbase.Count))" - Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($id in $policySetDefinitions.Keys) { - $policySetDefinition = $policySetDefinitions[$id] - Write-Information $policySetDefinition.displayName - $null = Remove-AzPolicySetDefinition -Id $id -Force + else { + $funcRemoveAzResourceByIdRestMethod = ${function:Remove-AzResourceByIdRestMethod}.ToString() + $chunks | ForEach-Object -ThrottleLimit $throttleLimit -Parallel { + if ($null -eq ${function:Remove-AzResourceByIdRestMethod}) { + ${function:Remove-AzResourceByIdRestMethod} = $using:funcRemoveAzResourceByIdRestMethod + } + $pacEnvironment = $using:pacEnvironment + foreach ($id in $_.Keys) { + $entry = $_.$id + Write-Information "$($entry.displayName) - $($id)" + Remove-AzResourceByIdRestMethod -Id $id -ApiVersion $pacEnvironment.apiVersions.policySetDefinitions + } + } } } - $policySetDefinitions = ConvertTo-HashTable $plan.policySetDefinitions.replace - if ($policySetDefinitions.psbase.Count -gt 0) { + $table = ConvertTo-HashTable $plan.policyDefinitions.replace + if ($table.psbase.Count -gt 0) { Write-Information "" Write-Information "===================================================================================================" - Write-Information "Delete replaced Policy Sets ($($policySetDefinitions.psbase.Count))" + Write-Information "Delete replaced Policies ($($table.psbase.Count))" Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($id in $policySetDefinitions.Keys) { - $policySetDefinition = $policySetDefinitions[$id] - Write-Information $policySetDefinition.displayName - $null = Remove-AzPolicySetDefinition -Id $id -Force + $chunks = Split-HashtableIntoChunks -Table $table -NumberOfChunks $throttleLimit -MinChunkingSize 10 + if ($chunks.psbase.Count -eq 1) { + $chunk = $chunks[0] + foreach ($id in $chunk.Keys) { + $entry = $chunk.$id + Write-Information "$($entry.displayName) - $($id)" + Remove-AzResourceByIdRestMethod -Id $id -ApiVersion $pacEnvironment.apiVersions.policyDefinitions + } } - } - - $policyDefinitions = ConvertTo-HashTable $plan.policyDefinitions.replace - if ($policyDefinitions.psbase.Count -gt 0) { - Write-Information "" - Write-Information "===================================================================================================" - Write-Information "Delete replaced Policies ($($policyDefinitions.psbase.Count))" - Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($id in $policyDefinitions.Keys) { - $policyDefinition = $policyDefinitions[$id] - Write-Information $policyDefinition.displayName - $null = Remove-AzPolicyDefinition -Id $id -Force + else { + $funcRemoveAzResourceByIdRestMethod = ${function:Remove-AzResourceByIdRestMethod}.ToString() + $chunks | ForEach-Object -ThrottleLimit $throttleLimit -Parallel { + if ($null -eq ${function:Remove-AzResourceByIdRestMethod}) { + ${function:Remove-AzResourceByIdRestMethod} = $using:funcRemoveAzResourceByIdRestMethod + } + $pacEnvironment = $using:pacEnvironment + foreach ($id in $_.Keys) { + $entry = $_.$id + Write-Information "$($entry.displayName) - $($id)" + Remove-AzResourceByIdRestMethod -Id $id -ApiVersion $pacEnvironment.apiVersions.policyDefinitions + } + } } } #endregion - #region create and update definitions - - $policyDefinitions = ConvertTo-HashTable $plan.policyDefinitions.new - if ($policyDefinitions.psbase.Count -gt 0) { - Write-Information "" - Write-Information "===================================================================================================" - Write-Information "Create new Policies ($($policyDefinitions.psbase.Count))" - Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($id in $policyDefinitions.Keys) { - $definitionObj = $policyDefinitions[$id] - Set-AzPolicyDefinitionRestMethod -Definition $definitionObj - } - } - - $policyDefinitions = ConvertTo-HashTable $plan.policyDefinitions.replace - if ($policyDefinitions.psbase.Count -gt 0) { - Write-Information "" - Write-Information "===================================================================================================" - Write-Information "Recreate replaced Policies ($($policyDefinitions.psbase.Count))" - Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($id in $policyDefinitions.Keys) { - $definitionObj = $policyDefinitions[$id] - Set-AzPolicyDefinitionRestMethod -Definition $definitionObj - } - } - - $policyDefinitions = ConvertTo-HashTable $plan.policyDefinitions.update - if ($policyDefinitions.psbase.Count -gt 0) { + $table = ConvertTo-HashTable $plan.policyDefinitions.new + $table += ConvertTo-HashTable $plan.policyDefinitions.replace + $table += ConvertTo-HashTable $plan.policyDefinitions.update + if ($table.psbase.Count -gt 0) { Write-Information "" Write-Information "===================================================================================================" - Write-Information "Update Policies ($($policyDefinitions.psbase.Count))" + Write-Information "Create and update Policies ($($table.psbase.Count))" Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($id in $policyDefinitions.Keys) { - $definitionObj = $policyDefinitions[$id] - Set-AzPolicyDefinitionRestMethod -Definition $definitionObj + $chunks = Split-HashtableIntoChunks -Table $table -NumberOfChunks $throttleLimit -MinChunkingSize 10 + if ($chunks.psbase.Count -eq 1) { + $chunk = $chunks[0] + foreach ($id in $chunk.Keys) { + $entry = $chunk.$id + Set-AzPolicyDefinitionRestMethod -Definition $entry -ApiVersion $pacEnvironment.apiVersions.policyDefinitions + } } - } - - $policySetDefinitions = ConvertTo-HashTable $plan.policySetDefinitions.new - if ($policySetDefinitions.psbase.Count -gt 0) { - Write-Information "" - Write-Information "===================================================================================================" - Write-Information "Create new Policy Sets ($($policySetDefinitions.psbase.Count))" - Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($id in $policySetDefinitions.Keys) { - $definitionObj = $policySetDefinitions[$id] - Set-AzPolicySetDefinitionRestMethod -Definition $definitionObj + else { + $funcSetAzPolicyDefinitionRestMethod = ${function:Set-AzPolicyDefinitionRestMethod}.ToString() + $funcRemoveNullFields = ${function:Remove-NullFields}.ToString() + $chunks | ForEach-Object -ThrottleLimit $throttleLimit -Parallel { + if ($null -eq ${function:Set-AzPolicyDefinitionRestMethod}) { + ${function:Set-AzPolicyDefinitionRestMethod} = $using:funcSetAzPolicyDefinitionRestMethod + ${function:Remove-NullFields} = $using:funcRemoveNullFields + } + $pacEnvironment = $using:pacEnvironment + foreach ($id in $_.Keys) { + $entry = $_.$id + Set-AzPolicyDefinitionRestMethod -Definition $entry -ApiVersion $pacEnvironment.apiVersions.policyDefinitions + } + } } } - $policySetDefinitions = ConvertTo-HashTable $plan.policySetDefinitions.replace - if ($policySetDefinitions.psbase.Count -gt 0) { + $table = ConvertTo-HashTable $plan.policySetDefinitions.new + $table += ConvertTo-HashTable $plan.policySetDefinitions.replace + $table += ConvertTo-HashTable $plan.policySetDefinitions.update + if ($table.psbase.Count -gt 0) { Write-Information "" Write-Information "===================================================================================================" - Write-Information "Recreate replaced Policy Sets ($($policySetDefinitions.psbase.Count))" + Write-Information "Create and update Policy Sets ($($table.psbase.Count))" Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($id in $policySetDefinitions.Keys) { - $definitionObj = $policySetDefinitions[$id] - Set-AzPolicySetDefinitionRestMethod -Definition $definitionObj + $chunks = Split-HashtableIntoChunks -Table $table -NumberOfChunks $throttleLimit -MinChunkingSize 10 + if ($chunks.psbase.Count -eq 1) { + $chunk = $chunks[0] + foreach ($id in $chunk.Keys) { + $entry = $chunk.$id + Set-AzPolicySetDefinitionRestMethod -Definition $entry -ApiVersion $pacEnvironment.apiVersions.policySetDefinitions + } } - } - - $policySetDefinitions = ConvertTo-HashTable $plan.policySetDefinitions.update - if ($policySetDefinitions.psbase.Count -gt 0) { - Write-Information "" - Write-Information "===================================================================================================" - Write-Information "Update Policy Sets ($($policySetDefinitions.psbase.Count))" - Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($id in $policySetDefinitions.Keys) { - $definitionObj = $policySetDefinitions[$id] - Set-AzPolicySetDefinitionRestMethod -Definition $definitionObj + else { + $funcSetAzPolicySetDefinitionRestMethod = ${function:Set-AzPolicySetDefinitionRestMethod}.ToString() + $funcRemoveNullFields = ${function:Remove-NullFields}.ToString() + $chunks | ForEach-Object -ThrottleLimit $throttleLimit -Parallel { + if ($null -eq ${function:Set-AzPolicySetDefinitionRestMethod}) { + ${function:Set-AzPolicySetDefinitionRestMethod} = $using:funcSetAzPolicySetDefinitionRestMethod + ${function:Remove-NullFields} = $using:funcRemoveNullFields + } + $pacEnvironment = $using:pacEnvironment + foreach ($id in $_.Keys) { + $entry = $_.$id + Set-AzPolicySetDefinitionRestMethod -Definition $entry -ApiVersion $pacEnvironment.apiVersions.policySetDefinitions + } + } } } # Policy Sets are updated, can now delete the obsolete Policies - $policyDefinitions = ConvertTo-HashTable $plan.policyDefinitions.delete - if ($policyDefinitions.psbase.Count -gt 0) { - Write-Information "" - Write-Information "===================================================================================================" - Write-Information "Delete Policies ($($policyDefinitions.psbase.Count))" - Write-Information "---------------------------------------------------------------------------------------------------" - - foreach ($policyDefinitionName in $policyDefinitions.Keys) { - $policyDefinition = $policyDefinitions[$policyDefinitionName] - Write-Information $policyDefinition.displayName - $null = Remove-AzPolicyDefinition -Id $policyDefinition.id -Force - } - } - - - - #endregion - - #region create and update assignments - - if ($newAssignments.psbase.Count -gt 0) { + $table = ConvertTo-HashTable $plan.policyDefinitions.delete + if ($table.psbase.Count -gt 0) { Write-Information "" Write-Information "===================================================================================================" - Write-Information "Create new Assignments ($($newAssignments.psbase.Count))" + Write-Information "Delete Policies ($($table.psbase.Count))" Write-Information "---------------------------------------------------------------------------------------------------" - $currentDisplayName = "-" - $newAssignments.Values | Sort-Object -Property { $_.displayName } | ForEach-Object -Process { - $currentDisplayName = Set-AzPolicyAssignmentRestMethod -Assignment $_ -CurrentDisplayName $currentDisplayName + $chunks = Split-HashtableIntoChunks -Table $table -NumberOfChunks $throttleLimit -MinChunkingSize 10 + if ($chunks.psbase.Count -eq 1) { + $chunk = $chunks[0] + foreach ($id in $chunk.Keys) { + $entry = $chunk.$id + Write-Information $entry.displayName + Remove-AzResourceByIdRestMethod -Id $id -ApiVersion $pacEnvironment.apiVersions.policyDefinitions + } } - } - - if ($replaceAssignments.psbase.Count -gt 0) { - Write-Information "" - Write-Information "===================================================================================================" - Write-Information "Recreate replaced Assignments ($($replaceAssignments.psbase.Count))" - Write-Information "---------------------------------------------------------------------------------------------------" - $currentDisplayName = "-" - $replaceAssignments.Values | Sort-Object -Property { $_.displayName } | ForEach-Object -Process { - $currentDisplayName = Set-AzPolicyAssignmentRestMethod -Assignment $_ -CurrentDisplayName $currentDisplayName + else { + $funcRemoveAzResourceByIdRestMethod = ${function:Remove-AzResourceByIdRestMethod}.ToString() + $chunks | ForEach-Object -ThrottleLimit $throttleLimit -Parallel { + if ($null -eq ${function:Remove-AzResourceByIdRestMethod}) { + ${function:Remove-AzResourceByIdRestMethod} = $using:funcRemoveAzResourceByIdRestMethod + } + $pacEnvironment = $using:pacEnvironment + foreach ($id in $_.Keys) { + $entry = $_.$id + Write-Information "$($entry.displayName) - $($id)" + Remove-AzResourceByIdRestMethod -Id $id -ApiVersion $pacEnvironment.apiVersions.policyDefinitions + } + } } } - if ($updateAssignments.psbase.Count -gt 0) { + $table = ConvertTo-HashTable $plan.assignments.new + $table += ConvertTo-HashTable $plan.assignments.replace + $table += ConvertTo-HashTable $plan.assignments.update + if ($table.psbase.Count -gt 0) { Write-Information "" Write-Information "===================================================================================================" - Write-Information "Update Assignments ($($updateAssignments.psbase.Count))" + Write-Information "Create and update Assignments ($($table.psbase.Count))" Write-Information "---------------------------------------------------------------------------------------------------" - $currentDisplayName = "-" - $updateAssignments.Values | Sort-Object -Property { $_.displayName } | ForEach-Object -Process { - $currentDisplayName = Set-AzPolicyAssignmentRestMethod -Assignment $_ -CurrentDisplayName $currentDisplayName + $chunks = Split-HashtableIntoChunks -Table $table -NumberOfChunks $throttleLimit -MinChunkingSize 10 + if ($chunks.psbase.Count -eq 1) { + $chunk = $chunks[0] + foreach ($id in $chunk.Keys) { + $entry = $chunk.$id + Set-AzPolicyAssignmentRestMethod -Assignment $entry -ApiVersion $pacEnvironment.apiVersions.policyAssignments + } } - } - - #endregion - - #region Exemptions - - $exemptions = ConvertTo-HashTable $plan.exemptions.new - if ($exemptions.psbase.Count -gt 0) { - Write-Information "" - Write-Information "===================================================================================================" - Write-Information "Create new Exemptions ($($exemptions.psbase.Count))" - Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($exemptionId in $exemptions.Keys) { - $exemption = $exemptions.$exemptionId - Set-AzPolicyExemptionRestMethod -ExemptionObj $exemption + else { + $funcSetAzPolicyAssignmentRestMethod = ${function:Set-AzPolicyAssignmentRestMethod}.ToString() + $funcGetDeepClone = ${function:Get-ClonedObject}.ToString() + $chunks | ForEach-Object -ThrottleLimit $throttleLimit -Parallel { + if ($null -eq ${function:Set-AzPolicyAssignmentRestMethod}) { + ${function:Set-AzPolicyAssignmentRestMethod} = $using:funcSetAzPolicyAssignmentRestMethod + ${function:Get-ClonedObject} = $using:funcGetDeepClone + } + $pacEnvironment = $using:pacEnvironment + foreach ($id in $_.Keys) { + $entry = $_.$id + Set-AzPolicyAssignmentRestMethod -Assignment $entry -ApiVersion $pacEnvironment.apiVersions.policyAssignments + } + } } } - $exemptions = ConvertTo-HashTable $plan.exemptions.replace - if ($exemptions.psbase.Count -gt 0) { + $table = ConvertTo-HashTable $plan.exemptions.new + $table += ConvertTo-HashTable $plan.exemptions.replace + $table += ConvertTo-HashTable $plan.exemptions.update + if ($table.psbase.Count -gt 0) { Write-Information "" Write-Information "===================================================================================================" - Write-Information "Create replaced Exemptions ($($exemptions.psbase.Count))" + Write-Information "Create and update Exemptions ($($table.psbase.Count))" Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($exemptionId in $exemptions.Keys) { - $exemption = $exemptions.$exemptionId - Set-AzPolicyExemptionRestMethod -ExemptionObj $exemption + $chunks = Split-HashtableIntoChunks -Table $table -NumberOfChunks $throttleLimit -MinChunkingSize 10 + if ($chunks.psbase.Count -eq 1) { + $chunk = $chunks[0] + foreach ($exemptionId in $chunk.Keys) { + $entry = $chunk.$exemptionId + Set-AzPolicyExemptionRestMethod -ExemptionObj $entry -ApiVersion $pacEnvironment.apiVersions.policyExemptions + } } - } - - $exemptions = (ConvertTo-HashTable $plan.exemptions.update) - if ($exemptions.psbase.Count -gt 0) { - Write-Information "" - Write-Information "===================================================================================================" - Write-Information "Update Exemptions ($($exemptions.psbase.Count))" - Write-Information "---------------------------------------------------------------------------------------------------" - foreach ($exemptionId in $exemptions.Keys) { - $exemption = $exemptions.$exemptionId - Set-AzPolicyExemptionRestMethod -ExemptionObj $exemption + else { + $funcSetAzPolicyExemptionRestMethod = ${function:Set-AzPolicyExemptionRestMethod}.ToString() + $funcRemoveNullFields = ${function:Remove-NullFields}.ToString() + $chunks | ForEach-Object -ThrottleLimit $throttleLimit -Parallel { + if ($null -eq ${function:Set-AzPolicyExemptionRestMethod}) { + ${function:Set-AzPolicyExemptionRestMethod} = $using:funcSetAzPolicyExemptionRestMethod + ${function:Remove-NullFields} = $using:funcRemoveNullFields + } + $pacEnvironment = $using:pacEnvironment + foreach ($exemptionId in $_.Keys) { + $entry = $_.$exemptionId + Set-AzPolicyExemptionRestMethod -ExemptionObj $entry -ApiVersion $pacEnvironment.apiVersions.policyExemptions + } + } } } - - #endregion - + Write-Information "" + Write-Information "***************************************************************************************************" + Write-Information "Policy resources deployed from plan in file '$planFile'" + Write-Information "***************************************************************************************************" } diff --git a/Scripts/Deploy/Deploy-RolesPlan.ps1 b/Scripts/Deploy/Deploy-RolesPlan.ps1 index cc48c6f8..0509cc9a 100644 --- a/Scripts/Deploy/Deploy-RolesPlan.ps1 +++ b/Scripts/Deploy/Deploy-RolesPlan.ps1 @@ -73,7 +73,7 @@ $plan = Get-DeploymentPlan -PlanFile $planFile -AsHashTable if ($null -eq $plan) { Write-Warning "***************************************************************************************************" - Write-Warning "Plan does not exist, skip Role assignments deployment." + Write-Warning "Plan file $planFile does not exist, skip Role assignments deployment." Write-Warning "***************************************************************************************************" Write-Warning "" } @@ -83,16 +83,24 @@ else { Write-Information "Deploy Role assignments from plan in file '$planFile'" Write-Information "Plan created on $($plan.createdOn)." Write-Information "***************************************************************************************************" + Write-Information "" - $removedRoleAssignments = $plan.roleAssignments.removed $addedRoleAssignments = $plan.roleAssignments.added + $updatedRoleAssignments = $plan.roleAssignments.updated + $removedRoleAssignments = $plan.roleAssignments.removed if ($removedRoleAssignments.psbase.Count -gt 0) { Write-Information "===================================================================================================" Write-Information "Remove ($($removedRoleAssignments.psbase.Count)) obsolete Role assignments" Write-Information "---------------------------------------------------------------------------------------------------" foreach ($roleAssignment in $removedRoleAssignments) { Write-Information "PrincipalId $($roleAssignment.principalId), role $($roleAssignment.roleDisplayName)($($roleAssignment.roleDefinitionId)) at $($roleAssignment.scope)" - $null = Remove-AzRoleAssignmentRestMethod -RoleAssignmentId $roleAssignment.id + if (!$roleAssignment.crossTenant) { + $null = Remove-AzRoleAssignmentRestMethod -RoleAssignmentId $roleAssignment.id -ApiVersion $pacEnvironment.apiVersions.roleAssignments + } + else { + $null = Remove-AzRoleAssignmentRestMethod -RoleAssignmentId $roleAssignment.id -TenantId $pacEnvironment.managingTenantId -ApiVersion $pacEnvironment.apiVersions.roleAssignments + } + } Write-Information "" } @@ -105,13 +113,16 @@ else { # Get identities for policy assignments from plan or by calling the REST API to retrieve the Policy Assignment $assignmentById = @{} foreach ($roleAssignment in $addedRoleAssignments) { - $principalId = $roleAssignment.principalId + $principalId = $roleAssignment.properties.principalId + $policyAssignmentId = $roleAssignment.assignmentId if ($null -eq $principalId) { - $policyAssignmentId = $roleAssignment.assignmentId $identity = $null $principalId = "" - if (-not $assignmentById.ContainsKey($policyAssignmentId)) { - $policyAssignment = Get-AzPolicyAssignmentRestMethod -AssignmentId $roleAssignment.assignmentId + if ($assignmentById.ContainsKey($policyAssignmentId)) { + $principalId = $assignmentById[$policyAssignmentId] + } + else { + $policyAssignment = Get-AzPolicyAssignmentRestMethod -AssignmentId $policyAssignmentId -ApiVersion $pacEnvironment.apiVersions.policyAssignments $identity = $policyAssignment.identity if ($identity -and $identity.type -ne "None") { $principalId = "" @@ -126,35 +137,26 @@ else { else { Write-Error "Identity not found for assignment '$($policyAssignmentId)'" -ErrorAction Stop } - $null = $assignmentById.Add($policyAssignmentId, @{ - principalId = $principalId - displayName = $policyAssignment.properties.displayName - }) + $null = $assignmentById.Add($policyAssignmentId, $principalId) } + $roleAssignment.properties.principalId = $principalId } - else { - $null = $assignmentById.Add($roleAssignment.assignmentId, @{ - principalId = $principalId - displayName = $roleAssignment.displayName - }) + elseif (-not $assignmentById.ContainsKey($policyAssignmentId)) { + $null = $assignmentById.Add($policyAssignmentId, $principalId) } + Set-AzRoleAssignmentRestMethod -RoleAssignment $roleAssignment -ApiVersion $pacEnvironment.apiVersions.roleAssignments } + Write-Information "" + } + if ($updatedRoleAssignments.psbase.Count -gt 0) { + Write-Information "===================================================================================================" + Write-Information "Update ($($updatedRoleAssignments.psbase.Count)) Role assignments" + Write-Information "---------------------------------------------------------------------------------------------------" - # Add the role assignments using the information collected above - foreach ($roleAssignment in $addedRoleAssignments) { - $assignmentId = $roleAssignment.assignmentId - $assignmentInfo = $assignmentById.$assignmentId - $splat = @{ - Scope = $roleAssignment.scope - ObjectType = $roleAssignment.objectType - ObjectId = $assignmentInfo.principalId - RoleDefinitionId = $roleAssignment.roleDefinitionId - RoleDisplayName = $roleAssignment.roleDisplayName - AssignmentDisplayName = $assignmentInfo.displayName - Description = "Deployed by EPAC" - } - Set-AzRoleAssignmentRestMethod @splat -IgnoreDuplicateError + # Get identities for policy assignments from plan or by calling the REST API to retrieve the Policy Assignment + foreach ($roleAssignment in $updatedRoleAssignments) { + Set-AzRoleAssignmentRestMethod -RoleAssignment $roleAssignment -ApiVersion $pacEnvironment.apiVersions.roleAssignments } + Write-Information "" } - Write-Information "" } diff --git a/Scripts/Helpers/Add-ErrorMessage.ps1 b/Scripts/Helpers/Add-ErrorMessage.ps1 index 96804239..835476d9 100644 --- a/Scripts/Helpers/Add-ErrorMessage.ps1 +++ b/Scripts/Helpers/Add-ErrorMessage.ps1 @@ -7,15 +7,13 @@ function Add-ErrorMessage { ) if ($EntryNumber -ne -1) { - if ($ErrorInfo.currentEntryNumber -ne $EntryNumber) { - $ErrorInfo.errorStrings.Add("- Entry number $($EntryNumber):") - } - $ErrorInfo.errorStrings.Add(" - $ErrorString") + $null = $ErrorInfo.errorStrings.Add(" $($EntryNumber): $ErrorString") } else { - $ErrorInfo.errorStrings.Add("- $ErrorString") + $null = $ErrorInfo.errorStrings.Add(" $ErrorString") } $ErrorInfo.errorsInFile++ $ErrorInfo.hasErrors = $true + $ErrorInfo.hasLocalErrors = $true $ErrorInfo.currentEntryNumber = $EntryNumber } diff --git a/Scripts/Helpers/Add-HelperScripts.ps1 b/Scripts/Helpers/Add-HelperScripts.ps1 index 8d3ae28f..7aa45e2b 100644 --- a/Scripts/Helpers/Add-HelperScripts.ps1 +++ b/Scripts/Helpers/Add-HelperScripts.ps1 @@ -2,6 +2,8 @@ # Load cmdlets . "$PSScriptRoot/Add-ErrorMessage.ps1" +. "$PSScriptRoot/Add-SelectedPacArray.ps1" +. "$PSScriptRoot/Add-SelectedPacValue.ps1" . "$PSScriptRoot/Build-AssignmentDefinitionAtLeaf.ps1" . "$PSScriptRoot/Build-AssignmentDefinitionEntry.ps1" @@ -11,12 +13,15 @@ . "$PSScriptRoot/Build-AssignmentPlan.ps1" . "$PSScriptRoot/Build-ExemptionsPlan.ps1" -. "$PSScriptRoot/Build-NotScopes.ps1" . "$PSScriptRoot/Build-PolicyPlan.ps1" . "$PSScriptRoot/Build-PolicySetPlan.ps1" . "$PSScriptRoot/Build-PolicySetPolicyDefinitionIds.ps1" -. "$PSScriptRoot/Confirm-AssignmentParametersMatch.ps1" +. "$PSScriptRoot/Build-ScopeTableForDeploymentRootScope.ps1" +. "$PSScriptRoot/Build-ScopeTableForManagementGroup.ps1" +. "$PSScriptRoot/Build-ScopeTableForSubscription.ps1" + +. "$PSScriptRoot/Confirm-EffectIsAllowed.ps1" . "$PSScriptRoot/Confirm-MetadataMatches.ps1" . "$PSScriptRoot/Confirm-NullOrEmptyValue.ps1" . "$PSScriptRoot/Confirm-PacOwner.ps1" @@ -36,36 +41,33 @@ . "$PSScriptRoot/Convert-EffectToMarkdownString.ps1" . "$PSScriptRoot/Convert-EffectToCsvString.ps1" . "$PSScriptRoot/Convert-OrdinalToEffectDisplayName.ps1" -. "$PSScriptRoot/Convert-ListToToCsvRow.ps1" . "$PSScriptRoot/Convert-ParametersToString.ps1" -. "$PSScriptRoot/Convert-PolicySetsToDetails.ps1" -. "$PSScriptRoot/Convert-PolicySetsToFlatList.ps1" +. "$PSScriptRoot/Convert-PolicyResourcesDetailsToFlatList.ps1" +. "$PSScriptRoot/Convert-PolicyResourcesToDetails.ps1" +. "$PSScriptRoot/Convert-PolicySetToDetails.ps1" +. "$PSScriptRoot/Convert-PolicyToDetails.ps1" . "$PSScriptRoot/ConvertTo-ArrayList.ps1" . "$PSScriptRoot/ConvertTo-HashTable.ps1" +. "$PSScriptRoot/Export-AssignmentNode.ps1" . "$PSScriptRoot/Find-AzNonCompliantResources.ps1" -. "$PSScriptRoot/Get-AssignmentsDetails.ps1" -. "$PSScriptRoot/Get-AzPolicyAssignmentRestMethod.ps1" +. "$PSScriptRoot/Get-AzPolicyOrSetDefinitions.ps1" +. "$PSScriptRoot/Get-AzPolicyAssignments.ps1" +. "$PSScriptRoot/Get-AzPolicyExemptions.ps1" . "$PSScriptRoot/Get-AzPolicyResources.ps1" -. "$PSScriptRoot/Get-AzScopeTree.ps1" +. "$PSScriptRoot/Get-AzPolicyResourcesDetails.ps1" +. "$PSScriptRoot/Get-CalculatedPolicyAssignmentsAndReferenceIds.ps1" +. "$PSScriptRoot/Get-ClonedObject.ps1" . "$PSScriptRoot/Get-CustomMetadata.ps1" -. "$PSScriptRoot/Get-DeepClone.ps1" . "$PSScriptRoot/Get-DefinitionsFullPath.ps1" . "$PSScriptRoot/Get-DeploymentPlan.ps1" -. "$PSScriptRoot/Get-ErrorTextFromInfo.ps1" -. "$PSScriptRoot/Get-FilteredHashTable.ps1" . "$PSScriptRoot/Get-GlobalSettings.ps1" -. "$PSScriptRoot/Get-HashtableShallowClone" -. "$PSScriptRoot/Get-HashtableWithPropertyNamesRemoved.ps1" . "$PSScriptRoot/Get-PacFolders.ps1" . "$PSScriptRoot/Get-ParameterNameFromValueString.ps1" -. "$PSScriptRoot/Get-PolicyResourceDetails.ps1" +. "$PSScriptRoot/Get-PolicyAssignmentsDetails.ps1" . "$PSScriptRoot/Get-PolicyResourceProperties.ps1" . "$PSScriptRoot/Get-ScrubbedString.ps1" -. "$PSScriptRoot/Get-SelectedPacValue.ps1" - -. "$PSScriptRoot/Invoke-AzResMethodWrapper.ps1" . "$PSScriptRoot/Merge-AssignmentParametersEx.ps1" . "$PSScriptRoot/Merge-ExportNodeAncestors.ps1" @@ -80,30 +82,34 @@ . "$PSScriptRoot/Out-PolicyExemptions.ps1" . "$PSScriptRoot/Out-PolicySetsDocumentationToFile.ps1" -. "$PSScriptRoot/Remove-AzRoleAssignmentRestMethod.ps1" . "$PSScriptRoot/Remove-NullFields.ps1" . "$PSScriptRoot/Remove-GlobalNotScopes.ps1" . "$PSScriptRoot/Search-AzGraphAllItems.ps1" - . "$PSScriptRoot/Select-PacEnvironment.ps1" . "$PSScriptRoot/Set-AzCloudTenantSubscription.ps1" -. "$PSScriptRoot/Set-AzPolicyAssignmentRestMethod.ps1" -. "$PSScriptRoot/Set-AzPolicyDefinitionRestMethod.ps1" -. "$PSScriptRoot/Set-AzPolicySetDefinitionRestMethod.ps1" -. "$PSScriptRoot/Set-AzPolicyExemptionRestMethod.ps1" -. "$PSScriptRoot/Set-AzRoleAssignmentRestMethod.ps1" - -. "$PSScriptRoot/Export-AssignmentNode.ps1" . "$PSScriptRoot/Set-ExportNode.ps1" . "$PSScriptRoot/Set-ExportNodeAncestors.ps1" - . "$PSScriptRoot/Set-UniqueRoleAssignmentScopes.ps1" +. "$PSScriptRoot/Split-ArrayIntoChunks.ps1" . "$PSScriptRoot/Split-AzPolicyResourceId.ps1" -. "$PSScriptRoot/Split-ScopeId.ps1" +. "$PSScriptRoot/Split-HashtableIntoChunks.ps1" . "$PSScriptRoot/Switch-PacEnvironment.ps1" . "$PSScriptRoot/Write-AssignmentDetails.ps1" +. "$PSScriptRoot/Write-ErrorsFromErrorInfo.ps1" + +. "$PSScriptRoot/RestMethods/Get-AzPolicyAssignmentRestMethod.ps1" +. "$PSScriptRoot/RestMethods/Get-AzPolicyExemptionsRestMethod.ps1" +. "$PSScriptRoot/RestMethods/Get-AzRoleAssignmentsRestMethod.ps1" +. "$PSScriptRoot/RestMethods/Get-AzRoleDefinitionsRestMethod.ps1" +. "$PSScriptRoot/RestMethods/Remove-AzResourceByIdRestMethod.ps1" +. "$PSScriptRoot/RestMethods/Remove-AzRoleAssignmentRestMethod.ps1" +. "$PSScriptRoot/RestMethods/Set-AzPolicyAssignmentRestMethod.ps1" +. "$PSScriptRoot/RestMethods/Set-AzPolicyDefinitionRestMethod.ps1" +. "$PSScriptRoot/RestMethods/Set-AzPolicySetDefinitionRestMethod.ps1" +. "$PSScriptRoot/RestMethods/Set-AzPolicyExemptionRestMethod.ps1" +. "$PSScriptRoot/RestMethods/Set-AzRoleAssignmentRestMethod.ps1" diff --git a/Scripts/Helpers/Add-SelectedPacArray.ps1 b/Scripts/Helpers/Add-SelectedPacArray.ps1 new file mode 100644 index 00000000..4c13feb0 --- /dev/null +++ b/Scripts/Helpers/Add-SelectedPacArray.ps1 @@ -0,0 +1,28 @@ +function Add-SelectedPacArray { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [hashtable] $InputObject, + + [Parameter(Mandatory = $true)] + [string] $PacSelector, + + [System.Collections.ArrayList] $OutputArrayList + ) + + $array = $InputObject.$PacSelector + if ($null -ne $array) { + if ($array -isnot [array]) { + $array = @($array) + } + $null = $OutputArrayList.AddRange($array) + } + + $array = $InputObject["*"] + if ($null -ne $array) { + if ($array -isnot [array]) { + $array = @($array) + } + $null = $OutputArrayList.AddRange($array) + } +} diff --git a/Scripts/Helpers/Add-SelectedPacValue.ps1 b/Scripts/Helpers/Add-SelectedPacValue.ps1 new file mode 100644 index 00000000..5b3c3791 --- /dev/null +++ b/Scripts/Helpers/Add-SelectedPacValue.ps1 @@ -0,0 +1,28 @@ +function Add-SelectedPacValue { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [hashtable] $InputObject, + + [Parameter(Mandatory = $true)] + [string] $PacSelector, + + [Parameter(Mandatory = $true)] + [hashtable] $OutputObject, + + [Parameter(Mandatory = $true)] + [string] $OutputKey + ) + + $value = $InputObject.$PacSelector + if ($null -eq $value) { + $value = $InputObject["*"] + } + + if ($null -ne $value) { + if ($value -is [array]) { + Write-Error "Value for '$PacSelector' is an array. It must be a single value. value is $(ConvertTo-Json $InputObject -Depth 100 -Compress)" -ErrorAction Stop + } + $OutputObject[$OutputKey] = $value + } +} diff --git a/Scripts/Helpers/Build-AssignmentDefinitionAtLeaf.ps1 b/Scripts/Helpers/Build-AssignmentDefinitionAtLeaf.ps1 index 5edc7858..8a3d3441 100644 --- a/Scripts/Helpers/Build-AssignmentDefinitionAtLeaf.ps1 +++ b/Scripts/Helpers/Build-AssignmentDefinitionAtLeaf.ps1 @@ -115,7 +115,7 @@ function Build-AssignmentDefinitionAtLeaf { #endregion Validate CSV data - $assignmentsList = @() + $assignmentsList = [System.Collections.ArrayList]::new() $policiesDetails = $CombinedPolicyDetails.policies $policySetsDetails = $CombinedPolicyDetails.policySets $effectProcessedForPolicy = @{} @@ -164,23 +164,18 @@ function Build-AssignmentDefinitionAtLeaf { continue } $enforcementMode = $AssignmentDefinition.enforcementMode - $metadata = $AssignmentDefinition.metadata - if ($metadata) { - if ($metadata.ContainsKey("pacOwnerId")) { - Write-Error " Leaf Node $($nodeName): metadata.pacOwnerId ($($metadata.pacOwnerId)) may not be set explicitly; it is reserved for EPAC usage." - $hasErrors = $true - continue - } - if ($metadata.ContainsKey("roles")) { - Write-Error " Leaf Node $($nodeName): metadata.roles ($($metadata.roles)) may not be set explicitly; it is reserved for EPAC usage." - $hasErrors = $true - continue - } - $metadata.pacOwnerId = $thisPacOwnerId + $metadata = Get-ClonedObject $AssignmentDefinition.metadata -AsHashTable + if ($metadata.ContainsKey("pacOwnerId")) { + Write-Error " Leaf Node $($nodeName): metadata.pacOwnerId ($($metadata.pacOwnerId)) may not be set explicitly; it is reserved for EPAC usage." + $hasErrors = $true + continue } - else { - $metadata = @{ pacOwnerId = $thisPacOwnerId } + if ($metadata.ContainsKey("roles")) { + Write-Error " Leaf Node $($nodeName): metadata.roles ($($metadata.roles)) may not be set explicitly; it is reserved for EPAC usage." + $hasErrors = $true + continue } + $metadata.pacOwnerId = $thisPacOwnerId #endregion assignment name, displayName, description, metadata, enforcementMode @@ -201,7 +196,7 @@ function Build-AssignmentDefinitionAtLeaf { } foreach ($nonComplianceMessageRaw in $nonComplianceMessagesList) { if ($null -eq $nonComplianceMessageRaw.message -or $nonComplianceMessageRaw.message -eq "") { - Write-Error " Leaf Node $($nodeName): each nonComplianceMessage must conatin a message string: $($nonComplianceMessageRaw | ConvertTo-Json -Depth 3 -Compress)" + Write-Error " Leaf Node $($nodeName): each nonComplianceMessage must conatin a message string: $($nonComplianceMessageRaw | ConvertTo-Json -Depth 100 -Compress)" $hasErrors = $true } } @@ -270,7 +265,7 @@ function Build-AssignmentDefinitionAtLeaf { $null = $resourceSelectorsList.Add($resourceSelectorFinal) } else { - Write-Error " Leaf Node $($nodeName): resourceSelector is invalid: $($resourceSelector | ConvertTo-Json -Depth 3 -Compress)" + Write-Error " Leaf Node $($nodeName): resourceSelector is invalid: $($resourceSelector | ConvertTo-Json -Depth 100 -Compress)" $hasErrors = $true } } @@ -301,12 +296,12 @@ function Build-AssignmentDefinitionAtLeaf { } } else { - Write-Error " Leaf Node $($nodeName): overrides must specify which Policy Set in the definitionEntryList they belong to by either using policySetName or policySetId: $($effectOverride | ConvertTo-Json -Depth 3 -Compress)" + Write-Error " Leaf Node $($nodeName): overrides must specify which Policy Set in the definitionEntryList they belong to by either using policySetName or policySetId: $($effectOverride | ConvertTo-Json -Depth 100 -Compress)" $hasErrors = $true } } elseif ($null -ne $policySetName -or $null -ne $policySetId) { - Write-Error " Leaf Node $($nodeName): overrides must NOT specify which Policy Set for a single definitionEntry it belongs to by using policySetName or policySetId: $($effectOverride | ConvertTo-Json -Depth 3 -Compress)" + Write-Error " Leaf Node $($nodeName): overrides must NOT specify which Policy Set for a single definitionEntry it belongs to by using policySetName or policySetId: $($effectOverride | ConvertTo-Json -Depth 100 -Compress)" $hasErrors = $true } else { @@ -328,12 +323,12 @@ function Build-AssignmentDefinitionAtLeaf { } } else { - Write-Error " Leaf Node $($nodeName): overrides must specify which Policy in the definitionEntryList they belong to by either using policyName or policyId: $($effectOverride | ConvertTo-Json -Depth 3 -Compress)" + Write-Error " Leaf Node $($nodeName): overrides must specify which Policy in the definitionEntryList they belong to by either using policyName or policyId: $($effectOverride | ConvertTo-Json -Depth 100 -Compress)" $hasErrors = $true } } elseif ($null -ne $policySetName -or $null -ne $policySetId) { - Write-Error " Leaf Node $($nodeName): overrides must NOT specify which Policy for a single definitionEntry it belongs to by using policyName or policyId: $($effectOverride | ConvertTo-Json -Depth 3 -Compress)" + Write-Error " Leaf Node $($nodeName): overrides must NOT specify which Policy for a single definitionEntry it belongs to by using policyName or policyId: $($effectOverride | ConvertTo-Json -Depth 100 -Compress)" $hasErrors = $true } else { @@ -356,7 +351,7 @@ function Build-AssignmentDefinitionAtLeaf { } } else { - Write-Error " Leaf Node $($nodeName): overrides must specify a selectors element for an assignment of a Policy Set: $($effectOverride | ConvertTo-Json -Depth 3 -Compress)" + Write-Error " Leaf Node $($nodeName): overrides must specify a selectors element for an assignment of a Policy Set: $($effectOverride | ConvertTo-Json -Depth 100 -Compress)" $hasErrors = $true } } @@ -370,12 +365,12 @@ function Build-AssignmentDefinitionAtLeaf { } } else { - Write-Error " Leaf Node $($nodeName): overrides must specify a valid effect ($($effectAllowedOverrides -join ",")): $($effectOverride | ConvertTo-Json -Depth 3 -Compress)" + Write-Error " Leaf Node $($nodeName): overrides must specify a valid effect ($($effectAllowedOverrides -join ",")): $($effectOverride | ConvertTo-Json -Depth 100 -Compress)" $hasErrors = $true } } else { - Write-Error " Leaf Node $($nodeName): overrides must NOT specify a selectors element for an assignment of a Policy: $($effectOverride | ConvertTo-Json -Depth 3 -Compress)" + Write-Error " Leaf Node $($nodeName): overrides must NOT specify a selectors element for an assignment of a Policy: $($effectOverride | ConvertTo-Json -Depth 100 -Compress)" $hasErrors = $true } } @@ -384,7 +379,7 @@ function Build-AssignmentDefinitionAtLeaf { } } else { - Write-Error " Leaf Node $($nodeName): overrides must specify a kind and value element: $($effectOverride | ConvertTo-Json -Depth 3 -Compress)" + Write-Error " Leaf Node $($nodeName): overrides must specify a kind and value element: $($effectOverride | ConvertTo-Json -Depth 100 -Compress)" $hasErrors = $true } } @@ -395,7 +390,6 @@ function Build-AssignmentDefinitionAtLeaf { #region identity (location, user-assigned, additionalRoleAssignments) - $baseRoleAssignmentSpecs = @() $roleDefinitionIds = $null $identityRequired = $false $managedIdentityLocation = $null @@ -425,7 +419,7 @@ function Build-AssignmentDefinitionAtLeaf { } } else { - Write-Error " Leaf Node $($nodeName): userAssignedIdentity must specify which Policy Set in the definitionEntryList they belong to by either using policySetName or policySetId: $($userAssignedIdentityRaw | ConvertTo-Json -Depth 3 -Compress)" + Write-Error " Leaf Node $($nodeName): userAssignedIdentity must specify which Policy Set in the definitionEntryList they belong to by either using policySetName or policySetId: $($userAssignedIdentityRaw | ConvertTo-Json -Depth 100 -Compress)" $hasErrors = $true continue } @@ -444,7 +438,7 @@ function Build-AssignmentDefinitionAtLeaf { } } else { - Write-Error " Leaf Node $($nodeName): userAssignedIdentity must specify which Policy in the definitionEntryList they belong to by either using policyName or policyId: $($userAssignedIdentityRaw | ConvertTo-Json -Depth 3 -Compress)" + Write-Error " Leaf Node $($nodeName): userAssignedIdentity must specify which Policy in the definitionEntryList they belong to by either using policyName or policyId: $($userAssignedIdentityRaw | ConvertTo-Json -Depth 100 -Compress)" $hasErrors = $true continue } @@ -452,7 +446,7 @@ function Build-AssignmentDefinitionAtLeaf { } } else { - Write-Error " Leaf Node $($nodeName): userAssignedIdentity is not valid: $($userAssignedIdentityRaw | ConvertTo-Json -Depth 3 -Compress)" -ErrorAction Stop + Write-Error " Leaf Node $($nodeName): userAssignedIdentity is not valid: $($userAssignedIdentityRaw | ConvertTo-Json -Depth 100 -Compress)" -ErrorAction Stop } } $identityRequired = $true @@ -476,23 +470,6 @@ function Build-AssignmentDefinitionAtLeaf { } } } - - $additionalRoleAssignments = $AssignmentDefinition.additionalRoleAssignments - if ($additionalRoleAssignments -and $additionalRoleAssignments.Length -gt 0) { - foreach ($additionalRoleAssignment in $additionalRoleAssignments) { - $roleDefinitionId = $additionalRoleAssignment.roleDefinitionId - $roleDisplayName = "Unknown" - $roleDefinitionName = ($roleDefinitionId.Split("/"))[-1] - if ($RoleDefinitions.ContainsKey($roleDefinitionName)) { - $roleDisplayName = $RoleDefinitions.$roleDefinitionName - } - $baseRoleAssignmentSpecs += @{ - scope = $additionalRoleAssignment.scope - roleDefinitionId = $roleDefinitionId - roleDisplayName = $roleDisplayName - } - } - } } else { $identitySpec = @{ @@ -590,43 +567,75 @@ function Build-AssignmentDefinitionAtLeaf { foreach ($scopeEntry in $scopeCollection) { # Clone hashtable - [hashtable] $scopedAssignment = Get-DeepClone $baseAssignment -AsHashTable + [hashtable] $scopedAssignment = Get-ClonedObject $baseAssignment -AsHashTable + + # Add scope and if defined notScopes() + $scope = $scopeEntry.scope + $id = "$scope/providers/Microsoft.Authorization/policyAssignments/$($baseAssignment.name)" + $scopedAssignment.id = $id + $scopedAssignment.scope = $scope + $notScopesList = $scopeEntry.notScopesList + $scopedAssignment.notScopes = $notScopesList - # Complete processing roleDefinitions and add with metadata to hashtable if ($identityRequired) { + # Add required roleDefinitions (required by Policy definitions) + $requiredRoleAssignments = [System.Collections.ArrayList]::new() + $policyRoleDefinitionIds = $PolicyRoleIds.$policyDefinitionId - $roleAssignmentSpecs = @() - $roleAssignmentSpecs += $baseRoleAssignmentSpecs - $roleDefinitionIds = $PolicyRoleIds.$policyDefinitionId - foreach ($roleDefinitionId in $roleDefinitionIds) { + foreach ($roleDefinitionId in $policyRoleDefinitionIds) { $roleDisplayName = "Unknown" if ($RoleDefinitions.ContainsKey($roleDefinitionId)) { $roleDisplayName = $RoleDefinitions.$roleDefinitionId } - $roleAssignmentSpecs += @{ + else { + $null = $null + } + $requiredRoleAssignment = @{ scope = $scopeEntry.scope roleDefinitionId = $roleDefinitionId roleDisplayName = $roleDisplayName + description = "Policy Assignment '$id': Role Assignment required by Policy, deployed by: '$($PacEnvironment.deployedBy)'" + crossTenant = $false + } + $null = $requiredRoleAssignments.Add($requiredRoleAssignment) + } + # Add required roleDefinitions from additionalRoleAssignments + $additionalRoleAssignments = $AssignmentDefinition.additionalRoleAssignments + if ($additionalRoleAssignments) { + foreach ($additionalRoleAssignment in $additionalRoleAssignments) { + $roleDefinitionId = $additionalRoleAssignment.roleDefinitionId + $roleDisplayName = "Unknown" + if ($RoleDefinitions.ContainsKey($roleDefinitionId)) { + $roleDisplayName = $RoleDefinitions.$roleDefinitionId + } + $requiredRoleAssignment = $null + if ($additionalRoleAssignment.crossTenant -eq $true) { + $requiredRoleAssignment = @{ + scope = $scopeEntry.scope + roleDefinitionId = $roleDefinitionId + roleDisplayName = $roleDisplayName + description = "Policy Assignment '$id': additional cross tenant Role Assignment deployed by: '$($PacEnvironment.deployedBy)'" + crossTenant = $true + } + } + else { + $requiredRoleAssignment = @{ + scope = $scopeEntry.scope + roleDefinitionId = $roleDefinitionId + roleDisplayName = $roleDisplayName + description = "Policy Assignment '$id': additional Role Assignment deployed by: '$($PacEnvironment.deployedBy)'" + crossTenant = $false + } + } + $null = $requiredRoleAssignments.Add($requiredRoleAssignment) } } - $scopedAssignment.metadata.roles = $roleAssignmentSpecs - } - # Add scope and if defined notScopes() - $scope = $scopeEntry.scope - $id = "$scope/providers/Microsoft.Authorization/policyAssignments/$($baseAssignment.name)" - $scopedAssignment.id = $id - $scopedAssignment.scope = $scope - if ($scopeEntry.notScope.Length -gt 0) { - $scopedAssignment.notScopes = @() + $scopeEntry.notScope - } - else { - $scopedAssignment.notScopes = @() + $scopedAssignment.requiredRoleAssignments = $requiredRoleAssignments } # Add completed hashtable to collection - $assignmentsList += $scopedAssignment - + $null = $assignmentsList.Add($scopedAssignment) } #endregion scopeCollection diff --git a/Scripts/Helpers/Build-AssignmentDefinitionNode.ps1 b/Scripts/Helpers/Build-AssignmentDefinitionNode.ps1 index f4be01cc..69924b80 100644 --- a/Scripts/Helpers/Build-AssignmentDefinitionNode.ps1 +++ b/Scripts/Helpers/Build-AssignmentDefinitionNode.ps1 @@ -14,11 +14,10 @@ function Build-AssignmentDefinitionNode { ) # Each tree branch needs a private copy - $definition = Get-DeepClone -InputObject $AssignmentDefinition -AsHashTable + $definition = Get-ClonedObject -InputObject $AssignmentDefinition $pacSelector = $PacEnvironment.pacSelector #region nodeName (required) - $nodeName = $definition.nodeName if ($DefinitionNode.nodeName) { $nodeName += $DefinitionNode.nodeName @@ -29,13 +28,11 @@ function Build-AssignmentDefinitionNode { $definition.hasErrors = $true } $definition.nodeName = $nodeName - #endregion nodeName (required) #region ignoreBranch and enforcementMode - - # Ignoring a branch can be useful for prep work to an future state - # Due to the history of EPAC, there are two ways ignoreBranch and enforcementMode + # Ignoring a branch can be useful for prep work to an future state + # Due to the history of EPAC, there are two ways ignoreBranch and enforcementMode if ($DefinitionNode.ignoreBranch) { # Does not deploy assignment(s), precedes Azure Policy feature enforcementMode Write-Warning " Node $($nodeName): ignoreBranch is legacy, consider using enforcementMode instead." @@ -75,11 +72,9 @@ function Build-AssignmentDefinitionNode { $definition.hasErrors = $true } } - #endregion assignment (required at least once per branch, concatenate strings) #region definitionEntry or definitionEntryList (required exactly once per branch) - $definitionEntry = $DefinitionNode.definitionEntry $definitionEntryList = $DefinitionNode.definitionEntryList $defEntryList = $definition.definitionEntryList @@ -87,8 +82,7 @@ function Build-AssignmentDefinitionNode { if ($null -eq $defEntryList -and ($null -ne $definitionEntry -xor $null -ne $definitionEntryList)) { # OK; first and only occurrence in tree branch - #region Validate and normalize definitionEntryList - + #region validate and normalize definitionEntryList if ($null -ne $definitionEntry) { # Convert to list $definitionEntryList = @( $definitionEntry ) @@ -135,18 +129,16 @@ function Build-AssignmentDefinitionNode { $definition.hasErrors = $true } } + #endregion validate and normalize definitionEntryList #region compile flat Policy List for all Policy Sets used in this branch - $flatPolicyList = $null $hasPolicySets = $itemList.Count -gt 0 - if ($hasPolicySets) { - $flatPolicyList = Convert-PolicySetsToFlatList ` + $flatPolicyList = Convert-PolicyResourcesDetailsToFlatList ` -ItemList $itemList.Values ` -Details $CombinedPolicyDetails.policySets } - #endregion compile flat Policy List for all Policy Sets used in this branch $definition.definitionEntryList = $normalizedDefinitionEntryList @@ -159,40 +151,32 @@ function Build-AssignmentDefinitionNode { $definition.hasErrors = $true } } - #endregion definitionEntry or definitionEntryList (required exactly once per branch) #region metadata - if ($DefinitionNode.metadata) { - if ($definition.metadata) { - # merge metadata - $metadata = $definition.metadata - $merge = Get-DeepClone $DefinitionNode.metadata -AsHashTable - foreach ($key in $merge) { - $metadata[$key] = $merge.$key - } - } - else { - $definition.metadata = Get-DeepClone $DefinitionNode.metadata -AsHashTable + # merge metadata + $metadata = $definition.metadata + $merge = Get-ClonedObject $DefinitionNode.metadata -AsHashTable + foreach ($key in $merge.Keys) { + $metadata[$key] = $merge.$key } } #endregion metadata - #region parameters - - # parameters in JSON; parameters defined at a deeper level override previous parameters (union operator) + #region parameters in JSON; parameters defined at a deeper level override previous parameters (union operator) if ($DefinitionNode.parameters) { $allParameters = $definition.parameters $addedParameters = $DefinitionNode.parameters foreach ($parameterName in $addedParameters.Keys) { $rawParameterValue = $addedParameters.$parameterName - $parameterValue = Get-DeepClone $rawParameterValue -AsHashTable + $parameterValue = Get-ClonedObject $rawParameterValue -AsHashTable $allParameters[$parameterName] = $parameterValue } } + #endregion parameters in JSON; parameters defined at a deeper level override previous parameters (union operator) - # Process parameterFileName and parameterSelector + #region process parameterFileName and parameterSelector if ($DefinitionNode.parameterSelector) { $parameterSelector = $DefinitionNode.parameterSelector $definition.parameterSelector = $parameterSelector @@ -205,7 +189,7 @@ function Build-AssignmentDefinitionNode { $fullName = $ParameterFilesCsv.$parameterFileName $content = Get-Content -Path $fullName -Raw -ErrorAction Stop $xlsArray = @() + ($content | ConvertFrom-Csv -ErrorAction Stop) - $csvParameterArray = Get-DeepClone $xlsArray -AsHashTable + $csvParameterArray = Get-ClonedObject $xlsArray -AsHashTable $definition.parameterFileName = $parameterFileName $definition.csvParameterArray = $csvParameterArray $definition.csvRowsValidated = $false @@ -219,9 +203,9 @@ function Build-AssignmentDefinitionNode { $definition.hasErrors = $true } } + #endregion process parameterFileName and parameterSelector - #region Validate CSV rows - + #region validate CSV rows if (!($definition.csvRowsValidated) -and $definition.hasPolicySets -and $definition.parameterFileName -and $definition.definitionEntryList) { $csvParameterArray = $definition.csvParameterArray @@ -276,23 +260,21 @@ function Build-AssignmentDefinitionNode { } } if ($rowHashtable.Count -gt 0) { - Write-Warning " Node $($nodeName): CSV parameterFile '$parameterFileName' contains rows for Policies not included in any of the Policy Sets:" + Write-Warning "Node $($nodeName): CSV parameterFile '$parameterFileName' contains rows for Policies not included in any of the Policy Sets. Remove the obsolete rows or regenerate the CSV file." foreach ($displayString in $rowHashtable.Values) { - Write-Information " $($displayString)" + Write-Information " $($displayString)" } } if ($missingInCsv.Count -gt 0) { - Write-Warning " Node $($nodeName): CSV parameterFile '$parameterFileName' is missing rows for Policies included in the Policy Sets:" + Write-Warning "Node $($nodeName): CSV parameterFile '$parameterFileName' is missing rows for Policies included in the Policy Sets. Regenerate the CSV file." foreach ($missing in $missingInCsv) { - Write-Information " $($missing)" + Write-Information " $($missing)" } } - } - #endregion parameters + #endregion validate CSV rows #region advanced - overrides, resourceSelectors and nonComplianceMessages - if ($DefinitionNode.overrides) { # Cumulative in branch # overrides behave like parameters, we define them similarly (simplified from Azure Policy) @@ -312,7 +294,6 @@ function Build-AssignmentDefinitionNode { if ($DefinitionNode.nonComplianceMessages) { $definition.nonComplianceMessages += $DefinitionNode.nonComplianceMessages } - #endregion advanced parameters - overrides and resourceSelectors #region scopes, notScopes @@ -322,111 +303,106 @@ function Build-AssignmentDefinitionNode { Write-Error " Node $($nodeName): multiple scope definitions at different tree levels are not allowed" $definition.hasErrors = $true } - if ($DefinitionNode.notScope) { + if ($DefinitionNode.notScope -or $DefinitionNode.notScopes) { Write-Error " Node $($nodeName): detected notScope definition in in a child node when the scope was already defined" $definition.hasErrors = $true } } else { - # may define notScope + # may define notScope or notScopes + $definitionNotScopesList = $definition.notScopesList if ($DefinitionNode.notScope) { - $notScope = $DefinitionNode.notScope - Write-Debug " notScope defined at $($nodeName) = $($notScope | ConvertTo-Json -Depth 100)" - foreach ($selector in $notScope.Keys) { - if ($selector -eq "*" -or $selector -eq $pacSelector) { - $notScopeList = $notScope.$selector - if ($definition.notScope) { - $definition.notScope += $notScopeList - } - else { - $definition.notScope = @() + $notScopeList - } - } - } + Add-SelectedPacArray -InputObject $DefinitionNode.notScope -PacSelector $pacSelector -OutputArrayList $definitionNotScopesList + } + if ($DefinitionNode.notScopes) { + Add-SelectedPacArray -InputObject $DefinitionNode.notScopes -PacSelector $pacSelector -OutputArrayList $definitionNotScopesList } if ($DefinitionNode.scope) { - ## Found a scope list - process notScope - $scopeList = $null - $scope = $DefinitionNode.scope - foreach ($selector in $scope.Keys) { - if ($selector -eq "*" -or $selector -eq $pacSelector) { - $scopeList = @() + $scope.$selector - break - } - } - if ($null -eq $scopeList) { + ## Found a scope list - process scope notScopes + $scopeList = [System.Collections.ArrayList]::new() + Add-SelectedPacArray -InputObject $DefinitionNode.scope -PacSelector $pacSelector -OutputArrayList $scopeList + if ($scopeList.Count -eq 0) { # This branch does not have a scope for this assignment's pacSelector; ignore branch $definition.hasOnlyNotSelectedEnvironments = $true } else { - if ($scopeList -is [array] -and $scopeList.Length -gt 0) { - $scopeCollection = @() - if ($definition.notScope) { - $uniqueNotScope = @() + ($definition.notScope | Sort-Object | Get-Unique) - $scopeCollection = Build-NotScopes -ScopeList $scopeList -notScope $uniqueNotScope -ScopeTable $ScopeTable + $scopeCollection = [System.Collections.ArrayList]::new() + foreach ($scope in $scopeList) { + $thisScopeDetails = $ScopeTable.$scope + if ($null -eq $thisScopeDetails) { + Write-Error " Node $($nodeName): scope '$scope' is not defined in the ScopeTable." + $definition.hasErrors = $true + continue } - else { - foreach ($scope in $scopeList) { - $scopeCollection += @{ - scope = $scope - notScope = @() + elseif ($thisScopeDetails.isExcluded) { + Write-Error " Node $($nodeName): scope '$scope' is excluded in the ScopeTable." + $definition.hasErrors = $true + continue + } + $thisNotScopeList = [System.Collections.ArrayList]::new() + $thisScopeChildren = $thisScopeDetails.childrenTable + $thisScopeGlobalNotScopeList = $thisScopeDetails.notScopesList + $thisScopeGlobalNotScopeTable = $thisScopeDetails.notScopesTable + foreach ($notScope in $definitionNotScopesList) { + if (-not $thisScopeGlobalNotScopeTable.ContainsKey($notScope)) { + if ($thisScopeChildren.ContainsKey($notScope)) { + $null = $thisNotScopeList.Add($notScope) + } + elseif ($notScope.Contains("*")) { + foreach ($scopeChildId in $thisScopeChildren.Keys) { + if ($scopeChildId -like $notScope) { + $null = $thisNotScopeList.Add($scopeChildId) + } + } + } + else { + continue } } } - $definition.scopeCollection = $scopeCollection - } - else { - Write-Error " Node $($nodeName): scope array must not be empty" - $definition.hasErrors = $true + $null = $thisNotScopeList.AddRange($thisScopeGlobalNotScopeList) + $thisNotScopeListUnique = $thisNotScopeList | Select-Object -Unique + if ($null -eq $thisNotScopeListUnique) { + $thisNotScopeListUnique = @() + } + elseif ($thisNotScopeListUnique -isnot [array]) { + $thisNotScopeListUnique = @($thisNotScopeListUnique) + } + $scopeResult = @{ + scope = $scope + notScopesList = $thisNotScopeListUnique + } + $null = $scopeCollection.Add($scopeResult) } + $definition.scopeCollection = $scopeCollection } } } #endregion scopes, notScopes #region identity and additionalRoleAssignments (optional, specific to an EPAC environment) - if ($DefinitionNode.additionalRoleAssignments) { # Process additional permissions needed to execute remediations; for example permissions to log to Event Hub, Storage Account or Log Analytics - $additionalRoleAssignments = $DefinitionNode.additionalRoleAssignments - foreach ($selector in $additionalRoleAssignments.Keys) { - if ($selector -eq "*" -or $selector -eq $pacSelector) { - $additionalRoleAssignmentsList = Get-DeepClone $additionalRoleAssignments.$selector -AsHashTable - if ($definition.additionalRoleAssignments) { - $definition.additionalRoleAssignments += $additionalRoleAssignmentsList - } - else { - $definition.additionalRoleAssignments = @() + $additionalRoleAssignmentsList - } - } - } + Add-SelectedPacArray -InputObject $DefinitionNode.additionalRoleAssignments -PacSelector $pacSelector -OutputArrayList $definition.additionalRoleAssignments } if ($DefinitionNode.managedIdentityLocations) { # Process managedIdentityLocation; can be overridden - $managedIdentityLocations = $DefinitionNode.managedIdentityLocations - $localManagedIdentityLocationValue = Get-SelectedPacValue $managedIdentityLocations -PacSelector $pacSelector - if ($null -ne $localManagedIdentityLocationValue) { - $definition.managedIdentityLocation = $localManagedIdentityLocationValue - } + Add-SelectedPacValue -InputObject $DefinitionNode.managedIdentityLocations -PacSelector $pacSelector -OutputObject $definition -OutputKey "managedIdentityLocation" } if ($DefinitionNode.userAssignedIdentity) { # Process userAssignedIdentity; can be overridden - $localUserAssignedIdentityRaw = Get-SelectedPacValue $DefinitionNode.userAssignedIdentity -PacSelector $pacSelector - if ($null -ne $localUserAssignedIdentityRaw) { - $definition.userAssignedIdentity = $localUserAssignedIdentityRaw - } + Add-SelectedPacValue -InputObject $DefinitionNode.userAssignedIdentity -PacSelector $pacSelector -OutputObject $definition -OutputKey "userAssignedIdentity" } - #endregion identity and additionalRoleAssignments (optional, specific to an EPAC environment) #region children and the leaf node - $assignmentsList = @() if ($DefinitionNode.children) { # Process child nodes Write-Debug " $($DefinitionNode.children.Count) children below at $($nodeName)" $hasErrors = $false + $assignmentsList = [System.Collections.ArrayList]::new() foreach ($child in $DefinitionNode.children) { $hasErrorsLocal, $assignmentsListLocal = Build-AssignmentDefinitionNode ` -PacEnvironment $PacEnvironment ` @@ -442,36 +418,27 @@ function Build-AssignmentDefinitionNode { $hasErrors = $true } elseif ($null -ne $assignmentsListLocal) { - $assignmentsList += $assignmentsListLocal + $null = $assignmentsList.AddRange($assignmentsListLocal) } } + return $hasErrors, $assignmentsList } else { # Arrived at a leaf node - return the values collected in this branch after checking validity if ($definition.ignoreBranch -or $definition.hasOnlyNotSelectedEnvironments -or $definition.hasErrors) { # Empty collection - return $definition.hasErrors, @() + return $definition.hasErrors, [System.Collections.ArrayList]::new() } else { - $hasErrors, $assignmentsList = Build-AssignmentDefinitionAtLeaf ` + $hasErrors, $assignmentsListAtLeaf = Build-AssignmentDefinitionAtLeaf ` -PacEnvironment $PacEnvironment ` -AssignmentDefinition $definition ` -CombinedPolicyDetails $CombinedPolicyDetails ` -PolicyRoleIds $PolicyRoleIds ` -RoleDefinitions $RoleDefinitions + return $hasErrors, $assignmentsListAtLeaf } } #endregion children and the leaf node - #region recursive return - if ($hasErrors) { - return $true, $null - } - elseif (($assignmentsList -is [array])) { - return $false, $assignmentsList - } - else { - return $false, $( $assignmentsList ) - } - #endregion recursive return } diff --git a/Scripts/Helpers/Build-AssignmentIdentityChanges.ps1 b/Scripts/Helpers/Build-AssignmentIdentityChanges.ps1 index 0b8cf9cc..bc8ecfbb 100644 --- a/Scripts/Helpers/Build-AssignmentIdentityChanges.ps1 +++ b/Scripts/Helpers/Build-AssignmentIdentityChanges.ps1 @@ -20,7 +20,7 @@ function Build-AssignmentIdentityChanges { $definedIdentity = $null $definedIdentityType = "None" $definedUserAssignedIdentity = $null - $requiredRoleDefinitions = @() + $requiredRoleAssignments = @() $existingLocation = $Existing.location $definedLocation = "global" @@ -46,7 +46,7 @@ function Build-AssignmentIdentityChanges { $definedUserAssignedIdentity = $definedIdentity.userAssignedIdentities.GetEnumerator().Name } $definedLocation = $Assignment.managedIdentityLocation - $requiredRoleDefinitions = $Assignment.metadata.roles + $requiredRoleAssignments = $Assignment.requiredRoleAssignments } $replaced = $ReplacedAssignment @@ -54,6 +54,7 @@ function Build-AssignmentIdentityChanges { $isUserAssigned = $false $changedIdentityStrings = @() $addedList = [System.Collections.ArrayList]::new() + $updatedList = [System.Collections.ArrayList]::new() $removedList = [System.Collections.ArrayList]::new() if ($hasExistingIdentity -or $identityRequired) { # need to check if either an existing identity or a newly added identity or existing and required identity @@ -105,16 +106,36 @@ function Build-AssignmentIdentityChanges { } if ($identityRequired) { if ($definedIdentityType -ne "UserAssigned") { - foreach ($requiredRoleDefinition in $requiredRoleDefinitions) { - $requiredRoleDefinitionId = $requiredRoleDefinition.roleDefinitionId - $addedEntry = @{ - assignmentId = $Assignment.id - displayName = $Assignment.displayName - scope = $requiredRoleDefinition.scope - principalId = $null - objectType = "ServicePrincipal" - roleDefinitionId = $requiredRoleDefinitionId - roleDisplayName = $requiredRoleDefinition.roleDisplayName + foreach ($requiredRoleAssignment in $requiredRoleAssignments) { + $addedEntry = $null + if ($requiredRoleAssignment.crossTenant) { + $addedEntry = @{ + assignmentId = $Assignment.id + assignmentDisplayName = $Assignment.displayName + roleDisplayName = $requiredRoleAssignment.roleDisplayName + scope = $requiredRoleAssignment.scope + properties = @{ + roleDefinitionId = $requiredRoleAssignment.roleDefinitionId + principalId = $null + principalType = "ServicePrincipal" + description = $requiredRoleAssignment.description + crossTenant = $true + } + } + } + else { + $addedEntry = @{ + assignmentId = $Assignment.id + assignmentDisplayName = $Assignment.displayName + roleDisplayName = $requiredRoleAssignment.roleDisplayName + scope = $requiredRoleAssignment.scope + properties = @{ + roleDefinitionId = $requiredRoleAssignment.roleDefinitionId + principalId = $null + principalType = "ServicePrincipal" + description = $requiredRoleAssignment.description + } + } } $null = $addedList.Add($addedEntry) } @@ -126,33 +147,66 @@ function Build-AssignmentIdentityChanges { } } else { - # Updating existing assignment + # Updating existing Policy assignment if ($existingIdentityType -ne "UserAssigned") { # calculate addedList role assignments (rare) - foreach ($requiredRoleDefinition in $requiredRoleDefinitions) { - $requiredRoleDefinitionId = $requiredRoleDefinition.roleDefinitionId + foreach ($requiredRoleAssignment in $requiredRoleAssignments) { + $requiredScope = $requiredRoleAssignment.scope + $requiredRoleDefinitionId = $requiredRoleAssignment.roleDefinitionId + $requiredDescription = $requiredRoleAssignment.description + $deployedRoleAssignmentWithUpdatedDescription = $null $matchFound = $false foreach ($deployedRoleAssignment in $existingRoleAssignments) { $deployedScope = $deployedRoleAssignment.scope $deployedRoleDefinitionId = $deployedRoleAssignment.roleDefinitionId - if (($deployedScope -eq $requiredRoleDefinition.scope) -and ($deployedRoleDefinitionId -eq $requiredRoleDefinitionId)) { + if (($deployedScope -eq $requiredScope) -and ($deployedRoleDefinitionId -eq $requiredRoleDefinitionId)) { + $deployedDescription = $deployedRoleAssignment.description + if ($deployedDescription -ne $requiredDescription) { + $deployedRoleAssignmentWithUpdatedDescription = $deployedRoleAssignment + } $matchFound = $true - # nothing to do break } } - if (!$matchFound) { - # add role + $addedEntry = $null + if ($requiredRoleAssignment.crossTenant) { + $addedEntry = @{ + assignmentId = $Assignment.id + assignmentDisplayName = $Assignment.displayName + roleDisplayName = $requiredRoleAssignment.roleDisplayName + scope = $requiredRoleAssignment.scope + properties = @{ + roleDefinitionId = $requiredRoleAssignment.roleDefinitionId + principalId = $null + principalType = "ServicePrincipal" + description = $requiredRoleAssignment.description + crossTenant = $true + } + } + } + else { $addedEntry = @{ - assignmentId = $Assignment.id - displayName = $Assignment.displayName - principalId = $principalIdForAddedRoles - objectType = "ServicePrincipal" - scope = $requiredRoleDefinition.scope - roleDefinitionId = $requiredRoleDefinitionId - roleDisplayName = $requiredRoleDefinition.roleDisplayName + assignmentId = $Assignment.id + assignmentDisplayName = $Assignment.displayName + roleDisplayName = $requiredRoleAssignment.roleDisplayName + scope = $requiredRoleAssignment.scope + properties = @{ + roleDefinitionId = $requiredRoleAssignment.roleDefinitionId + principalId = $null + principalType = "ServicePrincipal" + description = $requiredRoleAssignment.description + } + } + } + if ($matchFound) { + if ($null -ne $deployedRoleAssignmentWithUpdatedDescription) { + $addedEntry.id = $deployedRoleAssignmentWithUpdatedDescription.id + $addedEntry.properties.principalId = $deployedRoleAssignmentWithUpdatedDescription.principalId + $null = $updatedList.Add($addedEntry) } + } + else { $null = $addedList.Add($addedEntry) } } @@ -162,11 +216,11 @@ function Build-AssignmentIdentityChanges { $deployedScope = $deployedRoleAssignment.scope $deployedRoleDefinitionId = $deployedRoleAssignment.roleDefinitionId $matchFound = $false - foreach ($requiredRoleDefinition in $requiredRoleDefinitions) { - $requiredRoleDefinitionId = $requiredRoleDefinition.roleDefinitionId - if (($deployedScope -eq $requiredRoleDefinition.scope) -and ($deployedRoleDefinitionId -eq $requiredRoleDefinitionId)) { + foreach ($requiredRoleAssignment in $requiredRoleAssignments) { + $requiredScope = $requiredRoleAssignment.scope + $requiredRoleDefinitionId = $requiredRoleAssignment.roleDefinitionId + if (($deployedScope -eq $requiredScope) -and ($deployedRoleDefinitionId -eq $requiredRoleDefinitionId)) { $matchFound = $true - # Nothing to do break } } @@ -191,20 +245,27 @@ function Build-AssignmentIdentityChanges { $replaced = $true } + $numberOfChanges = 0 if ($addedList.Count -gt 0) { + $numberOfChanges += $addedList.Count $changedIdentityStrings += "addedRoleAssignments" } + if ($updatedList.Count -gt 0) { + $numberOfChanges += $updatedList.Count + $changedIdentityStrings += "updatedRoleAssignments" + } if ($removedList.Count -gt 0) { + $numberOfChanges += $removedList.Count $changedIdentityStrings += "removedRoleAssignments" } - $numberOfChanges = $addedList.Count + $removedList.Count return @{ replaced = $replaced requiresRoleChanges = $numberOfChanges -gt 0 numberOfChanges = $numberOfChanges changedIdentityStrings = $changedIdentityStrings isUserAssigned = $isUserAssigned - added = $addedList.ToArray() - removed = $removedList.ToArray() + added = $addedList + updated = $updatedList + removed = $removedList } } diff --git a/Scripts/Helpers/Build-AssignmentPlan.ps1 b/Scripts/Helpers/Build-AssignmentPlan.ps1 index b5949c0e..39768da3 100644 --- a/Scripts/Helpers/Build-AssignmentPlan.ps1 +++ b/Scripts/Helpers/Build-AssignmentPlan.ps1 @@ -7,348 +7,342 @@ function Build-AssignmentPlan { [hashtable] $DeployedPolicyResources, [hashtable] $Assignments, [hashtable] $RoleAssignments, - [hashtable] $AllDefinitions, [hashtable] $AllAssignments, [hashtable] $ReplaceDefinitions, - [hashtable] $PolicyRoleIds + [hashtable] $PolicyRoleIds, + [hashtable] $CombinedPolicyDetails ) Write-Information "===================================================================================================" Write-Information "Processing Policy Assignments JSON files in folder '$AssignmentsRootFolder'" Write-Information "===================================================================================================" - # Cache role definitions - [hashtable] $roleDefinitions = $DeployedPolicyResources.roleDefinitions - - # Populate allAssignments - $deployedPolicyAssignments = $DeployedPolicyResources.policyassignments.managed - $deployedRoleAssignmentsByPrincipalId = $DeployedPolicyResources.roleAssignmentsByPrincipalId - $deleteCandidates = Get-HashtableShallowClone $deployedPolicyAssignments - foreach ($id in $deployedPolicyAssignments.Keys) { - $AllAssignments[$id] = $deployedPolicyAssignments.$id - } - - if (!(Test-Path $AssignmentsRootFolder -PathType Container)) { - Write-Warning "Policy Assignments folder 'policyAssignments' not found. Assignments not managed by this EPAC instance." + $assignmentFiles = @() + $assignmentFiles += Get-ChildItem -Path $AssignmentsRootFolder -Recurse -File -Filter "*.json" + $assignmentFiles += Get-ChildItem -Path $AssignmentsRootFolder -Recurse -File -Filter "*.jsonc" + $csvFiles = Get-ChildItem -Path $AssignmentsRootFolder -Recurse -File -Filter "*.csv" + $parameterFilesCsv = @{} + if ($assignmentFiles.Length -gt 0) { + Write-Information "Number of Policy Assignment files = $($assignmentFiles.Length)" + foreach ($csvFile in $csvFiles) { + $parameterFilesCsv.Add($csvFile.Name, $csvFile.FullName) + } } else { + Write-Warning "No Policy Assignment files found! Deleting any Policy Assignments." + } + + # Cache role assognments and definitions + $deployedPolicyAssignments = $deployedPolicyResources.policyassignments.managed + $deployedRoleAssignmentsByPrincipalId = $DeployedPolicyResources.roleAssignmentsByPrincipalId + $deleteCandidates = Get-ClonedObject $deployedPolicyAssignments -AsHashTable -AsShallowClone + $roleDefinitions = $DeployedPolicyResources.roleDefinitions - # Convert Policy and PolicySetDefinition to detailed Info - $combinedPolicyDetails = Convert-PolicySetsToDetails ` - -AllPolicyDefinitions $AllDefinitions.policydefinitions ` - -AllPolicySetDefinitions $AllDefinitions.policysetdefinitions + # Process each assignment file + foreach ($assignmentFile in $assignmentFiles) { + $Json = Get-Content -Path $assignmentFile.FullName -Raw -ErrorAction Stop - $assignmentFiles = @() - $assignmentFiles += Get-ChildItem -Path $AssignmentsRootFolder -Recurse -File -Filter "*.json" - $assignmentFiles += Get-ChildItem -Path $AssignmentsRootFolder -Recurse -File -Filter "*.jsonc" - $csvFiles = Get-ChildItem -Path $AssignmentsRootFolder -Recurse -File -Filter "*.csv" - $parameterFilesCsv = @{} - if ($assignmentFiles.Length -gt 0) { - Write-Information "Number of Policy Assignment files = $($assignmentFiles.Length)" - foreach ($csvFile in $csvFiles) { - $parameterFilesCsv.Add($csvFile.Name, $csvFile.FullName) + $includedCloudEnvironments = ($Json | ConvertFrom-Json).epacCloudEnvironments + if ($includedCloudEnvironments) { + if ($pacEnvironment.cloud -notIn $includedCloudEnvironments) { + continue } } - else { - Write-Warning "No Policy Assignment files found! Deleting any Policy Assignments." - } - - # Process each assignment file - foreach ($assignmentFile in $assignmentFiles) { - $Json = Get-Content -Path $assignmentFile.FullName -Raw -ErrorAction Stop - $includedCloudEnvironments = ($Json | ConvertFrom-Json).epacCloudEnvironments - if ($includedCloudEnvironments) { - if ($pacEnvironment.cloud -notIn $includedCloudEnvironments) { - continue - } - } + # Write-Information "" + try { + $assignmentObject = $Json | ConvertFrom-Json -AsHashtable + } + catch { + Write-Error "Assignment JSON file '$($assignmentFile.FullName)' is not valid." -ErrorAction Stop + } + # Remove-NullFields $assignmentObject - # Write-Information "" - try { - $assignmentObject = $Json | ConvertFrom-Json -AsHashtable + # Collect all assignment definitions (values) + $rootAssignmentDefinition = @{ + nodeName = "/" + metadata = @{ + assignedBy = $PacEnvironment.deployedBy } - catch { - Write-Error "Assignment JSON file '$($assignmentFile.FullName)' is not valid." -ErrorAction Stop + assignment = @{ + append = $false + name = "" + displayName = "" + description = "" } - # Remove-NullFields $assignmentObject + enforcementMode = "Default" + parameters = @{} + additionalRoleAssignments = [System.Collections.ArrayList]::new() + requiredRoleAssignments = $null + nonComplianceMessages = [System.Collections.ArrayList]::new() + overrides = [System.Collections.ArrayList]::new() + resourceSelectors = [System.Collections.ArrayList]::new() + hasErrors = $false + hasOnlyNotSelectedEnvironments = $false + ignoreBranch = $false + managedIdentityLocation = $PacEnvironment.managedIdentityLocation + notScopesList = [System.Collections.ArrayList]::new() + csvRowsValidated = $false + } - # Collect all assignment definitions (values) - $rootAssignmentDefinition = @{ - nodeName = "/" - assignment = @{ - append = $false - name = "" - displayName = "" - description = "" - } - enforcementMode = "Default" - parameters = @{} - additionalRoleAssignments = @() - nonComplianceMessages = @() - overrides = @() - resourceSelectors = @() - hasErrors = $false - hasOnlyNotSelectedEnvironments = $false - ignoreBranch = $false - managedIdentityLocation = $PacEnvironment.managedIdentityLocation - notScope = $PacEnvironment.globalNotScopes - csvRowsValidated = $false - } + $hasErrors, $assignmentsList = Build-AssignmentDefinitionNode ` + -PacEnvironment $PacEnvironment ` + -ScopeTable $ScopeTable ` + -ParameterFilesCsv $parameterFilesCsv ` + -DefinitionNode $assignmentObject ` + -AssignmentDefinition $rootAssignmentDefinition ` + -CombinedPolicyDetails $CombinedPolicyDetails ` + -PolicyRoleIds $PolicyRoleIds ` + -RoleDefinitions $roleDefinitions - $hasErrors, $assignmentsList = Build-AssignmentDefinitionNode ` - -PacEnvironment $PacEnvironment ` - -ScopeTable $ScopeTable ` - -ParameterFilesCsv $parameterFilesCsv ` - -DefinitionNode $assignmentObject ` - -AssignmentDefinition $rootAssignmentDefinition ` - -CombinedPolicyDetails $combinedPolicyDetails ` - -PolicyRoleIds $PolicyRoleIds ` - -RoleDefinitions $roleDefinitions + if ($hasErrors) { + Write-Error "Assignment definitions content errors" -ErrorAction Stop + } - if ($hasErrors) { - Write-Error "Assignment definitions content errors" -ErrorAction Stop - } + $isUserAssignedAny = $false + foreach ($assignment in $assignmentsList) { - $isUserAssignedAny = $false - foreach ($assignment in $assignmentsList) { + # Remove-NullFields $assignment + $id = $assignment.id + $AllAssignments[$id] = $assignment + $displayName = $assignment.displayName + $description = $assignment.description + $metadata = $assignment.metadata + $parameters = $assignment.parameters + $policyDefinitionId = $assignment.policyDefinitionId + $scope = $assignment.scope + $notScopes = $assignment.notScopes + $enforcementMode = $assignment.enforcementMode + $nonComplianceMessages = $assignment.nonComplianceMessages + $overrides = $assignment.overrides + $resourceSelectors = $assignment.resourceSelectors + if ($deployedPolicyAssignments.ContainsKey($id)) { + # Update and replace scenarios + $deployedPolicyAssignment = $deployedPolicyAssignments[$id] + $deployedPolicyAssignmentProperties = Get-PolicyResourceProperties $deployedPolicyAssignment + $deleteCandidates.Remove($id) # do not delete - # Remove-NullFields $assignment - $id = $assignment.id - $AllAssignments[$id] = $assignment - $displayName = $assignment.displayName - $description = $assignment.description - $metadata = $assignment.metadata - $parameters = $assignment.parameters - $policyDefinitionId = $assignment.policyDefinitionId - $scope = $assignment.scope - $notScopes = $assignment.notScopes - $enforcementMode = $assignment.enforcementMode - $nonComplianceMessages = $assignment.nonComplianceMessages - $overrides = $assignment.overrides - $resourceSelectors = $assignment.resourceSelectors - if ($deployedPolicyAssignments.ContainsKey($id)) { - # Update and replace scenarios - $deployedPolicyAssignment = $deployedPolicyAssignments[$id] - $deployedPolicyAssignmentProperties = Get-PolicyResourceProperties $deployedPolicyAssignment - $deleteCandidates.Remove($id) # do not delete + $replacedDefinition = $ReplaceDefinitions.ContainsKey($policyDefinitionId) + $changedPolicyDefinitionId = $policyDefinitionId -ne $deployedPolicyAssignmentProperties.policyDefinitionId + $displayNameMatches = $displayName -eq $deployedPolicyAssignmentProperties.displayName + $descriptionMatches = $description -eq $deployedPolicyAssignmentProperties.description + $notScopesMatch = Confirm-ObjectValueEqualityDeep ` + $deployedPolicyAssignmentProperties.notScopes ` + $notScopes + $parametersMatch = Confirm-ParametersUsageMatches ` + -ExistingParametersObj $deployedPolicyAssignmentProperties.parameters ` + -DefinedParametersObj $parameters ` + -CompareValueEntryForExistingParametersObj + $metadataMatches, $changePacOwnerId = Confirm-MetadataMatches ` + -ExistingMetadataObj $deployedPolicyAssignmentProperties.metadata ` + -DefinedMetadataObj $metadata + $enforcementModeMatches = $enforcementMode -eq $deployedPolicyAssignmentProperties.EnforcementMode + $nonComplianceMessagesMatches = Confirm-ObjectValueEqualityDeep ` + $deployedPolicyAssignmentProperties.nonComplianceMessages ` + $nonComplianceMessages + $overridesMatch = Confirm-ObjectValueEqualityDeep ` + $deployedPolicyAssignmentProperties.overrides ` + $overrides + $resourceSelectorsMatch = Confirm-ObjectValueEqualityDeep ` + $deployedPolicyAssignmentProperties.resourceSelectors ` + $resourceSelectors + $identityStatus = Build-AssignmentIdentityChanges ` + -Existing $deployedPolicyAssignment ` + -Assignment $assignment ` + -ReplacedAssignment ($replacedDefinition -or $changedPolicyDefinitionId) ` + -DeployedRoleAssignmentsByPrincipalId $deployedRoleAssignmentsByPrincipalId + if ($identityStatus.requiresRoleChanges) { + $null = $RoleAssignments.added.AddRange($identityStatus.added) + $null = $RoleAssignments.updated.AddRange($identityStatus.updated) + $null = $RoleAssignments.removed.AddRange($identityStatus.removed) + $RoleAssignments.numberOfChanges += ($identityStatus.numberOfChanges) + } + if ($identityStatus.isUserAssigned) { + $isUserAssignedAny = $true + } - $replacedDefinition = $ReplaceDefinitions.ContainsKey($policyDefinitionId) - $changedPolicyDefinitionId = $policyDefinitionId -ne $deployedPolicyAssignmentProperties.policyDefinitionId - $displayNameMatches = $displayName -eq $deployedPolicyAssignmentProperties.displayName - $descriptionMatches = $description -eq $deployedPolicyAssignmentProperties.description - $notScopesMatch = Confirm-ObjectValueEqualityDeep ` - $deployedPolicyAssignmentProperties.notScopes ` - $notScopes - $parametersMatch = Confirm-ParametersUsageMatches ` - -ExistingParametersObj $deployedPolicyAssignmentProperties.parameters ` - -DefinedParametersObj $parameters ` - -CompareValueEntryForExistingParametersObj - $metadataMatches, $changePacOwnerId = Confirm-MetadataMatches ` - -ExistingMetadataObj $deployedPolicyAssignmentProperties.metadata ` - -DefinedMetadataObj $metadata - $enforcementModeMatches = $enforcementMode -eq $deployedPolicyAssignmentProperties.EnforcementMode - $nonComplianceMessagesMatches = Confirm-ObjectValueEqualityDeep ` - $deployedPolicyAssignmentProperties.nonComplianceMessages ` - $nonComplianceMessages ` - -HandleRandomOrderArray - $overridesMatch = Confirm-ObjectValueEqualityDeep ` - $deployedPolicyAssignmentProperties.overrides ` - $overrides ` - -HandleRandomOrderArray - $resourceSelectorsMatch = Confirm-ObjectValueEqualityDeep ` - $deployedPolicyAssignmentProperties.resourceSelectors ` - $resourceSelectors ` - -HandleRandomOrderArray + # Check if Policy assignment in Azure is the same as in the JSON file - $identityStatus = Build-AssignmentIdentityChanges ` - -Existing $deployedPolicyAssignment ` - -Assignment $assignment ` - -ReplacedAssignment ($replacedDefinition -or $changedPolicyDefinitionId) ` - -DeployedRoleAssignmentsByPrincipalId $deployedRoleAssignmentsByPrincipalId + $changesStrings = @() + $match = $displayNameMatches -and $descriptionMatches -and $parametersMatch -and $metadataMatches -and !$changePacOwnerId ` + -and $enforcementModeMatches -and $notScopesMatch -and $nonComplianceMessagesMatches -and $overridesMatch -and $resourceSelectorsMatch -and !$identityStatus.replaced + if ($match) { + # no Assignment properties changed + $Assignments.numberUnchanged++ if ($identityStatus.requiresRoleChanges) { - $RoleAssignments.added += ($identityStatus.added) - $RoleAssignments.removed += ($identityStatus.removed) - $RoleAssignments.numberOfChanges += ($identityStatus.numberOfChanges) + # role assignments for Managed Identity changed - caused by a mangedIdentityLocation changed or a previously failed role assignment failure + Write-AssignmentDetails -DisplayName $displayName -Scope $scope -Prefix "Update($($identityStatus.changedIdentityStrings -join ','))" -IdentityStatus $identityStatus } - if ($identityStatus.isUserAssigned) { - $isUserAssignedAny = $true + else { + # Write-AssignmentDetails -DisplayName $displayName -Scope $scope -Prefix "Unchanged" -IdentityStatus $identityStatus } - - # Check if Policy assignment in Azure is the same as in the JSON file - - $changesStrings = @() - $match = $displayNameMatches -and $descriptionMatches -and $parametersMatch -and $metadataMatches -and !$changePacOwnerId ` - -and $enforcementModeMatches -and $notScopesMatch -and $nonComplianceMessagesMatches -and $overridesMatch -and $resourceSelectorsMatch -and !$identityStatus.replaced - if ($match) { - # no Assignment properties changed - $Assignments.numberUnchanged++ - if ($identityStatus.requiresRoleChanges) { - # role assignments for Managed Identity changed - caused by a mangedIdentityLocation changed or a previously failed role assignment failure - Write-AssignmentDetails -DisplayName $displayName -Scope $scope -Prefix "Update($($identityStatus.changedIdentityStrings -join ','))" -IdentityStatus $identityStatus + } + else { + # One or more properties have changed + if ($identityStatus.replaced) { + # Assignment must be deleted and recreated (new) + if ($changedPolicyDefinitionId) { + $changesStrings += "definitionId" } - else { - # Write-AssignmentDetails -DisplayName $displayName -Scope $scope -Prefix "Unchanged" -IdentityStatus $identityStatus + if ($replacedDefinition) { + $changesStrings += "replacedDefinition" } + $changesStrings += ($identityStatus.changedIdentityStrings) } - else { - # One or more properties have changed - if ($identityStatus.replaced) { - # Assignment must be deleted and recreated (new) - if ($changedPolicyDefinitionId) { - $changesStrings += "definitionId" - } - if ($replacedDefinition) { - $changesStrings += "replacedDefinition" - } - $changesStrings += ($identityStatus.changedIdentityStrings) - } - - if (!$displayNameMatches) { - $changesStrings += "displayName" - } - if (!$descriptionMatches) { - $changesStrings += "description" - } - if ($changePacOwnerId) { - $changesStrings += "owner" - } - if (!$metadataMatches) { - $changesStrings += "metadata" - } - if (!$parametersMatch) { - $changesStrings += "parameters" - } - if (!$enforcementModeMatches) { - $changesStrings += "enforcementMode" - } - if (!$notScopesMatch) { - $changesStrings += "notScopes" - } - if (!$nonComplianceMessagesMatches) { - $changesStrings += "nonComplianceMessages" - } - if (!$overridesMatch) { - $changesStrings += "overrides" - } - if (!$resourceSelectorsMatch) { - $changesStrings += "resourceSelectors" - } - $changesString = $changesStrings -join "," - if ($identityStatus.replaced) { - # Assignment must be deleted and recreated (new) - $null = $Assignments.replace.Add($id, $assignment) - Write-AssignmentDetails -DisplayName $displayName -Scope $scope -Prefix "Replace($changesString)" -IdentityStatus $identityStatus - } - else { - $null = $Assignments.update.Add($id, $assignment) - Write-AssignmentDetails -DisplayName $displayName -Scope $scope -Prefix "Update($changesString)" -IdentityStatus $identityStatus - } - $Assignments.numberOfChanges++ + if (!$displayNameMatches) { + $changesStrings += "displayName" } - } - else { - # New Assignment - $null = $Assignments.new.Add($id, $assignment) - $Assignments.numberOfChanges++ - $identityStatus = Build-AssignmentIdentityChanges ` - -Existing $null ` - -Assignment $assignment ` - -ReplacedAssignment $false ` - -DeployedRoleAssignmentsByPrincipalId $deployedRoleAssignmentsByPrincipalId - if ($identityStatus.requiresRoleChanges) { - $RoleAssignments.added += ($identityStatus.added) - $RoleAssignments.numberOfChanges += ($identityStatus.numberOfChanges) + if (!$descriptionMatches) { + $changesStrings += "description" } - if ($identityStatus.isUserAssigned) { - $isUserAssignedAny = $true + if ($changePacOwnerId) { + $changesStrings += "owner" } - Write-AssignmentDetails -DisplayName $displayName -Scope $scope -Prefix "New" -IdentityStatus $identityStatus - } - } - } - - $strategy = $PacEnvironment.desiredState.strategy - $keepDfcSecurityAssignments = $PacEnvironment.desiredState.keepDfcSecurityAssignments - if ($deleteCandidates.psbase.Count -gt 0) { - foreach ($id in $deleteCandidates.Keys) { - $deleteCandidate = $deleteCandidates.$id - $deleteCandidateProperties = Get-PolicyResourceProperties $deleteCandidate - $name = $deleteCandidate.name - $displayName = $deleteCandidateProperties.displayName - $scope = $deleteCandidateProperties.scope - $pacOwner = $deleteCandidate.pacOwner - $shallDelete = Confirm-DeleteForStrategy -PacOwner $pacOwner -Strategy $strategy -KeepDfcSecurityAssignments $keepDfcSecurityAssignments - if ($shallDelete) { - # always delete if owned by this Policy as Code solution - # never delete if owned by another Policy as Code solution - # if strategy is "full", delete with unknown owner (missing pacOwnerId) - $identityStatus = Build-AssignmentIdentityChanges ` - -Existing $deleteCandidate ` - -Assignment $null ` - -ReplacedAssignment $false ` - -DeployedRoleAssignmentsByPrincipalId $deployedRoleAssignmentsByPrincipalId - if ($identityStatus.requiresRoleChanges) { - $RoleAssignments.removed += ($identityStatus.removed) - $RoleAssignments.numberOfChanges += ($identityStatus.numberOfChanges) + if (!$metadataMatches) { + $changesStrings += "metadata" + } + if (!$parametersMatch) { + $changesStrings += "parameters" + } + if (!$enforcementModeMatches) { + $changesStrings += "enforcementMode" + } + if (!$notScopesMatch) { + $changesStrings += "notScopes" + } + if (!$nonComplianceMessagesMatches) { + $changesStrings += "nonComplianceMessages" } - if ($identityStatus.isUserAssigned) { - $isUserAssignedAny = $true + if (!$overridesMatch) { + $changesStrings += "overrides" } - Write-AssignmentDetails -DisplayName $displayName -Scope $scope -Prefix "Delete" -IdentityStatus $identityStatus - $splat = @{ - id = $id - name = $name - scopeId = $scope - displayName = $displayName + if (!$resourceSelectorsMatch) { + $changesStrings += "resourceSelectors" } - $AllAssignments.Remove($id) - $Assignments.delete.Add($id, $splat) + $changesString = $changesStrings -join "," + $updateCollection = $Assignments.update + $prefixText = "Update($changesString)" + if ($identityStatus.replaced) { + $prefixText = "Replace($changesString)" + $updateCollection = $Assignments.replace + } + if ($Assignments.update.ContainsKey($id) -or $Assignments.replace.ContainsKey($id)) { + Write-Error "Duplicate Policy Assignment ID '$id' found in the JSON files." -ErrorAction Stop + } + $null = $updateCollection.Add($id, $assignment) + Write-AssignmentDetails -DisplayName $displayName -Scope $scope -Prefix $prefixText -IdentityStatus $identityStatus $Assignments.numberOfChanges++ + } + } + else { + # New Assignment + $null = $Assignments.new.Add($id, $assignment) + $Assignments.numberOfChanges++ + $identityStatus = Build-AssignmentIdentityChanges ` + -Existing $null ` + -Assignment $assignment ` + -ReplacedAssignment $false ` + -DeployedRoleAssignmentsByPrincipalId $deployedRoleAssignmentsByPrincipalId + if ($identityStatus.requiresRoleChanges) { + $null = $RoleAssignments.added.AddRange($identityStatus.added) + $RoleAssignments.numberOfChanges += ($identityStatus.numberOfChanges) + } + if ($identityStatus.isUserAssigned) { + $isUserAssignedAny = $true + } + Write-AssignmentDetails -DisplayName $displayName -Scope $scope -Prefix "New" -IdentityStatus $identityStatus + } + } + } + $strategy = $PacEnvironment.desiredState.strategy + $keepDfcSecurityAssignments = $PacEnvironment.desiredState.keepDfcSecurityAssignments + if ($deleteCandidates.psbase.Count -gt 0) { + foreach ($id in $deleteCandidates.Keys) { + $deleteCandidate = $deleteCandidates.$id + $deleteCandidateProperties = Get-PolicyResourceProperties $deleteCandidate + $name = $deleteCandidate.name + $displayName = $deleteCandidateProperties.displayName + $scope = $deleteCandidateProperties.scope + $pacOwner = $deleteCandidate.pacOwner + $shallDelete = Confirm-DeleteForStrategy ` + -PacOwner $pacOwner ` + -Strategy $strategy ` + -KeepDfcSecurityAssignments $keepDfcSecurityAssignments + if ($shallDelete) { + # always delete if owned by this Policy as Code solution + # never delete if owned by another Policy as Code solution + # if strategy is "full", delete with unknown owner (missing pacOwnerId) + $identityStatus = Build-AssignmentIdentityChanges ` + -Existing $deleteCandidate ` + -Assignment $null ` + -ReplacedAssignment $false ` + -DeployedRoleAssignmentsByPrincipalId $deployedRoleAssignmentsByPrincipalId + if ($identityStatus.requiresRoleChanges) { + $null = $RoleAssignments.removed.AddRange($identityStatus.added) + $RoleAssignments.numberOfChanges += ($identityStatus.numberOfChanges) } - else { - $identityStatus = @{ - requiresRoleChanges = $false - numberOfChanges = 0 - added = @() - removed = @() - changedIdentityStrings = @() - replaced = $false - isUserAssigned = $false + if ($identityStatus.isUserAssigned) { + $isUserAssignedAny = $true + } + Write-AssignmentDetails -DisplayName $displayName -Scope $scope -Prefix "Delete" -IdentityStatus $identityStatus + $splat = @{ + id = $id + name = $name + scopeId = $scope + displayName = $displayName + } + + $AllAssignments.Remove($id) + $Assignments.delete.Add($id, $splat) + $Assignments.numberOfChanges++ + + } + else { + $identityStatus = @{ + requiresRoleChanges = $false + numberOfChanges = 0 + added = @() + removed = @() + changedIdentityStrings = @() + replaced = $false + isUserAssigned = $false + } + $shortScope = $scope -replace "/providers/Microsoft.Management", "" + switch ($pacOwner) { + thisPaC { + Write-Error "Policy Assignment '$displayName' at $shortScope owned by this Policy as Code solution should have been deleted." -ErrorAction Stop } - $shortScope = $scope -replace "/providers/Microsoft.Management", "" - switch ($pacOwner) { - thisPaC { - Write-Error "Policy Assignment '$displayName' at $shortScope owned by this Policy as Code solution should have been deleted." -ErrorAction Stop - } - otherPaC { - if ($VerbosePreference -eq "Continue") { - Write-AssignmentDetails -DisplayName $displayName -Scope $shortScope -Prefix "Skipping delete (owened by other PaC):" -IdentityStatus $identityStatus - } + otherPaC { + if ($VerbosePreference -eq "Continue") { + Write-AssignmentDetails -DisplayName $displayName -Scope $shortScope -Prefix "Skipping delete (owened by other PaC):" -IdentityStatus $identityStatus } - unknownOwner { - if ($VerbosePreference -eq "Continue") { - Write-AssignmentDetails -DisplayName $displayName -Scope $shortScope -Prefix "Skipping delete (strategy $strategy):" -IdentityStatus $identityStatus - } + } + unknownOwner { + if ($VerbosePreference -eq "Continue") { + Write-AssignmentDetails -DisplayName $displayName -Scope $shortScope -Prefix "Skipping delete owmed by unknown (strategy $strategy):" -IdentityStatus $identityStatus } - managedByDfcSecurityPolicies { + } + managedByDfcSecurityPolicies { + if ($VerbosePreference -eq "Continue") { Write-AssignmentDetails -DisplayName $displayName -Scope $shortScope -Prefix "Skipping delete (DfC Security Policies):" -IdentityStatus $identityStatus } - managedByDfcDefenderPlans { + } + managedByDfcDefenderPlans { + if ($VerbosePreference -eq "Continue") { Write-AssignmentDetails -DisplayName $displayName -Scope $shortScope -Prefix "Skipping delete (DfC Defender Plans):" -IdentityStatus $identityStatus } } - } - } + } + } } + } - if ($isUserAssignedAny) { - Write-Warning "EPAC does not manage role assignments for Policy Assignments with user-assigned Managed Identities." - } - Write-Information "Number of unchanged Policy Assignments = $($Assignments.numberUnchanged)" + if ($isUserAssignedAny) { + Write-Warning "EPAC does not manage role assignments for Policy Assignments with user-assigned Managed Identities." } + Write-Information "Number of unchanged Policy Assignments = $($Assignments.numberUnchanged)" Write-Information "" } diff --git a/Scripts/Helpers/Build-ExemptionsPlan.ps1 b/Scripts/Helpers/Build-ExemptionsPlan.ps1 index b8102136..2829d6e9 100644 --- a/Scripts/Helpers/Build-ExemptionsPlan.ps1 +++ b/Scripts/Helpers/Build-ExemptionsPlan.ps1 @@ -4,7 +4,10 @@ function Build-ExemptionsPlan { [string] $ExemptionsRootFolder, [string] $ExemptionsAreNotManagedMessage, [hashtable] $PacEnvironment, + $ScopeTable, + [hashtable] $AllDefinitions, [hashtable] $AllAssignments, + [hashtable] $CombinedPolicyDetails, [hashtable] $Assignments, [hashtable] $DeployedExemptions, [hashtable] $Exemptions @@ -14,346 +17,778 @@ function Build-ExemptionsPlan { Write-Information "Processing Policy Exemption files in folder '$ExemptionsRootFolder'" Write-Information "===================================================================================================" - if ($ExemptionsAreNotManagedMessage -eq "") { - - [array] $exemptionFiles = @() - # Do not manage exemptions if directory does not exist - $exemptionFiles += Get-ChildItem -Path $ExemptionsRootFolder -Recurse -File -Filter "*.json" - $exemptionFiles += Get-ChildItem -Path $ExemptionsRootFolder -Recurse -File -Filter "*.jsonc" - $exemptionFiles += Get-ChildItem -Path $ExemptionsRootFolder -Recurse -File -Filter "*.csv" - - $allExemptions = @{} - $deployedManagedExemptions = $DeployedExemptions.managed - $deleteCandidates = Get-HashtableShallowClone $deployedManagedExemptions - $replacedAssignments = $Assignments.replace - if ($exemptionFiles.Length -eq 0) { - Write-Warning "No Policy Exemption files found." - Write-Warning "All exemptions will be deleted!" - Write-Information "" - } - else { - Write-Information "Number of Policy Exemption files = $($exemptionFiles.Length)" - $now = Get-Date -AsUTC - $numberOfFilesWithErrors = 0 - foreach ($file in $exemptionFiles) { + #region read files and cache data structures + [array] $exemptionFiles = @() + $exemptionFiles += Get-ChildItem -Path $ExemptionsRootFolder -Recurse -File -Filter "*.json" + $exemptionFiles += Get-ChildItem -Path $ExemptionsRootFolder -Recurse -File -Filter "*.jsonc" + $exemptionFiles += Get-ChildItem -Path $ExemptionsRootFolder -Recurse -File -Filter "*.csv" + + $uniqueIds = @{} + $deployedManagedExemptions = $DeployedExemptions.managed + $deleteCandidates = Get-ClonedObject $deployedManagedExemptions -AsHashTable -AsShallowClone + $replacedAssignments = $Assignments.replace + $xlsUsesPolicyMethod = "unknown" + $numberOfFilesWithErrors = 0 + $desiredState = $PacEnvironment.desiredState + $desiredStateStrategy = $desiredState.strategy + + $now = Get-Date -AsUTC + #endregion read files and cache data structures + + if ($exemptionFiles.Length -eq 0) { + Write-Warning "No Policy Exemption files found." + Write-Warning "All exemptions will be deleted!" + Write-Information "" + } + else { + Write-Information "Number of Policy Exemption files = $($exemptionFiles.Length)" + $resourceIdsExist = @{} + + #region pre-calculate assignments + $sortedAssignments = $AllAssignments.Values | Sort-Object -Property id # for a stable order + $calculatedResult = Get-CalculatedPolicyAssignmentsAndReferenceIds ` + -Assignments $sortedAssignments ` + -CombinedPolicyDetails $CombinedPolicyDetails + $byAssignmentIdCalculatedAssignments = $calculatedResult.byAssignmentIdCalculatedAssignments + $byPolicySetIdCalculatedAssignments = $calculatedResult.byPolicySetIdCalculatedAssignments + $byPolicyIdCalculatedAssignments = $calculatedResult.byPolicyIdCalculatedAssignments + #endregion pre-calculate assignments + + foreach ($file in $exemptionFiles) { + + #region read each file + $extension = $file.Extension + $fullName = $file.FullName + Write-Information "Processing file '$($fullName)'" + $errorInfo = New-ErrorInfo -FileName $fullName + $exemptionsArray = @() + $isCsvFile = $false + if ($extension -eq ".json" -or $extension -eq ".jsonc") { + $content = Get-Content -Path $fullName -Raw -ErrorAction Stop + try { + $jsonObj = ConvertFrom-Json $content -AsHashTable -Depth 100 + } + catch { + throw "Assignment JSON file '$($fullName)' is not valid." + } + Write-Information "" + if ($null -ne $jsonObj) { + $jsonExemptions = $jsonObj.exemptions + if ($null -ne $jsonExemptions -and $jsonExemptions.Count -gt 0) { + $exemptionsArray += $jsonExemptions + } + } - #region read each file + } + elseif ($extension -eq ".csv") { + $isCsvFile = $true + $content = Get-Content -Path $fullName -Raw -ErrorAction Stop + $xlsExemptions = ($content | ConvertFrom-Csv -ErrorAction Stop) + if ($xlsExemptions.Count -gt 0) { + $exemptionsArray += $xlsExemptions + } + } + #endregion read each file + + $entryNumber = $isCsvFile ? 1 : -1 + foreach ($row in $exemptionsArray) { + $errorInfo.hasLocalErrors = $false + $entryNumber++ + + #region read row values andd skip empty rows on CSV files + $name = $row.name + $displayName = $row.displayName + $exemptionCategory = $row.exemptionCategory + $scope = $row.scope + $policyAssignmentId = $row.policyAssignmentId + $policyDefinitionId = $null + $policySetDefinitionId = $null + $assignmentReferenceId = $row.assignmentReferenceId + $description = $row.description + $assignmentScopeValidation = $row.assignmentScopeValidation + $resourceSelectors = $row.resourceSelectors + $policyDefinitionReferenceIds = $row.policyDefinitionReferenceIds + $metadata = $row.metadata + if ($isCsvFile) { + if ([string]::IsNullOrWhitespace($name) ` + -and [string]::IsNullOrWhitespace($displayName) ` + -and [string]::IsNullOrWhitespace($exemptionCategory) ` + -and [string]::IsNullOrWhitespace($scope) ` + -and [string]::IsNullOrWhitespace($policyAssignmentId) ` + -and [string]::IsNullOrWhitespace($assignmentReferenceId) ` + -and [string]::IsNullOrWhitespace($description) ` + -and [string]::IsNullOrWhitespace($assignmentScopeValidation) ` + -and [string]::IsNullOrWhitespace($resourceSelectors) ` + -and [string]::IsNullOrWhitespace($policyDefinitionReferenceIds) ` + -and [string]::IsNullOrWhitespace($metadata)) { + #ignore empty lines from CSV + Write-Warning "Ignoring empty row $entryNumber" + continue + } + } + #endregion read row values andd skip empty rows on CSV files - $extension = $file.Extension - $fullName = $file.FullName - Write-Information "Processing file '$($fullName)'" - $errorInfo = New-ErrorInfo -FileName $fullName - $exemptionsArray = @() - $isXls = $false - if ($extension -eq ".json" -or $extension -eq ".jsonc") { - $content = Get-Content -Path $fullName -Raw -ErrorAction Stop - try { - $jsonObj = ConvertFrom-Json $content -AsHashTable -Depth 100 + #region check if scope defined + if ([string]::IsNullOrWhitespace($scope)) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "required Exemption scope missing" -EntryNumber $entryNumber + continue + } + $trimmedScope = $scope + if ($scope.StartsWith("/subscriptions/")) { + if ($scope.Contains("/providers/")) { + # an actual resource, keep just the "/subscriptions/.../resourceGroups/..." part + $splits = $scope -split "/" + $trimmedScope = $splits[0..4] -join "/" } - catch { - Write-Error "Assignment JSON file '$($fullName)' is not valid." -ErrorAction Stop + } + $exemptionScopeDetails = $ScopeTable.$trimmedScope + #endregion check if scope defined + + + #region Convert complex fields from CSV + if ($isCsvFile) { + + # Convert referenceIds into array (if cell empty, set to empty array) + $final = @() + $step1 = $policyDefinitionReferenceIds + if (-not [string]::IsNullOrWhiteSpace($step1)) { + $step2 = $step1.Trim() + $step3 = $step2 -split "," + foreach ($item in $step3) { + $step4 = $item.Trim() + if ($step4.Length -gt 0) { + $final += $step4 + } + } } - Write-Information "" - if ($null -ne $jsonObj) { - $jsonExemptions = $jsonObj.exemptions - if ($null -ne $jsonExemptions -and $jsonExemptions.Count -gt 0) { - $exemptionsArray += $jsonExemptions + $policyDefinitionReferenceIds = $final + + # Convert resourceSelectors into array (if cell empty, set to Snull) + $resourceSelectors = $null + $step1 = $row.resourceSelectors + if (-not [string]::IsNullOrWhiteSpace($step1)) { + $step2 = $step1.Trim() + if ($step2.StartsWith("{")) { + try { + $step3 = ConvertFrom-Json $step2 -AsHashTable -Depth 100 -NoEnumerate + } + catch { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "invalid resourceSelectors format, must be empty or legal JSON: '$step2'" -EntryNumber $entryNumber + } + if ($step3 -ne @{}) { + $resourceSelectors = $step3 + } } } - } - elseif ($extension -eq ".csv") { - $isXls = $true - $content = Get-Content -Path $fullName -Raw -ErrorAction Stop - $xlsExemptions = ($content | ConvertFrom-Csv -ErrorAction Stop) - if ($xlsExemptions.Count -gt 0) { - $exemptionsArray += $xlsExemptions + # Convert metadata JSON to object + $metadata = $null + $step1 = $row.metadata + if (-not [string]::IsNullOrWhiteSpace($step1)) { + $step2 = $step1.Trim() + if ($step2.StartsWith("{")) { + try { + $step3 = ConvertFrom-Json $step2 -AsHashTable -Depth 100 + } + catch { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "invalid metadata format, must be empty or legal JSON: '$step2'" -EntryNumber $entryNumber + } + if ($step3 -ne @{}) { + $metadata = $step3 + } + } } } + #endregion Convert complex fields from CSV + + if ($isCsvFile) { + + #region CSV files can define the assignment with assignmentReferenceId or the leagcy policyAssignmentId + if ([string]::IsNullOrWhitespace($assignmentReferenceId) -xor [string]::IsNullOrWhitespace($policyAssignmentId)) { + if (-not [string]::IsNullOrWhitespace($assignmentReferenceId)) { + $xlsUsesPolicyMethod = "assignmentReferenceId" + if ($assignmentReferenceId.StartsWith("policyDefinitions/")) { + $splits = $assignmentReferenceId -split "/" + $name = $splits[1] + $policyDefinitionId = Confirm-PolicyDefinitionUsedExists ` + -Name $name ` + -PolicyDefinitionsScopes $PacEnvironment.policyDefinitionsScopes ` + -AllDefinitions $AllDefinitions.policydefinitions ` + -SuppressErrorMessage + if ($null -eq $policyDefinitionId) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "assignmentReferenceId '$assignmentReferenceId' not found in current EPAC environment '$($PacEnvironment.pacSelector)'" -EntryNumber $entryNumber + } + } + elseif ($assignmentReferenceId.StartsWith("policySetDefinitions/")) { + $splits = $assignmentReferenceId -split "/" + $name = $splits[1] + $policySetDefinitionId = Confirm-PolicySetDefinitionUsedExists ` + -Name $name ` + -PolicyDefinitionsScopes $PacEnvironment.policyDefinitionsScopes ` + -AllPolicySetDefinitions $AllDefinitions.policysetdefinitions + if ($null -eq $policySetDefinitionId) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "assignmentReferenceId '$assignmentReferenceId' not found in current EPAC environment '$($PacEnvironment.pacSelector)'" -EntryNumber $entryNumber + } + } + elseif ($assignmentReferenceId.Contains("/providers/Microsoft.Authorization/policyDefinitions/")) { + $policyDefinitionId = Confirm-PolicyDefinitionUsedExists ` + -Id $assignmentReferenceId ` + -PolicyDefinitionsScopes $PacEnvironment.policyDefinitionsScopes ` + -AllDefinitions $AllDefinitions.policydefinitions ` + -SuppressErrorMessage + if ($null -eq $policyDefinitionId) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "assignmentReferenceId '$assignmentReferenceId' not found in current EPAC environment '$($PacEnvironment.pacSelector)'" -EntryNumber $entryNumber + } + } + elseif ($assignmentReferenceId.Contains("/providers/Microsoft.Authorization/policySetDefinitions/")) { + $policySetDefinitionId = Confirm-PolicySetDefinitionUsedExists ` + -Id $assignmentReferenceId ` + -PolicyDefinitionsScopes $PacEnvironment.policyDefinitionsScopes ` + -AllPolicySetDefinitions $AllDefinitions.policysetdefinitions + if ($null -eq $policySetDefinitionId) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "assignmentReferenceId '$assignmentReferenceId' not found in current EPAC environment '$($PacEnvironment.pacSelector)'" -EntryNumber $entryNumber + } + } + elseif ($assignmentReferenceId.Contains("/providers/Microsoft.Authorization/policyAssignments/")) { + $policyAssignmentId = $assignmentReferenceId + if ($AllAssignments.ContainsKey($policyAssignmentId)) { + $policyAssignmentId = $assignmentReferenceId + } + else { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "assignmentReferenceId '$assignmentReferenceId' not found in current root scope $($PacEnvironment.deploymentRootScope)" -EntryNumber $entryNumber + } + } + else { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "assignmentReferenceId '$assignmentReferenceId' of unknown type" -EntryNumber $entryNumber + } + } + else { + $xlsUsesPolicyMethod = "policyAssignmentId" + if (-not $AllAssignments.ContainsKey($policyAssignmentId)) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "assignmentReferenceId '$policyAssignmentId' not found in current root scope $($PacEnvironment.deploymentRootScope)" -EntryNumber $entryNumber + } + } + } + elseif ([string]::IsNullOrWhitespace($assignmentReferenceId) -and [string]::IsNullOrWhitespace($policyAssignmentId)) { + if ($xlsUsesPolicyMethod -eq "unknown") { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "exactly one of the columns policyAssignmentId or assignmentReferenceId is required" -EntryNumber $entryNumber + } + else { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "cell in $xlsUsesPolicyMethod column is empty" -EntryNumber $entryNumber + } + } + else { + throw "$($fullName): exactly one of the columns policyAssignmentId or assignmentReferenceId is allowed" + } + #endregion policyAssignmentId - $exemptionsNamesArray = @() - foreach ($item in $exemptionsArray) { - $exemptionsNamesArray += $item.name } + else { - #endregion read each file - - #region validate file contents - - if ($errorInfo.hasErrors) { - continue - } - - $entryNumber = $isXls ? 1 : 0 - foreach ($row in $exemptionsArray) { - - #region read and validate each row - - $name = $row.name - $displayName = $row.displayName - $exemptionCategory = $row.exemptionCategory - $scope = $row.scope - $policyAssignmentId = $row.policyAssignmentId - $description = $row.description - $assignmentScopeValidation = $row.assignmentScopeValidation - $resourceSelectors = $row.resourceSelectors - $policyDefinitionReferenceIds = $row.policyDefinitionReferenceIds - $metadata = $row.metadata - if ($isXls) { - if ([string]::IsNullOrWhitespace($name) ` - -and [string]::IsNullOrWhitespace($displayName) ` - -and [string]::IsNullOrWhitespace($exemptionCategory) ` - -and [string]::IsNullOrWhitespace($scope) ` - -and [string]::IsNullOrWhitespace($policyAssignmentId) ` - -and [string]::IsNullOrWhitespace($description) ` - -and [string]::IsNullOrWhitespace($assignmentScopeValidation) ` - -and [string]::IsNullOrWhitespace($resourceSelectors) ` - -and [string]::IsNullOrWhitespace($policyDefinitionReferenceIds) ` - -and [string]::IsNullOrWhitespace($metadata)) { - #ignore empty lines from CSV - # Write-Warning "Ignoring empty line in file" - continue + #region JSON files require exactly one field from set @(policyAssignmentId,policyDefinitionName,policyDefinitionId,policySetDefinitionName,policySetDefinitionId) + $numberOfDefinedfields = 0 + $allowedFields = @("policyAssignmentId", "policyDefinitionName", "policyDefinitionId", "policySetDefinitionName", "policySetDefinitionId") + foreach ($field in $allowedFields) { + if ($null -ne $row.$field) { + $numberOfDefinedfields++ } } - if ([string]::IsNullOrWhitespace($name)) { - Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "required name missing" -EntryNumber $entryNumber + if ($numberOfDefinedfields -ne 1) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "exactly one of the fields policyAssignmentId, policyDefinitionName, policyDefinitionId, policySetDefinitionName, policySetDefinitionId is required" -EntryNumber $entryNumber } - if (-not (Confirm-ValidPolicyResourceName -Name $name)) { - Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "name '$name' contains invalid charachters <>*%&:?.+/ or ends with a space." -EntryNumber $entryNumber + else { + if ($null -ne $row.policyAssignmentId) { + $policyAssignmentId = $row.policyAssignmentId + if (-not $AllAssignments.ContainsKey($policyAssignmentId)) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "policyAssignmentId '$assignmentReferenceId' not found in current root scope $($PacEnvironment.deploymentRootScope)" -EntryNumber $entryNumber + } + } + elseif ($null -ne $row.policyDefinitionName) { + $policyDefinitionId = Confirm-PolicyDefinitionUsedExists ` + -Name $row.policyDefinitionName ` + -PolicyDefinitionsScopes $PacEnvironment.policyDefinitionsScopes ` + -AllDefinitions $AllDefinitions.policydefinitions + if ($null -eq $policyDefinitionId) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "policyDefinitionName '$($row.policyDefinitionName)' not found in current EPAC environment '$($PacEnvironment.pacSelector)'" -EntryNumber $entryNumber + } + } + elseif ($null -ne $row.policyDefinitionId) { + $policyDefinitionId = Confirm-PolicyDefinitionUsedExists ` + -Id $row.policyDefinitionId ` + -PolicyDefinitionsScopes $PacEnvironment.policyDefinitionsScopes ` + -AllDefinitions $AllDefinitions.policydefinitions + if ($null -eq $policyDefinitionId) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "policyDefinitionId '$($row.policyDefinitionId)' not found in current EPAC environment '$($PacEnvironment.pacSelector)'" -EntryNumber $entryNumber + } + } + elseif ($null -ne $row.policySetDefinitionName) { + $policySetDefinitionId = Confirm-PolicySetDefinitionUsedExists ` + -Name $row.policySetDefinitionName ` + -PolicyDefinitionsScopes $PacEnvironment.policyDefinitionsScopes ` + -AllPolicySetDefinitions $AllDefinitions.policysetdefinitions + if ($null -eq $policySetDefinitionId) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "policySetDefinitionName '$($row.policySetDefinitionName)' not found in current EPAC environment '$($PacEnvironment.pacSelector)'" -EntryNumber $entryNumber + } + } + elseif ($null -ne $row.policySetDefinitionId) { + $policySetDefinitionId = Confirm-PolicySetDefinitionUsedExists ` + -Id $row.policySetDefinitionId ` + -PolicyDefinitionsScopes $PacEnvironment.policyDefinitionsScopes ` + -AllPolicySetDefinitions $AllDefinitions.policysetdefinitions + if ($null -eq $policySetDefinitionId) { + $policySetDefinitionId = $row.policySetDefinitionId + } + else { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "policySetDefinitionId '$($row.policySetDefinitionId)' not found in current EPAC environment '$($PacEnvironment.pacSelector)'" -EntryNumber $entryNumber + } + } } - if ([string]::IsNullOrWhitespace($displayName)) { - Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "required displayName missing" -EntryNumber $entryNumber + #endregion JSON files require exactly one field from set @(policyAssignmentId,policyDefinitionName,policyDefinitionId,policySetDefinitionName,policySetDefinitionId) + } + + #region check required fields + if ([string]::IsNullOrWhitespace($name)) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "required name missing" -EntryNumber $entryNumber + } + if (-not (Confirm-ValidPolicyResourceName -Name $name)) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "name '$name' contains invalid charachters <>*%&:?.+/ or ends with a space." -EntryNumber $entryNumber + } + if ([string]::IsNullOrWhitespace($displayName)) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "required displayName missing" -EntryNumber $entryNumber + } + if ([string]::IsNullOrWhitespace($exemptionCategory)) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "required exemptionCategory missing" -EntryNumber $entryNumber + } + else { + if ($exemptionCategory -ne "Waiver" -and $exemptionCategory -ne "Mitigated") { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "invalid exemptionCategory '$exemptionCategory' (must be 'Waiver' or 'Mitigated')" -EntryNumber $entryNumber } - if ([string]::IsNullOrWhitespace($exemptionCategory)) { - Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "required exemptionCategory missing" -EntryNumber $entryNumber + } + if (-not [string]::IsNullOrWhitespace($description)) { + if ($description.Length -gt 1024) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "description too long (max 1024 characters)" -EntryNumber $entryNumber } - else { - if ($exemptionCategory -ne "Waiver" -and $exemptionCategory -ne "Mitigated") { - Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "invalid exemptionCategory '$exemptionCategory' (must be 'Waiver' or 'Mitigated')" -EntryNumber $entryNumber - } + } + #Should add a check that name does not contain & or potentially any special characters. + if ([string]::IsNullOrWhitespace($assignmentScopeValidation)) { + $assignmentScopeValidation = "Default" + } + else { + if ($assignmentScopeValidation -ne "Default" -and $assignmentScopeValidation -ne "DoNotValidate") { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "invalid assignmentScopeValidation '$assignmentScopeValidation' (must be 'Default' or 'DoNotValidate')" -EntryNumber $entryNumber } - if ([string]::IsNullOrWhitespace($scope)) { - Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "required scope missing" -EntryNumber $entryNumber + } + #endregion check required fields + + #region validate scope + if ($null -eq $exemptionScopeDetails) { + Write-Warning "Exemption entry $($entryNumber): Exemption '$($displayName)'($($name)) scope $($scope) is not in current scope tree for root $($PacEnvironment.deploymentRootScope), skipping row." + continue + } + if ($assignmentScopeValidation -eq "Default") { + if ($exemptionScopeDetails.isInGlobalNotScope) { + Write-Warning "Exemption entry $($entryNumber): Exemption '$($displayName)'($($name)) scope $($scope) is in a global not scope, skipping row." + continue } - if ([string]::IsNullOrWhitespace($policyAssignmentId)) { - Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "required policyAssignmentId missing" -EntryNumber $entryNumber + } + #endregion validate scope + + $warning = $false + + #region calculate expiresOn + $expiresOn = $null + $expiresOnRaw = $row.expiresOn + if (-not [string]::IsNullOrWhitespace($expiresOnRaw)) { + if ($expiresOnRaw -is [datetime]) { + $expiresOn = $expiresOnRaw } - if (-not [string]::IsNullOrWhitespace($description)) { - if ($description.Length -gt 1024) { - Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "description too long (max 1024 characters)" -EntryNumber $entryNumber + elseif ($expiresOnRaw -is [string]) { + try { + $expiresOn = [datetime]::Parse($expiresOnRaw, $null, [System.Globalization.DateTimeStyles]::AssumeUniversal -bor [System.Globalization.DateTimeStyles]::AdjustToUniversal) + } + catch { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString $_ -EntryNumber $entryNumber } - } - #Should add a check that name does not contain & or potentially any special characters. - if ([string]::IsNullOrWhitespace($assignmentScopeValidation)) { - $assignmentScopeValidation = "Default" } else { - if ($assignmentScopeValidation -ne "Default" -and $assignmentScopeValidation -ne "DoNotValidate") { - Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "invalid assignmentScopeValidation '$assignmentScopeValidation' (must be 'Default' or 'DoNotValidate')" -EntryNumber $entryNumber + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "invalid expiresOn format, must be empty or a valid date/time: '$expiresOnRaw'" -EntryNumber $entryNumber + } + if ($expiresOn) { + $expired = $expiresOn -lt $now + $daysUntilExpired = (New-TimeSpan -Start $now -End $expiresOn).Days + if ($expired) { + $daysExpired = - $daysUntilExpired + if ($daysExpired -eq 0) { + Write-Warning "Exemption entry $($entryNumber): Exemption '$name' in definitions expired today, skipping row." + $warning = $true + } + else { + Write-Warning "Exemption entry $($entryNumber): Exemption '$name' in definitions expired $daysExpired days ago, skipping row." + $warning = $true + } + $warning = $true + } + elseif ($daysUntilExpired -le 15) { + Write-Warning "Exemption entry $($entryNumber): Exemption '$name' in definitions expires in $daysUntilExpired days." } } + } + #endregion calculate expiresOn - #endregion read and validate each row + if ($errorInfo.hasLocalErrors) { + continue + } - #region Convert complex fields from CSV + #region check if resource still exists; $scope indicating a resource container (resourceGroups, subscriptions, managementGroups) or an actual resource + $isIndividualResource = $true + if ($scope.StartsWith("/providers/Microsoft.Management/management")) { + $isIndividualResource = $false + } + elseif ($scope.Contains("/providers/")) { + $isIndividualResource = $true + } + else { + # subscription, resourceGroup + $isIndividualResource = $false + } - if ($isXls) { - # Convert referenceIds into array (if cell empty, set to empty array) - $final = @() - $step1 = $policyDefinitionReferenceIds - if (-not [string]::IsNullOrWhiteSpace($step1)) { - $step2 = $step1.Trim() - $step3 = $step2 -split "," - foreach ($item in $step3) { - $step4 = $item.Trim() - if ($step4.Length -gt 0) { - $final += $step4 - } - } + if ($isIndividualResource) { + $thisResourceIdExists = $false + if ($resourceIdsExist.ContainsKey($scope)) { + $thisResourceIdExists = $resourceIdsExist.$scope + } + else { + $resource = Get-AzResource -ResourceId $scope -ErrorAction SilentlyContinue + $thisResourceIdExists = $null -ne $resource + $resourceIdsExist[$scope] = $thisResourceIdExists + } + if (-not $thisResourceIdExists) { + Write-Warning "Row $($entryNumber): Resource '$scope' does not exist, skipping row." + $warning = $true + } + } + #endregion check if resource still exists; $scope indicating a resource container (resourceGroups, subscriptions, managementGroups) + + #region retrieve pre-calculated assignments for this row + $calculatedPolicyAssignments = $null + if ($null -ne $policyDefinitionId) { + $calculatedPolicyAssignments = $byPolicyIdCalculatedAssignments.$policyDefinitionId + if ($null -eq $calculatedPolicyAssignments -or $calculatedPolicyAssignments.Count -eq 0) { + Write-Warning "Row $($entryNumber): No assignments found for policyDefinitionId '$policyDefinitionId', skipping row" + $warning = $true + } + } + elseif ($null -ne $policySetDefinitionId) { + $calculatedPolicyAssignments = $byPolicySetIdCalculatedAssignments.$policySetDefinitionId + if ($null -eq $calculatedPolicyAssignments -or $calculatedPolicyAssignments.Count -eq 0) { + Write-Warning "Row $($entryNumber): No assignments found for policySetDefinitionId '$policySetDefinitionId', skipping row" + $warning = $true + } + } + elseif ($null -ne $policyAssignmentId) { + $calculatedPolicyAssignments = $byAssignmentIdCalculatedAssignments.$policyAssignmentId + if ($null -eq $calculatedPolicyAssignments -or $calculatedPolicyAssignments.Count -eq 0) { + Write-Warning "Row $($entryNumber): No assignment found for policyAssignmentId '$policyAssignmentId', skipping row" + $warning = $true + } + } + else { + throw "Code bug: policyDefinitionId, policySetDefinitionId, or policyAssignmentId must be defined" + } + #endregion retrieve pre-calculated assignments for this row + + if ($warning) { + foreach ($deployedManagedExemption in $deployedManagedExemptions.Values) { + $deployedId = $deployedManagedExemption.id + $deployedName = $deployedManagedExemption.name + if ($deployedName -eq $name -or $deployedName -like "$($name)___*") { + # do not delete the deployed exemption + $null = $deleteCandidates.Remove($deployedId) + break } - $policyDefinitionReferenceIds = $final + } + continue + } - # Convert resourceSelectors into array (if cell empty, set to Snull) - $resourceSelectors = $null - $step1 = $row.resourceSelectors - if (-not [string]::IsNullOrWhiteSpace($step1)) { - $step2 = $step1.Trim() - if ($step2.StartsWith("{")) { - try { - $step3 = ConvertFrom-Json $step2 -AsHashTable -Depth 100 -NoEnumerate - } - catch { - Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "invalid resourceSelectors format, must be empty or legal JSON: '$step2'" -EntryNumber $entryNumber - } - if ($step3 -ne @{}) { - $resourceSelectors = $step3 + #region filter out assignments that are not in the current scope tree or are in excluded scopes + $filteredPolicyAssignments = [System.Collections.ArrayList]::new() + foreach ($calculatedPolicyAssignment in $calculatedPolicyAssignments) { + $policyAssignmentScope = $calculatedPolicyAssignment.scope + if ($ScopeTable.ContainsKey($policyAssignmentScope)) { + $assignmentScopeDetails = $ScopeTable.$policyAssignmentScope + if (-not $assignmentScopeDetails.isExcluded) { + $exemptionScopeDetails = $ScopeTable.$trimmedScope + $parentTable = $exemptionScopeDetails.parentTable + #region validate that the Assignment scope is at or above the Exemption scope + $isAssignmentScopeValid = ($assignmentScopeValidation -ne "Default") -or ($trimmedScope -eq $policyAssignmentScope) -or $parentTable.ContainsKey($policyAssignmentScope) + if (-not $isAssignmentScopeValid) { + Write-Verbose "Exemption entry $($entryNumber): Exemption scope = '$scope' is NOT in a child scope for assignment $($calculatedPolicyAssignment.displayName)($($calculatedPolicyAssignment.id)), skipping assignment." + continue + } + #endregion validate that the Assignment scope is at or above the Exemption scope + + #region validate scope against the assignment's notScopes + if ($assignmentScopeValidation -eq "Default") { + foreach ($notScope in $calculatedPolicyAssignment.notScopes) { + if ($trimmedScope -eq $notScope -or $parentTable.ContainsKey($notScope)) { + Write-Warning "Exemption entry $($entryNumber): Exemption scope = '$scope' is in a not scope for assignment $($calculatedPolicyAssignment.displayName)($($calculatedPolicyAssignment.id)), skipping assignment." + $warning = $true + break + } } } - } + #endregion validate scope against the assignment's notScopes - # Convert metadata JSON to object - $metadata = $null - $step1 = $row.metadata - if (-not [string]::IsNullOrWhiteSpace($step1)) { - $step2 = $step1.Trim() - if ($step2.StartsWith("{")) { - try { - $step3 = ConvertFrom-Json $step2 -AsHashTable -Depth 100 - } - catch { - Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "invalid metadata format, must be empty or legal JSON: '$step2'" -EntryNumber $entryNumber - } - if ($step3 -ne @{}) { - $metadata = $step3 - } + if (-not $warning) { + $null = $filteredPolicyAssignments.Add($calculatedPolicyAssignment) } } else { - $metadata = $null + Write-Verbose "Assignment scope = '$($policyAssignmentScope)' is in a globally excluded scope" } } - - #endregion Convert complex fields from CSV - - #region calculate expiresOn - - $expiresOn = $null - $expired = $false - $expiresOnRaw = $row.expiresOn - if (-not [string]::IsNullOrWhitespace($expiresOnRaw)) { - if ($expiresOnRaw -is [datetime]) { - $expiresOn = $expiresOnRaw + else { + Write-Verbose "Assignment scope = '$($policyAssignmentScope)' not found in current scope tree for root $($PacEnvironment.deploymentRootScope)" + } + } + #endregion filter out assignments that are not in the current scope tree or are in excluded scopes + + $isMultipleAssignments = $filteredPolicyAssignments.Count -gt 1 + $ordinal = 1 + foreach ($calculatedPolicyAssignment in $filteredPolicyAssignments) { + $policyAssignmentId = $calculatedPolicyAssignment.id + $policyAssignmentName = $calculatedPolicyAssignment.name + $policyAssignmentReferenceIds = $calculatedPolicyAssignment.policyDefinitionReferenceIds + $policyAssignmentPerPolicyReferenceIdTable = $calculatedPolicyAssignment.perPolicyReferenceIdTable + $policyAssignmentByPolicyReferenceIds = $calculatedPolicyAssignment.policyDefinitionReferenceIds + $allowReferenceIdsInRow = $calculatedPolicyAssignment.allowReferenceIdsInRow + $isPolicyAssignment = $calculatedPolicyAssignment.isPolicyAssignment + + #region multiple assignments require unique names and displayNames + $tryName = $null + $tryId = $null + $tryDisplayName = $null + if ($isMultipleAssignments) { + $ordinalString = '{0:d2}' -f $ordinal + $possibleName = "$($name)-$($policyAssignmentName)" + $possibleDisplayName = "$($displayName) - $($policyAssignmentName)" + if ($possibleName.Length -gt 64) { + Write-Warning "Exemption entry $($entryNumber): Concatenated Exemption name for multiple assignments too long ($($possibleName.Length) - max 60 characters, truncating." + $possibleName = $possibleName.Substring(0, 60) } - elseif ($expiresOnRaw -is [string]) { - try { - $expiresOn = [datetime]::Parse($expiresOnRaw, $null, [System.Globalization.DateTimeStyles]::AssumeUniversal -bor [System.Globalization.DateTimeStyles]::AdjustToUniversal) + if ($possibleDisplayName.Length -gt 125) { + Write-Warning "Exemption entry $($entryNumber): Concatenated Exemption displayName for multiple assignments too long ($($possibleDisplayName.Length) - max 125 characters, truncating." + $possibleDisplayName = $possibleDisplayName.Substring(0, 125) + } + $tryName = $possibleName + $tryId = "$scope/providers/Microsoft.Authorization/policyExemptions/$tryName" + $tryDisplayName = $possibleDisplayName + if ($uniqueIds.ContainsKey($tryId)) { + # append ordinal string to name and displayName; last resort fallback + $tryName = "$($possibleName)-$($ordinalString)" + $tryId = "$scope/providers/Microsoft.Authorization/policyExemptions/$tryName" + $tryDisplayName = "$($possibleDisplayName);$($ordinalString)" + if ($uniqueIds.ContainsKey($tryId)) { + $tryName = $null + $tryId = $null + $tryDisplayName = $null } - catch { - Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString $_ -EntryNumber $entryNumber + else { + $ordinal++ } } else { - Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "invalid expiresOn format, must be empty or a valid date/time: '$expiresOnRaw'" -EntryNumber $entryNumber + $null = $null + } + if ($null -eq $tryName) { + # ultimate fall back, use the original name and displayName and an ordinal + do { + $tryName = "$($name)-$($ordinalString)" + if ($tryName.Length -gt 64) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "Exemption name for multiple assignments too long ($($tryName.Length) - max 60 characters), please shorten the Exemption name." -EntryNumber $entryNumber + break + } + if ($ordinal -gt 99) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "Exemption has too many assignments ($($ordinal), swich back to specifying the assignment" -EntryNumber $entryNumber + break + } + $tryId = "$scope/providers/Microsoft.Authorization/policyExemptions/$tryName" + $tryDisplayName = "$($displayName);$($ordinalString)" + $ordinal++ + } while ($uniqueIds.ContainsKey($tryId)) + if ($errorInfo.hasLocalErrors) { + continue + } } - if ($expiresOn) { - $expired = $expiresOn -lt $now + if ($displayNameAugmented.Length -gt 128) { + Write-Warning "Exemption entry $($entryNumber): Exemption displayName (for multiple assignments) too long ($($displayNameAugmented.Length) - max 128 characters), truncating." + $displayNameAugmented = $displayNameAugmented.Substring(0, 128) } } + else { + $tryName = $name + $tryId = "$scope/providers/Microsoft.Authorization/policyExemptions/$tryName" + $tryDisplayName = $displayName + if ($uniqueIds.ContainsKey($tryId)) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "Duplicate Exemption id '$tryId'." -EntryNumber $entryNumber + continue + } + } + $null = $uniqueIds.Add($tryId, $true) + $nameAugmented = $tryName + $displayNameAugmented = $tryDisplayName + $id = $tryId + #endregion multiple assignments require unique names and displayNames + + #region validate or create referenceIds + $policyDefinitionReferenceIdsAugmented = [System.Collections.ArrayList]::new() + if ($allowReferenceIdsInRow) { + if ($null -ne $policyDefinitionReferenceIds -and $policyDefinitionReferenceIds.Count -gt 0) { + foreach ($referenceId in $policyDefinitionReferenceIds) { + if ($policyAssignmentReferenceIds -contains $referenceId) { + $null = $policyDefinitionReferenceIdsAugmented.Add($referenceId) + } + elseif ($referenceId.StartsWith("policyDefinitions/")) { + $referenceIdTrimmed = $referenceId.Substring(18) + $policyDefinitionId = Confirm-PolicyDefinitionUsedExists ` + -Name $referenceIdTrimmed ` + -PolicyDefinitionsScopes $PacEnvironment.policyDefinitionsScopes ` + -AllDefinitions $AllDefinitions + if ($null -eq $policyDefinitionId) { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "policyDefinitionReference '$referenceId' not resolved for policyAssignment '$policyAssignmentName'" -EntryNumber $entryNumber + } + else { + if ($policyAssignmentPerPolicyReferenceIdTable.ContainsKey($policyDefinitionId)) { + $referenceIds = $policyAssignmentPerPolicyReferenceIdTable.$policyDefinitionId + $null = $policyDefinitionReferenceIdsAugmented.AddRange($referenceIds) + } + else { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "policyDefinitionReference '$referenceId' not resolved for policyAssignment '$policyAssignmentName'" -EntryNumber $entryNumber + } + } + } + elseif ($referenceId -contains "/providers/Microsoft.Authorization/policyDefinitions/") { + if ($policyAssignmentPerPolicyReferenceIdTable.ContainsKey($referenceId)) { + $referenceIds = $policyAssignmentPerPolicyReferenceIdTable.$referenceId + $null = $policyDefinitionReferenceIdsAugmented.AddRange($referenceIds) + } + else { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "policyDefinitionReference '$referenceId' not resolved for policyAssignment '$policyAssignmentName'" -EntryNumber $entryNumber + } + } + else { + Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "policyDefinitionReference '$referenceId' not resolved for policyAssignment '$policyAssignmentName'" -EntryNumber $entryNumber + } + } + } + } + elseif (-not $isPolicyAssignment) { + $null = $policyDefinitionReferenceIdsAugmented.AddRange($policyAssignmentByPolicyReferenceIds) + } + #endregion validate or create referenceIds - #endregion calculate expiresOn - - #region create $exemption - - $id = "$scope/providers/Microsoft.Authorization/policyExemptions/$name" - if ($allExemptions.ContainsKey($id)) { - Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "duplicate exemption id (name=$name, scope=$scope)" -EntryNumber $entryNumber + if ($metadata) { + $metadata.pacOwnerId = $PacEnvironment.pacOwnerId } else { - $allExemptions.Add($id, $true) + $metadata = @{ + pacOwnerId = $PacEnvironment.pacOwnerId + } + } + if (!$metadata.ContainsKey("deployedBy")) { + $metadata.deployedBy = $PacEnvironment.deployedBy } - if ($errorInfo.hasErrors) { + # bail if we encountered errors + if ($errorInfo.hasLocalErrors) { continue } - if ($metadata) { - $metadata.pacOwnerId = $PacEnvironment.pacOwnerId + #region check if the exemption already exists in Azure + $deployedManagedExemption = $null + if ($deployedManagedExemptions.ContainsKey($id)) { + $deployedManagedExemption = $deployedManagedExemptions.$id } else { - $metadata = @{ - pacOwnerId = $PacEnvironment.pacOwnerId + # try to find a matching deployed exemption + foreach ($possibleId in $deployedManagedExemptions.Keys) { + $deployedManagedExemption = $deployedManagedExemptions.$possibleId + $deployedName = $deployedManagedExemption.name + $deployedDisplayName = $deployedManagedExemption.displayName + $deployedPolicyAssignmentId = $deployedManagedExemption.policyAssignmentId + if ($deployedName.StartsWith($name) -and $deployedDisplayName.StartsWith($displayName) ` + -and $deployedPolicyAssignmentId -eq $policyAssignmentId) { + $oldFormat = $deployedName -match "^$($name)___\d{3}$" + if (-not $oldFormat) { + $null = $uniqueIds.Remove($nameAugmented) + $null = $uniqueIds.Add($deployedName, $true) + $id = $possibleId + $nameAugmented = $deployedName + $displayNameAugmented = $deployedManagedExemption.displayName + break + } + else { + $deployedManagedExemption = $null + } + } + else { + $deployedManagedExemption = $null + } } } - $exemption = [PSCustomObject]@{ + #endregion check if the exemption already exists in Azure + + #region create exemption object + $policyDefinitionReferenceIdsAugmentedArray = $policyDefinitionReferenceIdsAugmented.ToArray() + $exemption = [ordered]@{ id = $id - name = $name - displayName = $displayName + name = $nameAugmented + displayName = $displayNameAugmented description = $description exemptionCategory = $exemptionCategory expiresOn = $expiresOn scope = $scope policyAssignmentId = $policyAssignmentId assignmentScopeValidation = $assignmentScopeValidation - policyDefinitionReferenceIds = $policyDefinitionReferenceIds + policyDefinitionReferenceIds = $policyDefinitionReferenceIdsAugmentedArray resourceSelectors = $resourceSelectors metadata = $metadata } - - #endregion create $exemption - - #region expired and orphaned in definitions - - $deleteExpired = $PacEnvironment.desiredState.deleteExpiredExemptions - $deleteOrphaned = $PacEnvironment.desiredState.deleteOrphanedExemptions - $deployedManagedExemption = $null - if ($deployedManagedExemptions.ContainsKey($id)) { - $deployedManagedExemption = $deployedManagedExemptions.$id - # Filter orphaned and expired Exemptions in definitions; deleteCandidates will delete it from environment if it is still deployed - if (!$AllAssignments.ContainsKey($policyAssignmentId) -and $deleteOrphaned -eq $false) { - Write-Warning "Orphaned exemption (name=$name, scope=$scope) in definitions" - $deployedManagedExemption.pacOwner = "thisPac" - $deployedManagedExemptions.status = "orphaned" - continue - } - if ($expired -and $deleteExpired -eq $false) { - Write-Warning "Expired exemption (name=$name, scope=$scope) in definitions" - if ($deployedManagedExemption.status -ne "orphaned") { - $deployedManagedExemption.pacOwner = "thisPac" - $deployedManagedExemption.status = "expired" - } - continue - } - if (($deleteExpired -and $expired ) -or ($deleteOrphaned -and !$AllAssignments.ContainsKey($policyAssignmentId))) { - continue - } - } - else { - if (!$AllAssignments.ContainsKey($policyAssignmentId) -and $deleteOrphaned) { - Write-Warning "Orphaned exemption (name=$name, scope=$scope) in definitions" - continue - } - if ($expired -and $deleteExpired) { - Write-Warning "Expired exemption (name=$name, scope=$scope) in definitions" - continue - } - if (($DeleteExpired -eq $false -and $expired ) -or ($DeleteOrphaned -eq $false -and !$AllAssignments.ContainsKey($policyAssignmentId))) { - continue - } - } - - #endregion expired and orphaned in definitions + #endregion create exemption object #region calculate desired state mandated changes - - if ($deployedManagedExemption) { + if ($null -ne $deployedManagedExemption) { $deleteCandidates.Remove($id) if ($deployedManagedExemption.policyAssignmentId -ne $policyAssignmentId) { # Replaced Assignment - Write-Information "Replace(assignmentId changed) '$($name)', '$($scope)'" + if ($isMultipleAssignments) { + Write-Information "Replace(ordinal) '$($nameAugmented)', '$($scope)' from '$($deployedManagedExemption.policyAssignmentId)' to '$($policyAssignmentId)" + } + else { + Write-Information "Replace(assignmentId) '$($nameAugmented)', '$($scope)' from '$($deployedManagedExemption.policyAssignmentId)' to '$($policyAssignmentId)'" + } $null = $Exemptions.replace.Add($id, $exemption) $Exemptions.numberOfChanges++ } elseif ($replacedAssignments.ContainsKey($policyAssignmentId)) { # Replaced Assignment - Write-Information "Replace(replaced assignment) '$($name)', '$($scope)'" + Write-Information "Replace(replaced assignment) '$($nameAugmented)', '$($scope)', assignmentId '$($deployedManagedExemption.policyAssignmentId)'" $null = $Exemptions.replace.Add($id, $exemption) $Exemptions.numberOfChanges++ } else { # Maybe update existing Exemption - $displayNameMatches = $deployedManagedExemption.displayName -eq $displayName + $displayNameMatches = $deployedManagedExemption.displayName -eq $displayNameAugmented $descriptionMatches = ($deployedManagedExemption.description -eq $description) ` -or ([string]::IsNullOrWhiteSpace($deployedManagedExemption.description) -and [string]::IsNullOrWhiteSpace($description)) $exemptionCategoryMatches = $deployedManagedExemption.exemptionCategory -eq $exemptionCategory $expiresOnMatches = $deployedManagedExemption.expiresOn -eq $expiresOn - $clearExpiration = $false - if (-not $expiresOnMatches) { - if ($null -eq $expiresOn) { - $exemption.clearExpiration = $true - $clearExpiration = $true - } + $clearExpiration = !$expiresOnMatches -and $null -eq $expiresOn + $deployedPolicyDefinitionReferenceIdsArray = $deployedManagedExemption.policyDefinitionReferenceIds + if ($null -ne $deployedPolicyDefinitionReferenceIdsArray -and $deployedPolicyDefinitionReferenceIdsArray -isnot [array]) { + $deployedPolicyDefinitionReferenceIdsArray = @($deployedPolicyDefinitionReferenceIdsArray) } - $policyDefinitionReferenceIdsMatches = Confirm-ObjectValueEqualityDeep $deployedManagedExemption.policyDefinitionReferenceIds $policyDefinitionReferenceIds + $policyDefinitionReferenceIdsMatches = Confirm-ObjectValueEqualityDeep $deployedPolicyDefinitionReferenceIdsArray $policyDefinitionReferenceIdsAugmentedArray $metadataMatches, $changePacOwnerId = Confirm-MetadataMatches ` -ExistingMetadataObj $deployedManagedExemption.metadata ` -DefinedMetadataObj $metadata @@ -402,82 +837,79 @@ function Build-ExemptionsPlan { $changesString = $changesStrings -join "," $Exemptions.numberOfChanges++ $null = $Exemptions.update.Add($id, $exemption) - Write-Information "Update($changesString) '$($name)', '$($scope)'" + Write-Information "Update($changesString) '$($displayNameAugmented)'($($nameAugmented)), '$($scope)'" } } } else { # Create Exemption - Write-Information "New '$($name)', '$($scope)'" + Write-Information "New '$($displayNameAugmented)'($($nameAugmented)), '$($scope)'" $null = $Exemptions.new.Add($id, $exemption) $Exemptions.numberOfChanges++ } #endregion calculate desired state mandated changes } - if ($errorInfo.hasErrors) { - $errorText = Get-ErrorTextFromInfo -ErrorInfo $errorInfo - Write-Error $errorText -ErrorAction Continue - $numberOfFilesWithErrors++ - continue - } + } + if ($errorInfo.hasErrors) { + Write-ErrorsFromErrorInfo -ErrorInfo $errorInfo + $numberOfFilesWithErrors++ + continue } - if ($numberOfFilesWithErrors -gt 0) { - Write-Error "There were errors in $numberOfFilesWithErrors file(s)." -ErrorAction Stop - } - - #region delete removed, orphaned and expired exemptions - - $strategy = $PacEnvironment.desiredState.strategy - foreach ($id in $deleteCandidates.Keys) { - $exemption = $deleteCandidates.$id - $pacOwner = $exemption.pacOwner - $status = $exemption.status - if ($deleteExpired -eq $false -or $deleteOrphaned -eq $false) { - $currentExemptionName = $exemption.name - $removed = $false - if ($currentExemptionName -notin $exemptionsNamesArray -and ($status -ne "orphaned" -and $status -ne "expired")) { - $removed = $true - } - } - if ($null -eq $exemption.metadata.pacOwnerId -and $PacEnvironment.desiredState.strategy -eq "ownedOnly") { - $shallDelete = $false - } - else { - $shallDelete = Confirm-DeleteForStrategy -PacOwner $pacOwner ` - -Strategy $strategy ` - -Status $status ` - -DeleteExpired $deleteExpired ` - -DeleteOrphaned $deleteOrphaned ` - -Removed $removed - } + } + + if ($numberOfFilesWithErrors -gt 0) { + Write-Information "" + throw "There were errors in $numberOfFilesWithErrors file(s)." + } + } - if ($shallDelete) { - switch ($status) { - orphaned { - $Exemptions.numberOfOrphans++ - } - expired { - $Exemptions.numberOfExpired++ - } - } - Write-Information "Delete '$($exemption.name)', '$($exemption.scope)'" - $null = $Exemptions.delete[$exemption.id] = $exemption - $Exemptions.numberOfChanges++ + #region delete removed, orphaned and expired exemptions + foreach ($id in $deleteCandidates.Keys) { + $exemption = $deleteCandidates.$id + $pacOwner = $exemption.pacOwner + $status = $exemption.status + + $reason = "unknown" + $shallDelete = $false + switch ($pacOwner) { + thisPaC { + $shallDelete = $true + $reason = "thisOwner" + } + otherPac { + $shallDelete = $false + $reason = "otherPac" + } + unknownOwner { + if ($desiredStateStrategy -eq "full") { + $shallDelete = $true + $reason = "unknownOwner, strategy=full, status=$status" } else { - Write-Verbose "No delete($pacOwner,$strategy) '$($exemption.name)', '$($exemption.scope)'" + $shallDelete = $false + $reason = "unknownOwner, strategy=owwnedOnly, status=$status" } } - - #endregion delete removed, orphaned and expired exemptions - - Write-Information "" - if ($Exemptions.numberUnchanged -gt 0) { - Write-Information "$($Exemptions.numberUnchanged) unchanged Exemptions" + Default { + throw "Code bug: pacOwner must be one of @('thisPac','otherPac','unknownOwner')" } } - Write-Information "" + if ($shallDelete) { + # check fo special Exemption cases + Write-Information "Delete '$($exemption.displayName)'($($exemption.name)), '$($exemption.scope)', $reason" + $null = $Exemptions.delete[$id] = $exemption + $Exemptions.numberOfChanges++ + } + else { + Write-Verbose "Keep $($reason): '$($exemption.displayName)'($($exemption.name)), '$($exemption.scope)' $reason" + } + } + #endregion delete removed, orphaned and expired exemptions + + if ($Exemptions.numberUnchanged -gt 0) { + Write-Information "$($Exemptions.numberUnchanged) unchanged Exemptions" } + Write-Information "" } diff --git a/Scripts/Helpers/Build-NotScopes.ps1 b/Scripts/Helpers/Build-NotScopes.ps1 deleted file mode 100644 index fd36f8fa..00000000 --- a/Scripts/Helpers/Build-NotScopes.ps1 +++ /dev/null @@ -1,48 +0,0 @@ -#Requires -PSEdition Core -function Build-NotScopes { - param( - [parameter(Mandatory = $True)] [hashtable] $ScopeTable, - [parameter(Mandatory = $True)] [string[]] $ScopeList, - [parameter(Mandatory = $False)] [string[]] $NotScopeIn = @() - ) - - $scopeCollection = @() - foreach ($scope in $ScopeList) { - if ($ScopeTable.ContainsKey($scope)) { - if ($scope.Contains("/resourceGroups/")) { - $scopeCollection += @{ - scope = "$scope" - notScope = @() - } - } - else { - $notScopes = [System.Collections.ArrayList]::new() - $scopeEntry = $ScopeTable.$scope - $scopeChildren = $scopeEntry.childrenList - $scopeResourceGroups = $scopeEntry.resourceGroups - foreach ($notScope in $NotScopeIn) { - if ($notScope.StartsWith("/resourceGroupPatterns/")) { - $pattern = $notScope -replace "/resourceGroupPatterns/", "/subscriptions/*/resourceGroups/" - foreach ($id in $scopeResourceGroups.Keys) { - if ($id -like $pattern) { - $null = $notScopes.Add($id) - } - } - } - elseif ($scopeChildren.ContainsKey($notScope)) { - $null = $notScopes.Add($notScope) - } - } - $scopeCollection += @{ - scope = "$scope" - notScope = $notScopes.ToArray() - } - } - } - else { - Write-Error "Scope '$scope' not found in environment" -ErrorAction Stop - } - } - - Write-Output $scopeCollection -NoEnumerate -} diff --git a/Scripts/Helpers/Build-PolicyPlan.ps1 b/Scripts/Helpers/Build-PolicyPlan.ps1 index 27705490..cf93c867 100644 --- a/Scripts/Helpers/Build-PolicyPlan.ps1 +++ b/Scripts/Helpers/Build-PolicyPlan.ps1 @@ -14,237 +14,227 @@ function Build-PolicyPlan { Write-Information "Processing Policy JSON files in folder '$DefinitionsRootFolder'" Write-Information "===================================================================================================" - # Calculate roleDefinitionIds for built-in and inherited Policies - $readOnlyPolicyDefinitions = $DeployedDefinitions.readOnly - foreach ($id in $readOnlyPolicyDefinitions.Keys) { - $deployedDefinitionProperties = Get-PolicyResourceProperties -PolicyResource $readOnlyPolicyDefinitions.$id - if ($deployedDefinitionProperties.policyRule.then.details -and $deployedDefinitionProperties.policyRule.then.details.roleDefinitionIds) { - $roleIds = $deployedDefinitionProperties.policyRule.then.details.roleDefinitionIds - $null = $PolicyRoleIds.Add($id, $roleIds) - } + # Process Policy definitions JSON files, if any + $definitionFiles = @() + $definitionFiles += Get-ChildItem -Path $DefinitionsRootFolder -Recurse -File -Filter "*.json" + $definitionFiles += Get-ChildItem -Path $DefinitionsRootFolder -Recurse -File -Filter "*.jsonc" + if ($definitionFiles.Length -gt 0) { + Write-Information "Number of Policy files = $($definitionFiles.Length)" + } + else { + Write-Warning "No Policy files found! Deleting any custom Policy definitions." } - # Populate allDefinitions with all deployed definitions $managedDefinitions = $DeployedDefinitions.managed - $deleteCandidates = Get-HashtableShallowClone $managedDefinitions - $allDeployedDefinitions = $DeployedDefinitions.all - foreach ($id in $allDeployedDefinitions.Keys) { - $AllDefinitions.policydefinitions[$id] = $allDeployedDefinitions.$id - } + $deleteCandidates = Get-ClonedObject $managedDefinitions -AsHashTable -AsShallowClone $deploymentRootScope = $PacEnvironment.deploymentRootScope $duplicateDefinitionTracking = @{} + $definitionsNew = $Definitions.new + $definitionsUpdate = $Definitions.update + $definitionsReplace = $Definitions.replace + $definitionsUnchanged = 0 $thisPacOwnerId = $PacEnvironment.pacOwnerId - # Process Policy definitions JSON files, if any - if (!(Test-Path $DefinitionsRootFolder -PathType Container)) { - Write-Warning "Policy definitions 'policyDefinitions' folder not found. Policy definitions not managed by this EPAC instance." - } - else { + foreach ($file in $definitionFiles) { - $definitionFiles = @() - $definitionFiles += Get-ChildItem -Path $DefinitionsRootFolder -Recurse -File -Filter "*.json" - $definitionFiles += Get-ChildItem -Path $DefinitionsRootFolder -Recurse -File -Filter "*.jsonc" - if ($definitionFiles.Length -gt 0) { - Write-Information "Number of Policy files = $($definitionFiles.Length)" + # Write-Information "Processing $($definitionFilesSet.Length) Policy files in this parallel execution." + $Json = Get-Content -Path $file.FullName -Raw -ErrorAction Stop + try { + $definitionObject = $Json | ConvertFrom-Json + } + catch { + Write-Error "Assignment JSON file '$($file.FullName)' is not valid." -ErrorAction Stop + } + + $definitionProperties = Get-PolicyResourceProperties -PolicyResource $definitionObject + $name = $definitionObject.name + + $id = "$deploymentRootScope/providers/Microsoft.Authorization/policyDefinitions/$name" + $displayName = $definitionProperties.displayName + $description = $definitionProperties.description + $metadata = Get-ClonedObject $definitionProperties.metadata -AsHashTable + # $version = $definitionProperties.version + $mode = $definitionProperties.mode + $parameters = $definitionProperties.parameters + $policyRule = $definitionProperties.policyRule + if ($metadata) { + $metadata.pacOwnerId = $thisPacOwnerId } else { - Write-Warning "No Policy files found! Deleting any custom Policy definitions." + $metadata = @{ pacOwnerId = $thisPacOwnerId } + } + if ($metadata.epacCloudEnvironments) { + if ($pacEnvironment.cloud -notIn $metadata.epacCloudEnvironments) { + continue + } + } + if (!$metadata.ContainsKey("deployedBy")) { + $metadata.deployedBy = $PacEnvironment.deployedBy } + # Core syntax error checking + if ($null -eq $name) { + Write-Error "Policy from file '$($file.Name)' requires a name" -ErrorAction Stop + } + if (-not (Confirm-ValidPolicyResourceName -Name $name)) { + Write-Error "Policy from file '$($file.Name) has a name '$name' containing invalid charachters <>*%&:?.+/ or ends with a space." -ErrorAction Stop + } + if ($null -eq $displayName) { + Write-Error "Policy '$name' from file '$($file.Name)' requires a displayName" -ErrorAction Stop + } + if ($null -eq $mode) { + $mode = "All" # Default + } + if ($null -eq $policyRule) { + Write-Error "Policy '$displayName' from file '$($file.Name)' requires a policyRule" -ErrorAction Stop + } + if ($duplicateDefinitionTracking.ContainsKey($id)) { + Write-Error "Duplicate Policy '$($name)' in '$(($duplicateDefinitionTracking[$id]).FullName)' and '$($file.FullName)'" -ErrorAction Stop + } + else { + $null = $duplicateDefinitionTracking.Add($id, $file) + } - foreach ($file in $definitionFiles) { - $Json = Get-Content -Path $file.FullName -Raw -ErrorAction Stop - try { - $definitionObject = $Json | ConvertFrom-Json - } - catch { - Write-Error "Assignment JSON file '$($file.FullName)' is not valid." -ErrorAction Stop + # Calculate roleDefinitionIds for this Policy + if ($null -ne $definitionProperties.policyRule.then.details) { + $details = $definitionProperties.policyRule.then.details + if ($details -isnot [array]) { + $roleDefinitionIdsInPolicy = $details.roleDefinitionIds + if ($null -ne $roleDefinitionIdsInPolicy) { + $null = $PolicyRoleIds.Add($id, $roleDefinitionIdsInPolicy) + } } + } - $definitionProperties = Get-PolicyResourceProperties -PolicyResource $definitionObject - $name = $definitionObject.name - - $id = "$deploymentRootScope/providers/Microsoft.Authorization/policyDefinitions/$name" - $displayName = $definitionProperties.displayName - $description = $definitionProperties.description - $metadata = Get-DeepClone $definitionProperties.metadata -AsHashTable - $version = $definitionProperties.version - $mode = $definitionProperties.mode - $parameters = $definitionProperties.parameters - $policyRule = $definitionProperties.policyRule - if ($metadata) { - $metadata.pacOwnerId = $thisPacOwnerId + # Constructing Policy parameters for splatting + $definition = @{ + id = $id + name = $name + scopeId = $deploymentRootScope + displayName = $displayName + description = $description + mode = $mode + metadata = $metadata + # version = $version + parameters = $parameters + policyRule = $policyRule + } + $AllDefinitions.policydefinitions[$id] = $definition + + + if ($managedDefinitions.ContainsKey($id)) { + # Update and replace scenarios + $deployedDefinition = $managedDefinitions[$id] + $deployedDefinition = Get-PolicyResourceProperties -PolicyResource $deployedDefinition + + # Remove defined Policy entry from deleted hashtable (the hashtable originally contains all custom Policy in the scope) + $null = $deleteCandidates.Remove($id) + + # Check if Policy in Azure is the same as in the JSON file + $displayNameMatches = $deployedDefinition.displayName -eq $displayName + $descriptionMatches = $deployedDefinition.description -eq $description + $modeMatches = $deployedDefinition.mode -eq $definition.Mode + $metadataMatches, $changePacOwnerId = Confirm-MetadataMatches ` + -ExistingMetadataObj $deployedDefinition.metadata ` + -DefinedMetadataObj $metadata + # $versionMatches = $version -eq $deployedDefinition.version + $versionMatches = $true + $parametersMatch, $incompatible = Confirm-ParametersDefinitionMatch ` + -ExistingParametersObj $deployedDefinition.parameters ` + -DefinedParametersObj $parameters + $policyRuleMatches = Confirm-ObjectValueEqualityDeep ` + $deployedDefinition.policyRule ` + $policyRule + + # Update Policy in Azure if necessary + if ($displayNameMatches -and $descriptionMatches -and $modeMatches -and $metadataMatches -and !$changePacOwnerId -and $versionMatches -and $parametersMatch -and $policyRuleMatches) { + # Write-Information "Unchanged '$($displayName)'" + $definitionsUnchanged++ } else { - $metadata = @{ pacOwnerId = $thisPacOwnerId } - } - if ($metadata.epacCloudEnvironments) { - if ($pacEnvironment.cloud -notIn $metadata.epacCloudEnvironments) { - continue + $changesStrings = @() + if ($incompatible) { + $changesStrings += "param-incompat" } - } - # Core syntax error checking - if ($null -eq $name) { - Write-Error "Policy from file '$($file.Name)' requires a name" -ErrorAction Stop - } - if (-not (Confirm-ValidPolicyResourceName -Name $name)) { - Write-Error "Policy from file '$($file.Name) has a name '$name' containing invalid charachters <>*%&:?.+/ or ends with a space." -ErrorAction Stop - } - if ($null -eq $displayName) { - Write-Error "Policy '$name' from file '$($file.Name)' requires a displayName" -ErrorAction Stop - } - if ($null -eq $mode) { - $mode = "All" # Default - } - if ($null -eq $policyRule) { - Write-Error "Policy '$displayName' from file '$($file.Name)' requires a policyRule" -ErrorAction Stop - } - if ($duplicateDefinitionTracking.ContainsKey($id)) { - Write-Error "Duplicate Policy '$($name)' in '$(($duplicateDefinitionTracking[$id]).FullName)' and '$($file.FullName)'" -ErrorAction Stop - } - else { - $null = $duplicateDefinitionTracking.Add($id, $file) - } - - # Calculate roleDefinitionIds for this Policy - if ($null -ne $definitionProperties.policyRule.then.details) { - $details = $definitionProperties.policyRule.then.details - if ($details -isnot [array]) { - $roleDefinitionIdsInPolicy = $details.roleDefinitionIds - if ($null -ne $roleDefinitionIdsInPolicy) { - $null = $PolicyRoleIds.Add($id, $roleDefinitionIdsInPolicy) - } + if (!$displayNameMatches) { + $changesStrings += "display" } - } + if (!$descriptionMatches) { + $changesStrings += "description" + } + if (!$modeMatches) { + $changesStrings += "mode" + } + if ($changePacOwnerId) { + $changesStrings += "owner" + } + if (!$metadataMatches) { + $changesStrings += "metadata" + } + if (!$versionMatches) { + $changesStrings += "version" + } + if (!$parametersMatch -and !$incompatible) { + $changesStrings += "param" + } + if (!$policyRuleMatches) { + $changesStrings += "rule" + } + $changesString = $changesStrings -join "," - # Constructing Policy parameters for splatting - $definition = @{ - id = $id - name = $name - scopeId = $deploymentRootScope - displayName = $displayName - description = $description - mode = $mode - metadata = $metadata - # version = $version - parameters = $parameters - policyRule = $policyRule - } - # Remove-NullFields $definition - $AllDefinitions.policydefinitions[$id] = $definition - - - if ($managedDefinitions.ContainsKey($id)) { - # Update and replace scenarios - $deployedDefinition = $managedDefinitions[$id] - $deployedDefinition = Get-PolicyResourceProperties -PolicyResource $deployedDefinition - - # Remove defined Policy entry from deleted hashtable (the hashtable originally contains all custom Policy in the scope) - $null = $deleteCandidates.Remove($id) - - # Check if Policy in Azure is the same as in the JSON file - $displayNameMatches = $deployedDefinition.displayName -eq $displayName - $descriptionMatches = $deployedDefinition.description -eq $description - $modeMatches = $deployedDefinition.mode -eq $definition.Mode - $metadataMatches, $changePacOwnerId = Confirm-MetadataMatches ` - -ExistingMetadataObj $deployedDefinition.metadata ` - -DefinedMetadataObj $metadata - # $versionMatches = $version -eq $deployedDefinition.version - $versionMatches = $true - $parametersMatch, $incompatible = Confirm-ParametersDefinitionMatch ` - -ExistingParametersObj $deployedDefinition.parameters ` - -DefinedParametersObj $parameters - $policyRuleMatches = Confirm-ObjectValueEqualityDeep ` - $deployedDefinition.policyRule ` - $policyRule - - # Update Policy in Azure if necessary - if ($displayNameMatches -and $descriptionMatches -and $modeMatches -and $metadataMatches -and !$changePacOwnerId -and $versionMatches -and $parametersMatch -and $policyRuleMatches) { - # Write-Information "Unchanged '$($displayName)'" - $Definitions.numberUnchanged++ + if ($incompatible) { + # check if parameters are compatible with an update. Otherwise the Policy will need to be deleted (and any PolicySets and Assignments referencing the Policy) + Write-Information "Replace ($changesString) '$($displayName)'" + $null = $definitionsReplace.Add($id, $definition) + $null = $ReplaceDefinitions.Add($id, $definition) } else { - $Definitions.numberOfChanges++ - $changesStrings = @() - if ($incompatible) { - $changesStrings += "param-incompat" - } - if (!$displayNameMatches) { - $changesStrings += "display" - } - if (!$descriptionMatches) { - $changesStrings += "description" - } - if (!$modeMatches) { - $changesStrings += "mode" - } - if ($changePacOwnerId) { - $changesStrings += "owner" - } - if (!$metadataMatches) { - $changesStrings += "metadata" - } - if (!$versionMatches) { - $changesStrings += "version" - } - if (!$parametersMatch -and !$incompatible) { - $changesStrings += "param" - } - if (!$policyRuleMatches) { - $changesStrings += "rule" - } - $changesString = $changesStrings -join "," - - if ($incompatible) { - # check if parameters are compatible with an update. Otherwise the Policy will need to be deleted (and any PolicySets and Assignments referencing the Policy) - Write-Information "Replace ($changesString) '$($displayName)'" - $null = $Definitions.replace.Add($id, $definition) - $null = $ReplaceDefinitions.Add($id, $definition) - } - else { - Write-Information "Update ($changesString) '$($displayName)'" - $null = $Definitions.update.Add($id, $definition) - } + Write-Information "Update ($changesString) '$($displayName)'" + $null = $definitionsUpdate.Add($id, $definition) } } - else { - $null = $Definitions.new.Add($id, $definition) - $Definitions.numberOfChanges++ - Write-Information "New '$($displayName)'" - } } - - $strategy = $PacEnvironment.desiredState.strategy - foreach ($id in $deleteCandidates.Keys) { - $deleteCandidate = $deleteCandidates.$id - $deleteCandidateProperties = Get-PolicyResourceProperties $deleteCandidate - $displayName = $deleteCandidateProperties.displayName - $pacOwner = $deleteCandidate.pacOwner - $shallDelete = Confirm-DeleteForStrategy -PacOwner $pacOwner -Strategy $strategy - if ($shallDelete) { - # always delete if owned by this Policy as Code solution - # never delete if owned by another Policy as Code solution - # if strategy is "full", delete with unknown owner (missing pacOwnerId) - Write-Information "Delete '$($deleteCandidateProperties.displayName)'" - $splat = @{ - id = $id - name = $deleteCandidate.name - scopeId = $deploymentRootScope - DisplayName = $displayName - } - $null = $Definitions.delete.Add($id, $splat) - $Definitions.numberOfChanges++ - if ($AllDefinitions.policydefinitions.ContainsKey($id)) { - # should always be true - $null = $AllDefinitions.policydefinitions.Remove($id) - } + else { + $null = $definitionsNew.Add($id, $definition) + Write-Information "New '$($displayName)'" + } + } + + + $strategy = $PacEnvironment.desiredState.strategy + foreach ($id in $deleteCandidates.Keys) { + $deleteCandidate = $deleteCandidates.$id + $deleteCandidateProperties = Get-PolicyResourceProperties $deleteCandidate + $displayName = $deleteCandidateProperties.displayName + $pacOwner = $deleteCandidate.pacOwner + $shallDelete = Confirm-DeleteForStrategy -PacOwner $pacOwner -Strategy $strategy + if ($shallDelete) { + # always delete if owned by this Policy as Code solution + # never delete if owned by another Policy as Code solution + # if strategy is "full", delete with unknown owner (missing pacOwnerId) + Write-Information "Delete '$($deleteCandidateProperties.displayName)'" + $splat = @{ + id = $id + name = $deleteCandidate.name + scopeId = $deploymentRootScope + DisplayName = $displayName } - else { - # Write-Information "No delete($pacOwner,$strategy) '$($displayName)'" + $null = $Definitions.delete.Add($id, $splat) + if ($AllDefinitions.policydefinitions.ContainsKey($id)) { + # should always be true + $null = $AllDefinitions.policydefinitions.Remove($id) + } + } + else { + if ($VerbosePreference -eq "Continue") { + Write-Information "No delete($pacOwner,$strategy) '$($displayName)'" } } - - Write-Information "Number of unchanged Policies = $($Definitions.numberUnchanged)" } + + $Definitions.numberUnchanged = $definitionsUnchanged + $Definitions.numberOfChanges = $Definitions.new.Count + $Definitions.update.Count + $Definitions.replace.Count + $Definitions.delete.Count + + Write-Information "Number of unchanged Policies = $($Definitions.numberUnchanged)" Write-Information "" -} \ No newline at end of file +} diff --git a/Scripts/Helpers/Build-PolicySetPlan.ps1 b/Scripts/Helpers/Build-PolicySetPlan.ps1 index 90e2bb4e..3989569b 100644 --- a/Scripts/Helpers/Build-PolicySetPlan.ps1 +++ b/Scripts/Helpers/Build-PolicySetPlan.ps1 @@ -14,335 +14,309 @@ function Build-PolicySetPlan { Write-Information "Processing Policy Set JSON files in folder '$DefinitionsRootFolder'" Write-Information "===================================================================================================" - # Calculate roleDefinitionIds for built-in and inherited PolicySets - $readOnlyPolicySetDefinitions = $DeployedDefinitions.readOnly - foreach ($id in $readOnlyPolicySetDefinitions.Keys) { - $policySetProperties = Get-PolicyResourceProperties -PolicyResource $readOnlyPolicySetDefinitions.$id - $roleIds = @{} - foreach ($policyDefinition in $policySetProperties.policyDefinitions) { - $policyId = $policyDefinition.policyDefinitionId - if ($PolicyRoleIds.ContainsKey($policyId)) { - $addRoleDefinitionIds = $PolicyRoleIds.$policyId - foreach ($roleDefinitionId in $addRoleDefinitionIds) { - $roleIds[$roleDefinitionId] = "added" - } - } - } - if ($roleIds.psbase.Count -gt 0) { - $null = $PolicyRoleIds.Add($id, $roleIds.Keys) - } + # Process Policy Set JSON files if any + $definitionFiles = @() + $definitionFiles += Get-ChildItem -Path $DefinitionsRootFolder -Recurse -File -Filter "*.json" + $definitionFiles += Get-ChildItem -Path $DefinitionsRootFolder -Recurse -File -Filter "*.jsonc" + if ($definitionFiles.Length -gt 0) { + Write-Information "Number of Policy Set files = $($definitionFiles.Length)" + } + else { + Write-Warning "No Policy Set files found! Deleting any custom Policy Set definitions." } - - # Populate allDefinitions with deployed definitions $managedDefinitions = $DeployedDefinitions.managed - $deleteCandidates = Get-HashtableShallowClone $managedDefinitions - $allDeployedDefinitions = $DeployedDefinitions.all - foreach ($id in $allDeployedDefinitions.Keys) { - $AllDefinitions.policysetdefinitions[$id] = $allDeployedDefinitions.$id - } + $deleteCandidates = Get-ClonedObject $managedDefinitions -AsHashTable -AsShallowClone $deploymentRootScope = $PacEnvironment.deploymentRootScope $policyDefinitionsScopes = $PacEnvironment.policyDefinitionsScopes $duplicateDefinitionTracking = @{} $thisPacOwnerId = $PacEnvironment.pacOwnerId - # Process Policy Set JSON files if any - if (!(Test-Path $DefinitionsRootFolder -PathType Container)) { - Write-Warning "Policy Set definitions 'policySetDefinitions' folder not found. Policy Set definitions not managed by this EPAC instance." - } - else { + foreach ($file in $definitionFiles) { + $Json = Get-Content -Path $file.FullName -Raw -ErrorAction Stop - $definitionFiles = @() - $definitionFiles += Get-ChildItem -Path $DefinitionsRootFolder -Recurse -File -Filter "*.json" - $definitionFiles += Get-ChildItem -Path $DefinitionsRootFolder -Recurse -File -Filter "*.jsonc" - if ($definitionFiles.Length -gt 0) { - Write-Information "Number of Policy Set files = $($definitionFiles.Length)" + try { + $definitionObject = $Json | ConvertFrom-Json -Depth 100 } - else { - Write-Warning "No Policy Set files found! Deleting any custom Policy Set definitions." + catch { + Write-Error "Assignment JSON file '$($file.Name)' is not valid." -ErrorAction Stop } - - foreach ($file in $definitionFiles) { - $Json = Get-Content -Path $file.FullName -Raw -ErrorAction Stop - - try { - $definitionObject = $Json | ConvertFrom-Json -Depth 100 - } - catch { - Write-Error "Assignment JSON file '$($file.Name)' is not valid." -ErrorAction Stop + $definitionProperties = Get-PolicyResourceProperties -PolicyResource $definitionObject + $name = $definitionObject.name + $id = "$deploymentRootScope/providers/Microsoft.Authorization/policySetDefinitions/$name" + $displayName = $definitionProperties.displayName + $description = $definitionProperties.description + $metadata = Get-ClonedObject $definitionProperties.metadata -AsHashTable + # $version = $definitionProperties.version + $parameters = $definitionProperties.parameters + $policyDefinitions = $definitionProperties.policyDefinitions + $policyDefinitionGroups = $definitionProperties.policyDefinitionGroups + $importPolicyDefinitionGroups = $definitionProperties.importPolicyDefinitionGroups + if ($metadata) { + $metadata.pacOwnerId = $thisPacOwnerId + } + else { + $metadata = @{ pacOwnerId = $thisPacOwnerId } + } + if ($metadata.epacCloudEnvironments) { + if ($pacEnvironment.cloud -notIn $metadata.epacCloudEnvironments) { + #Need to come back and add this file to deleteCandidates + continue } + } + if (!$metadata.ContainsKey("deployedBy")) { + $metadata.deployedBy = $PacEnvironment.deployedBy + } - $definitionProperties = Get-PolicyResourceProperties -PolicyResource $definitionObject - $name = $definitionObject.name - $id = "$deploymentRootScope/providers/Microsoft.Authorization/policySetDefinitions/$name" - $displayName = $definitionProperties.displayName - $description = $definitionProperties.description - $metadata = Get-DeepClone $definitionProperties.metadata -AsHashTable - # $version = $definitionProperties.version - $parameters = $definitionProperties.parameters - $policyDefinitions = $definitionProperties.policyDefinitions - $policyDefinitionGroups = $definitionProperties.policyDefinitionGroups - $importPolicyDefinitionGroups = $definitionProperties.importPolicyDefinitionGroups - if ($metadata) { - $metadata.pacOwnerId = $thisPacOwnerId - } - else { - $metadata = @{ pacOwnerId = $thisPacOwnerId } - } - if ($metadata.epacCloudEnvironments) { - if ($pacEnvironment.cloud -notIn $metadata.epacCloudEnvironments) { - #Need to come back and add this file to deleteCandidates - continue - } - } - # Core syntax error checking - if ($null -eq $name) { - Write-Error "Policy Set from file '$($file.Name)' requires a name" -ErrorAction Stop - } - if (-not (Confirm-ValidPolicyResourceName -Name $name)) { - Write-Error "Policy Set from file '$($file.Name) has a name '$name' containing invalid charachters <>*%&:?.+/ or ends with a space." -ErrorAction Stop - } - if ($null -eq $displayName) { - Write-Error "Policy Set '$name' from file '$($file.Name)' requires a displayName" -ErrorAction Stop - } - if ($null -eq $policyDefinitions -or $policyDefinitions.Count -eq 0) { - Write-Error "Policy Set '$displayName' from file '$($file.Name)' requires a policyDefinitions array with at least one entry" -ErrorAction Stop - } - if ($duplicateDefinitionTracking.ContainsKey($id)) { - Write-Error "Duplicate Policy Set '$($name)' in '$(($duplicateDefinitionTracking[$id]).FullName)' and '$($file.FullName)'" -ErrorAction Stop - } - else { - $null = $duplicateDefinitionTracking.Add($id, $policyFile) - } + # Core syntax error checking + if ($null -eq $name) { + Write-Error "Policy Set from file '$($file.Name)' requires a name" -ErrorAction Stop + } + if (-not (Confirm-ValidPolicyResourceName -Name $name)) { + Write-Error "Policy Set from file '$($file.Name) has a name '$name' containing invalid charachters <>*%&:?.+/ or ends with a space." -ErrorAction Stop + } + if ($null -eq $displayName) { + Write-Error "Policy Set '$name' from file '$($file.Name)' requires a displayName" -ErrorAction Stop + } + if ($null -eq $policyDefinitions -or $policyDefinitions.Count -eq 0) { + Write-Error "Policy Set '$displayName' from file '$($file.Name)' requires a policyDefinitions array with at least one entry" -ErrorAction Stop + } + if ($duplicateDefinitionTracking.ContainsKey($id)) { + Write-Error "Duplicate Policy Set with name '$($name)' in '$($duplicateDefinitionTracking[$id])' and '$($file.FullName)'" -ErrorAction Stop + } + else { + $null = $duplicateDefinitionTracking.Add($id, $file.FullName) + } - # Calculate included policyDefinitions - $validPolicyDefinitions, $policyDefinitionsFinal, $policyRoleIdsInSet, $usedPolicyGroupDefinitions = Build-PolicySetPolicyDefinitionIds ` - -DisplayName $displayName ` - -PolicyDefinitions $policyDefinitions ` - -PolicyDefinitionsScopes $policyDefinitionsScopes ` - -AllDefinitions $AllDefinitions.policydefinitions ` - -PolicyRoleIds $PolicyRoleIds - $policyDefinitions = $policyDefinitionsFinal.ToArray() - if ($policyRoleIdsInSet.psbase.Count -gt 0) { - $null = $PolicyRoleIds.Add($id, $policyRoleIdsInSet.Keys) - } + # Calculate included policyDefinitions + $validPolicyDefinitions, $policyDefinitionsFinal, $policyRoleIdsInSet, $usedPolicyGroupDefinitions = Build-PolicySetPolicyDefinitionIds ` + -DisplayName $displayName ` + -PolicyDefinitions $policyDefinitions ` + -PolicyDefinitionsScopes $policyDefinitionsScopes ` + -AllDefinitions $AllDefinitions.policydefinitions ` + -PolicyRoleIds $PolicyRoleIds + $policyDefinitions = $policyDefinitionsFinal.ToArray() + if ($policyRoleIdsInSet.psbase.Count -gt 0) { + $null = $PolicyRoleIds.Add($id, $policyRoleIdsInSet.Keys) + } - # Process policyDefinitionGroups - $policyDefinitionGroupsHashTable = @{} - if ($null -ne $policyDefinitionGroups) { - # Explicitly defined policyDefinitionGroups - $null = $policyDefinitionGroups | ForEach-Object { - $groupName = $_.name - if ($usedPolicyGroupDefinitions.ContainsKey($groupName)) { - # Covered this use of a group name - $usedPolicyGroupDefinitions.Remove($groupName) - } - if (!$policyDefinitionGroupsHashTable.ContainsKey($groupName)) { - # Ignore duplicates - $policyDefinitionGroupsHashTable.Add($groupName, $_) - } + # Process policyDefinitionGroups + $policyDefinitionGroupsHashTable = @{} + if ($null -ne $policyDefinitionGroups) { + # Explicitly defined policyDefinitionGroups + $null = $policyDefinitionGroups | ForEach-Object { + $groupName = $_.name + if ($usedPolicyGroupDefinitions.ContainsKey($groupName)) { + # Covered this use of a group name + $usedPolicyGroupDefinitions.Remove($groupName) + } + if (!$policyDefinitionGroupsHashTable.ContainsKey($groupName)) { + # Ignore duplicates + $policyDefinitionGroupsHashTable.Add($groupName, $_) } } + } - # Importing policyDefinitionGroups from built-in PolicySets? - if ($null -ne $importPolicyDefinitionGroups) { - $limitReachedPolicyDefinitionGroups = $false + # Importing policyDefinitionGroups from built-in PolicySets? + if ($null -ne $importPolicyDefinitionGroups) { + $limitReachedPolicyDefinitionGroups = $false - # Trying to import missing policyDefinitionGroups entries - foreach ($importPolicyDefinitionGroup in $importPolicyDefinitionGroups) { - if ($usedPolicyGroupDefinitions.psbase.Count -eq 0 -or $limitReachedPolicyDefinitionGroups) { - break - } - $importPolicySetId = $importPolicyDefinitionGroup - if (!($importPolicyDefinitionGroup.StartsWith("/providers/Microsoft.Authorization/policySetDefinitions/", [System.StringComparison]::OrdinalIgnoreCase))) { - $importPolicySetId = "/providers/Microsoft.Authorization/policySetDefinitions/$importPolicyDefinitionGroup" - } - if (!($DeployedDefinitions.readOnly.ContainsKey($importPolicySetId))) { - Write-Error "$($displayName): Policy Set '$importPolicySetId' for group name import not found." -ErrorAction Stop - } - $importedPolicySetDefinition = $DeployedDefinitions.readOnly[$importPolicySetId] - $importedPolicyDefinitionGroups = $importedPolicySetDefinition.properties.policyDefinitionGroups - if ($null -ne $importedPolicyDefinitionGroups -and $importedPolicyDefinitionGroups.Count -gt 0) { - # Write-Information "$($displayName): Importing PolicyDefinitionGroups from '$($importedPolicySetDefinition.displayName)'" - foreach ($importedPolicyDefinitionGroup in $importedPolicyDefinitionGroups) { - $groupName = $importedPolicyDefinitionGroup.name - if ($usedPolicyGroupDefinitions.ContainsKey($groupName)) { - $usedPolicyGroupDefinitions.Remove($groupName) - $policyDefinitionGroupsHashTable.Add($groupName, $importedPolicyDefinitionGroup) - if ($policyDefinitionGroupsHashTable.psbase.Count -ge 1000) { - $limitReachedPolicyDefinitionGroups = $true - if ($usedPolicyGroupDefinitions.psbase.Count -gt 0) { - Write-Warning "$($displayName): Too many PolicyDefinitionGroups (1000+) - ignore remaining imports." - } - break + # Trying to import missing policyDefinitionGroups entries + foreach ($importPolicyDefinitionGroup in $importPolicyDefinitionGroups) { + if ($usedPolicyGroupDefinitions.psbase.Count -eq 0 -or $limitReachedPolicyDefinitionGroups) { + break + } + $importPolicySetId = $importPolicyDefinitionGroup + if (!($importPolicyDefinitionGroup.StartsWith("/providers/Microsoft.Authorization/policySetDefinitions/", [System.StringComparison]::OrdinalIgnoreCase))) { + $importPolicySetId = "/providers/Microsoft.Authorization/policySetDefinitions/$importPolicyDefinitionGroup" + } + if (!($DeployedDefinitions.readOnly.ContainsKey($importPolicySetId))) { + Write-Error "$($displayName): Policy Set '$importPolicySetId' for group name import not found." -ErrorAction Stop + } + $importedPolicySetDefinition = $DeployedDefinitions.readOnly[$importPolicySetId] + $importedPolicyDefinitionGroups = $importedPolicySetDefinition.properties.policyDefinitionGroups + if ($null -ne $importedPolicyDefinitionGroups -and $importedPolicyDefinitionGroups.Count -gt 0) { + # Write-Information "$($displayName): Importing PolicyDefinitionGroups from '$($importedPolicySetDefinition.displayName)'" + foreach ($importedPolicyDefinitionGroup in $importedPolicyDefinitionGroups) { + $groupName = $importedPolicyDefinitionGroup.name + if ($usedPolicyGroupDefinitions.ContainsKey($groupName)) { + $usedPolicyGroupDefinitions.Remove($groupName) + $policyDefinitionGroupsHashTable.Add($groupName, $importedPolicyDefinitionGroup) + if ($policyDefinitionGroupsHashTable.psbase.Count -ge 1000) { + $limitReachedPolicyDefinitionGroups = $true + if ($usedPolicyGroupDefinitions.psbase.Count -gt 0) { + Write-Warning "$($displayName): Too many PolicyDefinitionGroups (1000+) - ignore remaining imports." } + break } } - # Write-Information "$($displayName): Imported $($policyDefinitionGroupsHashTable.psbase.psbase.Count) PolicyDefinitionGroups from '$($importedPolicySetDefinition.displayName)'." - } - else { - Write-Error "$($displayName): Policy Set $($importedPolicySet.displayName) does not contain PolicyDefinitionGroups to import." -ErrorAction Stop } + # Write-Information "$($displayName): Imported $($policyDefinitionGroupsHashTable.psbase.psbase.Count) PolicyDefinitionGroups from '$($importedPolicySetDefinition.displayName)'." + } + else { + Write-Error "$($displayName): Policy Set $($importedPolicySet.displayName) does not contain PolicyDefinitionGroups to import." -ErrorAction Stop } } - $policyDefinitionGroupsFinal = $null - if ($policyDefinitionGroupsHashTable.Count -gt 0) { - $policyDefinitionGroupsFinal = @() + ($policyDefinitionGroupsHashTable.Values | Sort-Object -Property "name") - } + } + $policyDefinitionGroupsFinal = $null + if ($policyDefinitionGroupsHashTable.Count -gt 0) { + $policyDefinitionGroupsFinal = @() + ($policyDefinitionGroupsHashTable.Values | Sort-Object -Property "name") + } - if (!$validPolicyDefinitions) { - Write-Error "$($displayName): One or more invalid Policy entries referenced in Policy Set '$($displayName)' from '$($file.Name)'." -ErrorAction Stop - } + if (!$validPolicyDefinitions) { + Write-Error "$($displayName): One or more invalid Policy entries referenced in Policy Set '$($displayName)' from '$($file.Name)'." -ErrorAction Stop + } - # Constructing Policy Set parameters for splatting - $definition = @{ - id = $id - name = $name - scopeId = $deploymentRootScope - displayName = $displayName - description = $description - metadata = $metadata - # version = $version - parameters = $parameters - policyDefinitions = $policyDefinitionsFinal - policyDefinitionGroups = $policyDefinitionGroupsFinal - } - # Remove-NullFields $definition - $AllDefinitions.policysetdefinitions[$id] = $definition + # Constructing Policy Set parameters for splatting + $definition = @{ + id = $id + name = $name + scopeId = $deploymentRootScope + displayName = $displayName + description = $description + metadata = $metadata + # version = $version + parameters = $parameters + policyDefinitions = $policyDefinitionsFinal + policyDefinitionGroups = $policyDefinitionGroupsFinal + } + # Remove-NullFields $definition + $AllDefinitions.policysetdefinitions[$id] = $definition - if ($managedDefinitions.ContainsKey($id)) { - # Update or replace scenarios - $deployedDefinition = $managedDefinitions[$id] - $deployedDefinition = Get-PolicyResourceProperties -PolicyResource $deployedDefinition + if ($managedDefinitions.ContainsKey($id)) { + # Update or replace scenarios + $deployedDefinition = $managedDefinitions[$id] + $deployedDefinition = Get-PolicyResourceProperties -PolicyResource $deployedDefinition - # Remove defined Policy Set entry from deleted hashtable (the hashtable originally contains all custom Policy Sets in the scope) - $null = $deleteCandidates.Remove($id) + # Remove defined Policy Set entry from deleted hashtable (the hashtable originally contains all custom Policy Sets in the scope) + $null = $deleteCandidates.Remove($id) - # Check if Policy Set in Azure is the same as in the JSON file - $displayNameMatches = $deployedDefinition.displayName -eq $displayName - $descriptionMatches = $deployedDefinition.description -eq $description - $metadataMatches, $changePacOwnerId = Confirm-MetadataMatches ` - -ExistingMetadataObj $deployedDefinition.metadata ` - -DefinedMetadataObj $metadata - # $versionMatches = $version -eq $deployedDefinition.version - $versionMatches = $true - $parametersMatch, $incompatible = Confirm-ParametersDefinitionMatch ` - -ExistingParametersObj $deployedDefinition.parameters ` - -DefinedParametersObj $parameters - $policyDefinitionsMatch = Confirm-PolicyDefinitionsInPolicySetMatch ` - $deployedDefinition.policyDefinitions ` - $policyDefinitionsFinal - $policyDefinitionGroupsMatch = Confirm-ObjectValueEqualityDeep ` - $deployedDefinition.policyDefinitionGroups ` - $policyDefinitionGroupsFinal - $deletedPolicyDefinitionGroups = !$policyDefinitionGroupsMatch -and ($null -eq $policyDefinitionGroupsFinal -or $policyDefinitionGroupsFinal.Length -eq 0) + # Check if Policy Set in Azure is the same as in the JSON file + $displayNameMatches = $deployedDefinition.displayName -eq $displayName + $descriptionMatches = $deployedDefinition.description -eq $description + $metadataMatches, $changePacOwnerId = Confirm-MetadataMatches ` + -ExistingMetadataObj $deployedDefinition.metadata ` + -DefinedMetadataObj $metadata + # $versionMatches = $version -eq $deployedDefinition.version + $versionMatches = $true + $parametersMatch, $incompatible = Confirm-ParametersDefinitionMatch ` + -ExistingParametersObj $deployedDefinition.parameters ` + -DefinedParametersObj $parameters + $policyDefinitionsMatch = Confirm-PolicyDefinitionsInPolicySetMatch ` + $deployedDefinition.policyDefinitions ` + $policyDefinitionsFinal + $policyDefinitionGroupsMatch = Confirm-ObjectValueEqualityDeep ` + $deployedDefinition.policyDefinitionGroups ` + $policyDefinitionGroupsFinal + $deletedPolicyDefinitionGroups = !$policyDefinitionGroupsMatch -and ($null -eq $policyDefinitionGroupsFinal -or $policyDefinitionGroupsFinal.Length -eq 0) - # Update Policy Set in Azure if necessary - $containsReplacedPolicy = $false - foreach ($policyDefinitionEntry in $policyDefinitionsFinal) { - $policyId = $policyDefinitionEntry.policyDefinitionId - if ($ReplaceDefinitions.ContainsKey($policyId)) { - $containsReplacedPolicy = $true - break - } + # Update Policy Set in Azure if necessary + $containsReplacedPolicy = $false + foreach ($policyDefinitionEntry in $policyDefinitionsFinal) { + $policyId = $policyDefinitionEntry.policyDefinitionId + if ($ReplaceDefinitions.ContainsKey($policyId)) { + $containsReplacedPolicy = $true + break } - if (!$containsReplacedPolicy -and $displayNameMatches -and $descriptionMatches -and $metadataMatches -and $versionMatches -and !$changePacOwnerId -and $parametersMatch -and $policyDefinitionsMatch -and $policyDefinitionGroupsMatch) { - # Write-Information "Unchanged '$($displayName)'" - $Definitions.numberUnchanged++ + } + if (!$containsReplacedPolicy -and $displayNameMatches -and $descriptionMatches -and $metadataMatches -and $versionMatches -and !$changePacOwnerId -and $parametersMatch -and $policyDefinitionsMatch -and $policyDefinitionGroupsMatch) { + # Write-Information "Unchanged '$($displayName)'" + $Definitions.numberUnchanged++ + } + else { + $Definitions.numberOfChanges++ + $changesStrings = @() + if ($incompatible) { + $changesStrings += "paramIncompat" } - else { - $Definitions.numberOfChanges++ - $changesStrings = @() - if ($incompatible) { - $changesStrings += "paramIncompat" - } - if ($containsReplacedPolicy) { - $changesStrings += "replacedPolicy" - } - if (!$displayNameMatches) { - $changesStrings += "displayName" - } - if (!$descriptionMatches) { - $changesStrings += "description" - } - if ($changePacOwnerId) { - $changesStrings += "owner" - } - if (!$metadataMatches) { - $changesStrings += "metadata" - } - if (!$versionMatches) { - $changesStrings += "version" - } - if (!$parametersMatch -and !$incompatible) { - $changesStrings += "param" - } - if (!$policyDefinitionsMatch) { - $changesStrings += "policies" - } - if (!$policyDefinitionGroupsMatch) { - if ($deletedPolicyDefinitionGroups) { - $changesStrings += "groupsDeleted" - } - else { - $changesStrings += "groups" - } - } - $changesString = $changesStrings -join "," - - if ($incompatible -or $containsReplacedPolicy) { - # Check if parameters are compatible with an update or id the set includes at least one Policy which is being replaced. - Write-Information "Replace ($changesString) '$($displayName)'" - $null = $Definitions.replace.Add($id, $definition) - $null = $ReplaceDefinitions.Add($id, $definition) + if ($containsReplacedPolicy) { + $changesStrings += "replacedPolicy" + } + if (!$displayNameMatches) { + $changesStrings += "displayName" + } + if (!$descriptionMatches) { + $changesStrings += "description" + } + if ($changePacOwnerId) { + $changesStrings += "owner" + } + if (!$metadataMatches) { + $changesStrings += "metadata" + } + if (!$versionMatches) { + $changesStrings += "version" + } + if (!$parametersMatch -and !$incompatible) { + $changesStrings += "param" + } + if (!$policyDefinitionsMatch) { + $changesStrings += "policies" + } + if (!$policyDefinitionGroupsMatch) { + if ($deletedPolicyDefinitionGroups) { + $changesStrings += "groupsDeleted" } else { - Write-Information "Update ($changesString) '$($displayName)'" - $null = $Definitions.update.Add($id, $definition) + $changesStrings += "groups" } } - } - else { - Write-Information "New '$($displayName)'" - $null = $Definitions.new.Add($id, $definition) - $Definitions.numberOfChanges++ + $changesString = $changesStrings -join "," + if ($incompatible -or $containsReplacedPolicy) { + # Check if parameters are compatible with an update or id the set includes at least one Policy which is being replaced. + Write-Information "Replace ($changesString) '$($displayName)'" + $null = $Definitions.replace.Add($id, $definition) + $null = $ReplaceDefinitions.Add($id, $definition) + } + else { + Write-Information "Update ($changesString) '$($displayName)'" + $null = $Definitions.update.Add($id, $definition) + } } } + else { + Write-Information "New '$($displayName)'" + $null = $Definitions.new.Add($id, $definition) + $Definitions.numberOfChanges++ - $strategy = $PacEnvironment.desiredState.strategy - foreach ($id in $deleteCandidates.Keys) { - $deleteCandidate = $deleteCandidates.$id - $deleteCandidateProperties = Get-PolicyResourceProperties $deleteCandidate - $displayName = $deleteCandidateProperties.displayName - $pacOwner = $deleteCandidate.pacOwner - $shallDelete = Confirm-DeleteForStrategy -PacOwner $pacOwner -Strategy $strategy - if ($shallDelete) { - # always delete if owned by this Policy as Code solution - # never delete if owned by another Policy as Code solution - # if strategy is "full", delete with unknown owner (missing pacOwnerId) - Write-Information "Delete '$($deleteCandidateProperties.displayName)'" - $splat = @{ - id = $id - name = $deleteCandidate.name - scopeId = $deploymentRootScope - displayName = $displayName - } - $null = $Definitions.delete.Add($id, $splat) - $Definitions.numberOfChanges++ - if ($AllDefinitions.policydefinitions.ContainsKey($id)) { - # should always be true - $null = $AllDefinitions.policydefinitions.Remove($id) - } + } + } + + $strategy = $PacEnvironment.desiredState.strategy + foreach ($id in $deleteCandidates.Keys) { + $deleteCandidate = $deleteCandidates.$id + $deleteCandidateProperties = Get-PolicyResourceProperties $deleteCandidate + $displayName = $deleteCandidateProperties.displayName + $pacOwner = $deleteCandidate.pacOwner + $shallDelete = Confirm-DeleteForStrategy -PacOwner $pacOwner -Strategy $strategy + if ($shallDelete) { + # always delete if owned by this Policy as Code solution + # never delete if owned by another Policy as Code solution + # if strategy is "full", delete with unknown owner (missing pacOwnerId) + Write-Information "Delete '$($deleteCandidateProperties.displayName)'" + $splat = @{ + id = $id + name = $deleteCandidate.name + scopeId = $deploymentRootScope + displayName = $displayName } - else { - # Write-Information "No delete($pacOwner,$strategy) '$($displayName)'" + $null = $Definitions.delete.Add($id, $splat) + $Definitions.numberOfChanges++ + if ($AllDefinitions.policydefinitions.ContainsKey($id)) { + # should always be true + $null = $AllDefinitions.policydefinitions.Remove($id) + } + } + else { + if ($VerbosePreference -eq "Continue") { + Write-Information "No delete($pacOwner,$strategy) '$($displayName)'" } } - - Write-Information "Number of unchanged Policy SetPolicy Sets definition = $($Definitions.numberUnchanged)" } + + Write-Information "Number of unchanged Policy SetPolicy Sets definition = $($Definitions.numberUnchanged)" Write-Information "" } diff --git a/Scripts/Helpers/Build-ScopeTableForDeploymentRootScope.ps1 b/Scripts/Helpers/Build-ScopeTableForDeploymentRootScope.ps1 new file mode 100644 index 00000000..1534d1d7 --- /dev/null +++ b/Scripts/Helpers/Build-ScopeTableForDeploymentRootScope.ps1 @@ -0,0 +1,143 @@ +function Build-ScopeTableForDeploymentRootScope { + + param( + [hashtable] $PacEnvironment + ) + + $deploymentRootScope = $PacEnvironment.deploymentRootScope + $tenantId = $PacEnvironment.tenantId + Write-Information "" + Write-Information "===================================================================================================" + Write-Information "Get scope tree for EPAC environment '$($PacEnvironment.pacSelector)' at root scope $($deploymentRootScope -replace '/providers/Microsoft.Management','')" + Write-Information "===================================================================================================" + + $scopeTable = @{} + $tenantId = $PacEnvironment.tenantId + $resourceGroupsBySubscriptionId = @{} + $deploymentRootScopeSubscriptionId = $null + $deploymentRootScopeManagementGroupName = $null + $scopeSplat = $null + $resourceGroupQuery = "resourcecontainers | where type == 'microsoft.resources/subscriptions/resourcegroups'" + if ($deploymentRootScope.StartsWith("/providers/Microsoft.Management/managementGroups/")) { + $deploymentRootScopeManagementGroupName = $deploymentRootScope -replace "/providers/Microsoft.Management/managementGroups/" + $scopeSplat = @{ + ManagementGroup = $deploymentRootScopeManagementGroupName + } + } + elseif ($deploymentRootScope.StartsWith("/subscriptions/")) { + $deploymentRootScopeSubscriptionId = $deploymentRootScope -replace "/subscriptions/" + $scopeSplat = @{ + Subscription = $deploymentRootScopeSubscriptionId + } + $resourceGroupQuery = "resourcecontainers | where type == 'microsoft.resources/subscriptions/resourcegroups' and subscriptionId == '$($deploymentRootScopeSubscriptionId)'" + } + else { + throw "Invalid deploymentRootScope: $deploymentRootScope" + } + + #region collect resource groups + $resourceGroups = Search-AzGraphAllItems ` + -Query $resourceGroupQuery ` + -ScopeSplat $scopeSplat ` + -ProgressItemName "Resource Groups" + Write-Information "Processing $($resourceGroups.Count) Resource Groups..." + foreach ($resourceGroup in $resourceGroups) { + $subscriptionId = $resourceGroup.subscriptionId + $id = $resourceGroup.id + $isExcluded = $false + $isInGlobalNotScope = $false + foreach ($globalNotScope in $PacEnvironment.globalNotScopesResourceGroups) { + if ($id -like $globalNotScope) { + $isExcluded = $true + $isInGlobalNotScope = $true + break + } + } + if (!$isExcluded) { + foreach ($excludedScope in $PacEnvironment.globalExcludedScopesResourceGroups) { + if ($id -like $excludedScope) { + $isExcluded = $true + break + } + } + } + $scopeDetails = @{ + id = $resourceGroup.id + type = $resourceGroup.type + name = $resourceGroup.name + displayName = $resourceGroup.name + parentTable = @{} + childrenTable = @{} + resourceGroupsTable = @{} + notScopesList = [System.Collections.ArrayList]::new() + notScopesTable = @{} + excludedScopesTable = @{} + isExcluded = $isExcluded + isInGlobalNotScope = $isInGlobalNotScope + state = $resourceGroup.properties.provisioningState + location = $resourceContainer.location + } + + $resourceGroupList = $null + if ($resourceGroupsBySubscriptionId.ContainsKey($subscriptionId)) { + $resourceGroupList = $resourceGroupsBySubscriptionId.$subscriptionId + } + else { + $resourceGroupList = [System.Collections.ArrayList]::new() + $null = $resourceGroupsBySubscriptionId.Add($subscriptionId, $resourceGroupList) + } + $null = $resourceGroupList.Add($scopeDetails) + } + #endregion collect resource groups + + #region process subscriptions and/or management groups + $scopeDetails = $null + if ($null -ne $deploymentRootScopeSubscriptionId) { + $subscription = Get-AzSubscription -SubscriptionId $deploymentRootScopeSubscriptionId -TenantId $tenantId + $subscriptionId = $subscription.Id + $scopeDetails = Build-ScopeTableForSubscription ` + -SubscriptionId $subscriptionId ` + -SubscriptionName $subscription.Name ` + -ResourceGroupsBySubscriptionId $resourceGroupsBySubscriptionId ` + -PacEnvironment $PacEnvironment ` + -ScopeTable $scopeTable + } + else { + $managementGroup = Get-AzManagementGroup -GroupName $deploymentRootScopeManagementGroupName -Expand -Recurse + $scopeDetails = Build-ScopeTableForManagementGroup ` + -ManagementGroup $managementGroup ` + -ResourceGroupsBySubscriptionId $resourceGroupsBySubscriptionId ` + -PacEnvironment $PacEnvironment ` + -ScopeTable $scopeTable + } + $null = $scopeTable.Add($scopeDetails.id, $scopeDetails) + $null = $scopeTable.Add("root", $scopeDetails) + + # count each type of scope + $numberOfManagementGroups = 0 + $numberOfSubscriptions = 0 + $numberofResourceGroups = 0 + foreach ($scopeDetails in $scopeTable.Values) { + if ($scopeDetails.type -eq "Microsoft.Management/managementGroups") { + $numberOfManagementGroups++ + } + elseif ($scopeDetails.type -eq "/subscriptions") { + $numberOfSubscriptions++ + } + elseif ($scopeDetails.type -eq "microsoft.resources/subscriptions/resourcegroups") { + $numberofResourceGroups++ + } + } + #endregion process subscriptions and/or management groups + + Write-Information "" + Write-Information "Scope tree for EPAC environment '$($PacEnvironment.pacSelector)' at root scope $($deploymentRootScope -replace '/providers/Microsoft.Management','') complete." + if ($numberOfManagementGroups -gt 0) { + $numberOfManagementGroups-- # subtract 1 for the root scope + Write-Information " Management groups = $($numberOfManagementGroups)" + } + Write-Information " Subscriptions = $($numberOfSubscriptions)" + Write-Information " Resource groups = $($numberofResourceGroups)" + + return $scopeTable +} \ No newline at end of file diff --git a/Scripts/Helpers/Build-ScopeTableForManagementGroup.ps1 b/Scripts/Helpers/Build-ScopeTableForManagementGroup.ps1 new file mode 100644 index 00000000..d7a88f6f --- /dev/null +++ b/Scripts/Helpers/Build-ScopeTableForManagementGroup.ps1 @@ -0,0 +1,143 @@ +function Build-ScopeTableForManagementGroup { + [CmdletBinding()] + param ( + [parameter(Mandatory = $true)] $ManagementGroup, + [parameter(Mandatory = $true)] [hashtable] $ResourceGroupsBySubscriptionId, + [parameter(Mandatory = $true)] $PacEnvironment, + [parameter(Mandatory = $true)] [hashtable] $ScopeTable, + [parameter(Mandatory = $false)] [bool] $IsExcluded = $false, + [parameter(Mandatory = $false)] [bool] $IsInGlobalNotScope = $false, + [parameter(Mandatory = $false)] [hashtable] $ParentTable = @{}, + [parameter(Mandatory = $false)] [hashtable] $ParentScopeDetails = $null + ) + + #region initialize variables + $childrenTable = @{} + $resourceGroupsTable = @{} + $notScopesList = [System.Collections.ArrayList]::new() + $notScopesTable = @{} + $excludedScopesTable = @{} + $managementGroupType = $ManagementGroup.Type + $managementGroupId = $ManagementGroup.Id + $managementGroupName = $ManagementGroup.Name + $managementGroupDisplayName = $ManagementGroup.DisplayName + $managementGroupChildren = $ManagementGroup.Children + #endregion initialize variables + + #region build scope details + $thisNotScope = $null + if ($null -ne $ParentScopeDetails) { + # the root node is never not in scope or excluded + if (!$IsInGlobalNotScope) { + # optimized + foreach ($globalNotScope in $PacEnvironment.globalNotScopesManagementGroups) { + if ($managementGroupId -like $globalNotScope) { + $thisNotScope = $managementGroupId + $IsInGlobalNotScope = $true + $IsExcluded = $true + break + } + } + } + if (!$IsExcluded) { + # optimized + foreach ($globalExcludedScope in $PacEnvironment.globalExcludedScopesManagementGroups) { + if ($managementGroupId -like $globalExcludedScope) { + $IsExcluded = $true + break + } + } + } + } + $scopeDetails = @{ + id = $managementGroupId + type = $managementGroupType + name = $managementGroupName + displayName = $managementGroupDisplayName + parentTable = $ParentTable + childrenTable = $childrenTable + resourceGroupsTable = $resourceGroupsTable + notScopesList = $notScopesList + notScopesTable = $notScopesTable + excludedScopesTable = $excludedScopesTable + isExcluded = $IsExcluded + isInGlobalNotScope = $IsInGlobalNotScope + state = $resourceContainer.properties.state + location = "global" + } + if ($IsExcluded) { + $null = $excludedScopesTable.Add($managementGroupId, $scopeDetails) + } + if ($IsInGlobalNotScope) { + $null = $notScopesTable.Add($managementGroupId, $scopeDetails) + if ($null -ne $thisNotScope) { + $null = $notScopesList.Add($thisNotScope) + } + } + $myChildrensParentTable = $ParentTable.Clone() + $null = $myChildrensParentTable.Add($managementGroupId, $scopeDetails) + #endregion build scope details + + #region recurse down the tree + if ($null -ne $managementGroupChildren) { + foreach ($child in $managementGroupChildren) { + $childId = $child.Id + $childScopeDetails = $null + if ($child.Type -eq "/subscriptions") { + $childScopeDetails = Build-ScopeTableForSubscription ` + -SubscriptionId $child.Name ` + -SubscriptionName $child.DisplayName ` + -ResourceGroupsBySubscriptionId $ResourceGroupsBySubscriptionId ` + -PacEnvironment $PacEnvironment ` + -ScopeTable $ScopeTable ` + -IsExcluded $IsExcluded ` + -IsInGlobalNotScope $IsInGlobalNotScope ` + -ParentTable $myChildrensParentTable ` + -ParentScopeDetails $scopeDetails + } + else { + $childScopeDetails = Build-ScopeTableForManagementGroup ` + -ManagementGroup $child ` + -ResourceGroupsBySubscriptionId $ResourceGroupsBySubscriptionId ` + -PacEnvironment $PacEnvironment ` + -ScopeTable $ScopeTable ` + -IsExcluded $IsExcluded ` + -IsInGlobalNotScope $IsInGlobalNotScope ` + -ParentTable $myChildrensParentTable ` + -ParentScopeDetails $scopeDetails + } + $null = $ScopeTable.Add($childId, $childScopeDetails) + } + } + #endregion recurse down the tree + + #region augment this parents scope's details with this mangement group's details + if ($null -ne $ParentScopeDetails) { + $parentScopeChildrenTable = $ParentScopeDetails.childrenTable + $parentScopeResourceGroupsTable = $ParentScopeDetails.resourceGroupsTable + $parentScopeNotScopesList = $ParentScopeDetails.notScopesList + $parentScopeNotScopesTable = $ParentScopeDetails.notScopesTable + $parentScopeExcludedScopesTable = $ParentScopeDetails.excludedScopesTable + + foreach ($child in $childrenTable.Keys) { + $null = $parentScopeChildrenTable.Add($child, $childrenTable.$child) + } + $null = $parentScopeChildrenTable.Add($managementGroupId, $scopeDetails) + + foreach ($resourceGroup in $resourceGroupsTable.Keys) { + $null = $parentScopeResourceGroupsTable.Add($resourceGroup, $resourceGroupsTable.$resourceGroup) + } + + $null = $parentScopeNotScopesList.AddRange($notScopesList) + foreach ($notScope in $notScopesTable.Keys) { + $null = $parentScopeNotScopesTable.Add($notScope, $notScopesTable.$notScope) + } + + foreach ($excludedScope in $excludedScopesTable.Keys) { + $null = $parentScopeExcludedScopesTable.Add($excludedScope, $excludedScopesTable.$excludedScope) + } + } + #endregion augment this parents scope's details with this mangement group's details + + return $scopeDetails +} \ No newline at end of file diff --git a/Scripts/Helpers/Build-ScopeTableForSubscription.ps1 b/Scripts/Helpers/Build-ScopeTableForSubscription.ps1 new file mode 100644 index 00000000..e87940a0 --- /dev/null +++ b/Scripts/Helpers/Build-ScopeTableForSubscription.ps1 @@ -0,0 +1,137 @@ +function Build-ScopeTableForSubscription { + [CmdletBinding()] + param ( + [parameter(Mandatory = $true)] [string] $SubscriptionId, + [parameter(Mandatory = $true)] [string] $SubscriptionName, + [parameter(Mandatory = $true)] [hashtable] $ResourceGroupsBySubscriptionId, + [parameter(Mandatory = $true)] $PacEnvironment, + [parameter(Mandatory = $false)] [hashtable] $ScopeTable = @{}, + [parameter(Mandatory = $false)] [bool] $IsExcluded = $false, + [parameter(Mandatory = $false)] [bool] $IsInGlobalNotScope = $false, + [parameter(Mandatory = $false)] [hashtable] $ParentTable = @{}, + [parameter(Mandatory = $false)] [hashtable] $ParentScopeDetails = $null + ) + + #region initialize variables + $childrenTable = @{} + $resourceGroupsTable = @{} + $notScopesList = [System.Collections.ArrayList]::new() + $notScopesTable = @{} + $excludedScopesTable = @{} + $thisSubscriptionResourceGroups = [System.Collections.ArrayList]::new() + if ($resourceGroupsBySubscriptionId.ContainsKey($subscriptionId)) { + $thisSubscriptionResourceGroups = $resourceGroupsBySubscriptionId.$subscriptionId + } + $subscriptionResourceId = "/subscriptions/$SubscriptionId" + #endregion initialize variables + + #region build scope details + $thisNotScope = $null + if ($null -ne $ParentScopeDetails) { + # the root node is never not in scope or excluded + if (!$IsInGlobalNotScope) { + # optimized + foreach ($globalNotScope in $PacEnvironment.globalNotScopesSubscriptions) { + if ($subscriptionResourceId -like $globalNotScope) { + $thisNotScope = $subscriptionResourceId + $IsInGlobalNotScope = $true + $IsExcluded = $true + break + } + } + } + if (!$IsExcluded) { + # optimized + foreach ($globalExcludedScope in $PacEnvironment.globalExcludedScopesSubscriptions) { + if ($subscriptionResourceId -like $globalExcludedScope) { + $IsExcluded = $true + break + } + } + } + } + $scopeDetails = @{ + id = $subscriptionResourceId + type = "/subscriptions" + name = $subscriptionId + displayName = $subscriptionName + parentTable = $ParentTable + childrenTable = $childrenTable + resourceGroupsTable = $resourceGroupsTable + notScopesList = $notScopesList + notScopesTable = $notScopesTable + excludedScopesTable = $excludedScopesTable + isExcluded = $IsExcluded + isInGlobalNotScope = $IsInGlobalNotScope + state = $resourceContainer.State + location = "global" + } + if ($IsExcluded) { + $null = $excludedScopesTable.Add($subscriptionResourceId, $scopeDetails) + } + if ($IsInGlobalNotScope) { + $null = $notScopesTable.Add($subscriptionResourceId, $scopeDetails) + if ($null -ne $thisNotScope) { + $null = $notScopesList.Add($thisNotScope) + } + } + $myChildrensParentTable = $ParentTable.Clone() + $null = $myChildrensParentTable.Add($subscriptionResourceId, $scopeDetails) + #endregion build scope details + + #region augment resource groups scope details + foreach ($thisSubscriptionResourceGroup in $thisSubscriptionResourceGroups) { + $resourceGroupId = $thisSubscriptionResourceGroup.id + $thisSubscriptionResourceGroup.parentTable = $myChildrensParentTable + If ($IsInGlobalNotScope) { + $thisSubscriptionResourceGroup.isInGlobalNotScope = $true + } + elseif ($thisSubscriptionResourceGroup.isInGlobalNotScope) { + $null = $notScopesList.Add($resourceGroupId) + } + if ($IsExcluded) { + $thisSubscriptionResourceGroup.isExcluded = $true + } + + $null = $ScopeTable.Add($resourceGroupId, $thisSubscriptionResourceGroup) + $null = $childrenTable.Add($resourceGroupId, $thisSubscriptionResourceGroup) + $null = $resourceGroupsTable.Add($resourceGroupId, $thisSubscriptionResourceGroup) + if ($thisSubscriptionResourceGroup.isInGlobalNotScope) { + $null = $notScopesTable.Add($resourceGroupId, $thisSubscriptionResourceGroup) + } + if ($thisSubscriptionResourceGroup.isExcluded) { + $null = $excludedScopesTable.Add($resourceGroupId, $thisSubscriptionResourceGroup) + } + } + #endregion augment resource groups scope details + + #region augemnt this parents scope's details with this subscription's details + if ($null -ne $ParentScopeDetails) { + $parentScopeChildrenTable = $ParentScopeDetails.childrenTable + $parentScopeResourceGroupsTable = $ParentScopeDetails.resourceGroupsTable + $parentScopeNotScopesList = $ParentScopeDetails.notScopesList + $parentScopeNotScopesTable = $ParentScopeDetails.notScopesTable + $parentScopeExcludedScopesTable = $ParentScopeDetails.excludedScopesTable + + foreach ($child in $childrenTable.Keys) { + $null = $parentScopeChildrenTable.Add($child, $childrenTable.$child) + } + $null = $ParentScopeDetails.childrenTable.Add($subscriptionResourceId, $scopeDetails) + + foreach ($resourceGroup in $resourceGroupsTable.Keys) { + $null = $parentScopeResourceGroupsTable.Add($resourceGroup, $resourceGroupsTable.$resourceGroup) + } + + $null = $parentScopeNotScopesList.AddRange($notScopesList) + foreach ($notScope in $notScopesTable.Keys) { + $null = $parentScopeNotScopesTable.Add($notScope, $notScopesTable.$notScope) + } + + foreach ($excludedScope in $excludedScopesTable.Keys) { + $null = $parentScopeExcludedScopesTable.Add($excludedScope, $excludedScopesTable.$excludedScope) + } + } + #endregion augemnt this parents scope's details with this subscription's details + + return $scopeDetails +} \ No newline at end of file diff --git a/Scripts/Helpers/Confirm-AssignmentParametersMatch.ps1 b/Scripts/Helpers/Confirm-AssignmentParametersMatch.ps1 deleted file mode 100644 index 961ee27d..00000000 --- a/Scripts/Helpers/Confirm-AssignmentParametersMatch.ps1 +++ /dev/null @@ -1,48 +0,0 @@ -function Confirm-AssignmentParametersMatch { - [CmdletBinding()] - param( - $ExistingParametersObj, - $DefinedParametersObj, - [switch] $CompareTwoExistingParametersObj - ) - - $existingParameters = ConvertTo-HashTable $ExistingParametersObj - $definedParameters = ConvertTo-HashTable $DefinedParametersObj - $addedParameters = Get-HashtableShallowClone $definedParameters - foreach ($existingParameterName in $existingParameters.Keys) { - $found = $false - foreach ($definedParameterName in $definedParameters.Keys) { - if ($definedParameterName -eq $existingParameterName) { - # remove key from $addedParameters - $addedParameters.Remove($definedParameterName) - - # analyze parameter - $existing = $existingParameters.$existingParameterName.value - $defined = $definedParameters.$definedParameterName - if ($CompareTwoExistingParametersObj) { - $defined = $definedParameters.$definedParameterName.value - } - $match = Confirm-ObjectValueEqualityDeep $existing $defined - if (!$match) { - return $false - } - $found = $true - break - } - } - if (!$found) { - # parameter deleted - return $false - } - } - - # if condition instead of just returning the bool value is for easier debugging - if ( $addedParameters.psbase.Count -eq 0) { - # full match - return $true - } - else { - # parameter added - return $false - } -} diff --git a/Scripts/Helpers/Confirm-DeleteForStrategy.ps1 b/Scripts/Helpers/Confirm-DeleteForStrategy.ps1 index da140599..788d86a7 100644 --- a/Scripts/Helpers/Confirm-DeleteForStrategy.ps1 +++ b/Scripts/Helpers/Confirm-DeleteForStrategy.ps1 @@ -3,10 +3,6 @@ function Confirm-DeleteForStrategy { param ( [string] $PacOwner, [string] $Strategy, - [string] $Status, - [string] $DeleteExpired, - [string] $DeleteOrphaned, - [string] $Removed, [Parameter(Mandatory = $false)] $KeepDfcSecurityAssignments = $false @@ -14,30 +10,19 @@ function Confirm-DeleteForStrategy { $shallDelete = switch ($PacOwner) { "thisPaC" { - if (($DeleteExpired -eq $false -and $Status -eq "expired") -or ($DeleteOrphaned -eq $false -and $Status -eq "orphaned") -and $Removed -eq $false) { - $false - break - } - else { - $true - break - } + $true } "otherPaC" { $false - break } "unknownOwner" { $Strategy -eq "full" - break } "managedByDfcSecurityPolicies" { !$KeepDfcSecurityAssignments -and $Strategy -eq "full" - break } "managedByDfcDefenderPlans" { $false - break } } return $shallDelete diff --git a/Scripts/Helpers/Confirm-EffectIsAllowed.ps1 b/Scripts/Helpers/Confirm-EffectIsAllowed.ps1 new file mode 100644 index 00000000..1057164f --- /dev/null +++ b/Scripts/Helpers/Confirm-EffectIsAllowed.ps1 @@ -0,0 +1,14 @@ +function Confirm-EffectIsAllowed { + [CmdletBinding()] + param ( + $Effect, + $AllowedEffects + ) + + foreach ($allowedEffect in $AllowedEffects) { + if ($Effect -eq $allowedEffect) { + return $allowedEffect # fixes potentially wrong case, or keeps the original case + } + } + return $null +} \ No newline at end of file diff --git a/Scripts/Helpers/Confirm-MetadataMatches.ps1 b/Scripts/Helpers/Confirm-MetadataMatches.ps1 index 17dc4678..28df7805 100644 --- a/Scripts/Helpers/Confirm-MetadataMatches.ps1 +++ b/Scripts/Helpers/Confirm-MetadataMatches.ps1 @@ -7,8 +7,8 @@ function Confirm-MetadataMatches { $match = $false $changePacOwnerId = $false - $existingMetadata = Get-DeepClone $ExistingMetadataObj -AsHashTable - $definedMetadata = Get-DeepClone $DefinedMetadataObj -AsHashTable + $existingMetadata = Get-ClonedObject $ExistingMetadataObj -AsHashTable + $definedMetadata = Get-ClonedObject $DefinedMetadataObj -AsHashTable # remove system generated metadata from consideration if ($existingMetadata.ContainsKey("createdBy")) { @@ -27,6 +27,7 @@ function Confirm-MetadataMatches { $existingPacOwnerId = $existingMetadata.pacOwnerId $definedPacOwnerId = $definedMetadata.pacOwnerId if ($existingPacOwnerId -ne $definedPacOwnerId) { + Write-Information "pacOwnerId has changed from '$existingPacOwnerId' to '$definedPacOwnerId'" $changePacOwnerId = $true } if ($definedMetadata.ContainsKey("pacOwnerId")) { @@ -36,7 +37,7 @@ function Confirm-MetadataMatches { $null = $existingMetadata.Remove("pacOwnerId") } if ($existingMetadata.psbase.Count -eq $definedMetadata.psbase.Count) { - $match = Confirm-ObjectValueEqualityDeep $existingMetadata $definedMetadata -HandleRandomOrderArray + $match = Confirm-ObjectValueEqualityDeep $existingMetadata $definedMetadata } return $match, $changePacOwnerId diff --git a/Scripts/Helpers/Confirm-ObjectValueEqualityDeep.ps1 b/Scripts/Helpers/Confirm-ObjectValueEqualityDeep.ps1 index d31443e3..caf02380 100644 --- a/Scripts/Helpers/Confirm-ObjectValueEqualityDeep.ps1 +++ b/Scripts/Helpers/Confirm-ObjectValueEqualityDeep.ps1 @@ -5,10 +5,7 @@ function Confirm-ObjectValueEqualityDeep { $Object1, [Parameter(Position = 1)] - $Object2, - - [switch] $HandleRandomOrderArray, - [switch] $CaseInsensitiveKeys + $Object2 ) @@ -21,13 +18,11 @@ function Confirm-ObjectValueEqualityDeep { if ($null -eq $Object1) { # $Object1 is $null, swap $Object1 and $Object2 to ensure that Object1 (the old Object2) is not $null and Object2 (the old Object1) is $null (setting it to $null is ommited because it is not used in the subsequent code) $Object1 = $Object2 + $Object2 = $null } - if ($Object1 -is [System.Collections.IList]) { - # $Object1 is an array or ArrayList, if it is empty treat it as $null and therefore equal to Object2 - return $Object1.Count -eq 0 - } - elseif ($Object1 -is [System.Collections.IDictionary]) { - # $Object1 is a hashtable, if it is empty treat it as $null and therefore equal to Object2 + if ($Object1 -is [System.Collections.ICollection]) { + # $Object1 is an ICollection, if it has 0 elements treat it as $null and therefore equal to Object2 + # Arrays, ArrayList, Hashtables and other collections are all ICollection return $Object1.Count -eq 0 } elseif ($Object1 -is [string]) { @@ -40,11 +35,7 @@ function Confirm-ObjectValueEqualityDeep { } } else { - $type1 = $Object1.GetType() - $typeName1 = $type1.Name - $type2 = $Object2.GetType() - $typeName2 = $type2.Name - if ($Object1 -is [System.Collections.Ilist] -or $Object2 -is [System.Collections.Ilist]) { + if ($Object1 -is [System.Collections.IList] -or $Object2 -is [System.Collections.Ilist]) { # $Object1 or $Object2 is an array or ArrayList if ($Object1 -isnot [System.Collections.Ilist]) { $Object1 = @($Object1) @@ -57,50 +48,32 @@ function Confirm-ObjectValueEqualityDeep { } else { # iterate and recurse - if ($HandleRandomOrderArray) { - $object2List = [System.Collections.ArrayList]::new($Object2) - foreach ($item1 in $Object1) { - # iterate through Object1 and find a match in Object2 - $foundMatch = $false - for ($i = 0; $i -lt $object2List.Count; $i++) { - $item2 = $object2List[$i] - if ($item1 -eq $item2 -or (Confirm-ObjectValueEqualityDeep $item1 $item2 -HandleRandomOrderArray -CaseInsensitiveKeys:$CaseInsensitiveKeys)) { - # if either the array item values are equal or a deep inspection shows equal, continue to the next item by: - # 1. Setting $foundMatch to $true - # 2. Remove the matching item from the Object2 list, therefore reducing the computing complexity of the next iteration - # 3. Breaking out of the inner "for" loop - $foundMatch = $true - $null = $object2List.RemoveAt($i) - break - } - } - if (!$foundMatch) { - # no item in Object2 matches the current item in Object1, return false - return $false + $object2List = [System.Collections.ArrayList]::new($Object2) + foreach ($item1 in $Object1) { + # iterate through Object1 and find a match in Object2 + $foundMatch = $false + for ($i = 0; $i -lt $object2List.Count; $i++) { + $item2 = $object2List[$i] + if ($item1 -eq $item2 -or (Confirm-ObjectValueEqualityDeep $item1 $item2)) { + # if either the array item values are equal or a deep inspection shows equal, continue to the next item by: + # 1. Setting $foundMatch to $true + # 2. Remove the matching item from the Object2 list, therefore reducing the computing complexity of the next iteration + # 3. Breaking out of the inner "for" loop + $foundMatch = $true + $null = $object2List.RemoveAt($i) + break } } - # every item in Object1 has a match in Object2, return true - return $object2List.Count -eq 0 - } - else { - # iterate and recurse - for ($i = 0; $i -lt $Object1.Count; $i++) { - $item1 = $Object1[$i] - $item2 = $Object2[$i] - if ($item1 -eq $item2 -or (Confirm-ObjectValueEqualityDeep $item1 $item2 -CaseInsensitiveKeys:$CaseInsensitiveKeys)) { - # if either the array item values are equal or a deep inspection shows equal, continue to the next item - } - else { - # if the array item values are not equal and a deep inspection does not show equal, return false - return $false - } + if (!$foundMatch) { + # no item in Object2 matches the current item in Object1, return false + return $false } - # every item in the array has the same value, return true - return $true } + # every item in Object1 has a match in Object2, return true + return $true } } - elseif ($typeName1 -eq "DateTime" -or $typeName2 -eq "DateTime") { + elseif ($Object1 -is [datetime] -or $Object2 -is [datetime]) { # $Object1 or $Object2 is a DateTime # Note: this must be done prior to the next test, since [DateTime] is a [System.ValueType] $dateString1 = $Object1 @@ -113,55 +86,57 @@ function Confirm-ObjectValueEqualityDeep { } return $dateString1 -eq $dateString2 } - elseif ($typeName1 -eq "String" -or $typeName2 -eq "String" -or $Object1 -is [System.ValueType] -or $Object2 -is [System.ValueType]) { + elseif ($Object1 -is [string] -or $Object2 -is [string] -or $Object1 -is [System.ValueType] -or $Object2 -is [System.ValueType]) { # Will have caused $true by the first "if" statement if they match # Note: this must be done prior to the next test, since [string and [System.ValueType] are both [PSCustomObject] (PSCustomObject is PowerShells version of [object]) return $false } - elseif (($Object1 -is [System.Collections.IDictionary] -or $Object1 -is [PSCustomObject]) ` - -and ($Object2 -is [System.Collections.IDictionary] -or $Object2 -is [PSCustomObject])) { + elseif (($Object1 -is [System.Collections.IDictionary] -or $Object1 -is [psobject]) ` + -and ($Object2 -is [System.Collections.IDictionary] -or $Object2 -is [psobject])) { - # normalize Object1 and Object2 to hashtable - $normalizedObject1 = $Object1 - $normalizedObject2 = $Object2 - if ($Object1 -isnot [System.Collections.IDictionary]) { - $normalizedObject1 = $Object1 | ConvertTo-Json -Depth 100 -Compress | ConvertFrom-Json -AsHashtable + # normalize Object1 and Object2 keys or property names + $normalizedKeys1 = @() + $normalizedKeys2 = @() + if ($Object1 -is [System.Collections.IDictionary]) { + $normalizedKeys1 = $Object1.Keys + } + else { + $normalizedKeys1 = $Object1.PSObject.Properties.Name } - if ($Object2 -isnot [System.Collections.IDictionary]) { - $normalizedObject2 = $Object2 | ConvertTo-Json -Depth 100 -Compress | ConvertFrom-Json -AsHashtable + if ($Object2 -is [System.Collections.IDictionary]) { + $normalizedKeys2 = $Object2.Keys } - - $allKeys = $normalizedObject1.Keys + $normalizedObject2.Keys + else { + $normalizedKeys2 = $Object2.PSObject.Properties.Name + } + $key1IsNotArray = $normalizedKeys1 -isnot [array] + $key2IsNotArray = $normalizedKeys2 -isnot [array] + if ($key1IsNotArray) { + $normalizedKeys1 = @($normalizedKeys1) + } + if ($key2IsNotArray) { + $normalizedKeys2 = @($normalizedKeys2) + } + $allKeys = $normalizedKeys1 + $normalizedKeys2 $uniqueKeys = $allKeys | Sort-Object -Unique + if ($null -eq $uniqueKeys) { + # if there are no keys, return true + return $true + } + if ($uniqueKeys -isnot [array]) { + $uniqueKeys = @($uniqueKeys) + } + + # iterate and recurse foreach ($key in $uniqueKeys) { - #recurse - $item1 = $normalizedObject1.$key - $item2 = $normalizedObject2.$key - if ($CaseInsensitiveKeys) { - if ($null -eq $item1) { - # case of key does not match, find key for normalizedObject1 without considering case - $key1 = $normalizedObject1.Keys | Where-Object { $_.ToLower() -eq $key.ToLower() } - Write-Debug "key '$key' exists with a different case '$key1' in Object1 '$($normalizedObject1 | ConvertTo-Json -Depth 100 -Compress)'" - if ($null -ne $key1) { - $item1 = $normalizedObject1.$key1 - } - # else keep $item1 as $null; the recursive call will handle this case - } - if ($null -eq $item2) { - # case of key does not match, find key for normalizedObject2 without considering case - $key2 = $normalizedObject2.Keys | Where-Object { $_.ToLower() -eq $key.ToLower() } - Write-Debug "key '$key' exists with a different case '$key2' in Object2 '$($normalizedObject2 | ConvertTo-Json -Depth 100 -Compress)'" - if ($null -ne $key2) { - $item2 = $normalizedObject2.$key2 - } - # else keep $item2 as $null; the recursive call will handle this case - } - } - if ($item1 -eq $item2 -or (Confirm-ObjectValueEqualityDeep $item1 $item2 -CaseInsensitiveKeys:$CaseInsensitiveKeys -HandleRandomOrderArray:$HandleRandomOrderArray)) { - # if the values are equal, or a deep inspection shows equal then continue to the next key + $item1 = $Object1.$key + $item2 = $Object2.$key + + if ($item1 -eq $item2 -or (Confirm-ObjectValueEqualityDeep $item1 $item2)) { + # if either the property values are equal or a deep inspection shows equal, continue to the next property } else { - # if the values are not equal, and a deep inspection does not show equal, return false + # if the property values are not equal and a deep inspection does not show equal, return false return $false } } diff --git a/Scripts/Helpers/Confirm-ParametersDefinitionMatch.ps1 b/Scripts/Helpers/Confirm-ParametersDefinitionMatch.ps1 index 3d19e35d..5d190a30 100644 --- a/Scripts/Helpers/Confirm-ParametersDefinitionMatch.ps1 +++ b/Scripts/Helpers/Confirm-ParametersDefinitionMatch.ps1 @@ -9,7 +9,7 @@ function Confirm-ParametersDefinitionMatch { $existingParameters = ConvertTo-HashTable $ExistingParametersObj $definedParameters = ConvertTo-HashTable $DefinedParametersObj - $addedParameters = Get-HashtableShallowClone $definedParameters + $addedParameters = Get-ClonedObject $definedParameters -AsHashTable -AsShallowClone foreach ($existingParameterName in $existingParameters.Keys) { if ($definedParameters.Keys -contains $existingParameterName) { # Remove key from $addedParameters @@ -28,7 +28,7 @@ function Confirm-ParametersDefinitionMatch { } # Analyze parameter allowedValues - $thisMatch = Confirm-ObjectValueEqualityDeep $existing.allowedValues $defined.allowedValues -HandleRandomOrderArray + $thisMatch = Confirm-ObjectValueEqualityDeep $existing.allowedValues $defined.allowedValues if (!$thisMatch) { $match = $false if ($null -eq $defined.defaultValue) { @@ -46,7 +46,7 @@ function Confirm-ParametersDefinitionMatch { $existingMetadata = $existing.metadata $definedMetadata = $defined.metadata - $thisMatch = Confirm-ObjectValueEqualityDeep $existingMetadata $definedMetadata -HandleRandomOrderArray + $thisMatch = Confirm-ObjectValueEqualityDeep $existingMetadata $definedMetadata if (!$thisMatch) { $match = $false if ($existingMetadata.strongType -ne $definedMetadata.strongType) { diff --git a/Scripts/Helpers/Confirm-ParametersUsageMatches.ps1 b/Scripts/Helpers/Confirm-ParametersUsageMatches.ps1 index cbb55061..c92a9194 100644 --- a/Scripts/Helpers/Confirm-ParametersUsageMatches.ps1 +++ b/Scripts/Helpers/Confirm-ParametersUsageMatches.ps1 @@ -56,7 +56,7 @@ function Confirm-ParametersUsageMatches { $definedParameterValue = $definedParameter.value } - if (!(Confirm-ObjectValueEqualityDeep $existingParameterValue $definedParameterValue -HandleRandomOrderArray)) { + if (!(Confirm-ObjectValueEqualityDeep $existingParameterValue $definedParameterValue)) { return $false } } diff --git a/Scripts/Helpers/Confirm-PolicyDefinitionsParametersMatch.ps1 b/Scripts/Helpers/Confirm-PolicyDefinitionsParametersMatch.ps1 index a4153cad..46020cbd 100644 --- a/Scripts/Helpers/Confirm-PolicyDefinitionsParametersMatch.ps1 +++ b/Scripts/Helpers/Confirm-PolicyDefinitionsParametersMatch.ps1 @@ -7,7 +7,7 @@ function Confirm-PolicyDefinitionsParametersMatch { $existingParameters = ConvertTo-HashTable $ExistingParametersObj $definedParameters = ConvertTo-HashTable $DefinedParametersObj - $addedParameters = Get-HashtableShallowClone $definedParameters + $addedParameters = Get-ClonedObject $definedParameters -AsHashTable -AsShallowClone foreach ($existingParameterName in $existingParameters.Keys) { $found = $false foreach ($definedParameterName in $definedParameters.Keys) { diff --git a/Scripts/Helpers/Confirm-PolicyResourceExclusions.ps1 b/Scripts/Helpers/Confirm-PolicyResourceExclusions.ps1 index 02049cd3..bbfc55d4 100644 --- a/Scripts/Helpers/Confirm-PolicyResourceExclusions.ps1 +++ b/Scripts/Helpers/Confirm-PolicyResourceExclusions.ps1 @@ -4,10 +4,9 @@ function Confirm-PolicyResourceExclusions { $TestId, $ResourceId, $ScopeTable, - $IncludeResourceGroups, - $ExcludedScopes, - $ExcludedIds, - $PolicyResourceTable + $ExcludedScopesTable, + $ExcludedIds = @(), + $PolicyResourceTable = $null ) $testResourceIdParts = Split-AzPolicyResourceId -Id $TestId @@ -22,40 +21,30 @@ function Confirm-PolicyResourceExclusions { if ($scopeType -eq "builtin") { return $true, $resourceIdParts } - if (!$ScopeTable.ContainsKey($scope)) { - $PolicyResourceTable.counters.unmanagedScopes += 1 - return $false, $resourceIdParts - } - $scopeEntry = $ScopeTable.$scope - $parentList = $scopeEntry.parentList - if ($null -eq $parentList) { - Write-Error "Code bug parentList is $null $($scopeEntry | ConvertTo-Json -Depth 100 -Compress)" -ErrorAction Stop - } - if (!$IncludeResourceGroups -and $scopeType -eq "resourceGroups") { - Write-Verbose "Exclude(resourceGroup) $($ResourceId)" - $PolicyResourceTable.counters.excluded += 1 + if (-not $ScopeTable.ContainsKey($scope)) { + Write-Verbose "Unmanged scope '$scope', resource '$($ResourceId)'" + if ($null -ne $PolicyResourceTable) { + $PolicyResourceTable.counters.unmanagedScopes += 1 + } return $false, $resourceIdParts } - foreach ($testScope in $ExcludedScopes) { - if ($scope -like $testScope -or $parentList.ContainsKey($testScope)) { - Write-Verbose "Exclude(scope,$testScope) $($ResourceId)" + if ($ExcludedScopesTable.ContainsKey($scope)) { + Write-Verbose "Excluded scope '$scope', resource '$($ResourceId)'" + if ($null -ne $PolicyResourceTable) { $PolicyResourceTable.counters.excluded += 1 - return $false, $resourceIdParts } - elseif ($testScope -contains "*") { - foreach ($parentScope in $parentList.Keys) { - if ($parentScope -like $testScope) { - Write-Verbose "Exclude(scope,$testScope) $($ResourceId)" - $PolicyResourceTable.counters.excluded += 1 - return $false, $resourceIdParts - } - } + if ($resourceIdParts.kind -eq "policyAssignments") { + $excludedScope = $ExcludedScopesTable.$scope + $null = $null } + return $false, $resourceIdParts } foreach ($testExcludedId in $ExcludedIds) { if ($TestId -like $testExcludedId) { - Write-Verbose "Exclude(id,$testExcludedId) $($ResourceId)" - $PolicyResourceTable.counters.excluded += 1 + Write-Verbose "Excluded id '$($ResourceId)'" + if ($null -ne $PolicyResourceTable) { + $PolicyResourceTable.counters.excluded += 1 + } return $false, $resourceIdParts } } diff --git a/Scripts/Helpers/Convert-ListToToCsvRow.ps1 b/Scripts/Helpers/Convert-ListToToCsvRow.ps1 deleted file mode 100644 index f8faf7d0..00000000 --- a/Scripts/Helpers/Convert-ListToToCsvRow.ps1 +++ /dev/null @@ -1,18 +0,0 @@ -function Convert-ListToToCsvRow { - param ( - [System.Collections.IEnumerable] $List - ) - - [System.Text.StringBuilder] $rowText = [System.Text.StringBuilder]::new() - $comma = "" - foreach ($item in $List) { - if ($item -is [hashtable] -or $parameter -is [PSCustomObject]) { - $item = "object" - } - $itemEscaped = $item -replace "`"", "`"`"" - $null = $rowText.Append("$comma`"$itemEscaped`"") - $comma = "," - } - $rowString = $rowText.ToString() - return $rowString -} diff --git a/Scripts/Helpers/Convert-PolicySetsToFlatList.ps1 b/Scripts/Helpers/Convert-PolicyResourcesDetailsToFlatList.ps1 similarity index 99% rename from Scripts/Helpers/Convert-PolicySetsToFlatList.ps1 rename to Scripts/Helpers/Convert-PolicyResourcesDetailsToFlatList.ps1 index 6745984e..79f3d91f 100644 --- a/Scripts/Helpers/Convert-PolicySetsToFlatList.ps1 +++ b/Scripts/Helpers/Convert-PolicyResourcesDetailsToFlatList.ps1 @@ -1,4 +1,4 @@ -function Convert-PolicySetsToFlatList { +function Convert-PolicyResourcesDetailsToFlatList { [CmdletBinding()] param ( $ItemList, @@ -57,7 +57,7 @@ function Convert-PolicySetsToFlatList { $assignment = $detail.assignment $properties = Get-PolicyResourceProperties -PolicyResource $assignment $assignmentOverrides = $properties.overrides - $assignmentParameters = Get-DeepClone $properties.parameters -AsHashTable + $assignmentParameters = Get-ClonedObject $properties.parameters -AsHashTable } foreach ($policyInPolicySetInfo in $detail.policyDefinitions) { diff --git a/Scripts/Helpers/Convert-PolicyResourcesToDetails.ps1 b/Scripts/Helpers/Convert-PolicyResourcesToDetails.ps1 new file mode 100644 index 00000000..5808f382 --- /dev/null +++ b/Scripts/Helpers/Convert-PolicyResourcesToDetails.ps1 @@ -0,0 +1,139 @@ +function Convert-PolicyResourcesToDetails { + [CmdletBinding()] + param ( + [hashtable] $AllPolicyDefinitions, + [hashtable] $AllPolicySetDefinitions, + [Int16] $VirtualCores + ) + + Write-Information "===================================================================================================" + Write-Information "Pre-calculating parameters for Policy and Policy Set definitions" + Write-Information "===================================================================================================" + + # Convert Policy Definitions to Details + $policyDetails = @{} + if ($VirtualCores -gt 1) { + # maybe parallel processing + $throttleLimit = $VirtualCores + $chunks = Split-HashtableIntoChunks -Table $AllPolicyDefinitions -NumberOfChunks $throttleLimit + if ($chunks.Count -le 1) { + $chunks = $null + } + else { + $throttleLimit = $chunks.Count + } + } + + if ($null -ne $chunks) { + # create synchronized hashtables for parallel processing and functions to pass into parallel context + $syncPolicyDetails = [System.Collections.Hashtable]::Synchronized($policyDetails) + $funcConvertPolicyToDetails = ${function:Convert-PolicyToDetails}.ToString() + $funcGetPolicyResourceProperties = ${function:Get-PolicyResourceProperties}.ToString() + $funcGetParameterNameFromValueString = ${function:Get-ParameterNameFromValueString}.ToString() + $funcConvertToHashTable = ${function:ConvertTo-HashTable}.ToString() + + # loop through each chunk of Policy definitions and process in parallel + Write-Information "Processing $($AllPolicyDefinitions.psbase.Count) Policy definitions in $throttleLimit parallel threads." + $chunks | ForEach-Object -ThrottleLimit $chunks.count -Parallel { + # import dot sourced functions into context + if ($null -eq ${function:Get-PolicyResourceProperties}) { + ${function:Convert-PolicyToDetails} = $using:funcConvertPolicyToDetails + ${function:Get-PolicyResourceProperties} = $using:funcGetPolicyResourceProperties + ${function:Get-ParameterNameFromValueString} = $using:funcGetParameterNameFromValueString + ${function:ConvertTo-HashTable} = $using:funcConvertToHashTable + } + + # import parameters into context + $allPolicyDefinitionsLocal = $using:AllPolicyDefinitions + $syncPolicyDetails = $using:syncPolicyDetails + + foreach ($policyId in $_.Keys) { + $policy = $AllPolicyDefinitionsLocal.$policyId + Convert-PolicyToDetails ` + -PolicyId $policyId ` + -PolicyDefinition $policy ` + -PolicyDetails $syncPolicyDetails + } + } + } + else { + # non-parallel processing + Write-Information "Calculating effect parameters for $($AllPolicyDefinitions.psbase.Count) Policies." + foreach ($policyId in $AllPolicyDefinitions.Keys) { + $policy = $AllPolicyDefinitions.$policyId + Convert-PolicyToDetails ` + -PolicyId $policyId ` + -PolicyDefinition $policy ` + -PolicyDetails $policyDetails + } + } + + # Convert Policy Set Definitions to Details + $policySetDetails = @{} + if ($VirtualCores -gt 1) { + # maybe parallel processing + $throttleLimit = $VirtualCores + $chunks = Split-HashtableIntoChunks -Table $AllPolicySetDefinitions -NumberOfChunks $throttleLimit + if ($chunks.Count -le 1) { + $chunks = $null + } + else { + $throttleLimit = $chunks.Count + } + } + + if ($null -ne $chunks) { + # create synchronized hashtables for parallel processing and functions to pass into parallel context + $syncPolicySetDetails = [System.Collections.Hashtable]::Synchronized($policySetDetails) + $funcConvertPolicySetToDetails = ${function:Convert-PolicySetToDetails}.ToString() + $funcGetPolicyResourceProperties = ${function:Get-PolicyResourceProperties}.ToString() + $funcGetParameterNameFromValueString = ${function:Get-ParameterNameFromValueString}.ToString() + $funcConvertToHashTable = ${function:ConvertTo-HashTable}.ToString() + + # loop through each chunk of Policy definitions and process in parallel + Write-Information "Processing $($AllPolicySetDefinitions.psbase.Count) Policy Set definitions in $throttleLimit parallel threads." + $chunks | ForEach-Object -ThrottleLimit $chunks.count -Parallel { + # import dot sourced functions into context + if ($null -eq ${function:Get-PolicyResourceProperties}) { + ${function:Convert-PolicySetToDetails} = $using:funcConvertPolicySetToDetails + ${function:Get-PolicyResourceProperties} = $using:funcGetPolicyResourceProperties + ${function:Get-ParameterNameFromValueString} = $using:funcGetParameterNameFromValueString + ${function:ConvertTo-HashTable} = $using:funcConvertToHashTable + } + + # import parameters into context + $allPolicySetDefinitionsLocal = $using:AllPolicySetDefinitions + $syncPolicySetDetails = $using:syncPolicySetDetails + $policyDetails = $using:policyDetails + + foreach ($policySetId in $_.Keys) { + $policySet = $AllPolicySetDefinitionsLocal.$policySetId + Convert-PolicySetToDetails ` + -PolicySetId $policySetId ` + -PolicySetDefinition $policySet ` + -PolicySetDetails $syncPolicySetDetails ` + -PolicyDetails $policyDetails + } + } + } + else { + # non-parallel processing + Write-Information "Calculating effect parameters for $($AllPolicySetDefinitions.psbase.Count) Policy Sets." + foreach ($policySetId in $AllPolicySetDefinitions.Keys) { + $policySet = $AllPolicySetDefinitions.$policySetId + Convert-PolicySetToDetails ` + -PolicySetId $policySetId ` + -PolicySetDefinition $policySet ` + -PolicySetDetails $policySetDetails ` + -PolicyDetails $policyDetails + } + } + Write-Information "" + + # Assemble result + $combinedPolicyDetails = @{ + policies = $policyDetails + policySets = $policySetDetails + } + return $combinedPolicyDetails +} diff --git a/Scripts/Helpers/Convert-PolicySetToDetails.ps1 b/Scripts/Helpers/Convert-PolicySetToDetails.ps1 new file mode 100644 index 00000000..392576bf --- /dev/null +++ b/Scripts/Helpers/Convert-PolicySetToDetails.ps1 @@ -0,0 +1,196 @@ +function Convert-PolicySetToDetails { + [CmdletBinding()] + param ( + $PolicySetId, + $PolicySetDefinition, + $PolicySetDetails, + $PolicyDetails + ) + + $properties = Get-PolicyResourceProperties -PolicyResource $PolicySetDefinition + $category = "Unknown" + if ($properties.metadata -and $properties.metadata.category) { + $category = $properties.metadata.category + } + + [System.Collections.ArrayList] $policyInPolicySetDetailList = [System.Collections.ArrayList]::new() + $policySetParameters = $properties.parameters | ConvertTo-HashTable + $parametersAlreadyCovered = @{} + foreach ($policyInPolicySet in $properties.policyDefinitions) { + $policyId = $policyInPolicySet.policyDefinitionId + if ($PolicyDetails.ContainsKey($policyId)) { + $policyDetail = $PolicyDetails.$policyId + $policyInPolicySetParameters = $policyInPolicySet.parameters | ConvertTo-HashTable + + $policySetLevelEffectParameterName = $null + $effectParameterName = $policyDetail.effectParameterName + $effectValue = $policyDetail.effectValue + $effectDefault = $policyDetail.effectDefault + $effectAllowedValues = $policyDetail.effectAllowedValues + $effectAllowedOverrides = $policyDetail.effectAllowedOverrides + $effectReason = $policyDetail.effectReason + + $policySetLevelEffectParameterFound = $false + $policySetLevelEffectParameterName = "" + if ($effectReason -ne "Policy Fixed") { + # Effect is parameterized in Policy + if ($policyInPolicySetParameters.Keys -contains $effectParameterName) { + # Effect parameter is used by policySet + $policyInPolicySetParameter = $policyInPolicySetParameters.$effectParameterName + if ($null -eq $policyInPolicySetParameter) { + $key1 = $policyInPolicySetParameters.Keys | Where-Object { $_.ToLower() -eq $effectParameterName.ToLower() } + Write-Debug "key '$effectParameterName' exists with a different case '$key1' in '$($policyInPolicySetParameters | ConvertTo-Json -Depth 100 -Compress)'" + if ($null -ne $key1) { + $policyInPolicySetParameter = $policyInPolicySetParameters.$key1 + } + # else keep $policyInPolicySetParameter as $null + } + $policySetLevelEffectParameterFound = $false + $policySetLevelEffectParameterName = $null + if ($policyInPolicySetParameter) { + $effectRawValue = $policyInPolicySetParameter.value + $policySetLevelEffectParameterFound, $policySetLevelEffectParameterName = Get-ParameterNameFromValueString -ParamValue $effectRawValue + } + + if ($policySetLevelEffectParameterFound) { + # Effect parameter is surfaced by PolicySet + if ($policySetParameters.Keys -contains $policySetLevelEffectParameterName) { + $effectParameter = $policySetParameters.$policySetLevelEffectParameterName + if ($effectParameter.defaultValue) { + $effectValue = $effectParameter.defaultValue + $effectDefault = $effectParameter.defaultValue + $effectReason = "PolicySet Default" + } + else { + $effectReason = "PolicySet No Default" + + } + if ($effectParameter.allowedValues) { + $effectAllowedValues = $effectParameter.allowedValues + } + } + else { + Write-Error "Policy '$($policyId)', referenceId '$($policyInPolicySet.policyDefinitionReferenceId)' tries to pass an unknown Policy Set parameter '$policySetLevelEffectParameterName' to the Policy parameter '$effectParameterName'. Check the spelling of the parameters occurrences in the Policy Set." -ErrorAction Stop + } + } + else { + # Effect parameter is hard-coded (fixed) by PolicySet + $policySetLevelEffectParameterName = $null + $effectValue = $effectRawValue + $effectDefault = $effectRawValue + $effectReason = "PolicySet Fixed" + } + } + } + + # Process Policy parameters surfaced by PolicySet + $surfacedParameters = @{} + foreach ($parameterName in $policyInPolicySetParameters.Keys) { + $parameter = $policyInPolicySetParameters.$parameterName + $rawValue = $parameter.value + if ($rawValue -is [string]) { + $found, $policySetParameterName = Get-ParameterNameFromValueString -ParamValue $rawValue + if ($found) { + $policySetParameter = $policySetParameters.$policySetParameterName + $multiUse = $false + $defaultValue = $policySetParameter.defaultValue + $isEffect = $policySetParameterName -eq $policySetLevelEffectParameterName + if ($parametersAlreadyCovered.ContainsKey($policySetParameterName)) { + $multiUse = $true + } + else { + $null = $parametersAlreadyCovered.Add($policySetParameterName, $true) + } + $null = $surfacedParameters.Add($policySetParameterName, @{ + multiUse = $multiUse + isEffect = $isEffect + value = $defaultValue + defaultValue = $defaultValue + definition = $policySetParameter + } + ) + } + } + } + + # Assemble the info + $groupNames = @() + if ($policyInPolicySet.groupNames) { + $groupNames = $policyInPolicySet.groupNames + } + $policyDefinitionReferenceId = $policyInPolicySet.policyDefinitionReferenceId + $policyDetailId = $policyDetail.id + $policyInPolicySetDetail = @{ + id = $policyDetailId + name = $policyDetail.name + displayName = $policyDetail.displayName + description = $policyDetail.description + policyType = $policyDetail.policyType + category = $policyDetail.category + effectParameterName = $policySetLevelEffectParameterName + effectValue = $effectValue + effectDefault = $effectDefault + effectAllowedValues = $effectAllowedValues + effectAllowedOverrides = $effectAllowedOverrides + effectReason = $effectReason + parameters = $surfacedParameters + policyDefinitionReferenceId = $policyDefinitionReferenceId + groupNames = $groupNames + } + $null = $policyInPolicySetDetailList.Add($policyInPolicySetDetail) + } + else { + # This is a Policy of policyType static used for compliance purposes and not accessible to this code + # SKIP + } + } + + # Assemble Policy Set info + $displayName = $properties.displayName + if (-not $displayName -or $displayName -eq "") { + $displayName = $PolicySetDefinition.name + } + + $description = $properties.description + if (-not $description) { + $description = "" + } + + # Find Policies appearing more than once in PolicySet + $uniquePolicies = @{} + $policiesWithMultipleReferenceIds = @{} + foreach ($policyInPolicySetDetail in $policyInPolicySetDetailList) { + $policyId = $policyInPolicySetDetail.id + $policyDefinitionReferenceId = $policyInPolicySetDetail.policyDefinitionReferenceId + if ($uniquePolicies.ContainsKey($policyId)) { + if (-not $policiesWithMultipleReferenceIds.ContainsKey($policyId)) { + # First time detecting that this Policy has multiple references in the same PolicySet + $uniquePolicyReferenceIds = $uniquePolicies[$policyId] + $null = $policiesWithMultipleReferenceIds.Add($policyId, $uniquePolicyReferenceIds) + } + # Add current policyDefinitionReferenceId + $multipleReferenceIds = $policiesWithMultipleReferenceIds[$policyId] + $multipleReferenceIds += $policyDefinitionReferenceId + $policiesWithMultipleReferenceIds[$policyId] = $multipleReferenceIds + } + else { + # First time encounter in this PolicySet. Record Policy Id and remember policyDefinitionReferenceId + $null = $uniquePolicies.Add($policyId, @( $policyDefinitionReferenceId )) + } + } + + # collect the PolicySet details + $policySetDetail = @{ + id = $PolicySetId + name = $PolicySetDefinition.name + displayName = $displayName + description = $description + policyType = $properties.policyType + category = $category + parameters = $policySetParameters + policyDefinitions = $policyInPolicySetDetailList.ToArray() + policiesWithMultipleReferenceIds = $policiesWithMultipleReferenceIds + } + $null = $PolicySetDetails.Add($PolicySetId, $policySetDetail) + +} diff --git a/Scripts/Helpers/Convert-PolicySetsToDetails.ps1 b/Scripts/Helpers/Convert-PolicySetsToDetails.ps1 deleted file mode 100644 index 9f1ecf3e..00000000 --- a/Scripts/Helpers/Convert-PolicySetsToDetails.ps1 +++ /dev/null @@ -1,338 +0,0 @@ -function Convert-PolicySetsToDetails { - [CmdletBinding()] - param ( - [hashtable] $AllPolicyDefinitions, - [hashtable] $AllPolicySetDefinitions - ) - - $policyDetails = @{} - Write-Information "Calculating effect parameters for $($AllPolicyDefinitions.psbase.Count) Policies." - foreach ($policyId in $AllPolicyDefinitions.Keys) { - $policy = $AllPolicyDefinitions.$policyId - $properties = Get-PolicyResourceProperties -PolicyResource $policy - $category = "Unknown" - if ($properties.metadata -and $properties.metadata.category) { - $category = $properties.metadata.category - } - $effectRawValue = $properties.policyRule.then.effect - $found, $effectParameterName = Get-ParameterNameFromValueString -ParamValue $effectRawValue - - $effectValue = $null - $effectDefault = $null - $effectAllowedValues = @() - $effectAllowedOverrides = @() - $effectReason = "Policy No Default" - $parameters = $properties.parameters | ConvertTo-HashTable - if ($found) { - if ($parameters.Keys -contains $effectParameterName) { - $effectParameter = $parameters.$effectParameterName - if ($effectParameter.defaultValue) { - $effectValue = $effectParameter.defaultValue - $effectDefault = $effectParameter.defaultValue - $effectReason = "Policy Default" - } - } - else { - Write-Error "Policy uses parameter '$effectParameterName' for the effect not defined in the parameters. This should not be possible!" -ErrorAction Stop - } - if ($effectParameter.allowedValues) { - $effectAllowedValues = $effectParameter.allowedValues - $effectAllowedOverrides = $effectParameter.allowedValues - } - } - else { - # Fixed value - $effectValue = $effectRawValue - $effectDefault = $effectRawValue - $effectAllowedValues = @( $effectDefault ) - $effectReason = "Policy Fixed" - } - if ($effectAllowedOverrides.Count -eq 0) { - # Analyze Policy - $then = $properties.policyRule.then - $details = $then.details - $denyAction = $details -and $details.actionNames - $auditIfNotExists = $details -and $details.existenceCondition - $deployIfNotExists = $auditIfNotExists -and $details.deployment - $modify = $details -and $details.operations - $manual = $details -and $details.defaultState - $append = $details -and $details -is [array] - - if ($denyAction) { - $effectAllowedOverrides = @("Disabled", "DenyAction") - } - elseif ($manual) { - $effectAllowedOverrides = @("Disabled", "Manual") - } - elseif ($deployIfNotExists) { - $effectAllowedOverrides = @("Disabled", "AuditIfNotExists", "DeployIfNotExists") - } - elseif ($auditIfNotExists) { - $effectAllowedOverrides = @("Disabled", "AuditIfNotExists") - } - elseif ($modify) { - $effectAllowedOverrides = @("Disabled", "Audit", "Modify") - } - elseif ($append) { - $effectAllowedOverrides = @("Disabled", "Audit", "Deny", "Append") - } - else { - if ($effectReason -eq "Policy Fixed") { - if ($effectValue -eq "deny") { - $effectAllowedOverrides = @("Disabled", "Audit", "Deny") - } - elseif ($effectValue -eq "audit") { - $effectAllowedOverrides = @("Disabled", "Audit", "Deny") # Safe assumption if Audit or Disabled - deny is a valid case as well - see ALZ deny-unmanageddisk - } - else { - # Disabled: very weird for hard coded - $effectAllowedOverrides = @("Disabled", "Audit") # Safe assumption - } - } - else { - if ($effectDefault -eq "deny") { - $effectAllowedOverrides = @("Disabled", "Audit", "Deny") - } - else { - $effectAllowedOverrides = @("Disabled", "Audit", "Deny") # Guess, could be @("Disabled", "Audit") - } - } - } - } - - $displayName = $properties.displayName - if (-not $displayName -or $displayName -eq "") { - $displayName = $policy.name - } - - $description = $properties.description - if (-not $description) { - $description = "" - } - - $parameterDefinitions = @{} - foreach ($parameterName in $parameters.Keys) { - $parameter = $parameters.$parameterName - $parameterDefinition = @{ - isEffect = $parameterName -eq $effectParameterName - value = $null - defaultValue = $parameter.defaultValue - definition = $parameter - } - $null = $parameterDefinitions.Add($parameterName, $parameterDefinition) - } - - $policyDetail = @{ - id = $policyId - name = $policy.name - displayName = $displayName - description = $description - policyType = $properties.policyType - category = $category - effectParameterName = $effectParameterName - effectValue = $effectValue - effectDefault = $effectDefault - effectAllowedValues = $effectAllowedValues - effectAllowedOverrides = $effectAllowedOverrides - effectReason = $effectReason - parameters = $parameterDefinitions - } - $null = $policyDetails.Add($policyId, $policyDetail) - } - - Write-Information "Calculating effect parameters for $($AllPolicySetDefinitions.psbase.Count) Policy Sets." - $policySetDetails = @{} - foreach ($policySetId in $AllPolicySetDefinitions.Keys) { - $policySet = $AllPolicySetDefinitions.$policySetId - $properties = Get-PolicyResourceProperties -PolicyResource $policySet - $category = "Unknown" - if ($properties.metadata -and $properties.metadata.category) { - $category = $properties.metadata.category - } - - [System.Collections.ArrayList] $policyInPolicySetDetailList = [System.Collections.ArrayList]::new() - $policySetParameters = Get-DeepClone $properties.parameters -AsHashTable - $parametersAlreadyCovered = @{} - foreach ($policyInPolicySet in $properties.policyDefinitions) { - $policyId = $policyInPolicySet.policyDefinitionId - if ($policyDetails.ContainsKey($policyId)) { - $policyDetail = $policyDetails.$policyId - $policyInPolicySetParameters = $policyInPolicySet.parameters | ConvertTo-HashTable - - $policySetLevelEffectParameterName = $null - $effectParameterName = $policyDetail.effectParameterName - $effectValue = $policyDetail.effectValue - $effectDefault = $policyDetail.effectDefault - $effectAllowedValues = $policyDetail.effectAllowedValues - $effectAllowedOverrides = $policyDetail.effectAllowedOverrides - $effectReason = $policyDetail.effectReason - - $policySetLevelEffectParameterFound = $false - $policySetLevelEffectParameterName = "" - if ($effectReason -ne "Policy Fixed") { - # Effect is parameterized in Policy - if ($policyInPolicySetParameters.Keys -contains $effectParameterName) { - # Effect parameter is used by policySet - $policyInPolicySetParameter = $policyInPolicySetParameters.$effectParameterName - if ($null -eq $policyInPolicySetParameter) { - $key1 = $policyInPolicySetParameters.Keys | Where-Object { $_.ToLower() -eq $effectParameterName.ToLower() } - Write-Debug "key '$effectParameterName' exists with a different case '$key1' in '$($policyInPolicySetParameters | ConvertTo-Json -Depth 100 -Compress)'" - if ($null -ne $key1) { - $policyInPolicySetParameter = $policyInPolicySetParameters.$key1 - } - # else keep $policyInPolicySetParameter as $null - } - $policySetLevelEffectParameterFound = $false - $policySetLevelEffectParameterName = $null - if ($policyInPolicySetParameter) { - $effectRawValue = $policyInPolicySetParameter.value - $policySetLevelEffectParameterFound, $policySetLevelEffectParameterName = Get-ParameterNameFromValueString -ParamValue $effectRawValue - } - - if ($policySetLevelEffectParameterFound) { - # Effect parameter is surfaced by PolicySet - if ($policySetParameters.Keys -contains $policySetLevelEffectParameterName) { - $effectParameter = $policySetParameters.$policySetLevelEffectParameterName - if ($effectParameter.defaultValue) { - $effectValue = $effectParameter.defaultValue - $effectDefault = $effectParameter.defaultValue - $effectReason = "PolicySet Default" - } - else { - $effectReason = "PolicySet No Default" - - } - if ($effectParameter.allowedValues) { - $effectAllowedValues = $effectParameter.allowedValues - } - } - else { - Write-Error "Policy '$($policyId)', referenceId '$($policyInPolicySet.policyDefinitionReferenceId)' tries to pass an unknown Policy Set parameter '$policySetLevelEffectParameterName' to the Policy parameter '$effectParameterName'. Check the spelling of the parameters occurrences in the Policy Set." -ErrorAction Stop - } - } - else { - # Effect parameter is hard-coded (fixed) by PolicySet - $policySetLevelEffectParameterName = $null - $effectValue = $effectRawValue - $effectDefault = $effectRawValue - $effectReason = "PolicySet Fixed" - } - } - } - - # Process Policy parameters surfaced by PolicySet - $surfacedParameters = @{} - foreach ($parameterName in $policyInPolicySetParameters.Keys) { - $parameter = $policyInPolicySetParameters.$parameterName - $rawValue = $parameter.value - if ($rawValue -is [string]) { - $found, $policySetParameterName = Get-ParameterNameFromValueString -ParamValue $rawValue - if ($found) { - $policySetParameter = $policySetParameters.$policySetParameterName - $multiUse = $false - $defaultValue = $policySetParameter.defaultValue - $isEffect = $policySetParameterName -eq $policySetLevelEffectParameterName - if ($parametersAlreadyCovered.ContainsKey($policySetParameterName)) { - $multiUse = $true - } - else { - $null = $parametersAlreadyCovered.Add($policySetParameterName, $true) - } - $null = $surfacedParameters.Add($policySetParameterName, @{ - multiUse = $multiUse - isEffect = $isEffect - value = $defaultValue - defaultValue = $defaultValue - definition = $policySetParameter - } - ) - } - } - } - - # Assemble the info - $groupNames = @() - if ($policyInPolicySet.groupNames) { - $groupNames = $policyInPolicySet.groupNames - } - $policyInPolicySetDetail = @{ - id = $policyDetail.id - name = $policyDetail.name - displayName = $policyDetail.displayName - description = $policyDetail.description - policyType = $policyDetail.policyType - category = $policyDetail.category - effectParameterName = $policySetLevelEffectParameterName - effectValue = $effectValue - effectDefault = $effectDefault - effectAllowedValues = $effectAllowedValues - effectAllowedOverrides = $effectAllowedOverrides - effectReason = $effectReason - parameters = $surfacedParameters - policyDefinitionReferenceId = $policyInPolicySet.policyDefinitionReferenceId - groupNames = $groupNames - } - $null = $policyInPolicySetDetailList.Add($policyInPolicySetDetail) - } - else { - # This is a Policy of policyType static used for compliance purposes and not accessible to this code - # SKIP - } - } - - # Assemble Policy Set info - $displayName = $properties.displayName - if (-not $displayName -or $displayName -eq "") { - $displayName = $policySet.name - } - - $description = $properties.description - if (-not $description) { - $description = "" - } - - # Find Policies appearing more than once in PolicySet - $uniquePolicies = @{} - $policiesWithMultipleReferenceIds = @{} - foreach ($policyInPolicySetDetail in $policyInPolicySetDetailList) { - $policyId = $policyInPolicySetDetail.id - $policyDefinitionReferenceId = $policyInPolicySetDetail.policyDefinitionReferenceId - if ($uniquePolicies.ContainsKey($policyId)) { - if (-not $policiesWithMultipleReferenceIds.ContainsKey($policyId)) { - # First time detecting that this Policy has multiple references in the same PolicySet - $uniquePolicyReferenceIds = $uniquePolicies[$policyId] - $null = $policiesWithMultipleReferenceIds.Add($policyId, $uniquePolicyReferenceIds) - } - # Add current policyDefinitionReferenceId - $multipleReferenceIds = $policiesWithMultipleReferenceIds[$policyId] - $multipleReferenceIds += $policyDefinitionReferenceId - $policiesWithMultipleReferenceIds[$policyId] = $multipleReferenceIds - } - else { - # First time encounter in this PolicySet. Record Policy Id and remember policyDefinitionReferenceId - $null = $uniquePolicies.Add($policyId, @( $policyDefinitionReferenceId )) - } - } - - $policySetDetail = @{ - id = $policySetId - name = $policySet.name - displayName = $displayName - description = $description - policyType = $properties.policyType - category = $category - parameters = $policySetParameters - policyDefinitions = $policyInPolicySetDetailList.ToArray() - policiesWithMultipleReferenceIds = $policiesWithMultipleReferenceIds - } - $null = $policySetDetails.Add($policySetId, $policySetDetail) - } - - # Assemble result - $combinedPolicyDetails = @{ - policies = $policyDetails - policySets = $policySetDetails - } - - return $combinedPolicyDetails -} diff --git a/Scripts/Helpers/Convert-PolicyToDetails.ps1 b/Scripts/Helpers/Convert-PolicyToDetails.ps1 new file mode 100644 index 00000000..22df9b58 --- /dev/null +++ b/Scripts/Helpers/Convert-PolicyToDetails.ps1 @@ -0,0 +1,139 @@ +function Convert-PolicyToDetails { + [CmdletBinding()] + param ( + $PolicyId, + $PolicyDefinition, + $PolicyDetails + ) + + $properties = Get-PolicyResourceProperties -PolicyResource $PolicyDefinition + $category = "Unknown" + if ($properties.metadata -and $properties.metadata.category) { + $category = $properties.metadata.category + } + $effectRawValue = $properties.policyRule.then.effect + $found, $effectParameterName = Get-ParameterNameFromValueString -ParamValue $effectRawValue + + $effectValue = $null + $effectDefault = $null + $effectAllowedValues = @() + $effectAllowedOverrides = @() + $effectReason = "Policy No Default" + $parameters = $properties.parameters | ConvertTo-HashTable + if ($found) { + if ($parameters.Keys -contains $effectParameterName) { + $effectParameter = $parameters.$effectParameterName + if ($effectParameter.defaultValue) { + $effectValue = $effectParameter.defaultValue + $effectDefault = $effectParameter.defaultValue + $effectReason = "Policy Default" + } + } + else { + Write-Error "Policy uses parameter '$effectParameterName' for the effect not defined in the parameters. This should not be possible!" -ErrorAction Stop + } + if ($effectParameter.allowedValues) { + $effectAllowedValues = $effectParameter.allowedValues + $effectAllowedOverrides = $effectParameter.allowedValues + } + } + else { + # Fixed value + $effectValue = $effectRawValue + $effectDefault = $effectRawValue + $effectAllowedValues = @( $effectDefault ) + $effectReason = "Policy Fixed" + } + if ($effectAllowedOverrides.Count -eq 0) { + # Analyze Policy + $then = $properties.policyRule.then + $details = $then.details + $denyAction = $details -and $details.actionNames + $auditIfNotExists = $details -and $details.existenceCondition + $deployIfNotExists = $auditIfNotExists -and $details.deployment + $modify = $details -and $details.operations + $manual = $details -and $details.defaultState + $append = $details -and $details -is [array] + + if ($denyAction) { + $effectAllowedOverrides = @("Disabled", "DenyAction") + } + elseif ($manual) { + $effectAllowedOverrides = @("Disabled", "Manual") + } + elseif ($deployIfNotExists) { + $effectAllowedOverrides = @("Disabled", "AuditIfNotExists", "DeployIfNotExists") + } + elseif ($auditIfNotExists) { + $effectAllowedOverrides = @("Disabled", "AuditIfNotExists") + } + elseif ($modify) { + $effectAllowedOverrides = @("Disabled", "Audit", "Modify") + } + elseif ($append) { + $effectAllowedOverrides = @("Disabled", "Audit", "Deny", "Append") + } + else { + if ($effectReason -eq "Policy Fixed") { + if ($effectValue -eq "deny") { + $effectAllowedOverrides = @("Disabled", "Audit", "Deny") + } + elseif ($effectValue -eq "audit") { + $effectAllowedOverrides = @("Disabled", "Audit", "Deny") # Safe assumption if Audit or Disabled - deny is a valid case as well - see ALZ deny-unmanageddisk + } + else { + # Disabled: very weird for hard coded + $effectAllowedOverrides = @("Disabled", "Audit") # Safe assumption + } + } + else { + if ($effectDefault -eq "deny") { + $effectAllowedOverrides = @("Disabled", "Audit", "Deny") + } + else { + $effectAllowedOverrides = @("Disabled", "Audit", "Deny") # Guess, could be @("Disabled", "Audit") + } + } + } + } + + $displayName = $properties.displayName + if (-not $displayName -or $displayName -eq "") { + $displayName = $PolicyDefinition.name + } + + $description = $properties.description + if (-not $description) { + $description = "" + } + + $parameterDefinitions = @{} + foreach ($parameterName in $parameters.Keys) { + $parameter = $parameters.$parameterName + $parameterDefinition = @{ + isEffect = $parameterName -eq $effectParameterName + value = $null + defaultValue = $parameter.defaultValue + definition = $parameter + } + $null = $parameterDefinitions.Add($parameterName, $parameterDefinition) + } + + $name = $PolicyDefinition.name + $policyDetail = @{ + id = $PolicyId + name = $name + displayName = $displayName + description = $description + policyType = $properties.policyType + category = $category + effectParameterName = $effectParameterName + effectValue = $effectValue + effectDefault = $effectDefault + effectAllowedValues = $effectAllowedValues + effectAllowedOverrides = $effectAllowedOverrides + effectReason = $effectReason + parameters = $parameterDefinitions + } + $null = $PolicyDetails.Add($PolicyId, $policyDetail) +} diff --git a/Scripts/Helpers/ConvertTo-HashTable.ps1 b/Scripts/Helpers/ConvertTo-HashTable.ps1 index 039cb027..ca687a96 100644 --- a/Scripts/Helpers/ConvertTo-HashTable.ps1 +++ b/Scripts/Helpers/ConvertTo-HashTable.ps1 @@ -1,4 +1,4 @@ -function ConvertTo-HashTable { +function ConvertTo-HashTable { [CmdletBinding()] param ( @@ -25,5 +25,4 @@ function ConvertTo-HashTable { } } return $hashTable - } diff --git a/Scripts/Helpers/Find-AzNonCompliantResources.ps1 b/Scripts/Helpers/Find-AzNonCompliantResources.ps1 index 0c2aa6e3..e0aa4059 100644 --- a/Scripts/Helpers/Find-AzNonCompliantResources.ps1 +++ b/Scripts/Helpers/Find-AzNonCompliantResources.ps1 @@ -3,12 +3,12 @@ function Find-AzNonCompliantResources { param ( [switch] $RemediationOnly, $PacEnvironment, - [switch] $OnlyCheckManagedAssignments, [string[]] $PolicyDefinitionFilter, [string[]] $PolicySetDefinitionFilter, [string[]] $PolicyAssignmentFilter, [string[]] $PolicyExemptionFilter, [string[]] $PolicyEffectFilter, + [switch] $OnlyCheckManagedAssignments, [switch] $ExcludeManualPolicyEffect ) @@ -60,7 +60,7 @@ function Find-AzNonCompliantResources { $query = "policyresources | where type == `"microsoft.policyinsights/policystates`" and properties.complianceState <> `"Compliant`"$($effectFilter)" } Write-Information "Az Graph Query: '$query'" - $result = @() + (Search-AzGraphAllItems -Query $query -Scope @{ UseTenantScope = $true } -ProgressItemName "Policy compliance records") + $result = @() + (Search-AzGraphAllItems -Query $query -ProgressItemName "Policy compliance records") Write-Information "" $rawNonCompliantList = [System.Collections.ArrayList]::new() @@ -68,60 +68,62 @@ function Find-AzNonCompliantResources { $scopeTable = $null if ($result.Count -ne 0) { # Get all Policy Assignments, Policy Definitions and Policy Set Definitions - $scopeTable = Get-AzScopeTree -PacEnvironment $PacEnvironment - $notOnlyCheckManagedAssignments = -not $OnlyCheckManagedAssignments - $deployedPolicyResources = Get-AzPolicyResources -PacEnvironment $PacEnvironment -ScopeTable $scopeTable -SkipExemptions -SkipRoleAssignments -CollectAllPolicies:$notOnlyCheckManagedAssignments + $scopeTable = Build-ScopeTableForDeploymentRootScope -PacEnvironment $PacEnvironment + $deployedPolicyResources = Get-AzPolicyResources -PacEnvironment $PacEnvironment -ScopeTable $scopeTable -SkipExemptions -SkipRoleAssignments $allAssignments = $deployedPolicyResources.policyassignments.managed - $strategy = $pacEnvironment.desiredState.strategy # Filter result - if (-not $OnlyCheckManagedAssignments -and -not $PolicyDefinitionFilter -and -not $PolicySetDefinitionFilter -and -not $PolicyAssignmentFilter) { - $null = $rawNonCompliantList.AddRange($result) - } - else { - foreach ($entry in $result) { - $entryProperties = $entry.properties - $policyAssignmentId = $entryProperties.policyAssignmentId - if ($allAssignments.ContainsKey($policyAssignmentId)) { - $entryToAdd = $null - $assignment = $allAssignments.$policyAssignmentId - $assignmentPacOwner = $assignment.pacOwner - if (-not $OnlyCheckManagedAssignments -or ($assignmentPacOwner -eq "thisPaC" -or ($assignmentPacOwner -eq "unknownOwner" -and $strategy -eq "full"))) { - if ($PolicyDefinitionFilter -or $PolicySetDefinitionFilter -or $PolicyAssignmentFilter) { - if ($PolicyDefinitionFilter) { - foreach ($filterValue in $PolicyDefinitionFilter) { - if ($entryProperties.policyDefinitionName -eq $filterValue -or $entryProperties.policyDefinitionId -eq $filterValue) { - $entryToAdd = $entry - break - } + foreach ($entry in $result) { + $entryProperties = $entry.properties + $policyAssignmentId = $entryProperties.policyAssignmentId + if ($allAssignments.ContainsKey($policyAssignmentId)) { + $entryToAdd = $null + $assignment = $allAssignments.$policyAssignmentId + $assignmentPacOwner = $assignment.pacOwner + $process = $false + if ($OnlyCheckManagedAssignments -and $assignmentPacOwner -ne "otherPaC" -and $assignmentPacOwner -ne "unknownOwner") { + # owned by the PaC solution of auto-created by Defender for Cloud (DfC) + $process = $true + } + else { + $process = $true + } + if ($process) { + if ($PolicyDefinitionFilter -or $PolicySetDefinitionFilter -or $PolicyAssignmentFilter) { + if ($PolicyDefinitionFilter) { + foreach ($filterValue in $PolicyDefinitionFilter) { + if ($entryProperties.policyDefinitionName -eq $filterValue -or $entryProperties.policyDefinitionId -eq $filterValue) { + $entryToAdd = $entry + break } } - if (!$entryToAdd -and $PolicySetDefinitionFilter) { - foreach ($filterValue in $PolicySetDefinitionFilter) { - if ($entryProperties.policySetDefinitionName -eq $filterValue -or $entryProperties.policySetDefinitionId -eq $filterValue) { - $entryToAdd = $entry - break - } + } + if (!$entryToAdd -and $PolicySetDefinitionFilter) { + foreach ($filterValue in $PolicySetDefinitionFilter) { + if ($entryProperties.policySetDefinitionName -eq $filterValue -or $entryProperties.policySetDefinitionId -eq $filterValue) { + $entryToAdd = $entry + break } } - if (!$entryToAdd -and $PolicyAssignmentFilter) { - foreach ($filterValue in $PolicyAssignmentFilter) { - if ($entryProperties.policyAssignmentName -eq $filterValue -or $entryProperties.policyAssignmentId -eq $filterValue) { - $entryToAdd = $entry - break - } + } + if (!$entryToAdd -and $PolicyAssignmentFilter) { + foreach ($filterValue in $PolicyAssignmentFilter) { + if ($entryProperties.policyAssignmentName -eq $filterValue -or $entryProperties.policyAssignmentId -eq $filterValue) { + $entryToAdd = $entry + break } } } - else { - $entryToAdd = $entry - } } - if ($entryToAdd) { - $null = $rawNonCompliantList.Add($entryToAdd) + else { + $entryToAdd = $entry } } + if ($null -ne $entryToAdd) { + $null = $rawNonCompliantList.Add($entryToAdd) + } } } + } Write-Information "Found $($rawNonCompliantList.Count) non-compliant resources" Write-Information "" diff --git a/Scripts/Helpers/Get-AzPolicyAssignments.ps1 b/Scripts/Helpers/Get-AzPolicyAssignments.ps1 new file mode 100644 index 00000000..9d980886 --- /dev/null +++ b/Scripts/Helpers/Get-AzPolicyAssignments.ps1 @@ -0,0 +1,240 @@ +function Get-AzPolicyAssignments { + [CmdletBinding()] + param ( + $DeployedPolicyResources, + $PacEnvironment, + $ScopeTable, + $SkipRoleAssignments + ) + + $thisPacOwnerId = $PacEnvironment.pacOwnerId + $desiredState = $PacEnvironment.desiredState + $excludedPolicyResources = $desiredState.excludedPolicyAssignments + $environmentTenantId = $PacEnvironment.tenantId + $rootScopeDetails = $ScopeTable.root + $excludedScopesTable = $rootScopeDetails.excludedScopesTable + + $query = "PolicyResources | where type == 'microsoft.authorization/policyassignments'" + $ProgressItemName = "Policy Assignments" + $policyResources = Search-AzGraphAllItems -Query $query -ProgressItemName $ProgressItemName + + $policyResourcesTable = $DeployedPolicyResources.policyassignments + $uniquePrincipalIds = @{} + foreach ($policyResourceRaw in $policyResources) { + $resourceTenantId = $policyResourceRaw.tenantId + if ($resourceTenantId -in @($null, "", $environmentTenantId)) { + $policyResource = Get-ClonedObject $policyResourceRaw -AsHashTable -AsShallowClone + $id = $policyResource.id + $testId = $id + $properties = Get-PolicyResourceProperties $policyResource + $included = $true + $resourceIdParts = $null + $included, $resourceIdParts = Confirm-PolicyResourceExclusions ` + -TestId $testId ` + -ResourceId $id ` + -ScopeTable $ScopeTable ` + -ExcludedScopesTable $excludedScopesTable ` + -ExcludedIds $excludedPolicyResources ` + -PolicyResourceTable $policyResourcesTable + if ($included) { + $scope = $resourceIdParts.scope + $policyResource.resourceIdParts = $resourceIdParts + $policyResource.scope = $scope + $policyResource.pacOwner = Confirm-PacOwner -ThisPacOwnerId $thisPacOwnerId -PolicyResource $policyResource -Scope $scope -ManagedByCounters $policyResourcesTable.counters.managedBy + if ($policyResource.identity -and $policyResource.identity.type -ne "None") { + $principalId = "" + if ($policyResource.identity.type -eq "SystemAssigned") { + $principalId = $policyResource.identity.principalId + } + else { + $userAssignedIdentityId = $policyResource.identity.userAssignedIdentities.PSObject.Properties.Name + $principalId = $policyResource.identity.userAssignedIdentities.$userAssignedIdentityId.principalId + } + $uniquePrincipalIds[$principalId] = $true + $policyResourcesTable.counters.withIdentity += 1 + } + $null = $policyResourcesTable.managed.Add($id, $policyResource) + } + else { + Write-Verbose "Policy Assignment $id excluded" + } + } + } + + if (-not $skipRoleAssignmentsLocal) { + $DeployedPolicyResources.numberOfPrincipleIds = $uniquePrincipalIds.Count + $managedRoleAssignmentsByPrincipalId = $DeployedPolicyResources.roleAssignmentsByPrincipalId + $roleAssignments = [System.Collections.ArrayList]::new() + $roleDefinitions = [System.Collections.ArrayList]::new() + $principalIds = '"' + ($uniquePrincipalIds.Keys -join '", "') + '"' + $ProgressItemName = "Role Assignments" + if ($PacEnvironment.Cloud -in @("AzureChinaCloud", "AzureUSGovernment")) { + # if ($PacEnvironment.Cloud -notin @("AzureChinaCloud", "AzureUSGovernment")) { + # test normal environment + $roleAssignmentsCount = 0 + $roleAssignmentsLastCount = 0 + $roleAssignmentsProcessed = @{} + $roleDefinitionsProcessed = @{} + foreach ($scopeId in $ScopeTable.Keys) { + $scopeInformation = $ScopeTable.$scopeId + if ($scopeInformation.type -ne "microsoft.resources/subscriptions/resourceGroups" -and $scopeId -ne "root") { + $roleAssignmentsLocal = Get-AzRoleAssignmentsRestMethod -Scope $scopeId -ApiVersion $PacEnvironment.apiVersions.roleAssignments + $roleAssignmentsCount += $roleAssignmentsLocal.Count + if (($roleAssignmentsLastCount + 10000) -le $roleAssignmentsCount) { + Write-Information "Retrieved $roleAssignmentsCount $($ProgressItemName)" + $roleAssignmentsLastCount = $roleAssignmentsCount + } + foreach ($roleAssignment in $roleAssignmentsLocal) { + if ($uniquePrincipalIds.ContainsKey($roleAssignment.properties.principalId)) { + $id = $roleAssignment.id + if (!$roleAssignmentsProcessed.ContainsKey($id)) { + $null = $roleAssignmentsProcessed.Add($id, $true) + $null = $roleAssignments.Add($roleAssignment) + } + } + } + + } + } + if ($roleAssignmentsCount -gt $roleAssignmentsLastCount) { + Write-Information "Retrieved $roleAssignmentsCount $($ProgressItemName), collected $($roleAssignmentsProcessed.Count) unique $($ProgressItemName)" + } + $scopeInformation = $ScopeTable.root + $scopeId = $scopeInformation.id + $roleDefinitionsLocal = Get-AzRoleDefinitionsRestMethod -Scope $scopeId -ApiVersion $PacEnvironment.apiVersions.roleAssignments + $roleDefinitionsCount += $roleDefinitionsLocal.Count + foreach ($roleDefinition in $roleDefinitionsLocal) { + $id = $roleDefinition.id + if ($id.StartsWith("/subscriptions/")) { + $possibleScopeId = ($id -split '/', 5)[1..2] -join '/' + $subscriptionLevelRoleDefinition = $false + foreach ($assignableScope in $roleDefinition.properties.assignableScopes) { + if ($assignableScope.StartsWith("$possibleScopeId")) { + if (!$roleDefinitionsProcessed.ContainsKey($id)) { + $null = $roleDefinitionsProcessed.Add($id, $true) + $null = $roleDefinitions.Add($roleDefinition) + } + $subscriptionLevelRoleDefinition = $true + break + } + } + if (-not $subscriptionLevelRoleDefinition) { + $id = $id -replace $possibleScopeId, "" + $roleDefinition.id = $id + if (!$roleDefinitionsProcessed.ContainsKey($id)) { + $null = $roleDefinitionsProcessed.Add($id, $true) + $null = $roleDefinitions.Add($roleDefinition) + } + } + } + elseif (!$roleDefinitionsProcessed.ContainsKey($id)) { + $null = $roleDefinitionsProcessed.Add($id, $true) + $null = $roleDefinitions.Add($roleDefinition) + } + } + Write-Information "Retrieved $($roleDefinitionsProcessed.Count) unique Role Definitions" + } + else { + $roleAssignmentsLocal = Search-AzGraphAllItems ` + -Query "authorizationresources | where type == `"microsoft.authorization/roleassignments`" and properties.principalId in ( $principalIds )" ` + -ProgressItemName "Role Assignments" ` + -ProgressIncrement 1000 + $null = $roleAssignments.AddRange($roleAssignmentsLocal) + + $roleDefinitionsLocal = Search-AzGraphAllItems ` + -Query 'authorizationresources | where type == "microsoft.authorization/roledefinitions"' ` + -ProgressItemName "Role Definitions" ` + -ProgressIncrement 1000 + $null = $roleDefinitions.AddRange($roleDefinitionsLocal) + } + + if ($null -ne $PacEnvironment.managingTenantId) { + foreach ($subscription in $PacEnvironment.managingTenantRootScope) { + $remoteAssignments = Get-AzRoleAssignmentsRestMethod -Scope $subscription -ApiVersion $PacEnvironment.apiVersions.roleAssignments -Tenant $PacEnvironment.managingTenantId + foreach ($assignment in $remoteAssignments) { + #if the remote assignment is attached to a principal we are looking at then add to the known role assignments object ($roleAssignments) + if ($uniquePrincipalIds.ContainsKey($assignment.properties.principalId)) { + #Create object with necessary data to normalize + $roleAssignmentObj = @{ + id = $assignment.id + name = $assignment.name + properties = @{ + scope = $assignment.properties.scope + principalType = $assignment.properties.principalType + principalId = $assignment.properties.principalId + description = $assignment.properties.description + roleDefinitionId = "/" + ($assignment.properties.roleDefinitionId -split '/', 4)[3] -join '/' + } + displayName = "" + crossTenant = $true + } + $null = $roleAssignments.Add($roleAssignmentObj) + $DeployedPolicyResources.remoteAssignmentsCount += 1 + } + } + } + Write-Information "Retrieved $($DeployedPolicyResources.remoteAssignmentsCount) remote Role Assignments" + } + + $roleDefinitionsHt = $DeployedPolicyResources.roleDefinitions + foreach ($roleDefinition in $roleDefinitions) { + $roleDefinitionId = $roleDefinition.id + $roleDefinitionId = $roleDefinition.id + $roleDefinitionName = $roleDefinition.name + $roleDefinitionRoleName = $roleDefinition.properties.roleName + $null = $roleDefinitionsHt.Add($roleDefinitionId, $roleDefinitionRoleName) + $null = $roleDefinitionsHt.Add($roleDefinitionName, $roleDefinitionRoleName) + } + + # loop through the collected role assignments to collate by principalId + foreach ($roleAssignment in $roleAssignments) { + $properties = $roleAssignment.properties + $principalId = $roleAssignment.properties.principalId + $roleDefinitionId = $properties.roleDefinitionId + $roleDefinitionName = ($roleDefinitionId -split '/')[-1] + $roleDefinitionRoleName = $roleDefinitionName + $crossTenant = $roleAssignment.crossTenant + if ($roleDefinitionsHt.ContainsKey($roleDefinitionId)) { + $roleDefinitionRoleName = $roleDefinitionsHt.$roleDefinitionId + } + elseif ($roleDefinitionId.StartsWith("/subscriptions/")) { + $subscriptionId = ($roleDefinitionId -split '/')[0..2] -join '/' + $roleDefinitionId = $roleDefinitionId -replace $subscriptionId, "" + if ($roleDefinitionsHt.ContainsKey($roleDefinitionId)) { + $roleDefinitionRoleName = $roleDefinitionsHt.$roleDefinitionId + } + elseif ($roleDefinitionsHt.ContainsKey($roleDefinitionName)) { + $roleDefinitionRoleName = $roleDefinitionsHt.$roleDefinitionId + } + } + elseif ($roleDefinitionsHt.ContainsKey($roleDefinitionName)) { + $roleDefinitionRoleName = $roleDefinitionsHt.$roleDefinitionId + } + $normalizedRoleAssignment = @{ + id = $roleAssignment.id + name = $roleAssignment.name + scope = $properties.scope + displayName = "" + description = $properties.description + objectType = $properties.principalType + principalId = $principalId + roleDefinitionId = $roleDefinitionId + roleDisplayName = $roleDefinitionRoleName + } + if ($crossTenant -eq $true) { + $normalizedRoleAssignment["crossTenant"] = $true + } + $DeployedPolicyResources.numberOfRoleAssignments += 1 + + $normalizedRoleAssignments = [System.Collections.ArrayList]::new() + if ($managedRoleAssignmentsByPrincipalId.ContainsKey($principalId)) { + $normalizedRoleAssignments = $managedRoleAssignmentsByPrincipalId.$principalId + } + else { + $null = $managedRoleAssignmentsByPrincipalId.Add($principalId, $normalizedRoleAssignments) + } + $null = $normalizedRoleAssignments.Add($normalizedRoleAssignment) + } + } +} + diff --git a/Scripts/Helpers/Get-AzPolicyExemptions.ps1 b/Scripts/Helpers/Get-AzPolicyExemptions.ps1 new file mode 100644 index 00000000..7ac2966b --- /dev/null +++ b/Scripts/Helpers/Get-AzPolicyExemptions.ps1 @@ -0,0 +1,187 @@ +function Get-AzPolicyExemptions { + [CmdletBinding()] + param ( + $DeployedPolicyResources, + $PacEnvironment, + $ScopeTable + ) + + $desiredState = $PacEnvironment.desiredState + $excludedPolicyResources = $desiredState.excludedPolicyAssignments + $rootScopeDetails = $ScopeTable.root + $excludedScopesTable = $rootScopeDetails.excludedScopesTable + + $policyResources = [System.Collections.ArrayList]::new() + $ProgressItemName = "Policy Exemptions" + $now = Get-Date -AsUTC + $resourceIdsExist = @{} + if ($PacEnvironment.cloud -eq "AzureChinaCloud") { + # if ($PacEnvironment.cloud -ne "AzureChinaCloud") { + # test china cloud in normal environment + $count = 0 + $lastCount = 0 + $exemptionsProcessed = @{} + foreach ($scopeId in $ScopeTable.Keys) { + $scopeInformation = $ScopeTable.$scopeId + if ($scopeInformation.type -ne "microsoft.resources/subscriptions/resourceGroups" -and $scopeId -ne "root") { + $exemptionsLocal = @() + if ($scopeInformation.type -eq "microsoft.resources/subscriptions") { + $exemptionsLocal = Get-AzPolicyExemptionsRestMethod -Scope $scopeId -ApiVersion $PacEnvironment.apiVersions.policyExemptions + } + elseif ($scopeInformation.type -eq "Microsoft.Management/managementGroups") { + $exemptionsLocal = Get-AzPolicyExemptionsRestMethod -Scope $scopeId -Filter "atScope()" -ApiVersion $PacEnvironment.apiVersions.policyExemptions + } + $count += $exemptionsLocal.Count + if (($lastCount + 1000) -le $count) { + Write-Information "Retrieved $count $($ProgressItemName)" + $lastCount = $count + } + foreach ($exemption in $exemptionsLocal) { + $id = $exemption.id + if (!$exemptionsProcessed.ContainsKey($id)) { + $null = $exemptionsProcessed.Add($id, $true) + $null = $policyResources.Add($exemption) + } + } + } + } + Write-Information "Retrieved $($count) $($ProgressItemName), collected $($exemptionsProcessed.Count) unique $($ProgressItemName)" + } + else { + $query = "PolicyResources | where type == 'microsoft.authorization/policyexemptions'" + $policyResources = Search-AzGraphAllItems -Query $query -ProgressItemName $ProgressItemName + } + + $thisPacOwnerId = $PacEnvironment.pacOwnerId + $environmentTenantId = $PacEnvironment.tenantId + + $policyResourcesTable = $DeployedPolicyResources.policyexemptions + $policyExemptionsCounters = $policyResourcesTable.counters + + foreach ($policyResourceRaw in $policyResources) { + $resourceTenantId = $policyResourceRaw.tenantId + if ($resourceTenantId -in @($null, "", $environmentTenantId)) { + $policyResource = Get-ClonedObject $policyResourceRaw -AsHashTable -AsShallowClone + $properties = Get-PolicyResourceProperties $policyResource + + $id = $policyResource.id + $name = $policyResource.name + $testId = $properties.policyAssignmentId + + $included, $resourceIdParts = Confirm-PolicyResourceExclusions ` + -TestId $testId ` + -ResourceId $id ` + -ScopeTable $ScopeTable ` + -ExcludedScopesTable $excludedScopesTable ` + -ExcludedIds $excludedPolicyResources ` + -PolicyResourceTable $policyResourcesTable + if ($included) { + $scope = $resourceIdParts.scope + $policyResource.resourceIdParts = $resourceIdParts + $policyResource.scope = $scope + $displayName = $properties.displayName + if ($null -ne $displayName -and $displayName -eq "") { + $displayName = $null + } + $description = $properties.description + if ($null -ne $description -and $description -eq "") { + $description = $null + } + $exemptionCategory = $properties.exemptionCategory + $expiresOnRaw = $properties.expiresOn + $expiresOn = $null + if ($null -ne $expiresOnRaw -and $expiresOnRaw -ne "") { + if ($expiresOnRaw -is [datetime]) { + $expiresOn = $expiresOnRaw.ToUniversalTime + } + else { + $expiresOnDate = [datetime]::Parse($expiresOnRaw) + $expiresOn = $expiresOnDate.ToUniversalTime() + } + $expiresOn = $expiresOnRaw.ToUniversalTime() + } + $metadataRaw = $properties.metadata + $metadata = $null + if ($null -ne $metadataRaw -and $metadataRaw -ne @{} ) { + $metadata = $metadataRaw + } + $policyAssignmentId = $properties.policyAssignmentId + $policyDefinitionReferenceIdsRaw = $properties.policyDefinitionReferenceIds + $policyDefinitionReferenceIds = $null + if ($null -ne $policyDefinitionReferenceIdsRaw -and $policyDefinitionReferenceIdsRaw.Count -gt 0) { + $policyDefinitionReferenceIds = $policyDefinitionReferenceIdsRaw + } + $resourceSelectors = $properties.resourceSelectors + $assignmentScopeValidation = $properties.assignmentScopeValidation + $pacOwner = Confirm-PacOwner -ThisPacOwnerId $thisPacOwnerId -PolicyResource $policyResourceRaw -ManagedByCounters $policyExemptionsCounters.managedBy + $status = "active" + $expiresInDays = [Int32]::MaxValue + if ($expiresOn) { + $expiresIn = New-TimeSpan -Start $now -End $expiresOn + $expiresInDays = $expiresIn.Days + if ($expiresInDays -lt -15) { + $status = "expired-over-15-days" + $policyExemptionsCounters.expired += 1 + } + elseif ($expiresInDays -lt 0) { + $status = "expired-less-within-15-days" + $policyExemptionsCounters.expired += 1 + } + elseif ($expiresInDays -lt 15) { + $status = "active-expiring-within-15-days" + } + } + $isIndividualResource = $true + if ($scope.StartsWith("/providers/Microsoft.Management/management")) { + $isIndividualResource = $false + } + elseif ($scope.Contains("/providers/")) { + $isIndividualResource = $true + } + else { + # subscription, resourceGroup + $isIndividualResource = $false + } + if ($isIndividualResource) { + $thisResourceIdExists = $false + if ($resourceIdsExist.ContainsKey($scope)) { + $thisResourceIdExists = $resourceIdsExist.$scope + } + else { + $resource = Get-AzResource -ResourceId $scope -ErrorAction SilentlyContinue + $thisResourceIdExists = $null -ne $resource + $resourceIdsExist[$scope] = $thisResourceIdExists + } + if (-not $thisResourceIdExists) { + $policyResource.status = "orphaned-resource" + $policyExemptionsCounters.orphaned += 1 + Write-Information "Policy Exemption $id is orphaned (resource $scope does not exist)" + } + } + + $exemption = @{ + id = $id + name = $name + scope = $resourceIdParts.scope + displayName = $displayName + description = $description + exemptionCategory = $exemptionCategory + expiresOn = $expiresOn + metadata = $metadata + policyAssignmentId = $policyAssignmentId + policyDefinitionReferenceIds = $policyDefinitionReferenceIds + resourceSelectors = $resourceSelectors + assignmentScopeValidation = $assignmentScopeValidation + pacOwner = $pacOwner + status = $status + expiresInDays = $expiresInDays + } + $null = $policyResourcesTable.managed.Add($id, $exemption) + } + else { + Write-Verbose "Policy resource $id excluded" + } + } + } +} + diff --git a/Scripts/Helpers/Get-AzPolicyOrSetDefinitions.ps1 b/Scripts/Helpers/Get-AzPolicyOrSetDefinitions.ps1 new file mode 100644 index 00000000..9ca0c806 --- /dev/null +++ b/Scripts/Helpers/Get-AzPolicyOrSetDefinitions.ps1 @@ -0,0 +1,102 @@ +function Get-AzPolicyOrSetDefinitions { + [CmdletBinding()] + param ( + $DefinitionType, + $PolicyResourcesTable, + $PacEnvironment, + $ScopeTable, + $CollectAllPolicies + ) + + $desiredState = $PacEnvironment.desiredState + $rootScopeDetails = $ScopeTable.root + $excludedScopesTable = $rootScopeDetails.excludedScopesTable + $policyDefinitionsScopes = $PacEnvironment.policyDefinitionsScopes + $scopesLength = $policyDefinitionsScopes.Length + $scopesLast = $scopesLength - 1 + $thisPacOwnerId = $PacEnvironment.pacOwnerId + $environmentTenantId = $PacEnvironment.tenantId + + + $query = $null + $progressItemName = $null + $excludedIds = $null + switch ($DefinitionType) { + policyDefinitions { + $query = "PolicyResources | where type == 'microsoft.authorization/policydefinitions'" + $progressItemName = "Policy definitions" + $excludedIds = $desiredState.excludedPolicyDefinitions + } + policySetDefinitions { + $query = "PolicyResources | where type == 'microsoft.authorization/policysetdefinitions'" + $progressItemName = "Policy Set definitions" + $excludedIds = $desiredState.excludedPolicySetDefinitions + } + } + + $policyResources = Search-AzGraphAllItems -Query $query -ProgressItemName $progressItemName + foreach ($policyResourceRaw in $policyResources) { + $resourceTenantId = $policyResourceRaw.tenantId + if ($resourceTenantId -in @($null, "", $environmentTenantId)) { + $policyResource = Get-ClonedObject $policyResourceRaw -AsHashTable -AsShallowClone + $id = $policyResource.id + $testId = $id + $included, $resourceIdParts = Confirm-PolicyResourceExclusions ` + -TestId $testId ` + -ResourceId $id ` + -ScopeTable $ScopeTable ` + -ExcludedScopesTable $excludedScopesTable ` + -ExcludedIds $excludedIds ` + -PolicyResourceTable $PolicyResourcesTable + if ($included) { + $scope = $resourceIdParts.scope + $policyResource.resourceIdParts = $resourceIdParts + $policyResource.scope = $scope + $found = $false + for ($i = 0; $i -lt $scopesLength -and !$found; $i++) { + $currentScopeId = $policyDefinitionsScopes[$i] + if ($resourceIdParts.scope -eq $currentScopeId) { + switch ($i) { + 0 { + # deploymentRootScope + $policyResource.pacOwner = Confirm-PacOwner -ThisPacOwnerId $thisPacOwnerId -PolicyResource $policyResource -Scope $scope -ManagedByCounters $PolicyResourcesTable.counters.managedBy + $null = $PolicyResourcesTable.all.Add($id, $policyResource) + $null = $PolicyResourcesTable.managed.Add($id, $policyResource) + $found = $true + } + $scopesLast { + # BuiltIn or Static, since last entry in array is empty string ($currentPolicyDefinitionsScopeId) + $policyResource.pacOwner = "readOnly" + $null = $PolicyResourcesTable.all.Add($id, $policyResource) + $null = $PolicyResourcesTable.readOnly.Add($id, $policyResource) + $PolicyResourcesTable.counters.builtIn += 1 + $found = $true + } + Default { + # Read only definitions scopes + $policyResource.pacOwner = "builtin" + $null = $PolicyResourcesTable.all.Add($id, $policyResource) + $null = $PolicyResourcesTable.readOnly.Add($id, $policyResource) + $PolicyResourcesTable.counters.inherited += 1 + $found = $true + } + } + } + } + if (!$found) { + if ($CollectAllPolicies) { + $policyResource.pacOwner = Confirm-PacOwner -ThisPacOwnerId $thisPacOwnerId -PolicyResource $policyResource -ManagedByCounters $PolicyResourcesTable.counters.managedBy + $null = $PolicyResourcesTable.all.Add($id, $policyResource) + $null = $PolicyResourcesTable.managed.Add($id, $policyResource) + } + else { + $PolicyResourcesTable.counters.unmanagedScopes += 1 + } + } + } + else { + Write-Verbose "Policy resource $id excluded" + } + } + } +} \ No newline at end of file diff --git a/Scripts/Helpers/Get-AzPolicyResources.ps1 b/Scripts/Helpers/Get-AzPolicyResources.ps1 index 8c8c86f1..69d62889 100644 --- a/Scripts/Helpers/Get-AzPolicyResources.ps1 +++ b/Scripts/Helpers/Get-AzPolicyResources.ps1 @@ -6,25 +6,21 @@ function Get-AzPolicyResources { [switch] $SkipRoleAssignments, [switch] $SkipExemptions, - [switch] $CollectRemediations, - [switch] $CollectAllPolicies + [switch] $CollectAllPolicies, + [switch] $NoParallelProcessing ) $deploymentRootScope = $PacEnvironment.deploymentRootScope - $tenantId = $PacEnvironment.tenantId Write-Information "" Write-Information "===================================================================================================" Write-Information "Get Policy Resources for EPAC environment '$($PacEnvironment.pacSelector)' at root scope $($deploymentRootScope -replace '/providers/Microsoft.Management','')" Write-Information "===================================================================================================" - $prefBackup = $WarningPreference - $WarningPreference = 'SilentlyContinue' - $policyResources = Search-AzGraphAllItems ` - -Query 'PolicyResources | where (type == "microsoft.authorization/policyassignments") or (type == "microsoft.authorization/policysetdefinitions") or (type == "microsoft.authorization/policydefinitions")' ` - -Scope @{ UseTenantScope = $true } ` - -ProgressItemName "Policy definitions, Policy Set definitions, and Policy Assignments" - $WarningPreference = $prefBackup - $deployed = @{ + $skipExemptionsLocal = $SkipExemptions.IsPresent + $skipRoleAssignmentsLocal = $SkipRoleAssignments.IsPresent + $collectAllPoliciesLocal = $CollectAllPolicies.IsPresent + + $deployedPolicyResources = @{ policydefinitions = @{ all = @{} readOnly = @{} @@ -61,363 +57,197 @@ function Get-AzPolicyResources { managed = @{} counters = @{ managedBy = @{ - thisPaC = 0 - otherPaC = 0 + thisPaC = 0 + otherPaC = 0 dfcSecurityPolicies = 0 - dfcDefenderPlans = 0 - unknown = 0 + dfcDefenderPlans = 0 + unknown = 0 } excluded = 0 unmanagedScopes = 0 + withIdentity = 0 } } - policyExemptions = @{ + policyexemptions = @{ managed = @{} counters = @{ managedBy = @{ thisPaC = 0 otherPaC = 0 unknown = 0 - orphaned = 0 } + orphaned = 0 + expired = 0 excluded = 0 unmanagedScopes = 0 } } roleAssignmentsByPrincipalId = @{} + numberOfRoleAssignments = 0 + numberOfPrincipleIds = 0 + remoteAssignmentsCount = 0 roleDefinitions = @{} roleAssignmentsNotRetrieved = $false - nonComplianceSummary = @{} - remediationTasks = @{} + excludedScopes = $excludedScopes } - $desiredState = $PacEnvironment.desiredState - $includeResourceGroups = $desiredState.includeResourceGroups - $excludedPolicyAssignments = $desiredState.excludedPolicyAssignments - - $policyDefinitionsScopes = $PacEnvironment.policyDefinitionsScopes - $scopesLength = $policyDefinitionsScopes.Length - $scopesLast = $scopesLength - 1 - $customPolicyDefinitionScopes = $policyDefinitionsScopes[0..($scopesLast - 1)] - $globalNotScopes = $PacEnvironment.globalNotScopes - $excludedScopesRaw = @() - $excludedScopesRaw += $globalNotScopes - $excludedScopesRaw += $desiredState.excludedScopes - if ($excludedScopesRaw.Count -gt 1) { - $excludedScopesRaw = @() + (Sort-Object -InputObject $excludedScopesRaw -Unique) + $collectionList = [System.Collections.ArrayList]::new() + if ($skipExemptionsLocal) { + $collectionList.AddRange(@( ` + "policyDefinitions", ` + "policySetDefinitions", ` + "policyAssignments")) } - - $scopeCollection = Build-NotScopes -ScopeTable $ScopeTable -ScopeList $customPolicyDefinitionScopes -NotScopeIn $excludedScopesRaw - $excludedScopesHashtable = @{} - foreach ($scope in $scopeCollection) { - foreach ($notScope in $scope.notScope) { - $excludedScopesHashtable[$notScope] = $notScope - } + else { + $collectionList.AddRange(@( ` + "policyDefinitions", ` + "policySetDefinitions", ` + "policyAssignments", ` + "policyExemptions")) } - $excludedScopes = $excludedScopesHashtable.Keys - $policyDefinitionsScopes = $PacEnvironment.policyDefinitionsScopes - $scopesLength = $policyDefinitionsScopes.Length - $scopesLast = $scopesLength - 1 - $policyAssignmentsTable = $deployed.policyassignments - $thisPacOwnerId = $PacEnvironment.pacOwnerId - $uniquePrincipalIds = @{} - $assignmentsWithIdentity = @{} - $numberPolicyResourcesProcessed = 0 - foreach ($policyResourceRaw in $policyResources) { - $thisTenantId = $policyResourceRaw.tenantId - if ($thisTenantId -in @("", $tenantId)) { - $policyResource = Get-HashtableShallowClone $policyResourceRaw - $id = $policyResource.id - $kind = $policyResource.kind - $included = $true - $resourceIdParts = $null - if ($kind -eq "policyassignments") { - $included, $resourceIdParts = Confirm-PolicyResourceExclusions ` - -TestId $id ` - -ResourceId $id ` - -ScopeTable $ScopeTable ` - -IncludeResourceGroups $includeResourceGroups ` - -ExcludedScopes $excludedScopes ` - -ExcludedIds $excludedPolicyAssignments ` - -PolicyResourceTable $policyAssignmentsTable - if ($included) { - $scope = $resourceIdParts.scope - $policyResource.resourceIdParts = $resourceIdParts - $policyResource.pacOwner = Confirm-PacOwner -ThisPacOwnerId $thisPacOwnerId -PolicyResource $policyResource -Scope $scope -ManagedByCounters $policyAssignmentsTable.counters.managedBy - $null = $policyAssignmentsTable.managed.Add($id, $policyResource) - if ($policyResource.identity -and $policyResource.identity.type -ne "None") { - $principalId = "" - if ($policyResource.identity.type -eq "SystemAssigned") { - $principalId = $policyResource.identity.principalId - } - else { - $userAssignedIdentityId = $policyResource.identity.userAssignedIdentities.PSObject.Properties.Name - $principalId = $policyResource.identity.userAssignedIdentities.$userAssignedIdentityId.principalId - } - $uniquePrincipalIds[$principalId] = $true - $null = $assignmentsWithIdentity.Add($id, $policyResource) - } + + $deployedPolicyDefinitions = $deployedPolicyResources.policydefinitions + $deployedPolicySetDefinitions = $deployedPolicyResources.policysetdefinitions + if ($NoParallelProcessing) { + foreach ($collectionItem in $collectionList) { + switch ($collectionItem) { + policyDefinitions { + Get-AzPolicyOrSetDefinitions ` + -DefinitionType "policyDefinitions" ` + -PolicyResourcesTable $deployedPolicyResources.policydefinitions ` + -PacEnvironment $PacEnvironment ` + -ScopeTable $ScopeTable ` + -CollectAllPolicies $collectAllPoliciesLocal + break } - else { - Write-Verbose "Policy resource $id excluded" + policySetDefinitions { + Get-AzPolicyOrSetDefinitions ` + -DefinitionType "policySetDefinitions" ` + -PolicyResourcesTable $deployedPolicyResources.policysetdefinitions ` + -PacEnvironment $PacEnvironment ` + -ScopeTable $ScopeTable ` + -CollectAllPolicies $collectAllPoliciesLocal + break } - } - else { - $deployedPolicyTable = $deployed.$kind - $found = $false - $excludedList = $desiredState.excludedPolicyDefinitions - if ($kind -eq "policysetdefinitions") { - $excludedList = $desiredState.excludedPolicySetDefinitions + policyAssignments { + Get-AzPolicyAssignments ` + -DeployedPolicyResources $deployedPolicyResources ` + -PacEnvironment $PacEnvironment ` + -ScopeTable $ScopeTable ` + -SkipRoleAssignments $skipRoleAssignmentsLocal + break } - $included, $resourceIdParts = Confirm-PolicyResourceExclusions ` - -TestId $id ` - -ResourceId $id ` - -ScopeTable $ScopeTable ` - -IncludeResourceGroups $false ` - -ExcludedScopes $excludedScopes ` - -ExcludedIds $excludedList ` - -PolicyResourceTable $deployedPolicyTable - if ($included) { - $policyResource.resourceIdParts = $resourceIdParts - $found = $false - for ($i = 0; $i -lt $scopesLength -and !$found; $i++) { - $currentScopeId = $policyDefinitionsScopes[$i] - if ($resourceIdParts.scope -eq $currentScopeId) { - switch ($i) { - 0 { - # deploymentRootScope - $policyResource.pacOwner = Confirm-PacOwner -ThisPacOwnerId $thisPacOwnerId -PolicyResource $policyResource -ManagedByCounters $deployedPolicyTable.counters.managedBy - $null = $deployedPolicyTable.all.Add($id, $policyResource) - $null = $deployedPolicyTable.managed.Add($id, $policyResource) - $found = $true - } - $scopesLast { - # BuiltIn or Static, since last entry in array is empty string ($currentPolicyDefinitionsScopeId) - $null = $deployedPolicyTable.all.Add($id, $policyResource) - $null = $deployedPolicyTable.readOnly.Add($id, $policyResource) - $deployedPolicyTable.counters.builtIn += 1 - $found = $true - } - Default { - # Read only definitions scopes - $null = $deployedPolicyTable.all.Add($id, $policyResource) - $null = $deployedPolicyTable.readOnly.Add($id, $policyResource) - $deployedPolicyTable.counters.inherited += 1 - $found = $true - } - } - } - } - if (!$found) { - if ($CollectAllPolicies) { - $policyResource.pacOwner = Confirm-PacOwner -ThisPacOwnerId $thisPacOwnerId -PolicyResource $policyResource -ManagedByCounters $deployedPolicyTable.counters.managedBy - $null = $deployedPolicyTable.all.Add($id, $policyResource) - $null = $deployedPolicyTable.managed.Add($id, $policyResource) - } - else { - $deployedPolicyTable.counters.unmanagedScopes += 1 - } - $deployedPolicyTable.counters.unmanagedScopes += 1 - } + policyExemptions { + Get-AzPolicyExemptions ` + -DeployedPolicyResources $deployedPolicyResources ` + -PacEnvironment $PacEnvironment ` + -ScopeTable $ScopeTable + break } } } - $numberPolicyResourcesProcessed++ - if ($numberPolicyResourcesProcessed % 1000 -eq 0) { - Write-Information "Processed $numberPolicyResourcesProcessed Policy definitions, Policy Set definitions, and Policy Assignments" - } - } - if ($numberPolicyResourcesProcessed % 1000 -ne 0) { - Write-Information "Processed $numberPolicyResourcesProcessed Policy definitions, Policy Set definitions, and Policy Assignments" } + else { + $funcGetAzPolicyAssignments = ${function:Get-AzPolicyAssignments}.ToString() + $funcGetAzRoleAssignmentsRestMethod = ${function:Get-AzRoleAssignmentsRestMethod}.ToString() + $funcGetAzRoleDefinitionsRestMethod = ${function:Get-AzRoleDefinitionsRestMethod}.ToString() + $funcGetAzPolicyExemptions = ${function:Get-AzPolicyExemptions}.ToString() + $funcGetAzPolicyExemptionsRestMethod = ${function:Get-AzPolicyExemptionsRestMethod}.ToString() + $funcGetAzPolicyOrSetDefinitions = ${function:Get-AzPolicyOrSetDefinitions}.ToString() + $funcSearchAzGraphAllItems = ${function:Search-AzGraphAllItems}.ToString() + $funcDefGetClonedObject = ${function:Get-ClonedObject}.ToString() + $funcDefConfirmPolicyResourceExclusions = ${function:Confirm-PolicyResourceExclusions}.ToString() + $funcConfirmPacOwner = ${function:Confirm-PacOwner}.ToString() + $funcGetPolicyResourceProperties = ${function:Get-PolicyResourceProperties}.ToString() + $funcSplitAzPolicyResourceId = ${function:Split-AzPolicyResourceId}.ToString() + $funcConvertToHashTable = ${function:ConvertTo-HashTable}.ToString() + $funcSetUniqueRoleAssignmentScopes = ${function:Set-UniqueRoleAssignmentScopes}.ToString() - if (!$SkipExemptions) { - $prefBackup = $WarningPreference - $WarningPreference = 'SilentlyContinue' - Write-Information "" - $policyResources = Search-AzGraphAllItems ` - -Query 'PolicyResources | where type == "microsoft.authorization/policyexemptions"' ` - -Scope @{ UseTenantScope = $true } ` - -ProgressItemName "Policy Exemptions" - $WarningPreference = $prefBackup + $collectionList | Foreach-Object -Parallel { + # Import dot sourced functions into context + if ($null -eq ${function:Get-AzPolicyAssignments}) { + ${function:Get-AzPolicyAssignments} = $using:funcGetAzPolicyAssignments + ${function:Get-AzRoleAssignmentsRestMethod} = $using:funcGetAzRoleAssignmentsRestMethod + ${function:Get-AzRoleDefinitionsRestMethod} = $using:funcGetAzRoleDefinitionsRestMethod + ${function:Get-AzPolicyExemptions} = $using:funcGetAzPolicyExemptions + ${function:Get-AzPolicyExemptionsRestMethod} = $using:funcGetAzPolicyExemptionsRestMethod + ${function:Get-AzPolicyOrSetDefinitions} = $using:funcGetAzPolicyOrSetDefinitions + ${function:Search-AzGraphAllItems} = $using:funcSearchAzGraphAllItems + ${function:Get-ClonedObject} = $using:funcDefGetClonedObject + ${function:Confirm-PolicyResourceExclusions} = $using:funcDefConfirmPolicyResourceExclusions + ${function:Confirm-PacOwner} = $using:funcConfirmPacOwner + ${function:Get-PolicyResourceProperties} = $using:funcGetPolicyResourceProperties + ${function:Split-AzPolicyResourceId} = $using:funcSplitAzPolicyResourceId + ${function:ConvertTo-HashTable} = $using:funcConvertToHashTable + ${function:Set-UniqueRoleAssignmentScopes} = $using:funcSetUniqueRoleAssignmentScopes + } - $exemptionsTable = $deployed.policyExemptions - $managedByCounters = $exemptionsTable.counters.managedBy - $managedPolicyAssignmentsTable = $policyAssignmentsTable.managed - $numberPolicyResourcesProcessed = 0 - $now = [datetime]::UtcNow - foreach ($policyResourceRaw in $policyResources) { - $thisTenantId = $policyResourceRaw.tenantId - if ($thisTenantId -in @("", $tenantId)) { - $id = $policyResourceRaw.id - $name = $policyResourceRaw.name - $properties = $policyResourceRaw.properties - $displayName = $properties.displayName - if ($null -ne $displayName -and $displayName -eq "") { - $displayName = $null - } - $description = $properties.description - if ($null -ne $description -and $description -eq "") { - $description = $null + #Action that will run in Parallel. Reference the current object via $PSItem and bring in outside variables with $USING:varname + $PacEnvironment = $using:PacEnvironment + $ScopeTable = $using:ScopeTable + $skipRoleAssignmentsLocal = $using:skipRoleAssignmentsLocal + $deployedPolicyResources = $using:deployedPolicyResources + $deployedPolicyDefinitions = $using:deployedPolicyDefinitions + $deployedPolicySetDefinitions = $using:deployedPolicySetDefinitions + $collectAllPoliciesLocal = $using:collectAllPoliciesLocal + + switch ($_) { + policyDefinitions { + Get-AzPolicyOrSetDefinitions ` + -DefinitionType "policyDefinitions" ` + -PolicyResourcesTable $deployedPolicyDefinitions ` + -PacEnvironment $PacEnvironment ` + -ScopeTable $ScopeTable ` + -CollectAllPolicies $collectAllPoliciesLocal + break } - $exemptionCategory = $properties.exemptionCategory - $expiresOnRaw = $properties.expiresOn - $expiresOn = $null - if ($null -ne $expiresOnRaw -and $expiresOnRaw -ne "") { - if ($expiresOnRaw -is [datetime]) { - $expiresOn = $expiresOnRaw.ToUniversalTime - } - else { - $expiresOnDate = [datetime]::Parse($expiresOnRaw) - $expiresOn = $expiresOnDate.ToUniversalTime() - } - $expiresOn = $expiresOnRaw.ToUniversalTime() + policySetDefinitions { + Get-AzPolicyOrSetDefinitions ` + -DefinitionType "policySetDefinitions" ` + -PolicyResourcesTable $deployedPolicySetDefinitions ` + -PacEnvironment $PacEnvironment ` + -ScopeTable $ScopeTable ` + -CollectAllPolicies $collectAllPoliciesLocal + break } - $metadataRaw = $properties.metadata - $metadata = $null - if ($null -ne $metadataRaw -and $metadataRaw -ne @{} ) { - $metadata = $metadataRaw + policyAssignments { + Get-AzPolicyAssignments ` + -DeployedPolicyResources $deployedPolicyResources ` + -PacEnvironment $PacEnvironment ` + -ScopeTable $ScopeTable ` + -SkipRoleAssignments $skipRoleAssignmentsLocal + break } - $policyAssignmentId = $properties.policyAssignmentId - $policyDefinitionReferenceIdsRaw = $properties.policyDefinitionReferenceIds - $policyDefinitionReferenceIds = $null - if ($null -ne $policyDefinitionReferenceIdsRaw -and $policyDefinitionReferenceIdsRaw.Count -gt 0) { - $policyDefinitionReferenceIds = $policyDefinitionReferenceIdsRaw - } - $resourceSelectors = $properties.resourceSelectors - $assignmentScopeValidation = $properties.assignmentScopeValidation - $included, $resourceIdParts = Confirm-PolicyResourceExclusions ` - -TestId $policyAssignmentId ` - -ResourceId $id ` - -ScopeTable $ScopeTable ` - -IncludeResourceGroups $false ` - -ExcludedScopes $excludedScopes ` - -ExcludedIds $excludedPolicyAssignments ` - -PolicyResourceTable $exemptionsTable - if ($included) { - $status = "unknown" - $pacOwner = Confirm-PacOwner -ThisPacOwnerId $thisPacOwnerId -PolicyResource $policyResourceRaw -ManagedByCounters $managedByCounters - if ($managedPolicyAssignmentsTable.ContainsKey($policyAssignmentId)) { - $status = "active" - } - else { - $status = "orphaned" - } - $expiresInDays = [Int32]::MaxValue - if ($expiresOn) { - if ($expiresOn -lt $now) { - if ($status -eq "active") { - $status = "expired" - } - } - else { - $expiresIn = New-TimeSpan -Start $now -End $expiresOn - $expiresInDays = $expiresIn.Days - } - } - $exemption = @{ - id = $id - name = $name - scope = $resourceIdParts.scope - displayName = $displayName - description = $description - exemptionCategory = $exemptionCategory - expiresOn = $expiresOn - metadata = $metadata - policyAssignmentId = $policyAssignmentId - policyDefinitionReferenceIds = $policyDefinitionReferenceIds - resourceSelectors = $resourceSelectors - assignmentScopeValidation = $assignmentScopeValidation - pacOwner = $pacOwner - status = $status - expiresInDays = $expiresInDays - } - - # What is the context of this exemption; it depends on the assignment being exempted - if ($pacOwner -eq "thisPaC") { - $managedByCounters.thisPaC += 1 - } - elseif ($pacOwner -eq "otherPaC") { - $managedByCounters.otherPaC += 1 - } - elseif ($pacOwner -eq "unknownOwner") { - $managedByCounters.unknown += 1 - } - if ($status -eq "orphaned") { - $managedByCounters.orphaned += 1 - } - $null = $exemptionsTable.managed.Add($id, $exemption) + policyExemptions { + Get-AzPolicyExemptions ` + -DeployedPolicyResources $deployedPolicyResources ` + -PacEnvironment $PacEnvironment ` + -ScopeTable $ScopeTable + break } } - $numberPolicyResourcesProcessed++ - if ($numberPolicyResourcesProcessed % 1000 -eq 0) { - Write-Information "Processed $numberPolicyResourcesProcessed Policy Exemptions" - } - } - if ($numberPolicyResourcesProcessed % 1000 -ne 0) { - Write-Information "Processed $numberPolicyResourcesProcessed Policy Exemptions" } } - $deployedRoleAssignmentsByPrincipalId = $deployed.roleAssignmentsByPrincipalId - if (!$SkipRoleAssignments) { - $prefBackup = $WarningPreference - $WarningPreference = 'SilentlyContinue' - - Write-Information "" - $principalIds = '"' + ($uniquePrincipalIds.Keys -join '", "') + '"' - $roleAssignments = Search-AzGraphAllItems ` - -Query "authorizationresources | where type == `"microsoft.authorization/roleassignments`" and properties.principalId in ( $principalIds )" ` - -Scope @{ UseTenantScope = $true } ` - -ProgressItemName "Role Assignments" - $roleDefinitions = Search-AzGraphAllItems 'authorizationresources | where type == "microsoft.authorization/roledefinitions"' ` - -Scope @{ UseTenantScope = $true } ` - -ProgressItemName "Role Definitions" - - $roleDefinitionsHt = $deployed.roleDefinitions - foreach ($roleDefinition in $roleDefinitions) { - $roleDefinitionId = $roleDefinition.id - $roleDefinitionName = $roleDefinition.properties.roleName - $null = $roleDefinitionsHt.Add($roleDefinitionId, $roleDefinitionName) - } - $WarningPreference = $prefBackup - - # loop through the collected role assignments to collate by principalId - $roleAssignmentsCount = 0 - foreach ($roleAssignment in $roleAssignments) { - $properties = $roleAssignment.properties - $principalId = $roleAssignment.properties.principalId - $roleDefinitionId = $properties.roleDefinitionId - $roleDefinitionName = $roleDefinitionId - if ($roleDefinitionsHt.ContainsKey($roleDefinitionId)) { - $roleDefinitionName = $roleDefinitionsHt.$roleDefinitionId - } - $normalizedRoleAssignment = @{ - id = $roleAssignment.id - name = $roleAssignment.name - scope = $properties.scope - displayName = "" - objectType = $properties.principalType - principalId = $principalId - roleDefinitionId = $roleDefinitionId - roleDisplayName = $roleDefinitionName - } - if ($deployedRoleAssignmentsByPrincipalId.ContainsKey($principalId)) { - $normalizedRoleAssignments = $deployedRoleAssignmentsByPrincipalId.$principalId - $normalizedRoleAssignments += $normalizedRoleAssignment - $deployedRoleAssignmentsByPrincipalId[$principalId] = $normalizedRoleAssignments - } - else { - $null = $deployedRoleAssignmentsByPrincipalId.Add($principalId, @( $normalizedRoleAssignment )) - } - $roleAssignmentsCount++ - if ($roleAssignmentsCount % 1000 -eq 0) { - Write-Information "Processed $roleAssignmentsCount Role Assignments" + Write-Information "Processing Exemptions for orphaned assignments" + if (-not $skipExemptionsLocal) { + $policyExemptionsCounters = $deployedPolicyResources.policyexemptions.counters + $managedPolicyExemptionsTable = $deployedPolicyResources.policyexemptions.managed + $managedPolicyAssignmentsTable = $deployedPolicyResources.policyassignments.managed + # change exemption status if exemption orphaned (policyAssignment with policyAssignmentId does not exist) + foreach ($policyResource in $managedPolicyExemptionsTable.Values) { + if ($policyResource.assignmentScopeValidation -eq "Default") { + $assignmentId = $policyResource.policyAssignmentId + $assignmentScopeValidation = $policyResource.assignmentScopeValidation + if ($assignmentScopeValidation -eq "Default") { + if (-not $managedPolicyAssignmentsTable.ContainsKey($assignmentId)) { + $policyResource.status = "orphaned-assignment" + $policyExemptionsCounters.orphaned += 1 + continue + } + } } } - if ($roleAssignmentsCount % 1000 -ne 0) { - Write-Information "Processed $roleAssignmentsCount Policy Exemptions" - } } Write-Information "" @@ -426,7 +256,7 @@ function Get-AzPolicyResources { Write-Information "===================================================================================================" foreach ($kind in @("policydefinitions", "policysetdefinitions")) { - $deployedPolicyTable = $deployed.$kind + $deployedPolicyTable = $deployedPolicyResources.$kind $counters = $deployedPolicyTable.counters $managedBy = $counters.managedBy $managedByAny = $managedBy.thisPaC + $managedBy.otherPaC + $managedBy.unknown @@ -447,7 +277,7 @@ function Get-AzPolicyResources { Write-Verbose " Not our scopes = $($counters.unmanagedScopes)" } - $counters = $deployed.policyassignments.counters + $counters = $deployedPolicyResources.policyassignments.counters $managedBy = $counters.managedBy $managedByAny = $managedBy.thisPaC + $managedBy.otherPaC + $managedBy.unknown + $managedBy.dfcSecurityPolicies + $managedBy.dfcDefenderPlans Write-Information "" @@ -458,35 +288,43 @@ function Get-AzPolicyResources { Write-Information " Unknown = $($managedBy.unknown)" Write-Information " DfC Security Policies = $($managedBy.dfcSecurityPolicies)" Write-Information " DfC Defender Plans = $($managedBy.dfcDefenderPlans)" - Write-Information " With identity = $($assignmentsWithIdentity.psbase.Count)" + Write-Information " With identity = $($counters.withIdentity)" Write-Information " Excluded = $($counters.excluded)" Write-Verbose " Not our scopes = $($counters.unmanagedScopes)" - if (!$SkipExemptions) { - $counters = $exemptionsTable.counters + if (!$skipExemptionsLocal) { + $counters = $deployedPolicyResources.policyexemptions.counters $managedBy = $counters.managedBy $managedByAny = $managedBy.thisPaC + $managedBy.otherPaC + $managedBy.unknown Write-Information "" Write-Information "Policy Exemptions:" Write-Information " Managed ($($managedByAny)) by:" - Write-Information " This PaC = $($managedBy.thisPaC)" - Write-Information " Other PaC = $($managedBy.otherPaC)" - Write-Information " Unknown = $($managedBy.unknown)" - Write-Information " Orphaned = $($managedBy.orphaned)" - Write-Information " Excluded = $($counters.excluded)" - Write-Verbose " Not our scopes = $($counters.unmanagedScopes)" + Write-Information " This PaC = $($managedBy.thisPaC)" + Write-Information " Other PaC = $($managedBy.otherPaC)" + Write-Information " Unknown = $($managedBy.unknown)" + Write-Information " Orphaned = $($counters.orphaned)" + Write-Information " Expired = $($counters.expired)" + Write-Information " Excluded = $($counters.excluded)" } if (!$SkipRoleAssignments) { + $managedRoleAssignmentsByPrincipalId = $deployedPolicyResources.roleAssignmentsByPrincipalId Write-Information "" - if ($uniquePrincipalIds.Count -gt 0 -and $deployedRoleAssignmentsByPrincipalId.Count -eq 0) { - Write-Warning "Role assignment retrieval failed to receive any role assignments. This likely due to a missing permission for the SPN running the pipeline. Please read the pipeline documentation in EPAC. In rare cases, this can happen when a previous role assignment failed." -WarningAction Continue - $deployed.roleAssignmentsNotRetrieved = $true + $numberPrincipalIds = $deployedPolicyResources.numberOfPrincipleIds + $numberPrincipalIdsWithRoleAssignments = $managedRoleAssignmentsByPrincipalId.Count + if ($numberPrincipalIds -ne $numberPrincipalIdsWithRoleAssignments) { + Write-Warning "Role assignment not retrived for every principal Id ($($numberPrincipalIds) in assignments, $($numberPrincipalIdsWithRoleAssignments) retrieved).`n This is likely due to a missing permission for the SPN running the pipeline. Please read the pipeline documentation in EPAC.`n In rare cases, this can happen when a previous role assignment failed." -WarningAction Continue + $deployedPolicyResources.roleAssignmentsNotRetrieved = $numberPrincipalIdsWithRoleAssignments -eq 0 } Write-Information "Role Assignments:" - Write-Information " Total principalIds = $($deployedRoleAssignmentsByPrincipalId.Count)" - Write-Information " Total Role Assignments = $($roleAssignmentsCount)" + Write-Information " Principal Ids = $($numberPrincipalIds)" + Write-Information " With Role Assignments = $($numberPrincipalIdsWithRoleAssignments)" + Write-Information " Role Assignments = $($deployedPolicyResources.numberOfRoleAssignments)" + if ($PacEnvironment.managingTenantId) { + Write-Information " Remote Role Assignments = $($deployedPolicyResources.remoteAssignmentsCount)" + } } + Write-Information "" - return $deployed + return $deployedPolicyResources } diff --git a/Scripts/Helpers/Get-PolicyResourceDetails.ps1 b/Scripts/Helpers/Get-AzPolicyResourcesDetails.ps1 similarity index 54% rename from Scripts/Helpers/Get-PolicyResourceDetails.ps1 rename to Scripts/Helpers/Get-AzPolicyResourcesDetails.ps1 index 802cbe72..cd9280ad 100644 --- a/Scripts/Helpers/Get-PolicyResourceDetails.ps1 +++ b/Scripts/Helpers/Get-AzPolicyResourcesDetails.ps1 @@ -1,9 +1,10 @@ -function Get-PolicyResourceDetails { +function Get-AzPolicyResourcesDetails { [CmdletBinding()] param ( [string] $PacEnvironmentSelector, [hashtable] $PacEnvironment, - [hashtable] $CachedPolicyResourceDetails + [hashtable] $CachedPolicyResourceDetails, + [Int16] $VirtualCores ) $policyResourceDetails = $null @@ -12,14 +13,20 @@ function Get-PolicyResourceDetails { } else { # New root scope found - $scopeTable = Get-AzScopeTree -PacEnvironment $PacEnvironment + $scopeTable = Build-ScopeTableForDeploymentRootScope -PacEnvironment $PacEnvironment + $NoParallelProcessing = $VirtualCores -eq 0 + # $NoParallelProcessing = $true $deployed = Get-AzPolicyResources ` -PacEnvironment $PacEnvironment ` -ScopeTable $scopeTable ` -SkipRoleAssignments ` - -SkipExemptions + -SkipExemptions ` + -NoParallelProcessing:$NoParallelProcessing - $policyResourceDetails = Convert-PolicySetsToDetails -AllPolicyDefinitions $deployed.policydefinitions.all -AllPolicySetDefinitions $deployed.policysetdefinitions.all + $policyResourceDetails = Convert-PolicyResourcesToDetails ` + -AllPolicyDefinitions $deployed.policydefinitions.all ` + -AllPolicySetDefinitions $deployed.policysetdefinitions.all ` + -VirtualCores $VirtualCores $null = $policyResourceDetails.policyAssignments = $deployed.policyassignments.managed $null = $CachedPolicyResourceDetails.Add($PacEnvironmentSelector, $policyResourceDetails) } diff --git a/Scripts/Helpers/Get-AzPolicySetParameters.ps1 b/Scripts/Helpers/Get-AzPolicySetParameters.ps1 deleted file mode 100644 index 61726014..00000000 --- a/Scripts/Helpers/Get-AzPolicySetParameters.ps1 +++ /dev/null @@ -1,27 +0,0 @@ -function Get-AzPolicySetParameters { - [CmdletBinding()] - param ( - [hashtable] $ParametersIn = @{}, # empty hashtable means processing a Policy Set instead of Assignment(s) - [hashtable] $DefinedParameters - ) - - [hashtable] $parametersOut = @{} - foreach ($name in $DefinedParameters.Keys) { - $definedParameter = $DefinedParameters.$name - if ($ParametersIn.ContainsKey($name)) { - $null = $parametersOut.Add($name, @{ - paramValue = $ParametersIn[$name].value - type = "SetInAssignment" - defaultValue = $definedParameter.defaultValue - }) - } - else { - $null = $parametersOut.Add($name, @{ - paramValue = $definedParameter.defaultValue - type = "PolicySet DefaultValue" - defaultValue = $definedParameter.defaultValue - }) - } - } - return $parametersOut -} diff --git a/Scripts/Helpers/Get-AzScopeTree.ps1 b/Scripts/Helpers/Get-AzScopeTree.ps1 deleted file mode 100644 index 0ab2885a..00000000 --- a/Scripts/Helpers/Get-AzScopeTree.ps1 +++ /dev/null @@ -1,211 +0,0 @@ -function Get-AzScopeTree { - - param( - [hashtable] $PacEnvironment, - [switch] $IgnoreScopeTreeErrors - ) - - $deploymentRootScope = $PacEnvironment.deploymentRootScope - $tenantId = $PacEnvironment.tenantId - Write-Information "" - Write-Information "===================================================================================================" - Write-Information "Get scope tree for EPAC environment '$($PacEnvironment.pacSelector)' at root scope $($deploymentRootScope -replace '/providers/Microsoft.Management','')" - Write-Information "===================================================================================================" - $prefBackup = $WarningPreference - $WarningPreference = 'SilentlyContinue' - $scope = Split-ScopeId ` - -ScopeId $deploymentRootScope ` - -ParameterNameForManagementGroup "ManagementGroup" ` - -ParameterNameForSubscription "Subscription" ` - -AsSplat - $resourceContainers = Search-AzGraphAllItems ` - -Query "ResourceContainers" ` - -Scope $scope ` - -ProgressItemName "resource containers" - $WarningPreference = $prefBackup - Write-Information "" - Write-Information "Processing $($resourceContainers.Count) resource containers:" - - # Process subscriptions and management groups - $scopeTable = @{} - $numberOfManagementGroups = 0 - $numberOfSubscriptions = 0 - foreach ($resourceContainer in $resourceContainers) { - # resource groups require a second pass - $type = $resourceContainer.type - if ($resourceContainer.tenantId -eq $tenantId -and $type -ne "microsoft.resources/subscriptions/resourcegroups") { - $id = $resourceContainer.id - $rootScopeReached = $id -eq $deploymentRootScope - $managementGroupAncestorsChain = @() - if ($type -eq "microsoft.management/managementgroups") { - $managementGroupAncestorsChain = $resourceContainer.properties.details.managementGroupAncestorsChain - } - else { - $managementGroupAncestorsChain = $resourceContainer.properties.managementGroupAncestorsChain - } - $numberOfAncestors = $managementGroupAncestorsChain.Count - $newNodeCandidates = [System.Collections.ArrayList]::new() - $parentList = @{} - $childrenList = @{ $id = $type } - $i = 0 - while (!$rootScopeReached -and $i -lt $numberOfAncestors) { - $currentParent = $managementGroupAncestorsChain[$i] - $currentId = "/providers/Microsoft.Management/managementGroups/$($currentParent.name)" - if ($currentId -eq $deploymentRootScope) { - $rootScopeReached = $true - } - $null = $parentList.Add($currentId, "microsoft.management/managementgroups") - if ($scopeTable.ContainsKey($currentId)) { - $currentScopeInformation = $scopeTable.$currentId - $currentChildrenList = $currentScopeInformation.childrenList - foreach ($child in $childrenList.Keys) { - $currentChildrenList[$child] = $childrenList.$child - } - } - else { - $scopeInformation = @{ - id = $currentId - type = "microsoft.management/managementgroups" - name = $currentParent.name - displayName = $currentParent.displayName - parentList = @{} - childrenList = Get-HashtableShallowClone $childrenList - resourceGroups = @{} - state = $null - location = "global" - } - $null = $newNodeCandidates.Add($scopeInformation) - } - $i++ - } - if ($rootScopeReached) { - # candidates become actual nodes (not yet completed) - foreach ($newNodeCandidate in $newNodeCandidates) { - $null = $scopeTable.Add($newNodeCandidate.id, $newNodeCandidate) - } - if ($scopeTable.ContainsKey($id)) { - # has any children already; needs parentList - $scopeInformation = $scopeTable.$id - $scopeInformation.parentList = $parentList - $scopeInformation.state = $resourceContainer.properties.state - } - else { - $scopeInformation = $null - if ($resourceContainer.type -eq "microsoft.management/managementgroups") { - $scopeInformation = @{ - id = $id - type = $type - name = $resourceContainer.name - displayName = $resourceContainer.properties.displayName - parentList = $parentList - childrenList = @{} - resourceGroups = @{} - state = $null - location = "global" - } - } - else { - $scopeInformation = @{ - id = $id - type = $type - name = $resourceContainer.name - displayName = $resourceContainer.name - parentList = $parentList - childrenList = @{} - resourceGroups = @{} - state = $resourceContainer.properties.state - location = "global" - } - } - $null = $scopeTable.Add($id, $scopeInformation) - } - if ($resourceContainer.type -eq "microsoft.management/managementgroups") { - $numberOfManagementGroups++ - } - else { - $numberOfSubscriptions++ - } - } - else { - # should not be possible - if ($IgnoreScopeTreeErrors) { - Write-Error "Code bug: Our root is not in this tree" -ErrorAction SilentlyContinue - } - else { - Write-Error "Code bug: Our root is not in this tree" -ErrorAction Stop - } - - } - } - } - Write-Information " Management groups = $($numberOfManagementGroups)" - Write-Information " Subscriptions = $($numberOfSubscriptions)" - - # Process resourceGroups since the only contain the subscription information, needs managementGroup information as well - $numberOfResourceGroups = 0 - foreach ($resourceContainer in $resourceContainers) { - # resource groups require a second pass - $type = $resourceContainer.type - if ($resourceContainer.tenantId -eq $tenantId -and $type -eq "microsoft.resources/subscriptions/resourcegroups") { - $id = $resourceContainer.id - $name = $resourceContainer.name - $subscriptionId = "/subscriptions/$($resourceContainer.subscriptionId)" - if ($scopeTable.ContainsKey($subscriptionId)) { - $subscriptionInformation = $scopeTable.$subscriptionId - $subscriptionParentList = $subscriptionInformation.parentList - $parentList = Get-HashtableShallowClone $subscriptionParentList - $null = $parentList.Add($subscriptionId, $subscriptionInformation.type) - foreach ($parentId in $parentList.Keys) { - $parentInformation = $scopeTable.$parentId - $parentChildrenList = $parentInformation.childrenList - $parentResourceGroups = $parentInformation.resourceGroups - $null = $parentChildrenList.Add($id, "microsoft.resources/subscriptions/resourcegroups") - $null = $parentResourceGroups.Add($id, "microsoft.resources/subscriptions/resourcegroups") - } - $scopeInformation = @{ - id = $id - type = $type - name = $name - displayName = $name - parentList = $parentList - childrenList = @{} - resourceGroups = @{} - state = $null - location = $resourceContainer.location - } - $null = $scopeTable.Add($id, $scopeInformation) - $numberOfResourceGroups++ - } - else { - # should not be possible - } - } - } - Write-Information " Resource groups = $($numberOfResourceGroups)" - - if ($PacEnvironment.policyDefinitionsScopes.Count -gt 2) { - # Process policy definitions scopes - $numberOfPolicyDefinitionsScopes = 0 - foreach ($policyDefinitionsScope in $PacEnvironment.policyDefinitionsScopes) { - if ($scopeTable.ContainsKey($policyDefinitionsScope) -or $policyDefinitionsScope -eq "") {} - else { - $scopeInformation = @{ - id = $policyDefinitionsScope - type = "microsoft.management/managementgroups" - name = $policyDefinitionsScope - displayName = $policyDefinitionsScope - parentList = @{} - childrenList = @{} - resourceGroups = @{} - state = $null - location = "global" - } - $null = $scopeTable.Add($policyDefinitionsScope, $scopeInformation) - $numberOfPolicyDefinitionsScopes++ - } - } - Write-Information " Policy definitions scopes = $($numberOfPolicyDefinitionsScopes)" - } - - return $scopeTable -} diff --git a/Scripts/Helpers/Get-CalculatedPolicyAssignmentsAndReferenceIds.ps1 b/Scripts/Helpers/Get-CalculatedPolicyAssignmentsAndReferenceIds.ps1 new file mode 100644 index 00000000..c85ba1a2 --- /dev/null +++ b/Scripts/Helpers/Get-CalculatedPolicyAssignmentsAndReferenceIds.ps1 @@ -0,0 +1,182 @@ +function Get-CalculatedPolicyAssignmentsAndReferenceIds { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [array] $Assignments, + + [Parameter(Mandatory = $true)] + [hashtable] $CombinedPolicyDetails + ) + + # calculated assignments + $byAssignmentIdCalculatedAssignments = @{} + $byPolicySetIdCalculatedAssignments = @{} + $byPolicyIdCalculatedAssignments = @{} + + # by Policy Set calculated policyDefinitionReferenceIds and by policyDefinitionIds in Policy Set policyDefinitionReferenceIds + $byPolicySetIdPolicyDefinitionReferences = @{} + + $index = 0 + foreach ($assignment in $Assignments) { + $assignmentId = $assignment.id + $assignmentPoperties = Get-PolicyResourceProperties $assignment + $assignedPolicyDefinitionId = $assignmentPoperties.policyDefinitionId + + if ($assignedPolicyDefinitionId.Contains("/providers/Microsoft.Authorization/policyDefinitions/", [StringComparison]::InvariantCultureIgnoreCase)) { + + #region calculate assignment for this policyAssignment and assignments for the Policy definition id + $calculatedPolicyAssignment = @{ + ordinal = $index + id = $assignmentId + scope = $assignment.scope + name = $assignment.name + displayName = $assignmentPoperties.displayName + assignedPolicyDefinitionId = $assignedPolicyDefinitionId + policyDefinitionId = $assignedPolicyDefinitionId + notScopes = $assignmentPoperties.notScopes + isPolicyAssignment = $true + allowReferenceIdsInRow = $false + policyDefinitionReferenceIds = $null + policyDefinitionIds = $null + byPolicyDefinitionIdReferences = $null + } + $calculatedPolicyAssignments = [System.Collections.ArrayList]::new() + $calculatedPolicyAssignments.Add($calculatedPolicyAssignment) + $null = $byAssignmentIdCalculatedAssignments.Add($assignmentId, $calculatedPolicyAssignments) + + $calculatedPolicyAssignments = $null + if ($byPolicyIdCalculatedAssignments.ContainsKey($assignedPolicyDefinitionId)) { + $calculatedPolicyAssignments = $byPolicyIdCalculatedAssignments.$assignedPolicyDefinitionId + } + else { + $calculatedPolicyAssignments = [System.Collections.ArrayList]::new() + $null = $byPolicyIdCalculatedAssignments.Add($assignedPolicyDefinitionId, $calculatedPolicyAssignments) + } + $null = $calculatedPolicyAssignments.Add($calculatedPolicyAssignment) + #endregion calculate assignment for this policyAssignment and assignments for the Policy definition id + + } + elseif ($assignedPolicyDefinitionId.Contains("/providers/Microsoft.Authorization/policySetDefinitions/", [StringComparison]::InvariantCultureIgnoreCase)) { + $thisPolicySetReferences = $null + + #region caclculate referenceId values for this Policy Set + if ($byPolicySetIdPolicyDefinitionReferences.ContainsKey($assignedPolicyDefinitionId)) { + # use previously calculated values + $thisPolicySetReferences = $byPolicySetIdPolicyDefinitionReferences.$assignedPolicyDefinitionId + } + else { + # create empty values for this Policy Set + $thisPolicySetReferences = @{ + policyDefinitionIds = [System.Collections.ArrayList]::new() + policyDefinitionReferenceIds = [System.Collections.ArrayList]::new() + byPolicyDefinitionIdReferences = @{} + } + $null = $byPolicySetIdPolicyDefinitionReferences.Add($assignedPolicyDefinitionId, $thisPolicySetReferences) + + # calculate values for this Policy Set + $policySetDetailsHt = $CombinedPolicyDetails.policySets + $thisPolicySetDetails = $policySetDetailsHt.$assignedPolicyDefinitionId + $policyIndex = 0 + foreach ($policyDefinitionInPolicySet in $thisPolicySetDetails.policyDefinitions) { + $policyDefinitionId = $policyDefinitionInPolicySet.id + $policyDefinitionReferenceId = $policyDefinitionInPolicySet.policyDefinitionReferenceId + + # flat lists + $null = $thisPolicySetReferences.policyDefinitionIds.Add($policyDefinitionId) + $null = $thisPolicySetReferences.policyDefinitionReferenceIds.Add($policyDefinitionReferenceId) + + # calculate per Policy + $thisPolicyDefinitionIdReferences = $null + if ($thisPolicySetReferences.byPolicyDefinitionIdReferences.ContainsKey($policyDefinitionId)) { + $thisPolicyDefinitionIdReferences = $thisPolicySetReferences.byPolicyDefinitionIdReferences[$policyDefinitionId] + } + else { + $thisPolicyDefinitionIdReferences = @{ + referenceIds = [System.Collections.ArrayList]::new() + policyIndexes = [System.Collections.ArrayList]::new() + } + $null = $thisPolicySetReferences.byPolicyDefinitionIdReferences.Add($policyDefinitionId, $thisPolicyDefinitionIdReferences) + } + $null = $thisPolicyDefinitionIdReferences.referenceIds.Add($policyDefinitionReferenceId) + $null = $thisPolicyDefinitionIdReferences.policyIndexes.Add($policyIndex) + $policyIndex++ + } + } + #endregion caclculate referenceId values for this Policy Set + + #region calculated assignment for this policyAssignment AND for this policySetId + $calculatedPolicyAssignment = @{ + ordinal = $index + id = $assignmentId + scope = $assignment.scope + name = $assignment.name + displayName = $assignmentPoperties.displayName + assignedPolicyDefinitionId = $assignedPolicyDefinitionId + policyDefinitionId = $null + notScopes = $assignmentPoperties.notScopes + isPolicyAssignment = $false + allowReferenceIdsInRow = $true + policyDefinitionReferenceIds = $thisPolicySetReferences.policyDefinitionReferenceIds + policyDefinitionIds = $thisPolicySetReferences.policyDefinitionIds + byPolicyDefinitionIdReferences = $thisPolicySetReferences.byPolicyDefinitionIdReferences + } + $calculatedPolicyAssignments = [System.Collections.ArrayList]::new() + $calculatedPolicyAssignments.Add($calculatedPolicyAssignment) + $null = $byAssignmentIdCalculatedAssignments.Add($assignmentId, $calculatedPolicyAssignments) + + $calculatedPolicyAssignments = $null + if ($byPolicySetIdCalculatedAssignments.ContainsKey($assignedPolicyDefinitionId)) { + $calculatedPolicyAssignments = $byPolicySetIdCalculatedAssignments.$assignedPolicyDefinitionId + } + else { + $calculatedPolicyAssignments = [System.Collections.ArrayList]::new() + $null = $byPolicySetIdCalculatedAssignments.Add($assignedPolicyDefinitionId, $calculatedPolicyAssignments) + } + $null = $calculatedPolicyAssignments.Add($calculatedPolicyAssignment) + #endregion calculated assignment for this policyAssignment AND for this policySetId + + #region calculated assignment for each policyDefinition id in this Policy Set + foreach ($policyDefinitionId in $thisPolicySetReferences.policyDefinitionIds) { + $thisPolicyReferences = $thisPolicySetReferences.byPolicyDefinitionIdReferences.$policyDefinitionId + $calculatedPolicyAssignment = @{ + ordinal = $index + id = $assignmentId + scope = $assignment.scope + name = $assignment.name + displayName = $assignmentPoperties.displayName + assignedPolicyDefinitionId = $assignedPolicyDefinitionId + policyDefinitionId = $policyDefinitionId + notScopes = $assignmentPoperties.notScopes + isPolicyAssignment = $false + allowReferenceIdsInRow = $false + policyDefinitionReferenceIds = $thisPolicyReferences.referenceIds + policyDefinitionIds = $null + byPolicyDefinitionIdReferences = $null + } + $calculatedPolicyAssignments = $null + if ($byPolicyIdCalculatedAssignments.ContainsKey($policyDefinitionId)) { + $calculatedPolicyAssignments = $byPolicyIdCalculatedAssignments.$policyDefinitionId + } + else { + $calculatedPolicyAssignments = [System.Collections.ArrayList]::new() + $null = $byPolicyIdCalculatedAssignments.Add($policyDefinitionId, $calculatedPolicyAssignments) + } + $null = $calculatedPolicyAssignments.Add($calculatedPolicyAssignment) + } + #endregion calculated assignment for each policyDefinition id in this Policy Set + } + else { + #should NEVER happen + throw "Invalid Policy definition id ($assignedPolicyDefinitionId) in Policy assignment '$($assignment.displayName)'($assignmentId)" + } + $index++ + } + + $result = @{ + byAssignmentIdCalculatedAssignments = $byAssignmentIdCalculatedAssignments + byPolicySetIdCalculatedAssignments = $byPolicySetIdCalculatedAssignments + byPolicyIdCalculatedAssignments = $byPolicyIdCalculatedAssignments + } + + return $result +} \ No newline at end of file diff --git a/Scripts/Helpers/Get-ClonedObject.ps1 b/Scripts/Helpers/Get-ClonedObject.ps1 new file mode 100644 index 00000000..7d73745c --- /dev/null +++ b/Scripts/Helpers/Get-ClonedObject.ps1 @@ -0,0 +1,88 @@ +function Get-ClonedObject { + [CmdletBinding()] + param( + [parameter(Position = 0, ValueFromPipeline = $true)] + $InputObject, + + [switch] $AsHashTable, + [switch] $AsShallowClone + ) + + $clone = $InputObject + if ($AsHashTable) { + if ($null -ne $InputObject) { + if ($AsShallowClone) { + if ($InputObject -is [psobject] -and $InputObject -isnot [System.ValueType]) { + $clone = [ordered]@{} + foreach ($property in $InputObject.PSObject.Properties) { + $null = $clone.Add($property.Name, $property.Value) + } + } + elseif ($InputObject -is [System.ICloneable]) { + $clone = $InputObject.Clone() + } + } + else { + $json = ConvertTo-Json $InputObject -Depth 100 -Compress + $clone = ConvertFrom-Json $json -NoEnumerate -Depth 100 -AsHashTable + } + } + else { + $clone = @{} + } + } + else { + if ($null -ne $InputObject) { + if ($AsShallowClone) { + if ($InputObject -is [System.ICloneable]) { + $clone = $InputObject.Clone() + } + } + elseif ($InputObject -is [System.ValueType] -or $InputObject -is [datetime]) { + $clone = $InputObject + } + else { + if ($InputObject -is [System.Collections.IDictionary]) { + $clone = $InputObject.Clone() + foreach ($key in $InputObject.Keys) { + $value = $InputObject[$key] + $isComplex = -not ($null -eq $value -or $value -is [string] -or $value -is [System.ValueType] -or $value -is [datetime]) + if ($isComplex) { + $clone[$key] = Get-ClonedObject -InputObject $value + } + } + } + elseif ($InputObject -is [System.Collections.IList]) { + $clone = $InputObject.Clone() + for ($i = 0; $i -lt $clone.Count; $i++) { + $value = $InputObject[$i] + $isComplex = -not ($null -eq $value -or $value -is [string] -or $value -is [System.ValueType] -or $value -is [datetime]) + if ($isComplex) { + $clone[$i] = Get-ClonedObject -InputObject $value + } + else { + # assumin uniform IList + break + } + } + } + elseif ($InputObject -is [psobject]) { + $clone = $InputObject.PSObject.Copy() + foreach ($propertyName in $InputObject.PSObject.Properties.Name) { + $value = $InputObject.$propertyName + $isComplex = -not ($null -eq $value -or $value -is [string] -or $value -is [System.ValueType] -or $value -is [datetime]) + if ($isComplex) { + $clone.$propertyName = Get-ClonedObject -InputObject $value + } + } + } + } + } + } + if ($clone -is [System.Collections.IList]) { + Write-Output $clone -NoEnumerate + } + else { + Write-Output $clone + } +} diff --git a/Scripts/Helpers/Get-DeepClone.ps1 b/Scripts/Helpers/Get-DeepClone.ps1 deleted file mode 100644 index a28d0cae..00000000 --- a/Scripts/Helpers/Get-DeepClone.ps1 +++ /dev/null @@ -1,26 +0,0 @@ -function Get-DeepClone { - [CmdletBinding()] - param( - [parameter(Position = 0, ValueFromPipeline = $true)] - $InputObject, - - [switch] $AsHashTable - ) - - if ($null -ne $InputObject) { - $json = ConvertTo-Json $InputObject -Depth 100 -Compress - $clone = ConvertFrom-Json $json -NoEnumerate -Depth 100 -AsHashTable:$AsHashTable - if ($InputObject -is [System.Collections.IList]) { - Write-Output -NoEnumerate $clone - } - else { - return $clone - } - } - elseif ($AsHashTable) { - return @{} - } - else { - return $null - } -} diff --git a/Scripts/Helpers/Get-ErrorTextFromInfo.ps1 b/Scripts/Helpers/Get-ErrorTextFromInfo.ps1 deleted file mode 100644 index 683bf658..00000000 --- a/Scripts/Helpers/Get-ErrorTextFromInfo.ps1 +++ /dev/null @@ -1,14 +0,0 @@ -function Get-ErrorTextFromInfo { - [CmdletBinding()] - param ( - [hashtable] $ErrorInfo - ) - if ($ErrorInfo.hasErrors) { - $bodyText = $ErrorInfo.errorStrings -join "`n`r" - $errorText = "'$($ErrorInfo.fileName)' has $($ErrorInfo.errorsInFile) errors:`n`r$bodyText" - $errorText - } - else { - "No errors found" - } -} diff --git a/Scripts/Helpers/Get-FilteredHashTable.ps1 b/Scripts/Helpers/Get-FilteredHashTable.ps1 deleted file mode 100644 index 65ad7c93..00000000 --- a/Scripts/Helpers/Get-FilteredHashTable.ps1 +++ /dev/null @@ -1,108 +0,0 @@ -function Get-FilteredHashTable { - [CmdletBinding()] - param - ( - [parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, HelpMessage = "Hashtable or custom object containing the values needed.")] - [PSCustomObject] $Splat, - - [Parameter(HelpMessage = " - Format is a string with a space separated list of substrings. Each substring: - - argName - selects that argument (if it exists) from the splat to the returned splat - - argName/commandArgName - changes the argName in the returned splat to the commandArgName - - argName:typeOverride - selects that argument (if it exists) from the splat to the returned splat AND overrides the implied argument value type - - argName/commandArgName:typeOverride - changes the argName in the returned splat to the commandArgName AND overrides the implied argument value type - Examples: - - Id DisplayName Description Metadata ExemptionCategory ExpiresOn ClearExpiration PolicyDefinitionReferenceIds/PolicyDefinitionReferenceId - - name/Name displayName/DisplayName description/Description parameter/Parameter:json Policy:json - ")] - [string] $SplatTransform = $null, - - [Parameter(HelpMessage = "Output will be formatted for use in az cli (instead of PowerShell modules")] - [switch] $FormatForAzCli - - ) - - [hashtable] $filteredSplat = @{} - if ($null -ne $Splat) { - # ignore an empty splat - if (-not ($Splat -is [hashtable])) { - $ht = ConvertTo-HashTable $Splat - $Splat = $ht - } - - $transforms = $Splat.Keys - if ($SplatTransform) { - $transforms = $SplatTransform.Split() - } - foreach ($transform in $transforms) { - $typeOverrideSplits = $transform.Split(":") - $argNamesTransform = $typeOverrideSplits[0] - $argNameSplits = $argNamesTransform.Split("/") - if (!($argNameSplits.Count -in @( 1, 2 ) -and $typeOverrideSplits.Count -in @( 1, 2 ))) { - Write-Error "Get-FilteredHashTable: splatTransform `"$SplatTransform`" contains an invalid element `"$transform`" - code bug" -ErrorAction Stop - } - $argName = $argNameSplits[0] - $commandArgName = $argNameSplits[-1] - $type = "infer" - if ($typeOverrideSplits.Count -eq 2) { - $type = $typeOverrideSplits[1] - } - if ($type -notin @("infer", "json", "hashtable", "array", "key", "value", "keyValue", "policyScope")) { - Write-Error "Get-FilteredHashTable: splatTransform `"$SplatTransform`" contains an invalid type override in element `"$transform`" - code bug" -ErrorAction Stop - } - - if ($Splat.ContainsKey($argName)) { - - $splatValue = $Splat.$argName - if ($null -ne $splatValue) { - - if ($type -eq "infer") { - # Infer format from data type - if ($splatValue -is [array]) { - $type = "array" - foreach ($value in $splatValue) { - if (-not($value -is [string] -or $value -is [System.ValueType])) { - $type = "json" - break - } - } - } - elseif ($splatValue -is [string] -or $splatValue -is [System.ValueType]) { - $type = "value" - } - else { - $type = "json" - } - } - - switch ($type) { - json { - $argValue = ConvertTo-Json $splatValue -Depth 100 -Compress - $null = $filteredSplat.Add($commandArgName, $argValue) - } - hashtable { - $argValue = Get-DeepClone $splatValue -AsHashTable - $null = $filteredSplat.Add($commandArgName, $argValue) - } - key { - # Just the key (no value) - $null = $filteredSplat.Add($commandArgName, $true) - } - value { - $null = $filteredSplat.Add($commandArgName, $splatValue) - } - array { - $null = $filteredSplat.Add($commandArgName, $splatValue) - } - policyScope { - $argName, $argValue = Split-ScopeId -ScopeId $splatValue - $filteredSplat.Add($argName, $argValue) - } - } - } - } - } - } - - return $filteredSplat -} diff --git a/Scripts/Helpers/Get-GlobalSettings.ps1 b/Scripts/Helpers/Get-GlobalSettings.ps1 index d89a44e6..1c60f661 100644 --- a/Scripts/Helpers/Get-GlobalSettings.ps1 +++ b/Scripts/Helpers/Get-GlobalSettings.ps1 @@ -1,4 +1,5 @@ function Get-GlobalSettings { + [CmdletBinding()] param ( [Parameter(Mandatory = $false)] [string] $DefinitionsRootFolder, @@ -24,214 +25,328 @@ function Get-GlobalSettings { Write-Information "PowerShell Versions: $($PSVersionTable.PSVersion)" $Json = Get-Content -Path $globalSettingsFile -Raw -ErrorAction Stop + $settings = @{} try { - [hashtable] $settings = $Json | ConvertFrom-Json -AsHashTable + $settings = $Json | ConvertFrom-Json -AsHashTable } catch { Write-Error "Assignment JSON file '$($globalSettingsFile)' is not valid." -ErrorAction Stop } - [array] $pacEnvironments = $settings.pacEnvironments - [hashtable] $pacEnvironmentDefinitions = @{} - [string[]] $pacEnvironmentSelectors = @() - $telemetryOptOut = $settings.telemetryOptOut $telemetryEnabled = $true - if ($telemetryOptOut) { - $telemetryEnabled = $false + if ($null -ne $telemetryOptOut) { + $telemetryEnabled = -not $telemetryOptOut } + [hashtable] $pacEnvironmentDefinitions = @{} + $pacEnvironmentSelectors = [System.Collections.ArrayList]::new() + $hasErrors = $false $pacOwnerId = $settings.pacOwnerId if ($null -eq $pacOwnerId) { - Write-Error "global-settings does not contain a pacOwnerId. Add a pacOwnerId field with a GUID or other unique id!" -ErrorAction Stop + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: does not contain the required pacOwnerId field. Add a pacOwnerId field with a GUID or other unique id!" + $hasErrors = $true } - foreach ($pacEnvironment in $pacEnvironments) { + if ($null -ne $settings.globalNotScopes) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: contains a deprecated globalNotScopes field. Move the values into each pacEnvironment!" + $hasErrors = $true + } + if ($null -ne $settings.managedIdentityLocations -or $null -ne $settings.managedIdentityLocation) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: contains a deprecated managedIdentityLocations field. Move the values into each pacEnvironment!" + $hasErrors = $true + } - $pacSelector = $pacEnvironment.pacSelector - if ($null -eq $pacSelector) { - Write-Error "Policy as Code pacEnvironments array element does not contain a pacSelector." -ErrorAction Stop - } - $pacEnvironmentSelectors += $pacSelector + $pacEnvironments = $settings.pacEnvironments + if ($null -eq $pacEnvironments) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: does not contain a pacEnvironments array. Add a pacEnvironments array with at least one environment!" + $hasErrors = $true + } + elseif ($pacEnvironments -isnot [array]) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironments must be an array of objects." + $hasErrors = $true + } + elseif ($pacEnvironments.Count -eq 0) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironments array must contain at least one environment." + $hasErrors = $true + } + else { + foreach ($pacEnvironment in $pacEnvironments) { - $cloud = $pacEnvironment.cloud - if ($null -eq $cloud) { - Write-Warning "Policy as Code environment $pacSelector does not define the cloud to use, default to 'AzureCloud'" - $cloud = "AzureCloud" - } + $pacSelector = $pacEnvironment.pacSelector + if ($null -eq $pacSelector) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: a pacEnvironments array element does not contain the required pacSelector element." + $hasErrors = $true + } + $null = $pacEnvironmentSelectors.Add($pacSelector) - $tenantId = $pacEnvironment.tenantId - if ($null -eq $tenantId) { - Write-Error "Policy as Code environment $pacSelector does not contain a tenantId." -ErrorAction Stop - } + $cloud = $pacEnvironment.cloud + if ($null -eq $cloud) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector does not define the required cloud element." + $hasErrors = $true + } - $defaultSubscriptionId = $pacEnvironment.defaultSubscriptionId - if ($null -ne $defaultSubscriptionId) { - Write-Warning "Policy as Code environment $pacSelector contains a legacy defaultSubscriptionId. Remove it!" -ErrorAction Stop - } - if ($null -ne $pacEnvironment.rootScope) { - Write-Error "Policy as Code environment $pacSelector contains a legacy rootScope. Replace rootScope with deploymentRootScope containing a fully qualified scope id!" -ErrorAction Stop - } + $tenantId = $pacEnvironment.tenantId + if ($null -eq $tenantId) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector does not contain required tenantId field." + $hasErrors = $true + } - $policyDefinitionsScopes = @() - $deploymentRootScope = $null - if ($null -ne $pacEnvironment.deploymentRootScope) { - $deploymentRootScope = $pacEnvironment.deploymentRootScope - $policyDefinitionsScopes += $deploymentRootScope + # Managed identity location + $managedIdentityLocation = $pacEnvironment.managedIdentityLocation + if ($null -eq $managedIdentityLocation) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector does not contain required managedIdentityLocation field." + $hasErrors = $true + } - if ($null -ne $pacEnvironment.inheritedDefinitionsScopes) { - $inheritedDefinitionsScopes = $pacEnvironment.inheritedDefinitionsScopes - if ($inheritedDefinitionsScopes -isnot [array]) { - Write-Error "Policy as Code environment $pacSelector element inheritedDefinitionsScopes must be an array of strings." -ErrorAction Stop + $managingTenantId = $pacEnvironment.managingTenant.managingTenantId + $managingTenantRootScope = $pacEnvironment.managingTenant.managingTenantRootScope + if ($null -ne $managingTenantId) { + if ($null -eq $pacEnvironment.managingTenant.managingTenantRootScope) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector element managingTenantRootScope must have a valid value when managingTenantID has a value." + $hasErrors = $true + } + $objectGuid = [System.Guid]::empty + # Returns True if successfully parsed, otherwise returns False. + $isGUID = [System.Guid]::TryParse($managingTenantId, [System.Management.Automation.PSReference]$objectGuid) + if ($isGUID -ne $true) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field managingTenant ($managingTenantId) must be a GUID." + $hasErrors = $true + } + } + elseif ($null -ne $managingTenantRootScope) { + if ($null -eq $managingTenantId) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector element managingTenantID must be a valid GUID when managingTenantRootScope has a value." + $hasErrors = $true } - $policyDefinitionsScopes += $inheritedDefinitionsScopes } - $policyDefinitionsScopes += "" - } - else { - Write-Error "Policy as Code environment $pacSelector must contain a deploymentRootScope field." -ErrorAction Stop - } - # globalNotScopes - [array] $globalNotScopeList = @() - if ($null -ne $settings.globalNotScopes) { - $globalNotScopes = $settings.globalNotScopes - if ($globalNotScopes.ContainsKey($pacSelector)) { - $globalNotScopeList += $globalNotScopes[$pacSelector] + $defaultSubscriptionId = $pacEnvironment.defaultSubscriptionId + if ($null -ne $defaultSubscriptionId) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector contains a deprecated defaultSubscriptionId. Remove it!" + $hasErrors = $true } - if ($globalNotScopes.ContainsKey("*")) { - $globalNotScopeList += $globalNotScopes["*"] + if ($null -ne $pacEnvironment.rootScope) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector contains a deprecated rootScope. Replace rootScope with deploymentRootScope containing a fully qualified scope id!" + $hasErrors = $true + } + if ($null -ne $pacEnvironment.inheritedDefinitionsScopes) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector contains a deprecated inheritedDefinitionsScopes. To cover the use case see https://aka.ms/epac/settings-desired-state.md#use-case-4-multiple-teams-in-a-hierarchical-organization!" + $hasErrors = $true } - } - $desiredState = @{ # defaults - strategy = "full" # Mirrors previous behavior (before desireState feature). -NoDelete would be equivalent to ownedOnly - includeResourceGroups = $false # Mirrors previous behavior (before desireState feature). -IncludeResourceGroups would be equivalent to $true - excludedScopes = [System.Collections.ArrayList]::new() - excludedPolicyDefinitions = @() - excludedPolicySetDefinitions = @() - excludedPolicyAssignments = @() - deleteExpiredExemptions = $true - deleteOrphanedExemptions = $true - keepDfcSecurityAssignments = $false - } - if ($null -ne $pacEnvironment.desiredState) { - $desired = $pacEnvironment.desiredState - $strategy = $desired.strategy - if ($null -ne $strategy) { - $valid = @("full", "ownedOnly") - if ($strategy -notin $valid) { - Write-Error "Policy as Code environment $pacSelector field desiredState.strategy ($strategy) must be one of $(ConvertTo-Json $valid -Compress)." -ErrorAction Stop - } - $desiredState.strategy = $strategy + $deploymentRootScope = $pacEnvironment.deploymentRootScope + if ($null -eq $pacEnvironment.deploymentRootScope) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector does not contain deploymentRootScope field." + $hasErrors = $true } - $includeResourceGroups = $desired.includeResourceGroups - if ($null -ne $includeResourceGroups) { - if ($includeResourceGroups -is [bool]) { - $desiredState.includeResourceGroups = $includeResourceGroups + $policyDefinitionsScopes = @( $deploymentRootScope, "") + + $deployedBy = "epac/$pacOwnerId/$pacSelector" + if ($null -ne $pacEnvironment.deployedBy) { + $deployedBy = $pacEnvironment.deployedBy + } + + # globalNotScopes + $globalNotScopesList = [System.Collections.ArrayList]::new() + $globalNotScopesResourceGroupsList = [System.Collections.ArrayList]::new() + $globalNotScopesSubscriptionsList = [System.Collections.ArrayList]::new() + $globalNotScopesManagementGroupsList = [System.Collections.ArrayList]::new() + $excludedScopesList = [System.Collections.ArrayList]::new() + $globalExcludedScopesResourceGroupsList = [System.Collections.ArrayList]::new() + $globalExcludedScopesSubscriptionsList = [System.Collections.ArrayList]::new() + $globalExcludedScopesManagementGroupsList = [System.Collections.ArrayList]::new() + + $pacEnvironmentGlobalNotScopes = $pacEnvironment.globalNotScopes + if ($null -ne $pacEnvironmentGlobalNotScopes) { + if ($pacEnvironmentGlobalNotScopes -isnot [array]) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field globalNotScopes must be an array of strings." + $hasErrors = $true } else { - Write-Error "Policy as Code environment $pacSelector field desiredState.includeResourceGroups ($includeResourceGroups) must be a boolean value." -ErrorAction Stop + foreach ($globalNotScope in $pacEnvironmentGlobalNotScopes) { + if ($globalNotScope -isnot [string]) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field globalNotScopes must be an array of strings." + $hasErrors = $true + } + elseif ($globalNotScope.Contains("/resourceGroupPatterns/", [System.StringComparison]::OrdinalIgnoreCase)) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field globalNotScopes entry ($globalNotScope) must not contain deprecated /resourceGroupPatterns/.`n`rReplace it with excludedScopes pattern `"/subscriptions/*/resourceGroups/`"" + $hasErrors = $true + } + else { + $null = $excludedScopesList.Add($globalNotScope) + if ($globalNotScope.StartsWith("/subscriptions/")) { + if ($globalNotScope.Contains("/resourceGroups/", [System.StringComparison]::OrdinalIgnoreCase)) { + $null = $globalExcludedScopesResourceGroupsList.Add($globalNotScope) + $null = $globalNotScopesResourceGroupsList.Add($globalNotScope) + } + else { + $null = $globalExcludedScopesSubscriptionsList.Add($globalNotScope) + $null = $globalNotScopesSubscriptionsList.Add($globalNotScope) + } + } + elseif ($globalNotScope.StartsWith("/providers/Microsoft.Management/managementGroups/")) { + $null = $globalExcludedScopesManagementGroupsList.Add($globalNotScope) + $null = $globalNotScopesManagementGroupsList.Add($globalNotScope) + } + else { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field globalNotScopes entry ($globalNotScope) must be a valid scope." + $hasErrors = $true + } + } + } } } - $keepDfcSecurityAssignments = $desired.keepDfcSecurityAssignments - if ($null -ne $keepDfcSecurityAssignments) { - if ($keepDfcSecurityAssignments -is [bool]) { - $desiredState.keepDfcSecurityAssignments = $keepDfcSecurityAssignments + + $desiredState = @{ + strategy = "undefined" + keepDfcSecurityAssignments = $false + excludedScopes = $excludedScopesList + globalExcludedScopesResourceGroups = $globalExcludedScopesResourceGroupsList + globalExcludedScopesSubscriptions = $globalExcludedScopesSubscriptionsList + globalExcludedScopesManagementGroups = $globalExcludedScopesManagementGroupsList + excludedPolicyDefinitions = @() + excludedPolicySetDefinitions = @() + excludedPolicyAssignments = @() + } + + $desired = $pacEnvironment.desiredState + if ($null -eq $desired) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector does not contain required desiredState field." + $hasErrors = $true + } + else { + $strategy = $desired.strategy + if ($null -eq $strategy) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector does not contain required desiredState.strategy field." + $hasErrors = $true } else { - Write-Error "Policy as Code environment $pacSelector field desiredState.keepDfcSecurityAssignments ($keepDfcSecurityAssignments) must be a boolean value." -ErrorAction Stop + $valid = @("full", "ownedOnly") + if ($strategy -notin $valid) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field desiredState.strategy ($strategy) must be one of $(ConvertTo-Json $valid -Compress)." + $hasErrors = $true + } + $desiredState.strategy = $strategy } - } - $excluded = $desired.excludedScopes - if ($null -ne $excluded) { - if ($excluded -isnot [array]) { - Write-Error "Policy as Code environment $pacSelector field desiredState.excludedScopes ($(ConvertTo-Json $excluded -Compress)) must be an array of strings." -ErrorAction Stop + $includeResourceGroups = $desired.includeResourceGroups + if ($null -ne $includeResourceGroups) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field desiredState.includeResourceGroups is deprecated.`n`rIf set to false, replace it with excludedScopes pattern `"/subscriptions/*/resourceGroups/*`"" + $hasErrors = $true } - foreach ($entry in $excluded) { - if ($null -ne $entry -and $entry -is [string] -and $entry -ne "") { - $null = $desiredState.excludedScopes.Add($entry) - } + $keepDfcSecurityAssignments = $desired.keepDfcSecurityAssignments + if ($null -eq $keepDfcSecurityAssignments) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector does not contain required desiredState.keepDfcSecurityAssignments field." } - } - $excluded = $desired.excludedPolicyDefinitions - if ($null -ne $excluded) { - if ($excluded -isnot [array]) { - Write-Error "Policy as Code environment $pacSelector field desiredState.excludedPolicyDefinitions ($(ConvertTo-Json $excluded -Compress)) must be an array of strings." -ErrorAction Stop + else { + if ($keepDfcSecurityAssignments -is [bool]) { + $desiredState.keepDfcSecurityAssignments = $keepDfcSecurityAssignments + } + else { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field desiredState.keepDfcSecurityAssignments ($keepDfcSecurityAssignments) must be a boolean value." + $hasErrors = $true + } } - $desiredState.excludedPolicyDefinitions = $excluded - } - $excluded = $desired.excludedPolicySetDefinitions - if ($null -ne $excluded) { - if ($excluded -isnot [array]) { - Write-Error "Policy as Code environment $pacSelector field desiredState.excludedPolicySetDefinitions ($(ConvertTo-Json $excluded -Compress)) must be an array of strings." -ErrorAction Stop + $excludedScopes = $desired.excludedScopes + if ($null -ne $excluded) { + if ($excludedScopes -isnot [array]) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field desiredState.excludedScopes must be an array of strings." + $hasErrors = $true + } + foreach ($excludedScope in $excludedScopes) { + if ($null -ne $excludedScope -and $excludedScope -is [string] -and $excludedScope -ne "") { + if ($excludedScope.Contains("/resourceGroupPatterns/", [System.StringComparison]::OrdinalIgnoreCase)) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field desiredState.excludedScopes ($excludedScope) must not contain deprecated /resourceGroupPatterns/.`n`rReplace it with excludedScopes pattern `"/subscriptions/*/resourceGroups/`"" + $hasErrors = $true + } + else { + $null = $excludedScopesList.Add($excludedScope) + if ($excludedScope.StartsWith("/subscriptions/")) { + if ($excludedScope.Contains("/resourceGroups/", [System.StringComparison]::OrdinalIgnoreCase)) { + $null = $globalExcludedScopesResourceGroupsList.Add($excludedScope) + } + else { + $null = $globalNotScopesSubscriptionsList.Add($excludedScope) + } + } + elseif ($excludedScope.StartsWith("/providers/Microsoft.Management/managementGroups/")) { + $null = $globalExcludedScopesManagementGroupsList.Add($excludedScope) + } + else { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field desiredState.excludedScopes ($excludedScope) must be a valid scope." + $hasErrors = $true + } + } + } + } } - $desiredState.excludedPolicySetDefinitions = $excluded - } - $excluded = $desired.excludedPolicyAssignments - if ($null -ne $excluded) { - if ($excluded -isnot [array]) { - Write-Error "Policy as Code environment $pacSelector field desiredState.excludedPolicyAssignments ($(ConvertTo-Json $excluded -Compress)) must be an array of strings." -ErrorAction Stop + $excluded = $desired.excludedPolicyDefinitions + if ($null -ne $excluded) { + if ($excluded -isnot [array]) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field desiredState.excludedPolicyDefinitions must be an array of strings." + $hasErrors = $true + } + $desiredState.excludedPolicyDefinitions = $excluded } - $desiredState.excludedPolicyAssignments = $excluded - } - $deleteExpired = $desired.deleteExpiredExemptions - if ($null -ne $deleteExpired) { - if ($deleteExpired -is [bool]) { - $desiredState.deleteExpiredExemptions = $deleteExpired + $excluded = $desired.excludedPolicySetDefinitions + if ($null -ne $excluded) { + if ($excluded -isnot [array]) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field desiredState.excludedPolicySetDefinitions must be an array of strings." + $hasErrors = $true + } + $desiredState.excludedPolicySetDefinitions = $excluded } - else { - Write-Error "Policy as Code environment $pacSelector field desiredState.deleteExpiredExemptions ($deleteExpired) must be a boolean value." -ErrorAction Stop + $excluded = $desired.excludedPolicyAssignments + if ($null -ne $excluded) { + if ($excluded -isnot [array]) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field desiredState.excludedPolicyAssignments must be an array of strings." + $hasErrors = $true + } + $desiredState.excludedPolicyAssignments = $excluded } - } - $deleteOrphaned = $desired.deleteOrphanedExemptions - if ($null -ne $deleteOrphaned) { - if ($deleteOrphaned -is [bool]) { - $desiredState.deleteOrphanedExemptions = $deleteOrphaned + $deleteExpired = $desired.deleteExpiredExemptions + if ($null -ne $deleteExpired) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field desiredState.deleteExpiredExemptions is deprecated. Remove it!" } - else { - Write-Error "Policy as Code environment $pacSelector field desiredState.deleteOrphanedExemptions ($deleteOrphaned) must be a boolean value." -ErrorAction Stop + $deleteOrphaned = $desired.deleteOrphanedExemptions + if ($null -ne $deleteOrphaned) { + Write-Host -ForegroundColor Red "Error in global-settings.jsonc: pacEnvironment $pacSelector field desiredState.deleteOrphanedExemptions is deprecated. Remove it!" } } - } - foreach ($entry in $globalNotScopeList) { - if ($null -ne $entry -and $entry -ne "" -and !$entry.Contains("*")) { - $null = $desiredState.excludedScopes.Add($entry) - } - } - # Managed identity location - $managedIdentityLocation = $null - if ($settings.managedIdentityLocations) { - $managedIdentityLocations = $settings.managedIdentityLocations - if ($managedIdentityLocations.ContainsKey($pacSelector)) { - $managedIdentityLocation = $managedIdentityLocations[$pacSelector] + $pacEnvironmentDefinition = @{ + pacSelector = $pacSelector + pacOwnerId = $pacOwnerId + deployedBy = $deployedBy + cloud = $cloud + tenantId = $tenantId + managingTenantId = $managingTenantId + managingTenantRootScope = $managingTenantRootScope + deploymentRootScope = $deploymentRootScope + policyDefinitionsScopes = $policyDefinitionsScopes + desiredState = $desiredState + managedIdentityLocation = $managedIdentityLocation + globalNotScopes = $globalNotScopesList.ToArray() + globalNotScopesResourceGroups = $globalNotScopesResourceGroupsList.ToArray() + globalNotScopesSubscriptions = $globalNotScopesSubscriptionsList.ToArray() + globalNotScopesManagementGroups = $globalNotScopesManagementGroupsList.ToArray() } - elseif ($managedIdentityLocations.ContainsKey("*")) { - $managedIdentityLocation = $managedIdentityLocations["*"] - } + $null = $pacEnvironmentDefinitions.Add($pacSelector, $pacEnvironmentDefinition) } - $null = $pacEnvironmentDefinitions.Add($pacSelector, @{ - pacSelector = $pacSelector - pacOwnerId = $pacOwnerId - cloud = $cloud - tenantId = $tenantId - deploymentRootScope = $deploymentRootScope - policyDefinitionsScopes = $policyDefinitionsScopes - desiredState = $desiredState - globalNotScopes = $globalNotScopeList - managedIdentityLocation = $managedIdentityLocation - } - ) } - $prompt = $pacEnvironmentSelectors | Join-String -Separator ', ' + + if ($hasErrors) { + Write-Error "Global settings contains errors." -ErrorAction Stop + } Write-Information "PAC Environments: $($prompt)" + Write-Information "PAC Owner Id: $pacOwnerId" Write-Information "Definitions root folder: $DefinitionsRootFolder" Write-Information "Input folder: $InputFolder" Write-Information "Output folder: $OutputFolder" Write-Information "" + $policyDocumentationsFolder = "$DefinitionsRootFolder/policyDocumentations" $policyDefinitionsFolder = "$DefinitionsRootFolder/policyDefinitions" diff --git a/Scripts/Helpers/Get-HashtableShallowClone.ps1 b/Scripts/Helpers/Get-HashtableShallowClone.ps1 deleted file mode 100644 index 3bd1c05a..00000000 --- a/Scripts/Helpers/Get-HashtableShallowClone.ps1 +++ /dev/null @@ -1,19 +0,0 @@ -#Requires -PSEdition Core -function Get-HashtableShallowClone { - [cmdletbinding()] - param( - [parameter(Position = 0, ValueFromPipeline = $true)] - $InputObject - ) - - $clone = @{} - if ($null -ne $InputObject) { - if ($InputObject -isnot [hashtable]) { - $clone = ConvertTo-HashTable $InputObject - } - else { - $clone = $InputObject.Clone() - } - } - return $clone -} diff --git a/Scripts/Helpers/Get-HashtableWithPropertyNamesRemoved.ps1 b/Scripts/Helpers/Get-HashtableWithPropertyNamesRemoved.ps1 deleted file mode 100644 index a25d9b21..00000000 --- a/Scripts/Helpers/Get-HashtableWithPropertyNamesRemoved.ps1 +++ /dev/null @@ -1,38 +0,0 @@ -function Get-HashtableWithPropertyNamesRemoved { - [CmdletBinding()] - param( - $Object, - $PropertyNames - ) - - $objectClone = $Object - if ($Object -is [System.Collections.IDictionary]) { - $objectClone1 = $Object.Clone() - if ($PropertyNames -is [System.Collections.IList]) { - foreach ($propertyName in $PropertyNames) { - $objectClone1.Remove($propertyName) - } - } - else { - $objectClone1.Remove($PropertyNames) - } - $objectClone = @{} - foreach ($key in $objectClone1.Keys) { - $value = $objectClone1.$key - $newValue = Get-HashtableWithPropertyNamesRemoved -Object $value -property $PropertyNames - $null = $objectClone.Add($key, $newValue) - } - return $objectClone - } - elseif ($Object -is [System.Collections.IList]) { - $objectClone = [System.Collections.ArrayList]::new() - foreach ($item in $Object) { - $newValue = Get-HashtableWithPropertyNamesRemoved -Object $item -property $PropertyNames - $null = $objectClone.Add($newValue) - } - Write-Output $objectClone -NoEnumerate - } - else { - return $objectClone - } -} diff --git a/Scripts/Helpers/Get-AssignmentsDetails.ps1 b/Scripts/Helpers/Get-PolicyAssignmentsDetails.ps1 similarity index 95% rename from Scripts/Helpers/Get-AssignmentsDetails.ps1 rename to Scripts/Helpers/Get-PolicyAssignmentsDetails.ps1 index 84ac393f..c456894a 100644 --- a/Scripts/Helpers/Get-AssignmentsDetails.ps1 +++ b/Scripts/Helpers/Get-PolicyAssignmentsDetails.ps1 @@ -1,4 +1,4 @@ -function Get-AssignmentsDetails { +function Get-PolicyAssignmentsDetails { [CmdletBinding()] param ( [array] $AssignmentArray, @@ -36,7 +36,7 @@ function Get-AssignmentsDetails { if ($policySetId.Contains("policySetDefinition", [StringComparison]::InvariantCultureIgnoreCase)) { # PolicySet if ($policySetsDetails.ContainsKey($policySetId)) { - $combinedDetail = Get-DeepClone $policySetsDetails.$policySetId -AsHashTable + $combinedDetail = Get-ClonedObject $policySetsDetails.$policySetId -AsHashTable $combinedDetail.assignmentId = $assignmentId $combinedDetail.assignment = $assignment $combinedDetail.policySetId = $policySetId diff --git a/Scripts/Helpers/Get-SelectedPacValue.ps1 b/Scripts/Helpers/Get-SelectedPacValue.ps1 deleted file mode 100644 index 9703b878..00000000 --- a/Scripts/Helpers/Get-SelectedPacValue.ps1 +++ /dev/null @@ -1,34 +0,0 @@ -function Get-SelectedPacValue { - [CmdletBinding()] - param ( - [parameter(Position = 0, ValueFromPipeline = $true)] - $InputObject, - - [string] $PacSelector, - [switch] $DeepClone - ) - - [hashtable] $selectableHashtable = @{} - $value = $null - if ($DeepClone) { - $selectableHashtable = Get-DeepClone $InputObject -AsHashTable - } - else { - $selectableHashtable = Get-HashtableShallowClone $InputObject - } - if ($selectableHashtable.ContainsKey("*")) { - # default - $value = $selectableHashtable["*"] - } - if ($selectableHashtable.ContainsKey($PacSelector)) { - # specific, overrides default - $value = $selectableHashtable[$PacSelector] - } - - if ($value -is [array] -and $value.Count -le 1) { - Write-Output $value -NoEnumerate - } - else { - return $value - } -} diff --git a/Scripts/Helpers/Invoke-AzResMethodWrapper.ps1 b/Scripts/Helpers/Invoke-AzResMethodWrapper.ps1 deleted file mode 100644 index d5a962c6..00000000 --- a/Scripts/Helpers/Invoke-AzResMethodWrapper.ps1 +++ /dev/null @@ -1,42 +0,0 @@ -function Invoke-AzRestMethodWrapper { - [CmdletBinding()] - param ( - [Parameter(Mandatory = $true)] - [string] $ObjectName, - - [Parameter(Mandatory = $true)] - [string] $Path, - - [Parameter(Mandatory = $true)] - [string] $Method, - - [Parameter(Mandatory = $false)] - [string] $Payload = "" - ) - - $response = $null - if ([string]::IsNullOrWhiteSpace($Payload)) { - $response = Invoke-AzRestMethod -Path $Path -Method $Method - } - else { - $response = Invoke-AzRestMethod -Path $Path -Method $Method -Payload $Payload - } - - # Process response - $statusCode = $response.StatusCode - if ($statusCode -lt 200 -or $statusCode -ge 300) { - $content = $response.Content - # truncate $Payload to avoid spamming the log - $PayLoadTruncated = $Payload - if ($Payload.Length -gt 200) { - $PayLoadTruncated = $Payload.Substring(0, 199) + "..." - } - Write-Information "$($ObjectName) error:" - Write-Information " httpStatus = $($statusCode)" - Write-Information " error = '$($content)'" - Write-Information " path = '$($path)'" - Write-Information " payload = '$($PayLoadTruncated)'" - Write-Error "Invoke-AzRestMethod returned an error" -ErrorAction Continue - } - $response -} \ No newline at end of file diff --git a/Scripts/Helpers/Merge-AssignmentParametersEx.ps1 b/Scripts/Helpers/Merge-AssignmentParametersEx.ps1 index 09bdf7b1..0c97e8d4 100644 --- a/Scripts/Helpers/Merge-AssignmentParametersEx.ps1 +++ b/Scripts/Helpers/Merge-AssignmentParametersEx.ps1 @@ -1,5 +1,4 @@ function Merge-AssignmentParametersEx { - # Recursive Function param( $NodeName, $PolicySetId, @@ -16,32 +15,32 @@ function Merge-AssignmentParametersEx { $nonComplianceMessageColumn = $ParameterInstructions.nonComplianceMessageColumn #region parameters column - - $parameters = Get-DeepClone $BaseAssignment.parameters -AsHashTable + $parameters = Get-ClonedObject $BaseAssignment.parameters -AsHashTable foreach ($row in $csvParameterArray) { if ($row.flatPolicyEntryKey) { $parametersColumnCell = $row[$parametersColumn] if ($null -ne $parametersColumnCell -and $parametersColumnCell -ne "") { $addedParameters = ConvertFrom-Json $parametersColumnCell -Depth 100 -AsHashTable - if ($null -ne $addedParameters -and $addedParameters.psbase.Count -gt 0) { + if ($null -ne $addedParameters) { foreach ($parameterName in $addedParameters.Keys) { - $rawParameterValue = $addedParameters.$parameterName - $parameterValue = Get-DeepClone $rawParameterValue -AsHashTable - $parameters[$parameterName] = $parameterValue + if (!$parameters.ContainsKey($parameterName)) { + $parameterValue = $addedParameters.$parameterName + $parameters[$parameterName] = $parameterValue + } } } } } } - #endregion parameters column - #region parameters column = mutual exclusion handled - + #region effects column = mutual exclusion handled $overridesByEffect = @{} $nonComplianceMessages = $BaseAssignment.nonComplianceMessages $hasErrors = $false + $rowNumber = 1 foreach ($row in $csvParameterArray) { + ++$rowNumber $flatPolicyEntryKey = $row.flatPolicyEntryKey if ($flatPolicyEntryKey) { $name = $row.name @@ -53,141 +52,110 @@ function Merge-AssignmentParametersEx { if ($policySetList.ContainsKey($PolicySetId)) { # Policy in this for loop iteration is referenced in the Policy Set currently being processed - #region effect parameters including overrides + $requestedEffect = $row[$effectColumn] + $planedEffect = $requestedEffect + $isProcessed = $EffectProcessedForPolicy.ContainsKey($flatPolicyEntryKey) $perPolicySet = $policySetList.$PolicySetId $effectParameterName = $perPolicySet.effectParameterName - $effect = $row[$effectColumn] - $setEffectAllowedValues = $perPolicySet.effectAllowedValues - $effectAllowedOverrides = $flatPolicyEntry.effectAllowedOverrides + $effectAllowedValues = $perPolicySet.effectAllowedValues + $effectAllowedOverrides = $perPolicySet.effectAllowedOverrides $effectDefault = $perPolicySet.effectDefault - $desiredEffect = $effect.ToLower() - $useOverrides = $false - $policyDefinitionReferenceId = $perPolicySet.policyDefinitionReferenceId - $isProcessed = $EffectProcessedForPolicy.ContainsKey($flatPolicyEntryKey) - $modifiedEffect = $desiredEffect if ($isProcessed) { - # the second and subsequent time this Policy is processed, the effect must be adjusted to audit - if ($desiredEffect -eq $EffectProcessedForPolicy.$flatPolicyEntryKey) { - # Adjust desiredEffect - $modifiedEffect = switch ($desiredEffect) { - append { - "Audit" - } - modify { - "Audit" - } - deny { - "Audit" - } - deployIfNotExists { - "AuditIfNotExists" - } - manual { - "Manual" - } - Default { - $_ - } + #region the second and subsequent time this Policy is processed, the effect must be adjusted to audit + $planedEffect = switch ($requestedEffect) { + "Append" { + "Audit" + break } - } - } - else { - # first encounter of this Policy, use desired value (previously set) and enter in list of processed Policies - $null = $EffectProcessedForPolicy.Add($flatPolicyEntryKey, $desiredEffect) - } - - $isAllowed = $false - if ($perPolicySet.isEffectParameterized) { - if ($desiredEffect -ne $modifiedEffect) { - # check if the modified effect is an allowed parameter value or an allowed override value - if ($setEffectAllowedValues -contains $modifiedEffect) { - # the modified effect is an allowed parameter value - $isAllowed = $true - $desiredEffect = $modifiedEffect + "Modify" { + "Audit" + break } - elseif ($effectAllowedOverrides -contains $modifiedEffect) { - # the modified effect is an allowed override value - $desiredEffect = $modifiedEffect - $isAllowed = $true - $useOverrides = $true + "Deny" { + "Audit" + break } - } - if (!$isAllowed) { - # check if the original desired effect is an allowed parameter value or an allowed override value - if ($setEffectAllowedValues -contains $desiredEffect) { - # the original desired effect is an allowed parameter value - $isAllowed = $true + "DeployIfNotExists" { + "AuditIfNotExists" + break } - elseif ($effectAllowedOverrides -contains $desiredEffect) { - # the original desired effect is an allowed override value - $isAllowed = $true - $useOverrides = $true + "DenyAction" { + "Disabled" + break + } + default { + $_ } } + #endregion the second and subsequent time this Policy is processed, the effect must be adjusted to audit } else { - # the effect is not parameterized - if ($desiredEffect -ne $modifiedEffect) { - # check if the modified effect is an allowed override value - if ($effectAllowedOverrides -contains $modifiedEffect) { - # the modified effect is an allowed override value - $desiredEffect = $modifiedEffect - $isAllowed = $true + $EffectProcessedForPolicy[$flatPolicyEntryKey] = $true + } + + if ($planedEffect -ne $effectDefault) { + + #region effect parameters including overrides + $policyDefinitionReferenceId = $perPolicySet.policyDefinitionReferenceId + + $useOverrides = $false + $confirmedEffect = $null + if ($perPolicySet.isEffectParameterized) { + # test parameter + $useOverrides = $false + $confirmedEffect = Confirm-EffectIsAllowed -Effect $planedEffect -AllowedEffects $effectAllowedValues + if ($null -eq $confirmedEffect) { + # fallback 1: test override $useOverrides = $true + $confirmedEffect = Confirm-EffectIsAllowed -Effect $planedEffect -AllowedEffects $effectAllowedOverrides + if ($null -eq $confirmedEffect -and $requestedEffect -ne $planedEffect) { + # fallback 2: if this is the second processed Policy Set, try parameter with original requested effect + $useOverrides = $false + $confirmedEffect = Confirm-EffectIsAllowed -Effect $requestedEffect -AllowedEffects $effectAllowedValues + if ($null -eq $confirmedEffect) { + # fallback 3: try overrides with the original requested effect + $useOverrides = $true + $confirmedEffect = Confirm-EffectIsAllowed -Effect $requestedEffect -AllowedEffects $effectAllowedOverrides + } + } } } - if (!$isAllowed) { - # check if the original desired effect is an allowed override value - if ($effectAllowedOverrides -contains $desiredEffect) { - # the original desired effect is an allowed override value - $isAllowed = $true - $useOverrides = $true + else { + # the effect is not parameterized + $useOverrides = $true + $confirmedEffect = Confirm-EffectIsAllowed -Effect $planedEffect -AllowedEffects $effectAllowedOverrides + if ($null -eq $confirmedEffect) { + # fallback: try overrides with the original requested effect + $confirmedEffect = Confirm-EffectIsAllowed -Effect $requestedEffect -AllowedEffects $effectAllowedOverrides } } - } - if (!$isAllowed) { - # the effect is not an allowed value - Write-Error " Node $($NodeName): CSV parameterFile '$parameterFileName' row for Policy name '$name': the effect ($effect) must be an allowed value." - $hasErrors = $true - continue - } - else { - if ($desiredEffect -ne $effectDefault) { - # the effect is not the default value + if ($null -eq $confirmedEffect) { + # the effect is not an allowed value + Write-Error " Node $($NodeName): CSV parameterFile '$parameterFileName' row $rowNumber for Policy name '$name': the effect ($effect) must be an allowed value." -ErrorAction Continue + $hasErrors = $true + continue + } + elseif ($confirmedEffect -ne $effectDefault) { if ($useOverrides) { - # find the correct case for the allowed override value - foreach ($effectAllowedOverride in $effectAllowedOverrides) { - if ($effectAllowedOverride -eq $desiredEffect) { - $desiredEffect = $effectAllowedOverride # fixes potentially wrong case, or keeps the original case - break - } - } # collate the overrides by effect $byEffectList = $null - if ($overridesByEffect.ContainsKey($desiredEffect)) { - $byEffectList = $overridesByEffect[$desiredEffect] + if ($overridesByEffect.ContainsKey($confirmedEffect)) { + $byEffectList = $overridesByEffect[$confirmedEffect] } else { $byEffectList = [System.Collections.ArrayList]::new() - $overridesByEffect[$desiredEffect] = $byEffectList + $overridesByEffect[$confirmedEffect] = $byEffectList } $null = $byEffectList.Add($policyDefinitionReferenceId) } else { - # find the correct case for the allowed parameter value - foreach ($setEffectAllowedValue in $setEffectAllowedValues) { - if ($setEffectAllowedValue -eq $desiredEffect) { - $desiredEffect = $setEffectAllowedValue # fixes potentially wrong case, or keeps the original case - break - } - } # set the effect parameter - $parameters[$effectParameterName] = $desiredEffect + $parameters[$effectParameterName] = $confirmedEffect } } + #endregion effect parameters including overrides } - #endregion effect parameters including overrides #region nonComplianceMessages if ($null -ne $nonComplianceMessageColumn) { @@ -206,10 +174,9 @@ function Merge-AssignmentParametersEx { } } - #endregion parameters column = mutual exclusion handled + #endregion effects column = mutual exclusion handled #region optimize overrides - $effectsCount = $overridesByEffect.psbase.Count if ($effectsCount -gt 0) { $finalOverrides = [System.Collections.ArrayList]::new() diff --git a/Scripts/Helpers/New-ErrorInfo.ps1 b/Scripts/Helpers/New-ErrorInfo.ps1 index 6a6be2ec..c393f0b3 100644 --- a/Scripts/Helpers/New-ErrorInfo.ps1 +++ b/Scripts/Helpers/New-ErrorInfo.ps1 @@ -8,6 +8,7 @@ function New-ErrorInfo { errorsInFile = 0 currentEntryNumber = -1 hasErrors = $false + hasLocalErrors = $false fileName = $FileName } $errorInfo diff --git a/Scripts/Helpers/Out-PolicyAssignmentDocumentationToFile.ps1 b/Scripts/Helpers/Out-PolicyAssignmentDocumentationToFile.ps1 index 464b009f..86a660ad 100644 --- a/Scripts/Helpers/Out-PolicyAssignmentDocumentationToFile.ps1 +++ b/Scripts/Helpers/Out-PolicyAssignmentDocumentationToFile.ps1 @@ -4,7 +4,8 @@ function Out-PolicyAssignmentDocumentationToFile { [string] $OutputPath, [switch] $WindowsNewLineCells, $DocumentationSpecification, - [hashtable] $AssignmentsByEnvironment + [hashtable] $AssignmentsByEnvironment, + [switch] $IncludeManualPolicies ) [string] $fileNameStem = $DocumentationSpecification.fileNameStem @@ -38,102 +39,109 @@ function Out-PolicyAssignmentDocumentationToFile { $perEnvironment = $AssignmentsByEnvironment.$environmentCategory $flatPolicyList = $perEnvironment.flatPolicyList foreach ($policyTableId in $flatPolicyList.Keys) { + $flatPolicyEntry = $flatPolicyList.$policyTableId $isEffectParameterized = $flatPolicyEntry.isEffectParameterized - - $flatPolicyEntryAcrossEnvironments = @{} - if ($flatPolicyListAcrossEnvironments.ContainsKey($policyTableId)) { - $flatPolicyEntryAcrossEnvironments = $flatPolicyListAcrossEnvironments.$policyTableId - if ($isEffectParameterized) { - $flatPolicyEntry.isEffectParameterized = $true - } + $effectValue = "Unknown" + if ($null -ne $flatPolicyEntry.effectValue) { + $effectValue = $flatPolicyEntry.effectValue } else { - $flatPolicyEntryAcrossEnvironments = @{ - policyTableId = $policyTableId - name = $flatPolicyEntry.name - referencePath = $flatPolicyEntry.ReferencePath - displayName = $flatPolicyEntry.displayName - description = $flatPolicyEntry.description - policyType = $flatPolicyEntry.policyType - category = $flatPolicyEntry.category - isEffectParameterized = $isEffectParameterized - ordinal = 99 - effectAllowedValues = @{} - effectAllowedOverrides = $flatPolicyEntry.effectAllowedOverrides - environmentList = @{} - groupNames = [System.Collections.ArrayList]::new() - policySetList = @{} - policySetEffectStrings = $flatPolicyEntry.policySetEffectStrings - } - $null = $flatPolicyListAcrossEnvironments.Add($policyTableId, $flatPolicyEntryAcrossEnvironments) + $effectValue = $flatPolicyEntry.effectDefault } - # Find out lowest ordinal for grouping (optional) - if ($flatPolicyEntry.ordinal -lt $flatPolicyEntryAcrossEnvironments.ordinal) { - $flatPolicyEntryAcrossEnvironments.ordinal = $flatPolicyEntry.ordinal - } + if ($effectValue -ne "Manual" -or $IncludeManualPolicies) { - # Collect union of all effect parameter allowed values - $effectAllowedValues = $flatPolicyEntryAcrossEnvironments.effectAllowedValues - foreach ($allowedValue in $flatPolicyEntry.effectAllowedValues.Keys) { - if (-not $effectAllowedValues.ContainsKey($allowedValue)) { - $null = $effectAllowedValues.Add($allowedValue, $allowedValue) + $flatPolicyEntryAcrossEnvironments = @{} + if ($flatPolicyListAcrossEnvironments.ContainsKey($policyTableId)) { + $flatPolicyEntryAcrossEnvironments = $flatPolicyListAcrossEnvironments.$policyTableId + if ($isEffectParameterized) { + $flatPolicyEntry.isEffectParameterized = $true + } + } + else { + $flatPolicyEntryAcrossEnvironments = @{ + policyTableId = $policyTableId + name = $flatPolicyEntry.name + referencePath = $flatPolicyEntry.ReferencePath + displayName = $flatPolicyEntry.displayName + description = $flatPolicyEntry.description + policyType = $flatPolicyEntry.policyType + category = $flatPolicyEntry.category + isEffectParameterized = $isEffectParameterized + ordinal = 99 + effectAllowedValues = @{} + effectAllowedOverrides = $flatPolicyEntry.effectAllowedOverrides + environmentList = @{} + groupNames = [System.Collections.ArrayList]::new() + policySetList = @{} + policySetEffectStrings = $flatPolicyEntry.policySetEffectStrings + } + $null = $flatPolicyListAcrossEnvironments.Add($policyTableId, $flatPolicyEntryAcrossEnvironments) } - } - # Collect union of all group names - $groupNamesList = $flatPolicyEntry.groupNamesList - if ($null -ne $groupNamesList -and $groupNamesList.Count -gt 0) { - $existingGroupNames = $flatPolicyEntryAcrossEnvironments.groupNames - $existingGroupNames.AddRange($groupNamesList) - } + # Find out lowest ordinal for grouping (optional) + if ($flatPolicyEntry.ordinal -lt $flatPolicyEntryAcrossEnvironments.ordinal) { + $flatPolicyEntryAcrossEnvironments.ordinal = $flatPolicyEntry.ordinal + } - # Collect environment category specific items - $environmentList = $flatPolicyEntryAcrossEnvironments.environmentList - if ($environmentList.ContainsKey($environmentCategory)) { - Write-Error "Duplicate environmentCategory '$environmentCategory' encountered - bug in EPAC PowerShell code" -ErrorAction Stop - } - $effectValue = "Unknown" - if ($null -ne $flatPolicyEntry.effectValue) { - $effectValue = $flatPolicyEntry.effectValue - } - else { - $effectValue = $flatPolicyEntry.effectDefault - } - $environmentCategoryInfo = @{ - environmentCategory = $environmentCategory - effectValue = $effectValue - parameters = $flatPolicyEntry.parameters + # Collect union of all effect parameter allowed values + $effectAllowedValues = $flatPolicyEntryAcrossEnvironments.effectAllowedValues + foreach ($allowedValue in $flatPolicyEntry.effectAllowedValues.Keys) { + if (-not $effectAllowedValues.ContainsKey($allowedValue)) { + $null = $effectAllowedValues.Add($allowedValue, $allowedValue) + } + } - policySetList = $flatPolicyEntry.policySetList - } - $null = $environmentList.Add($environmentCategory, $environmentCategoryInfo) - - # Collect policySet specific items - $policySetList = $flatPolicyEntryAcrossEnvironments.policySetList - $flatPolicyEntryPolicySetList = $flatPolicyEntry.policySetList - foreach ($shortName in $flatPolicyEntryPolicySetList.Keys) { - $policySetInfo = $flatPolicyEntryPolicySetList.$shortName - if (-not $policySetList.ContainsKey($shortName)) { - $policySetEntry = @{ - shortName = $shortName - id = $policySetInfo.id - name = $policySetInfo.name - displayName = $policySetInfo.displayName - description = $policySetInfo.description - policyType = $policySetInfo.policyType - effectParameterName = $policySetInfo.effectParameterName - effectDefault = $policySetInfo.effectDefault - effectAllowedValues = $policySetInfo.effectAllowedValues - effectAllowedOverrides = $policySetInfo.effectAllowedOverrides - effectReason = $policySetInfo.effectReason - isEffectParameterized = $policySetInfo.isEffectParameterized - parameters = $policySetInfo.parameters + # Collect union of all group names + $groupNamesList = $flatPolicyEntry.groupNamesList + if ($null -ne $groupNamesList -and $groupNamesList.Count -gt 0) { + $existingGroupNames = $flatPolicyEntryAcrossEnvironments.groupNames + $existingGroupNames.AddRange($groupNamesList) + } + + # Collect environment category specific items + $environmentList = $flatPolicyEntryAcrossEnvironments.environmentList + if ($environmentList.ContainsKey($environmentCategory)) { + Write-Error "Duplicate environmentCategory '$environmentCategory' encountered - bug in EPAC PowerShell code" -ErrorAction Stop + } + $environmentCategoryInfo = @{ + environmentCategory = $environmentCategory + effectValue = $effectValue + parameters = $flatPolicyEntry.parameters + + policySetList = $flatPolicyEntry.policySetList + } + $null = $environmentList.Add($environmentCategory, $environmentCategoryInfo) + + # Collect policySet specific items + $policySetList = $flatPolicyEntryAcrossEnvironments.policySetList + $flatPolicyEntryPolicySetList = $flatPolicyEntry.policySetList + foreach ($shortName in $flatPolicyEntryPolicySetList.Keys) { + $policySetInfo = $flatPolicyEntryPolicySetList.$shortName + if (-not $policySetList.ContainsKey($shortName)) { + $policySetEntry = @{ + shortName = $shortName + id = $policySetInfo.id + name = $policySetInfo.name + displayName = $policySetInfo.displayName + description = $policySetInfo.description + policyType = $policySetInfo.policyType + effectParameterName = $policySetInfo.effectParameterName + effectDefault = $policySetInfo.effectDefault + effectAllowedValues = $policySetInfo.effectAllowedValues + effectAllowedOverrides = $policySetInfo.effectAllowedOverrides + effectReason = $policySetInfo.effectReason + isEffectParameterized = $policySetInfo.isEffectParameterized + parameters = $policySetInfo.parameters + } + $null = $policySetList.Add($shortName, $policySetEntry) } - $null = $policySetList.Add($shortName, $policySetEntry) } } + else { + Write-Verbose "Skipping Manual effect Policy '$($flatPolicyEntry.displayName)'" + } } } diff --git a/Scripts/Helpers/Out-PolicySetsDocumentationToFile.ps1 b/Scripts/Helpers/Out-PolicySetsDocumentationToFile.ps1 index 558a7e8f..e651a655 100644 --- a/Scripts/Helpers/Out-PolicySetsDocumentationToFile.ps1 +++ b/Scripts/Helpers/Out-PolicySetsDocumentationToFile.ps1 @@ -8,7 +8,8 @@ function Out-PolicySetsDocumentationToFile { [array] $ItemList, [array] $EnvironmentColumnsInCsv, [hashtable] $PolicySetDetails, - [hashtable] $FlatPolicyList + [hashtable] $FlatPolicyList, + [switch] $IncludeManualPolicies ) Write-Information "Generating Policy Set documentation for '$Title', files '$FileNameStem'." @@ -49,37 +50,51 @@ function Out-PolicySetsDocumentationToFile { $policySetList = $_.policySetList $addedEffectColumns = "" $addedRows = "" - foreach ($item in $ItemList) { - $shortName = $item.shortName - if ($policySetList.ContainsKey($shortName)) { - $perPolicySet = $policySetList.$shortName - $effectValue = $perPolicySet.effectValue - $effectAllowedValues = $perPolicySet.effectAllowedValues - $text = Convert-EffectToMarkdownString ` - -Effect $effectValue ` - -AllowedValues $effectAllowedValues - $addedEffectColumns += " $text |" - - [array] $groupNames = $perPolicySet.groupNames - $parameters = $perPolicySet.parameters - if ($parameters.psbase.Count -gt 0 -or $groupNames.Count -gt 0) { - $addedRows += "
*$($perPolicySet.displayName):*" - $text = Convert-ParametersToString -Parameters $parameters -OutputType "markdown" - $addedRows += $text - foreach ($groupName in $groupNames) { - $addedRows += "
      $groupName" + $effectValue = "Unknown" + if ($null -ne $_.effectValue) { + $effectValue = $_.effectValue + } + else { + $effectValue = $_.effectDefault + } + + if ($effectValue -ne "Manual" -or $IncludeManualPolicies) { + + foreach ($item in $ItemList) { + $shortName = $item.shortName + if ($policySetList.ContainsKey($shortName)) { + $perPolicySet = $policySetList.$shortName + $effectValue = $perPolicySet.effectValue + $effectAllowedValues = $perPolicySet.effectAllowedValues + $text = Convert-EffectToMarkdownString ` + -Effect $effectValue ` + -AllowedValues $effectAllowedValues + $addedEffectColumns += " $text |" + + [array] $groupNames = $perPolicySet.groupNames + $parameters = $perPolicySet.parameters + if ($parameters.psbase.Count -gt 0 -or $groupNames.Count -gt 0) { + $addedRows += "
*$($perPolicySet.displayName):*" + $text = Convert-ParametersToString -Parameters $parameters -OutputType "markdown" + $addedRows += $text + foreach ($groupName in $groupNames) { + $addedRows += "
      $groupName" + } } } + else { + $addedEffectColumns += " |" + } } - else { - $addedEffectColumns += " |" + $referencePathString = "" + if ($_.referencePath -ne "") { + $referencePathString = "      referencePath: ``$($_.referencePath)``
" } + $null = $body.Add("| $($_.category) | **$($_.displayName)**
$($referencePathString)$($_.description)$($addedRows) |$addedEffectColumns") } - $referencePathString = "" - if ($_.referencePath -ne "") { - $referencePathString = "      referencePath: ``$($_.referencePath)``
" + else { + Write-Verbose "Skipping manual policy: $($_.name)" } - $null = $body.Add("| $($_.category) | **$($_.displayName)**
$($referencePathString)$($_.description)$($addedRows) |$addedEffectColumns") } $null = $headerAndToc.Add("`n
") $null = $allLines.AddRange($headerAndToc) @@ -138,38 +153,52 @@ function Out-PolicySetsDocumentationToFile { $effectDefault = $_.effectDefault $policySetEffectStrings = $_.policySetEffectStrings - # Build common columns - $rowObj.name = $_.name - $rowObj.referencePath = $_.referencePath - $rowObj.policyType = $_.policyType - $rowObj.category = $_.category - $rowObj.displayName = $_.displayName - $rowObj.description = $_.description - if ($groupNamesList.Count -gt 0) { - $rowObj.groupNames = $groupNamesList -join $inCellSeparator3 + $effectValue = "Unknown" + if ($null -ne $_.effectValue) { + $effectValue = $_.effectValue } - if ($policySetEffectStrings.Count -gt 0) { - $rowObj.policySets = $policySetEffectStrings -join $inCellSeparator3 - } - $rowObj.allowedEffects = Convert-AllowedEffectsToCsvString ` - -DefaultEffect $effectDefault ` - -IsEffectParameterized $isEffectParameterized ` - -EffectAllowedValues $effectAllowedValues.Keys ` - -EffectAllowedOverrides $effectAllowedOverrides ` - -InCellSeparator1 $inCellSeparator1 ` - -InCellSeparator2 $inCellSeparator2 - - # Per environment columns - $parameters = $_.parameters - $parametersValueString = Convert-ParametersToString -Parameters $parameters -OutputType "csvValues" - $normalizedEffectDefault = Convert-EffectToCsvString -Effect $effectDefault - foreach ($environmentCategory in $EnvironmentColumnsInCsv) { - $rowObj["$($environmentCategory)Effect"] = $normalizedEffectDefault - $rowObj["$($environmentCategory)Parameters"] = $parametersValueString + else { + $effectValue = $_.effectDefault } - # Add row to spreadsheet - $null = $allRows.Add($rowObj) + if ($effectValue -ne "Manual" -or $IncludeManualPolicies) { + + # Build common columns + $rowObj.name = $_.name + $rowObj.referencePath = $_.referencePath + $rowObj.policyType = $_.policyType + $rowObj.category = $_.category + $rowObj.displayName = $_.displayName + $rowObj.description = $_.description + if ($groupNamesList.Count -gt 0) { + $rowObj.groupNames = $groupNamesList -join $inCellSeparator3 + } + if ($policySetEffectStrings.Count -gt 0) { + $rowObj.policySets = $policySetEffectStrings -join $inCellSeparator3 + } + $rowObj.allowedEffects = Convert-AllowedEffectsToCsvString ` + -DefaultEffect $effectDefault ` + -IsEffectParameterized $isEffectParameterized ` + -EffectAllowedValues $effectAllowedValues.Keys ` + -EffectAllowedOverrides $effectAllowedOverrides ` + -InCellSeparator1 $inCellSeparator1 ` + -InCellSeparator2 $inCellSeparator2 + + # Per environment columns + $parameters = $_.parameters + $parametersValueString = Convert-ParametersToString -Parameters $parameters -OutputType "csvValues" + $normalizedEffectDefault = Convert-EffectToCsvString -Effect $effectDefault + foreach ($environmentCategory in $EnvironmentColumnsInCsv) { + $rowObj["$($environmentCategory)Effect"] = $normalizedEffectDefault + $rowObj["$($environmentCategory)Parameters"] = $parametersValueString + } + + # Add row to spreadsheet + $null = $allRows.Add($rowObj) + } + else { + Write-Verbose "Skipping manual policy: $($_.name)" + } } # Output file diff --git a/Scripts/Helpers/Remove-AzRoleAssignmentRestMethod.ps1 b/Scripts/Helpers/Remove-AzRoleAssignmentRestMethod.ps1 deleted file mode 100644 index 66e68570..00000000 --- a/Scripts/Helpers/Remove-AzRoleAssignmentRestMethod.ps1 +++ /dev/null @@ -1,15 +0,0 @@ -function Remove-AzRoleAssignmentRestMethod { - [CmdletBinding()] - param ( - [string] $RoleAssignmentId - ) - - $response = Invoke-AzRestMethod -Path "$($RoleAssignmentId)?api-version=2022-04-01" -Method Delete - - # Process response - $statusCode = $response.StatusCode - if ($statusCode -lt 200 -or $statusCode -ge 300) { - $content = $response.Content - Write-Error "Role assignment deletion failed with error $($statusCode) -- $($content)" -ErrorAction Stop - } -} diff --git a/Scripts/Helpers/Get-AzPolicyAssignmentRestMethod.ps1 b/Scripts/Helpers/RestMethods/Get-AzPolicyAssignmentRestMethod.ps1 similarity index 65% rename from Scripts/Helpers/Get-AzPolicyAssignmentRestMethod.ps1 rename to Scripts/Helpers/RestMethods/Get-AzPolicyAssignmentRestMethod.ps1 index a12e330b..852e8294 100644 --- a/Scripts/Helpers/Get-AzPolicyAssignmentRestMethod.ps1 +++ b/Scripts/Helpers/RestMethods/Get-AzPolicyAssignmentRestMethod.ps1 @@ -1,17 +1,18 @@ function Get-AzPolicyAssignmentRestMethod { [CmdletBinding()] param ( - [string] $AssignmentID + [string] $AssignmentID, + [string] $ApiVersion ) # Invoke the REST API - $response = Invoke-AzRestMethod -Path "$($AssignmentId)?api-version=2022-06-01" -Method GET + $response = Invoke-AzRestMethod -Path "$($AssignmentId)?api-version=$ApiVersion" -Method GET # Process response $statusCode = $response.StatusCode if ($statusCode -lt 200 -or $statusCode -ge 300) { $content = $response.Content - Write-Error "Get Policy Assignment error for '$policyAssignmentId' $($statusCode) -- $($content)" -ErrorAction Stop + Write-Error "Get Policy Assignment error for '$AssignmentId' $($statusCode) -- $($content)" -ErrorAction Stop } return $response.Content | ConvertFrom-Json -Depth 100 diff --git a/Scripts/Helpers/RestMethods/Get-AzPolicyExemptionsRestMethod.ps1 b/Scripts/Helpers/RestMethods/Get-AzPolicyExemptionsRestMethod.ps1 new file mode 100644 index 00000000..bdde2dd2 --- /dev/null +++ b/Scripts/Helpers/RestMethods/Get-AzPolicyExemptionsRestMethod.ps1 @@ -0,0 +1,26 @@ +function Get-AzPolicyExemptionsRestMethod { + [CmdletBinding()] + param ( + [string] $Scope, + [string] $Filter = "", + [string] $ApiVersion + ) + + $filterString = "" + if (-not [string]::IsNullOrEmpty($Filter)) { + $filterString = "`$filter=$Filter&" + } + + $response = Invoke-AzRestMethod -Path "$($Scope)/providers/Microsoft.Authorization/policyExemptions?$($filterString)api-version=$ApiVersion" -Method GET + + # Process response + $statusCode = $response.StatusCode + if ($statusCode -lt 200 -or $statusCode -ge 300) { + $content = $response.Content + Write-Error "Policy Exemption error for scope '$Scope' $($statusCode) -- $($content)" -ErrorAction Stop + } + + $content = $response.Content + $exemptions = $content | ConvertFrom-Json -Depth 100 + Write-Output $exemptions.value -NoEnumerate +} diff --git a/Scripts/Helpers/RestMethods/Get-AzRoleAssignmentsRestMethod.ps1 b/Scripts/Helpers/RestMethods/Get-AzRoleAssignmentsRestMethod.ps1 new file mode 100644 index 00000000..6676fa9b --- /dev/null +++ b/Scripts/Helpers/RestMethods/Get-AzRoleAssignmentsRestMethod.ps1 @@ -0,0 +1,31 @@ +function Get-AzRoleAssignmentsRestMethod { + [CmdletBinding()] + param ( + [string] $Scope, + [string] $ApiVersion, + [string] $TenantId = "" + ) + + $tenantIdString = "" + if (-not [string]::IsNullOrEmpty($TenantId)) { + $tenantIdString = "&tenantId=$TenantId" + } + # Invoke the REST API + $response = Invoke-AzRestMethod -Path "$($Scope)/providers/Microsoft.Authorization/roleAssignments?api-version=$($ApiVersion)$($tenantIdString)" -Method GET + + # Process response + $statusCode = $response.StatusCode + if ($statusCode -lt 200 -or $statusCode -ge 300) { + $content = $response.Content + Write-Error "Get Role Assignment error for '$Scope' $($statusCode) -- $($content)" -ErrorAction Stop + } + + $content = $response.Content + $roleAssignments = $content | ConvertFrom-Json -Depth 100 + Write-Output $roleAssignments.value -NoEnumerate +} + +# $roleAssignments1 = Get-AzRoleAssignmentsRestMethod -ApiVersion "2022-04-01" -Scope "/subscriptions/d1f55a08-5325-4bd8-910f-f8e1456c8c0f" +# $null = $null +# $roleAssignments2 = Get-AzRoleAssignmentsRestMethod -ApiVersion "2022-04-01" -Scope "/providers/Microsoft.Management/managementGroups/mg-Dev" +# $null = $null diff --git a/Scripts/Helpers/RestMethods/Get-AzRoleDefinitionsRestMethod.ps1 b/Scripts/Helpers/RestMethods/Get-AzRoleDefinitionsRestMethod.ps1 new file mode 100644 index 00000000..c2fc6bca --- /dev/null +++ b/Scripts/Helpers/RestMethods/Get-AzRoleDefinitionsRestMethod.ps1 @@ -0,0 +1,71 @@ +function Get-AzRoleDefinitionsRestMethod { + [CmdletBinding()] + param ( + [string] $Scope, + [string] $ApiVersion + ) + + # Invoke the REST API + $response = Invoke-AzRestMethod -Path "$($Scope)/providers/Microsoft.Authorization/roleDefinitions?$filter=atScopeAndBelow&api-version=$($ApiVersion)" -Method GET + + # Process response + $statusCode = $response.StatusCode + if ($statusCode -lt 200 -or $statusCode -ge 300) { + $content = $response.Content + Write-Error "Get Role Assignment error for scope '$Scope' $($statusCode) -- $($content)" -ErrorAction Stop + } + + $content = $response.Content + $roleDefinitions = $content | ConvertFrom-Json -Depth 100 + Write-Output $roleDefinitions.value -NoEnumerate +} + +# $roleDefinitions0 = Get-AzRoleDefinitionsRestMethod -ApiVersion "2022-04-01" -Scope "/subscriptions/d1f55a08-5325-4bd8-910f-f8e1456c8c0f" +# foreach ($roleDefinition in $roleDefinitions0) { +# $id = $roleDefinition.id +# if ($id.StartsWith("/providers/Microsoft.Management/managementGroups")) { +# $null = $null +# } +# elseif ($id.StartsWith("/subscriptions")) { +# foreach ($assignableScope in $roleDefinition.properties.assignableScopes) { +# if ($assignableScope.StartsWith("/subscriptions/d1f55a08-5325-4bd8-910f-f8e1456c8c0f")) { +# $null = $null +# } +# else { +# $null = $null +# } +# } +# } +# else { +# $null = $null +# } +# } +# $null = $null +# $roleDefinitions1 = Get-AzRoleDefinitionsRestMethod -ApiVersion "2022-04-01" -Scope "/providers/Microsoft.Management/managementGroups/mg-Enterprise" +# foreach ($roleDefinition in $roleDefinitions1) { +# $id = $roleDefinition.id +# if ($id.StartsWith("/providers/Microsoft.Management/managementGroups")) { +# $null = $null +# } +# elseif ($id.StartsWith("/subscriptions")) { +# $null = $null +# } +# else { +# $null = $null +# } +# } +# $null = $null +# $roleDefinitions2 = Get-AzRoleDefinitionsRestMethod -ApiVersion "2022-04-01" -Scope "" +# foreach ($roleDefinition in $roleDefinitions2) { +# $id = $roleDefinition.id +# if ($id.StartsWith("/providers/Microsoft.Management/managementGroups")) { +# $null = $null +# } +# elseif ($id.StartsWith("/subscriptions")) { +# $null = $null +# } +# else { +# $null = $null +# } +# } +# $null = $null diff --git a/Scripts/Helpers/RestMethods/Remove-AzResourceByIdRestMethod.ps1 b/Scripts/Helpers/RestMethods/Remove-AzResourceByIdRestMethod.ps1 new file mode 100644 index 00000000..5e70b676 --- /dev/null +++ b/Scripts/Helpers/RestMethods/Remove-AzResourceByIdRestMethod.ps1 @@ -0,0 +1,30 @@ +function Remove-AzResourceByIdRestMethod { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [string] $Id, + + [Parameter(Mandatory = $true)] + [string] $ApiVersion + ) + + # Write log info + Write-Information $Id + + # Invoke the REST API + $path = "$($Id)?api-version=$($ApiVersion)" + # Write-Information "DELETE $path" + $response = Invoke-AzRestMethod -Path $path -Method DELETE + + # Process response + $statusCode = $response.StatusCode + if (($statusCode -lt 200 -or $statusCode -ge 300) -and $statusCode -ne 404) { + $content = $response.Content + if ($content.Contains("ScopeLocked", [StringComparison]::InvariantCultureIgnoreCase)) { + Write-Warning "Ignoring scope locked error: $($statusCode) -- $($content)" + } + else { + Write-Error "Remove Az Resource error $($statusCode) -- $($content)" + } + } +} diff --git a/Scripts/Helpers/RestMethods/Remove-AzRoleAssignmentRestMethod.ps1 b/Scripts/Helpers/RestMethods/Remove-AzRoleAssignmentRestMethod.ps1 new file mode 100644 index 00000000..17fd3b24 --- /dev/null +++ b/Scripts/Helpers/RestMethods/Remove-AzRoleAssignmentRestMethod.ps1 @@ -0,0 +1,21 @@ +function Remove-AzRoleAssignmentRestMethod { + [CmdletBinding()] + param ( + [string] $RoleAssignmentId, + [string] $TenantId, + [string] $ApiVersion + ) + if (!$TenantId) { + $response = Invoke-AzRestMethod -Path "$($RoleAssignmentId)?api-version=$ApiVersion" -Method Delete + } + else { + $response = Invoke-AzRestMethod -Path "$($RoleAssignmentId)?api-version=$ApiVersion&tenantId=$($TenantId)" -Method Delete + } + + # Process response + $statusCode = $response.StatusCode + if ($statusCode -lt 200 -or $statusCode -ge 300) { + $content = $response.Content + Write-Error "Role assignment deletion failed with error $($statusCode) -- $($content)" -ErrorAction Stop + } +} diff --git a/Scripts/Helpers/Set-AzPolicyAssignmentRestMethod.ps1 b/Scripts/Helpers/RestMethods/Set-AzPolicyAssignmentRestMethod.ps1 similarity index 81% rename from Scripts/Helpers/Set-AzPolicyAssignmentRestMethod.ps1 rename to Scripts/Helpers/RestMethods/Set-AzPolicyAssignmentRestMethod.ps1 index 9a4a292a..5a72a572 100644 --- a/Scripts/Helpers/Set-AzPolicyAssignmentRestMethod.ps1 +++ b/Scripts/Helpers/RestMethods/Set-AzPolicyAssignmentRestMethod.ps1 @@ -2,18 +2,16 @@ function Set-AzPolicyAssignmentRestMethod { [CmdletBinding()] param ( [PSCustomObject] $AssignmentObj, - [string] $CurrentDisplayName + [string] $ApiVersion ) # Write log info + $id = $AssignmentObj.id $displayName = $AssignmentObj.displayName - if ($displayName -ne $CurrentDisplayName) { - Write-Information $displayName - } - Write-Information " $($AssignmentObj.id)" + Write-Information "$displayName - $id" # Fix parameters to the weird way assignments uses JSON - $parametersTemp = Get-DeepClone $AssignmentObj.parameters -AsHashTable + $parametersTemp = Get-ClonedObject $AssignmentObj.parameters -AsHashTable $parameters = @{} foreach ($parameterName in $parametersTemp.Keys) { $value = $parametersTemp.$parameterName @@ -52,15 +50,13 @@ function Set-AzPolicyAssignmentRestMethod { # Invoke the REST API $assignmentJson = ConvertTo-Json $assignment -Depth 100 -Compress - $response = Invoke-AzRestMethod -Path "$($AssignmentObj.id)?api-version=2022-06-01" -Method PUT -Payload $assignmentJson + $response = Invoke-AzRestMethod -Path "$($id)?api-version=$ApiVersion" -Method PUT -Payload $assignmentJson # Process response $statusCode = $response.StatusCode - if ($statusCode -ne 201) { + if ($statusCode -ge 300 -or $statusCode -lt 200) { $content = $response.Content Write-Information "assignment: $assignmentJson" Write-Error "Assignment error $($statusCode) -- $($content)" -ErrorAction Stop } - - return $displayName } diff --git a/Scripts/Helpers/Set-AzPolicyDefinitionRestMethod.ps1 b/Scripts/Helpers/RestMethods/Set-AzPolicyDefinitionRestMethod.ps1 similarity index 89% rename from Scripts/Helpers/Set-AzPolicyDefinitionRestMethod.ps1 rename to Scripts/Helpers/RestMethods/Set-AzPolicyDefinitionRestMethod.ps1 index 60fd3e53..5b276c2b 100644 --- a/Scripts/Helpers/Set-AzPolicyDefinitionRestMethod.ps1 +++ b/Scripts/Helpers/RestMethods/Set-AzPolicyDefinitionRestMethod.ps1 @@ -1,7 +1,8 @@ function Set-AzPolicyDefinitionRestMethod { [CmdletBinding()] param ( - [PSCustomObject] $DefinitionObj + [PSCustomObject] $DefinitionObj, + [string] $ApiVersion ) # Write log info @@ -25,7 +26,7 @@ function Set-AzPolicyDefinitionRestMethod { # Invoke the REST API $definitionJson = ConvertTo-Json $definition -Depth 100 -Compress - $response = Invoke-AzRestMethod -Path "$($DefinitionObj.id)?api-version=2021-06-01" -Method PUT -Payload $definitionJson + $response = Invoke-AzRestMethod -Path "$($DefinitionObj.id)?api-version=$ApiVersion" -Method PUT -Payload $definitionJson # Process response $statusCode = $response.StatusCode diff --git a/Scripts/Helpers/Set-AzPolicyExemptionRestMethod.ps1 b/Scripts/Helpers/RestMethods/Set-AzPolicyExemptionRestMethod.ps1 similarity index 75% rename from Scripts/Helpers/Set-AzPolicyExemptionRestMethod.ps1 rename to Scripts/Helpers/RestMethods/Set-AzPolicyExemptionRestMethod.ps1 index c3e9c514..c062b476 100644 --- a/Scripts/Helpers/Set-AzPolicyExemptionRestMethod.ps1 +++ b/Scripts/Helpers/RestMethods/Set-AzPolicyExemptionRestMethod.ps1 @@ -1,7 +1,8 @@ function Set-AzPolicyExemptionRestMethod { [CmdletBinding()] param ( - [PSCustomObject] $ExemptionObj + [PSCustomObject] $ExemptionObj, + [string] $ApiVersion ) # Write log info @@ -28,12 +29,17 @@ function Set-AzPolicyExemptionRestMethod { # Invoke the REST API $exemptionJson = ConvertTo-Json $exemption -Depth 100 -Compress - $response = Invoke-AzRestMethod -Path "$($ExemptionObj.id)?api-version=2022-07-01-preview" -Method PUT -Payload $exemptionJson + $response = Invoke-AzRestMethod -Path "$($ExemptionObj.id)?api-version=$ApiVersion" -Method PUT -Payload $exemptionJson # Process response $statusCode = $response.StatusCode if ($statusCode -lt 200 -or $statusCode -ge 300) { $content = $response.Content - Write-Error "Policy Exemption error $($statusCode) -- $($content)" -ErrorAction Stop + if ($content.Contains("ScopeLocked", [StringComparison]::InvariantCultureIgnoreCase)) { + Write-Warning "Ignoring scope locked error: $($statusCode) -- $($content)" + } + else { + Write-Error "Policy Exemption error $($statusCode) -- $($content)" + } } } diff --git a/Scripts/Helpers/Set-AzPolicySetDefinitionRestMethod.ps1 b/Scripts/Helpers/RestMethods/Set-AzPolicySetDefinitionRestMethod.ps1 similarity index 89% rename from Scripts/Helpers/Set-AzPolicySetDefinitionRestMethod.ps1 rename to Scripts/Helpers/RestMethods/Set-AzPolicySetDefinitionRestMethod.ps1 index e291d5e6..c3efa726 100644 --- a/Scripts/Helpers/Set-AzPolicySetDefinitionRestMethod.ps1 +++ b/Scripts/Helpers/RestMethods/Set-AzPolicySetDefinitionRestMethod.ps1 @@ -1,7 +1,8 @@ function Set-AzPolicySetDefinitionRestMethod { [CmdletBinding()] param ( - [PSCustomObject] $DefinitionObj + [PSCustomObject] $DefinitionObj, + [string] $ApiVersion ) # Write log info @@ -25,7 +26,7 @@ function Set-AzPolicySetDefinitionRestMethod { # Invoke the REST API $definitionJson = ConvertTo-Json $definition -Depth 100 -Compress - $response = Invoke-AzRestMethod -Path "$($DefinitionObj.id)?api-version=2021-06-01" -Method PUT -Payload $definitionJson + $response = Invoke-AzRestMethod -Path "$($DefinitionObj.id)?api-version=$ApiVersion" -Method PUT -Payload $definitionJson # Process response $statusCode = $response.StatusCode diff --git a/Scripts/Helpers/RestMethods/Set-AzRoleAssignmentRestMethod.ps1 b/Scripts/Helpers/RestMethods/Set-AzRoleAssignmentRestMethod.ps1 new file mode 100644 index 00000000..e15f1848 --- /dev/null +++ b/Scripts/Helpers/RestMethods/Set-AzRoleAssignmentRestMethod.ps1 @@ -0,0 +1,41 @@ +function Set-AzRoleAssignmentRestMethod { + [CmdletBinding()] + param ( + $RoleAssignment, + [string] $ApiVersion + ) + + $properties = $RoleAssignment.properties + $path = $null + if ($null -ne $RoleAssignment.id) { + # update existing role assignment + $path = "$($RoleAssignment.id)?api-version=$ApiVersion" + } + else { + # create new role assignment + $guid = New-Guid + $scope = $RoleAssignment.scope + $path = "$scope/providers/Microsoft.Authorization/roleAssignments/$($guid.ToString())?api-version=$ApiVersion" + } + $body = @{ + properties = $RoleAssignment.properties + } + Write-Information "Assignment '$($RoleAssignment.assignmentDisplayName)', principalId $($properties.principalId), role '$($RoleAssignment.roleDisplayName)' at $scope" + + # Invoke the REST API + $bodyJson = ConvertTo-Json $body -Depth 100 -Compress + $response = Invoke-AzRestMethod -Path $path -Method PUT -Payload $bodyJson + + # Process response + $statusCode = $response.StatusCode + if ($statusCode -lt 200 -or $statusCode -ge 300) { + $content = $response.Content + if ($statusCode -eq 409) { + $errorBody = $content | ConvertFrom-Json -Depth 100 + Write-Information $errorBody.error.message + } + else { + Write-Error "Role Assignment error $($statusCode) -- $($content)" -ErrorAction Stop + } + } +} diff --git a/Scripts/Helpers/Search-AzGraphAllItems.ps1 b/Scripts/Helpers/Search-AzGraphAllItems.ps1 index 2cb59a35..c3fac121 100644 --- a/Scripts/Helpers/Search-AzGraphAllItems.ps1 +++ b/Scripts/Helpers/Search-AzGraphAllItems.ps1 @@ -1,26 +1,27 @@ function Search-AzGraphAllItems { param ( [string] $Query, - [hashtable] $Scope, - $ProgressItemName + [hashtable] $ScopeSplat = @{ UseTenantScope = $true }, + $ProgressItemName, + $ProgressIncrement = 1000 ) [System.Collections.ArrayList] $data = [System.Collections.ArrayList]::new() # Search-AzGraph can only return a maximum of 1000 items. Without the -First it will only return 100 items - $result = Search-AzGraph $Query -First 1000 @scope + $result = Search-AzGraph $Query -First 1000 @ScopeSplat $null = $data.AddRange($result.Data) while ($null -ne $result.SkipToken) { # More data available, SkipToken will allow the next query in this loop to continue where the last invocation ended $count = $data.Count - if ($count % 1000 -eq 0) { + if ($count % $ProgressIncrement -eq 0) { Write-Information "Retrieved $count $ProgressItemName" } - $result = Search-AzGraph $Query -First 1000 -SkipToken $result.SkipToken @scope + $result = Search-AzGraph $Query -First 1000 -SkipToken $result.SkipToken @ScopeSplat $null = $data.AddRange($result.Data) } $count = $data.Count - if ($count % 1000 -ne 0) { + if ($count % $ProgressIncrement -ne 0) { Write-Information "Retrieved $($count) $ProgressItemName" } - return $data + Write-Output $data -NoEnumerate } diff --git a/Scripts/Helpers/Select-PacEnvironment.ps1 b/Scripts/Helpers/Select-PacEnvironment.ps1 index 9fa7ee81..2876bfe3 100644 --- a/Scripts/Helpers/Select-PacEnvironment.ps1 +++ b/Scripts/Helpers/Select-PacEnvironment.ps1 @@ -5,22 +5,26 @@ function Select-PacEnvironment { [Parameter(Mandatory = $false)] [string] $DefinitionsRootFolder, [Parameter(Mandatory = $false)] [string] $OutputFolder, [Parameter(Mandatory = $false)] [string] $InputFolder, - [Parameter(Mandatory = $false)] [bool] $Interactive = $false + [Parameter(Mandatory = $false)] [bool] $Interactive = $false, + [switch] $PickFirstPacEnvironment ) $globalSettings = Get-GlobalSettings -DefinitionsRootFolder $DefinitionsRootFolder -OutputFolder $OutputFolder -InputFolder $InputFolder $pacEnvironment = $null $pacEnvironments = $globalSettings.pacEnvironments + + if ($PickFirstPacEnvironment) { + $PacEnvironmentSelector = $globalSettings.pacEnvironmentSelectors[0] + } + if ($PacEnvironmentSelector -eq "") { # Interactive $InformationPreference = "Continue" $Interactive = $true if ($pacEnvironments.Count -eq 1) { - $pacEnvironment = @{} # Build hashtable for single PAC environment - $pacEnvironments.Values.Keys | Foreach-Object { - $pacEnvironment.Add($_, $pacEnvironments.Values.$_) - } + $PacEnvironmentSelector = $globalSettings.pacEnvironmentSelectors[0] + $pacEnvironment = $pacEnvironments[$PacEnvironmentSelector] } else { $prompt = $globalSettings.pacEnvironmentPrompt @@ -54,13 +58,32 @@ function Select-PacEnvironment { $OutputFolder = $globalSettings.outputFolder $InputFolder = $globalSettings.inputFolder - $pacEnvironmentDefinition = $pacEnvironment + $globalSettings + @{ + $apiVersions = @{ + policyDefinitions = "2023-04-01" + policySetDefinitions = "2023-04-01" + policyAssignments = "2023-04-01" + policyExemptions = "2022-07-01-preview" + roleAssignments = "2022-04-01" + } + if ($pacEnvironment.cloud -eq "AzureChinaCloud") { + $apiVersions = @{ + policyDefinitions = "2021-06-01" + policySetDefinitions = "2021-06-01" + policyAssignments = "2022-06-01" + policyExemptions = "2022-07-01-preview" + roleAssignments = "2022-04-01" + } + } + $planFiles = @{ interactive = $Interactive policyPlanOutputFile = "$($OutputFolder)/plans-$PacEnvironmentSelector/policy-plan.json" rolesPlanOutputFile = "$($OutputFolder)/plans-$PacEnvironmentSelector/roles-plan.json" policyPlanInputFile = "$($InputFolder)/plans-$PacEnvironmentSelector/policy-plan.json" rolesPlanInputFile = "$($InputFolder)/plans-$PacEnvironmentSelector/roles-plan.json" - } + $pacEnvironmentDefinition = $pacEnvironment + $planFiles + $globalSettings + @{ + apiVersions = $apiVersions + } + return $pacEnvironmentDefinition } diff --git a/Scripts/Helpers/Set-AzRoleAssignmentRestMethod.ps1 b/Scripts/Helpers/Set-AzRoleAssignmentRestMethod.ps1 deleted file mode 100644 index 80e41886..00000000 --- a/Scripts/Helpers/Set-AzRoleAssignmentRestMethod.ps1 +++ /dev/null @@ -1,45 +0,0 @@ -function Set-AzRoleAssignmentRestMethod { - [CmdletBinding()] - param ( - $Scope, - $ObjectType, - $ObjectId, - $RoleDefinitionId, - $AssignmentDisplayName, - $RoleDisplayName, - [switch] $IgnoreDuplicateError - ) - - # Write log info - Write-Information "Assignment '$AssignmentDisplayName', principalId $ObjectId, role $RoleDisplayName($roleDefinitionId) at $scope" - - # Build the Path - $guid = New-Guid - $path = "$scope/providers/Microsoft.Authorization/roleAssignments/$($guid.ToString())?api-version=2022-04-01" - - # Build the REST API body - $body = @{ - properties = @{ - roleDefinitionId = $RoleDefinitionId - principalId = $ObjectId - principalType = $ObjectType - } - } - - # Invoke the REST API - $bodyJson = ConvertTo-Json $body -Depth 100 -Compress - $response = Invoke-AzRestMethod -Path $path -Method PUT -Payload $bodyJson - - # Process response - $statusCode = $response.StatusCode - if ($statusCode -lt 200 -or $statusCode -ge 300) { - $content = $response.Content - if ($IgnoreDuplicateError -and $statusCode -eq 409) { - $errorBody = $content | ConvertFrom-Json -Depth 100 - Write-Information $errorBody.error.message - } - else { - Write-Error "Role Assignment error $($statusCode) -- $($content)" -ErrorAction Stop - } - } -} diff --git a/Scripts/Helpers/Split-ArrayIntoChunks.ps1 b/Scripts/Helpers/Split-ArrayIntoChunks.ps1 new file mode 100644 index 00000000..0acb5cd8 --- /dev/null +++ b/Scripts/Helpers/Split-ArrayIntoChunks.ps1 @@ -0,0 +1,44 @@ +function Split-ArrayIntoChunks { + param ( + [Parameter(Mandatory = $true)] + [array] $Array, + + [Parameter(Mandatory = $false)] + $NumberOfChunks = 5, + + [Parameter(Mandatory = $false)] + $MinChunkingSize = 5 + ) + + # split array into chunks + $count = $Array.Count + if ($count -le $MinChunkingSize) { + [array] $chunks = [array]::CreateInstance([array], 1) + $chunks[0] = $Array + return , $chunks + } + else { + $chunkingSize = [math]::Ceiling($count / $NumberOfChunks) + if ($chunkingSize -lt $MinChunkingSize) { + $NumberOfChunks = [math]::Ceiling($count / $MinChunkingSize) + $chunkingSize = [math]::Ceiling($count / $NumberOfChunks) + } + [array] $chunks = [array]::CreateInstance([array], $NumberOfChunks) + if ($NumberOfChunks -eq 1) { + Write-Error "Coding error: NumberOfChunks is 1" -ErrorAction Continue + $chunks[0] = $Array + return , $chunks + } + else { + for ($i = 0; $i -lt $NumberOfChunks; $i++) { + $start = $i * $chunkingSize + $end = $start + $chunkingSize - 1 + if ($end -ge $count) { + $end = $count - 1 + } + $chunks[$i] = $Array[$start..$end] + } + return $chunks + } + } +} diff --git a/Scripts/Helpers/Split-HashtableIntoChunks.ps1 b/Scripts/Helpers/Split-HashtableIntoChunks.ps1 new file mode 100644 index 00000000..ff8d599a --- /dev/null +++ b/Scripts/Helpers/Split-HashtableIntoChunks.ps1 @@ -0,0 +1,52 @@ +function Split-HashtableIntoChunks { + param ( + [Parameter(Mandatory = $true)] + [hashtable] $Table, + + [Parameter(Mandatory = $false)] + $NumberOfChunks = 5, + + [Parameter(Mandatory = $false)] + $MinChunkingSize = 5 + ) + + # split definition array into chunks + $count = $Table.Count + if ($count -le $MinChunkingSize) { + [array] $chunks = [array]::CreateInstance([array], 1) + $chunks[0] = $Table + return , $chunks + } + else { + $chunkingSize = [math]::Ceiling($count / $NumberOfChunks) + if ($chunkingSize -lt $MinChunkingSize) { + $NumberOfChunks = [math]::Ceiling($count / $MinChunkingSize) + $chunkingSize = [math]::Ceiling($count / $NumberOfChunks) + } + [array] $chunks = [array]::CreateInstance([array], $NumberOfChunks) + if ($NumberOfChunks -eq 1) { + Write-Error "Coding error: NumberOfChunks is 1" -ErrorAction Continue + $chunks[0] = $Table + return , $chunks + } + else { + $chunk = @{} + $itemCount = 0 + $i = 0 + $Table.GetEnumerator() | ForEach-Object { + $chunk[$_.key] = $_.value + $itemCount++ + if ($itemCount -eq $chunkingSize) { + $chunks[$i] = $chunk + $i++ + $chunk = @{} + $itemCount = 0 + } + } + if ($itemCount -gt 0) { + $chunks[$i] = $chunk + } + return $chunks + } + } +} diff --git a/Scripts/Helpers/Switch-PacEnvironment.ps1 b/Scripts/Helpers/Switch-PacEnvironment.ps1 index 3471e6ce..a20fafc5 100644 --- a/Scripts/Helpers/Switch-PacEnvironment.ps1 +++ b/Scripts/Helpers/Switch-PacEnvironment.ps1 @@ -1,8 +1,6 @@ function Switch-PacEnvironment { [CmdletBinding()] param ( - [int] $DefinitionStartingLine, - [int] $DefinitionEndingLine, [hashtable] $PacEnvironments, [string] $PacEnvironmentSelector, [bool] $Interactive @@ -14,7 +12,7 @@ function Switch-PacEnvironment { $pacEnvironment = $PacEnvironments.$PacEnvironmentSelector } else { - Write-Error " pacEnvironment '$PacEnvironmentSelector' in definition on lines $DefinitionStartingLine - $DefinitionEndingLine does not exist" -ErrorAction Stop + Write-Error " pacEnvironment '$PacEnvironmentSelector' does not exist" -ErrorAction Stop } $null = Set-AzCloudTenantSubscription ` -Cloud $pacEnvironment.cloud ` diff --git a/Scripts/Helpers/Write-AssignmentDetails.ps1 b/Scripts/Helpers/Write-AssignmentDetails.ps1 index 3c3944fa..dffc7f91 100644 --- a/Scripts/Helpers/Write-AssignmentDetails.ps1 +++ b/Scripts/Helpers/Write-AssignmentDetails.ps1 @@ -18,12 +18,22 @@ function Write-AssignmentDetails { foreach ($role in $IdentityStatus.added) { $roleScope = $role.scope $roleShortScope = $roleScope -replace "/providers/Microsoft.Management", "" - Write-Information " add role $($role.roleDisplayName) at $($roleShortScope)" + if (!$role.crossTenant) { + Write-Information " add role $($role.roleDisplayName) at $($roleShortScope)" + } + else { + Write-Information " add role $($role.roleDisplayName) at $($roleShortScope) (remote)" + } } foreach ($role in $IdentityStatus.removed) { $roleScope = $role.scope $roleShortScope = $roleScope -replace "/providers/Microsoft.Management", "" - Write-Information " remove role $($role.roleDisplayName) at $($roleShortScope)" + if (!$role.crossTenant) { + Write-Information " remove role $($role.roleDisplayName) at $($roleShortScope)" + } + else { + Write-Information " remove role $($role.roleDisplayName) at $($roleShortScope) (remote)" + } } } } diff --git a/Scripts/Helpers/Write-ErrorsFromErrorInfo.ps1 b/Scripts/Helpers/Write-ErrorsFromErrorInfo.ps1 new file mode 100644 index 00000000..4c184699 --- /dev/null +++ b/Scripts/Helpers/Write-ErrorsFromErrorInfo.ps1 @@ -0,0 +1,13 @@ +function Write-ErrorsFromErrorInfo { + [CmdletBinding()] + param ( + [hashtable] $ErrorInfo + ) + if ($ErrorInfo.hasErrors) { + Write-Host -ForegroundColor Red "Errors in file '$($ErrorInfo.fileName)' list of $($ErrorInfo.errorsInFile):'" + foreach ($errorString in $ErrorInfo.errorStrings) { + Write-Host -ForegroundColor DarkYellow " $errorString" + } + Write-Host -ForegroundColor Red "End of errors in file '$($ErrorInfo.fileName)' list of $($ErrorInfo.errorsInFile)." + } +} diff --git a/Scripts/Operations/Build-PolicyDocumentation.ps1 b/Scripts/Operations/Build-PolicyDocumentation.ps1 index 259b6938..c6a16c43 100644 --- a/Scripts/Operations/Build-PolicyDocumentation.ps1 +++ b/Scripts/Operations/Build-PolicyDocumentation.ps1 @@ -17,6 +17,13 @@ .PARAMETER SuppressConfirmation Suppresses prompt for confirmation to delete existing file in interactive mode +.PARAMETER IncludeManualPolicies + Include Policies with effect Manual. Default: do not include Polcies with effect Manual. + +.PARAMETER VirtualCores + Number of virtual cores to use for the operation. Default is 4. + + .EXAMPLE Build-PolicyDocumentation.ps1 -DefinitionsRootFolder "C:\PAC\Definitions" -OutputFolder "C:\PAC\Output" -Interactive Builds documentation from instructions in policyDocumentations folder reading the delployed Policy Resources from the EPAC envioronment. @@ -49,7 +56,13 @@ param ( [bool] $Interactive = $true, [Parameter(Mandatory = $false, HelpMessage = "Suppresses prompt for confirmation of each file in interactive mode")] - [switch] $SuppressConfirmation + [switch] $SuppressConfirmation, + + [Parameter(Mandatory = $false, HelpMessage = "Include Policies with effect Manual. Default: do not include Polcies with effect Manual.")] + [switch] $IncludeManualPolicies, + + [Parameter(Mandatory = $false, HelpMessage = "Number of virtual cores to use for the operation. Default is 4.")] + [Int16] $VirtualCores = 4 ) # Dot Source Helper Scripts @@ -185,15 +198,15 @@ foreach ($file in $files) { -PacEnvironmentSelector $currentPacEnvironmentSelector ` -PacEnvironments $pacEnvironments ` -Interactive $Interactive - } } # Retrieve Policies and PolicySets for current pacEnvironment from cache or from Azure - $policyResourceDetails = Get-PolicyResourceDetails ` + $policyResourceDetails = Get-AzPolicyResourcesDetails ` -PacEnvironmentSelector $pacEnvironmentSelector ` -PacEnvironment $pacEnvironment ` - -CachedPolicyResourceDetails $cachedPolicyResourceDetails + -CachedPolicyResourceDetails $cachedPolicyResourceDetails ` + -VirtualCores $VirtualCores $policySetDetails = $policyResourceDetails.policySets # Calculate itemList @@ -227,7 +240,7 @@ foreach ($file in $files) { $itemList = $itemArrayList.ToArray() # flatten structure and reconcile most restrictive effect for each policy - $flatPolicyList = Convert-PolicySetsToFlatList ` + $flatPolicyList = Convert-PolicyResourcesDetailsToFlatList ` -ItemList $itemList ` -Details $policySetDetails @@ -240,7 +253,8 @@ foreach ($file in $files) { -ItemList $itemList ` -EnvironmentColumnsInCsv $environmentColumnsInCsv ` -PolicySetDetails $policySetDetails ` - -FlatPolicyList $flatPolicyList + -FlatPolicyList $flatPolicyList ` + -IncludeManualPolicies:$IncludeManualPolicies } } @@ -266,22 +280,23 @@ foreach ($file in $files) { } # Retrieve Policies and PolicySets for current pacEnvironment from cache or from Azure - $policyResourceDetails = Get-PolicyResourceDetails ` + $policyResourceDetails = Get-AzPolicyResourcesDetails ` -PacEnvironmentSelector $currentPacEnvironmentSelector ` -PacEnvironment $pacEnvironment ` - -CachedPolicyResourceDetails $cachedPolicyResourceDetails + -CachedPolicyResourceDetails $cachedPolicyResourceDetails ` + -VirtualCores $VirtualCores # Retrieve assignments and process information or retrieve from cache is assignment previously processed $assignmentArray = $environmentCategoryEntry.representativeAssignments - $itemList, $assignmentsDetails = Get-AssignmentsDetails ` + $itemList, $assignmentsDetails = Get-PolicyAssignmentsDetails ` -PacEnvironmentSelector $currentPacEnvironmentSelector ` -AssignmentArray $assignmentArray ` -PolicyResourceDetails $policyResourceDetails ` -CachedAssignmentsDetails $cachedAssignmentsDetails # Flatten Policy lists in Assignments and reconcile the most restrictive effect for each Policy - $flatPolicyList = Convert-PolicySetsToFlatList ` + $flatPolicyList = Convert-PolicyResourcesDetailsToFlatList ` -ItemList $itemList ` -Details $assignmentsDetails @@ -307,7 +322,8 @@ foreach ($file in $files) { -OutputPath $outputPath ` -WindowsNewLineCells:$WindowsNewLineCells ` -DocumentationSpecification $documentationSpecification ` - -AssignmentsByEnvironment $assignmentsByEnvironment + -AssignmentsByEnvironment $assignmentsByEnvironment ` + -IncludeManualPolicies:$IncludeManualPolicies # Out-PolicyAssignmentDocumentationToFile ` # -OutputPath $outputPath ` # -WindowsNewLineCells:$true ` diff --git a/Scripts/Operations/Create-AzRemediationTasks.ps1 b/Scripts/Operations/Create-AzRemediationTasks.ps1 index 2bb6c1b0..b4fc8c9c 100644 --- a/Scripts/Operations/Create-AzRemediationTasks.ps1 +++ b/Scripts/Operations/Create-AzRemediationTasks.ps1 @@ -61,7 +61,7 @@ https://docs.microsoft.com/en-us/azure/governance/policy/how-to/remediate-resour https://azure.github.io/enterprise-azure-policy-as-code/operational-scripts/#build-policyassignmentdocumentationps1 #> -[CmdletBinding()] +[CmdletBinding(SupportsShouldProcess = $true)] param( [parameter(Mandatory = $false, HelpMessage = "Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a value. The values are read from `$DefinitionsRootFolder/global-settings.jsonc.", Position = 0)] [string] $PacEnvironmentSelector, @@ -85,7 +85,10 @@ param( [string[]] $PolicyAssignmentFilter = $null, [Parameter(Mandatory = $false, HelpMessage = "Filter by Policy Effect")] - [string[]] $PolicyEffectFilter = $null + [string[]] $PolicyEffectFilter = $null, + + [Parameter(Mandatory = $false, HelpMessage = "Do not wait for the tasks to complete")] + [switch] $NoWait ) # Dot Source Helper Scripts @@ -166,12 +169,7 @@ else { } } $taskName = "$policyAssignmentName-$(New-Guid)" - $shortScope = $policyAssignmentScope - $resourceIdParts = Split-AzPolicyResourceId -Id $policyAssignmentId - if ($resourceIdParts.scopeType -eq "managementGroups") { - $shortScope = "/mg/$($resourceIdParts.splits[4]))" - } - + $shortScope = $policyAssignmentScope -replace "/providers/microsoft.management", "" $parametersSplat = $null if ($policyDefinitionReferenceId -and $policyDefinitionReferenceId -ne "") { $parametersSplat = [ordered]@{ @@ -216,10 +214,23 @@ else { } Write-Information "" - Write-Information "--- Creating $($collatedByAssignmentId.Count) remediation tasks sorted by Assignment Id and (if Policy Set) Category and Policy Name ---" - - $failedPolicyRemediationTasks = @() - $runningPolicyRemediationTasks = @() + if ($WhatIfPreference) { + Write-Information "===================================================================================================" + Write-Information "WhatIf: Creating $($collatedByAssignmentId.Count) remediation tasks..." + Write-Information "===================================================================================================" + } + else { + Write-Information "===================================================================================================" + Write-Information "Creating $($collatedByAssignmentId.Count) remediation tasks..." + Write-Information "===================================================================================================" + } + $failedPolicyRemediationTasks = [System.Collections.ArrayList]::new() + $runningPolicyRemediationTasks = [System.Collections.ArrayList]::new() + $needed = $collatedByAssignmentId.Count + $created = 0 + $failedToCreate = 0 + $failed = 0 + $succeded = 0 $collatedByAssignmentId.Values | Sort-Object { $_.policyAssignmentId }, { $_.category }, { $_.policyName } | ForEach-Object { if ($_.policyDefinitionReferenceId) { Write-Information "'$($_.shortScope)/$($_.policyAssignmentName)|$($_.policyDefinitionReferenceId)': $($_.resourceCount) resources, '$($_.policyDefinitionName)', $($_.policyDefinitionAction)" @@ -229,65 +240,164 @@ else { } $parameters = $_.parametersSplat Write-Verbose "Parameters: $($parameters | ConvertTo-Json -Depth 99)" - $newPolicyRemediationTask = Start-AzPolicyRemediation @parameters - if ($newPolicyRemediationTask.ProvisioningState -eq 'Succeeded') { - Write-Information "`tThe provisioning state of the Remediation Task is set to 'Succeeded'. Moving on to the next Remediation Task" - } - elseif ($newPolicyRemediationTask.ProvisioningState -eq 'Failed') { - Write-Information "`tThe provisioning state of the Remediation Task is set to 'Failed'. Adding it to the array of failed Remediation Tasks" - $failedPolicyRemediationTask = [PSCustomObject]@{ - 'Remediation Task Name' = $newPolicyRemediationTask.Name - 'Remediation Task Id' = $newPolicyRemediationTask.Id - 'Policy Assignment Id' = $newPolicyRemediationTask.PolicyAssignmentId - 'Provisioning State' = $newPolicyRemediationTask.ProvisioningState + if ($WhatIfPreference) { + Write-Information "`tWhatIf: Remediation Task would have been created." + $newPolicyRemediationTask = [PSCustomObject]@{ + Name = $parameters.Name + Id = $parameters.Name + PolicyAssignmentId = $_.PolicyAssignmentId + ProvisioningState = "Running" } - $failedPolicyRemediationTasks += $failedPolicyRemediationTask + # $null = $runningPolicyRemediationTasks.Add($newPolicyRemediationTask) + $created++ + $succeded++ } else { - Write-Information "`tThe Remediation Task has not succeeded or failed right away. Adding it to a variable to regularly check the provisioning state and moving on to the next Remediation Task" - $runningPolicyRemediationTasks += $newPolicyRemediationTask + $newPolicyRemediationTask = Start-AzPolicyRemediation @parameters -ErrorAction SilentlyContinue -WhatIf:$WhatIfPreference + + if ($null -eq $newPolicyRemediationTask) { + Write-Information "`tRemediation Task could not be created." + $failedPolicyRemediationTask = [PSCustomObject]@{ + Name = $parameters.Name + Id = "Not created" + PolicyAssignmentId = $_.PolicyAssignmentId + ProvisioningState = "Failed" + } + $null = $failedPolicyRemediationTasks.Add($failedPolicyRemediationTask) + $failedToCreate++ + } + elseif ($newPolicyRemediationTask.ProvisioningState -eq 'Succeeded') { + Write-Information "`tRemediation Task succeeded immediately." + $succeded++ + $created++ + } + elseif ($newPolicyRemediationTask.ProvisioningState -eq 'Failed') { + Write-Information "`tRemediation Task failed immediately." + $null = $failedPolicyRemediationTasks.Add($newPolicyRemediationTask) + $failed++ + $created++ + } + else { + Write-Information "`tRemediation Task started." + $null = $runningPolicyRemediationTasks.Add($newPolicyRemediationTask) + $created++ + } } } - if ($runningPolicyRemediationTasks.Count -ge 1) { - Write-Information "`nAt the moment, '$($runningPolicyRemediationTasks.Count)' Remediation Tasks are still running. Checking their provisioning state on a regular basis until they have succeeded or failed" - do { - foreach ($runningPolicyRemediationTask in $runningPolicyRemediationTasks) { - Write-Verbose "`tChecking the provisioning state of the '$($runningPolicyRemediationTask.Name)' Remediation Task" - $remediationTaskState = (Get-AzPolicyRemediation -ResourceId $runningPolicyRemediationTask.Id).ProvisioningState - if ($remediationTaskState -eq 'Succeeded') { - Write-Information "`tThe '$($runningPolicyRemediationTask.Name)' Remediation Task has succeeded. Removing it from the array of running Remediation Tasks" - $runningPolicyRemediationTasks = $runningPolicyRemediationTasks | Where-Object -FilterScript { $_.Id -ne $runningPolicyRemediationTask.Id } #Removing the completed Remediation Task from the array of running Remediation Tasks + + $maxNumberOfChecks = 30 + $waitPeriod = 60 + $checkForMinutes = [int]([math]::Ceiling($waitPeriod * $maxNumberOfChecks / 60)) + Write-Information "" + if ($runningPolicyRemediationTasks.Count -gt 0) { + if ($NoWait) { + $maxNumberOfChecks = 1 + $waitPeriod = 120 + $checkForMinutes = [int]([math]::Ceiling($waitPeriod * $maxNumberOfChecks / 60)) + Write-Information "===================================================================================================" + Write-Information "NoWait: waiting $checkForMinutes minutes for remediation tasks to complete or fail..." + Write-Information "===================================================================================================" + } + else { + Write-Information "===================================================================================================" + Write-Information "Waiting for remediation tasks to complete or fail, checking every minute for $checkForMinutes minutes..." + Write-Information "===================================================================================================" + } + $numberOfChecks = 0 + $canceled = 0 + while ($runningPolicyRemediationTasks.Count -ge 1 -and $numberOfChecks -lt $maxNumberOfChecks) { + $numberOfChecks++ + Start-Sleep -Seconds $waitPeriod + Write-Information "`nChecking $($runningPolicyRemediationTasks.Count) remediation tasks' provisioning state..." + $count = $runningPolicyRemediationTasks.Count + $newRunningPolicyRemediationTasks = [System.Collections.ArrayList]::new() + for ($i = 0; $i -lt $count; $i++) { + $runningPolicyRemediationTask = $runningPolicyRemediationTasks[$i] + $remediationTaskState = "Check for status failed" + $taskDone = $false + if ($WhatIfPreference) { + $remediationTaskState = "WhatIf - Succeeded" + Write-Information "`tWhatIf: Remediation Task '$($runningPolicyRemediationTask.Name)' might have succeeded." + $taskDone = $true + $succeded++ } - elseif ($remediationTaskState -eq 'Failed') { - Write-Information "`tThe '$($runningPolicyRemediationTask.Name)' Remediation Task has failed. Adding it to the array of failed Remediation Tasks and removing it from the array of running Remediation Tasks" - $failedPolicyRemediationTask = [PSCustomObject]@{ - 'Remediation Task Name' = $runningPolicyRemediationTask.Name - 'Remediation Task Id' = $runningPolicyRemediationTask.Id - 'Policy Assignment Id' = $runningPolicyRemediationTask.PolicyAssignmentId - 'Provisioning State' = $runningPolicyRemediationTask.ProvisioningState + else { + Write-Verbose "`tChecking the provisioning state of the '$($runningPolicyRemediationTask.Name)' Remediation Task" + $remediationTaskResult = Get-AzPolicyRemediation -ResourceId $runningPolicyRemediationTask.Id -ErrorAction Continue + if ($null -ne $remediationTaskResult) { + $remediationTaskState = $remediationTaskResult.ProvisioningState + } + if ($remediationTaskState -eq 'Succeeded') { + Write-Information "`tRemediation Task '$($runningPolicyRemediationTask.Name)' succeeded." + $taskDone = $true + $succeded++ + } + elseif ($remediationTaskState -eq 'Failed') { + Write-Information "`tRemediation Task '$($runningPolicyRemediationTask.Name)' failed." + $failedPolicyRemediationTask = [PSCustomObject]@{ + Name = $runningPolicyRemediationTask.Name + Id = $runningPolicyRemediationTask.Id + PolicyAssignmentId = $runningPolicyRemediationTask.PolicyAssignmentId + ProvisioningState = $runningPolicyRemediationTask.ProvisioningState + } + $failedPolicyRemediationTasks += $failedPolicyRemediationTask + $taskDone = $true + $failed++ + } + elseif ($remediationTaskState -eq 'Canceled') { + Write-Information "`tRemediation Task '$($runningPolicyRemediationTask.Name)' was canceled." + $canceled++ + $taskDone = $true + } + else { + Write-Information "`tRemediation Task '$($runningPolicyRemediationTask.Name)' provisioning state is '$($remediationTaskState)'." } - $failedPolicyRemediationTasks += $failedPolicyRemediationTask - $runningPolicyRemediationTasks = $runningPolicyRemediationTasks | Where-Object -FilterScript { $_.Id -ne $runningPolicyRemediationTask.Id } #Removing the completed Remediation Task from the array of running Remediation Tasks } - else { - Write-Verbose "`tThe provisioning state of the '$($runningPolicyRemediationTask.Name)' Remediation Task is still set to '$($remediationTaskState)', Moving on to the next Remediation Task" + if (-not $taskDone) { + $null = $newRunningPolicyRemediationTasks.Add($runningPolicyRemediationTask) } } - } until ($runningPolicyRemediationTasks.Count -eq 0) - } - else { - Write-Information "`nAll Remediation Tasks have succeeded or failed right away." + $runningPolicyRemediationTasks = $newRunningPolicyRemediationTasks + } } - if ($failedPolicyRemediationTasks.Count -ge 1) { - Write-Information "`nUnfortunately, '$($failedPolicyRemediationTasks.Count)' Remediation Task(s) has/have failed. Outputting the failedPolicyRemediationTasksJsonString variable as for later use in the Azure DevOps Pipeline" - $failedPolicyRemediationTasksJsonString = $failedPolicyRemediationTasks | ConvertTo-Json -Depth 10 -Compress - Write-Output "##vso[task.setvariable variable=failedPolicyRemediationTasksJsonString;isOutput=true]$($failedPolicyRemediationTasksJsonString)" - $createWorkItem = $true + + $createWorkItem = $false + Write-Information "" + if ($WhatIfPreference) { + Write-Information "===================================================================================================" + Write-Information "WhatIf: Remediation Task Status" + Write-Information "===================================================================================================" + Write-Information "WhatIf: $needed needed" + Write-Information "WhatIf: $created created" + Write-Information "WhatIf: $succeded succeded" } else { - Write-Information "`nNo Remediation Tasks have failed. Ending the Azure DevOps Pipeline" - $createWorkItem = $false + Write-Information "===================================================================================================" + Write-Information "Remediation Task Status" + Write-Information "===================================================================================================" + $stillRunning = $runningPolicyRemediationTasks.Count + Write-Information "$needed needed" + if ($failedToCreate -gt 0) { + Write-Information "$failedToCreate failed to create" + } + Write-Information "$created created" + Write-Information "$succeded succeded" + if ($failed -gt 0) { + Write-Information "$failed failed" + if (-not $Interactive) { + $failedPolicyRemediationTasksJsonString = $failedPolicyRemediationTasks | ConvertTo-Json -Depth 10 -Compress + Write-Output "##vso[task.setvariable variable=failedPolicyRemediationTasksJsonString;isOutput=true]$($failedPolicyRemediationTasksJsonString)" + $createWorkItem = $true + } + } + if ($canceled -gt 0) { + Write-Information "$canceled canceled" + } + if ($stillRunning -gt 0) { + Write-Information "$stillRunning still running after $checkForMinutes minutes" + } + if (-not $Interactive) { + Write-Output "##vso[task.setvariable variable=createWorkItem;isOutput=true]$($createWorkItem)" + } } - Write-Output "##vso[task.setvariable variable=createWorkItem;isOutput=true]$($createWorkItem)" } -Write-Information "" \ No newline at end of file diff --git a/Scripts/Operations/Create-AzureDevOpsBug.ps1 b/Scripts/Operations/Create-AzureDevOpsBug.ps1 index ca68f245..e25af7fd 100644 --- a/Scripts/Operations/Create-AzureDevOpsBug.ps1 +++ b/Scripts/Operations/Create-AzureDevOpsBug.ps1 @@ -1,6 +1,6 @@ <# .SYNOPSIS - This PowerShell script creates a Bug when there are one or multiple failed Remedation Tasks. + This PowerShell script creates a Bug when there are one or multiple failed Remediation Tasks. .DESCRIPTION The Create-AzureDevOpsBug.ps1 PowerShell script creates a Bug on the current Iteration of a team when one or diff --git a/Scripts/Operations/Create-GitHubIssue.ps1 b/Scripts/Operations/Create-GitHubIssue.ps1 index c3288c40..b90a223a 100644 --- a/Scripts/Operations/Create-GitHubIssue.ps1 +++ b/Scripts/Operations/Create-GitHubIssue.ps1 @@ -1,6 +1,6 @@ <# .SYNOPSIS - This PowerShell script creates an Issue when there are one or multiple failed Remedation Tasks. + This PowerShell script creates an Issue when there are one or multiple failed Remediation Tasks. .DESCRIPTION The Create-GitHubIssue.ps1 PowerShell script creates an Issue in a GitHub Repository that is located under diff --git a/Scripts/Operations/Export-AzPolicyResources.ps1 b/Scripts/Operations/Export-AzPolicyResources.ps1 index fd2d6653..fbbfa750 100644 --- a/Scripts/Operations/Export-AzPolicyResources.ps1 +++ b/Scripts/Operations/Export-AzPolicyResources.ps1 @@ -4,8 +4,8 @@ Exports Azure Policy resources in EPAC format or raw format. .DESCRIPTION Exports Azure Policy resources in EPAC format or raw format. It has 4 operating modes - see -Mode parameter for details. -It also generates documentaion for the exported resources (can be suppressed with -SuppressDocumentation). -To just generate EPAC formatted Definitions without generating documentaion files, use -supressEpacOutput. +It also generates documentation for the exported resources (can be suppressed with -SuppressDocumentation). +To just generate EPAC formatted Definitions without generating documentation files, use -supressEpacOutput. .PARAMETER DefinitionsRootFolder Definitions folder path. Defaults to environment variable $env:PAC_DEFINITIONS_FOLDER or './Definitions'. @@ -217,7 +217,7 @@ if ($Mode -ne 'exportFromRawFiles') { elseif ($Mode -eq 'psrule' -and $PSRuleIgnoreFullScope -eq $true) { $pacEnvironmentOriginalScope = $pacEnvironment.deploymentRootScope } - $scopeTable = Get-AzScopeTree -PacEnvironment $pacEnvironment + $scopeTable = Build-ScopeTableForDeploymentRootScope -PacEnvironment $pacEnvironment if ($Mode -eq 'psrule') { $newScopeTable = @{} foreach ($scope in $scopeTable.GetEnumerator()) { @@ -402,18 +402,31 @@ foreach ($pacSelector in $globalSettings.pacEnvironmentSelectors) { $rowObj.pacSelector = $pacSelector $rowObj.kind = "Policy" if ($policyDefinition.pacOwner -eq "otherPaC") { - $rowObj.owner = "otherPaC($($rawMetadata.pacOwnerId))" + $rowObj.owner = "otherPaC(pacOwnerId=$($rawMetadata.pacOwnerId))" } else { $rowObj.owner = $policyDefinition.pacOwner } + if ($null -ne $rawMetadata.updatedBy) { + $rowObj.principalId = $rawMetadata.updatedBy + $rowObj.lastChange = ($rawMetadata.updatedOn).ToString("s") + } + else { + $rowObj.principalId = $rawMetadata.createdBy + $rowObj.lastChange = ($rawMetadata.createdOn).ToString("s") + } if ($null -ne $rawMetadata.category) { $rowObj.category = $rawMetadata.category } else { $rowObj.category = "" } - $rowObj.displayName = $properties.displayName + if ($null -ne $properties.displayName) { + $rowObj.displayName = $properties.displayName + } + else { + $rowObj.displayName = $policyDefinition.name + } $rowObj.id = $policyDefinition.id $null = $allRows.Add($rowObj) @@ -487,18 +500,31 @@ foreach ($pacSelector in $globalSettings.pacEnvironmentSelectors) { $rowObj.pacSelector = $pacSelector $rowObj.kind = "Policy Set" if ($policySetDefinition.pacOwner -eq "otherPaC") { - $rowObj.owner = "otherPaC($($rawMetadata.pacOwnerId))" + $rowObj.owner = "otherPaC(pacOwnerId=$($rawMetadata.pacOwnerId))" } else { $rowObj.owner = $policySetDefinition.pacOwner } + if ($null -ne $rawMetadata.updatedBy) { + $rowObj.principalId = $rawMetadata.updatedBy + $rowObj.lastChange = ($rawMetadata.updatedOn).ToString("s") + } + else { + $rowObj.principalId = $rawMetadata.createdBy + $rowObj.lastChange = ($rawMetadata.createdOn).ToString("s") + } if ($null -ne $rawMetadata.category) { $rowObj.category = $rawMetadata.category } else { $rowObj.category = "" } - $rowObj.displayName = $properties.displayName + if ($null -ne $properties.displayName) { + $rowObj.displayName = $properties.displayName + } + else { + $rowObj.displayName = $policySetDefinition.name + } $rowObj.id = $policySetDefinition.id $null = $allRows.Add($rowObj) @@ -517,7 +543,7 @@ foreach ($pacSelector in $globalSettings.pacEnvironmentSelectors) { # } # Adjust policyDefinitions for EPAC - $policyDefinitionsIn = Get-DeepClone $properties.policyDefinitions -AsHashTable + $policyDefinitionsIn = Get-ClonedObject $properties.policyDefinitions -AsHashTable $policyDefinitionsOut = [System.Collections.ArrayList]::new() foreach ($policyDefinitionIn in $policyDefinitionsIn) { $parts = Split-AzPolicyResourceId -Id $policyDefinitionIn.policyDefinitionId @@ -609,18 +635,31 @@ foreach ($pacSelector in $globalSettings.pacEnvironmentSelectors) { $policyType = if ($parts.scopeType -eq "builtin") { "Builtin" } else { "Custom" } $rowObj.kind = "Assignment($($policyKind)-$($policyType))" if ($policyAssignment.pacOwner -eq "otherPaC") { - $rowObj.owner = "otherPaC($($rawMetadata.pacOwnerId))" + $rowObj.owner = "otherPaC(pacOwnerId=$($rawMetadata.pacOwnerId))" } else { $rowObj.owner = $policyAssignment.pacOwner } + if ($null -ne $rawMetadata.updatedBy) { + $rowObj.principalId = $rawMetadata.updatedBy + $rowObj.lastChange = ($rawMetadata.updatedOn).ToString("s") + } + else { + $rowObj.principalId = $rawMetadata.createdBy + $rowObj.lastChange = ($rawMetadata.createdOn).ToString("s") + } if ($null -ne $rawMetadata.category) { $rowObj.category = $rawMetadata.category } else { $rowObj.category = "" } - $rowObj.displayName = $properties.displayName + if ($null -ne $properties.displayName) { + $rowObj.displayName = $properties.displayName + } + else { + $rowObj.displayName = $policyAssignment.name + } $rowObj.id = $policyAssignment.id $null = $allRows.Add($rowObj) @@ -698,7 +737,7 @@ foreach ($pacSelector in $globalSettings.pacEnvironmentSelectors) { $parameters = @{} if ($null -ne $properties.parameters -and $properties.parameters.psbase.Count -gt 0) { - $parametersClone = Get-DeepClone $properties.parameters -AsHashTable + $parametersClone = Get-ClonedObject $properties.parameters -AsHashTable foreach ($parameterName in $parametersClone.Keys) { $parameterValue = $parametersClone.$parameterName $parameters[$parameterName] = $parameterValue.value @@ -770,13 +809,20 @@ foreach ($pacSelector in $globalSettings.pacEnvironmentSelectors) { $rowObj.kind = "Exemption($($exemption.status))" $rawMetadata = $exemption.metadata if ($exemption.pacOwner -eq "otherPaC") { - $rowObj.owner = "otherPaC($($rawMetadata.pacOwnerId))" + $rowObj.owner = "otherPaC(pacOwnerId=$($rawMetadata.pacOwnerId))" } else { $rowObj.owner = $exemption.pacOwner } + $rowObj.principalId = "n/a" + $rowObj.lastChange = "n/a" $rowObj.category = $exemption.exemptionCategory - $rowObj.displayName = $exemption.displayName + if ($null -ne $exemption.displayName) { + $rowObj.displayName = $exemption.displayName + } + else { + $rowObj.displayName = $exemption.name + } $rowObj.id = $exemption.id $null = $allRows.Add($rowObj) } @@ -806,11 +852,6 @@ Write-Information "============================================================= Write-Information "Optimizing $($assignmentsByPolicyDefinition.psbase.Count) Policy Assignment trees" Write-Information "===================================================================================================" -# $fullPath = "$policyAssignmentsFolder/tree-raw.$FileExtension" -# $object = Get-HashtableWithPropertyNamesRemoved -Object $assignmentsByPolicyDefinition -PropertyNames "parent", "clusters" -# $json = ConvertTo-Json $object -Depth 100 -# $null = New-Item $fullPath -Force -ItemType File -Value $json - foreach ($policyDefinitionKey in $assignmentsByPolicyDefinition.Keys) { $perDefinition = $assignmentsByPolicyDefinition.$policyDefinitionKey foreach ($child in $perDefinition.children) { @@ -821,12 +862,6 @@ foreach ($policyDefinitionKey in $assignmentsByPolicyDefinition.Keys) { } } -# $fullPath = "$policyAssignmentsFolder/tree-optimized.$FileExtension" -# $object = Get-HashtableWithPropertyNamesRemoved -Object $assignmentsByPolicyDefinition -PropertyNames "parent", "clusters" -# $json = ConvertTo-Json $object -Depth 100 -# $null = New-Item $fullPath -Force -ItemType File -Value $json -# $assignmentsByPolicyDefinition = $object - #endregion prep tree for collapsing nodes #region create assignment files (one per definition id), use clusters to collapse tree diff --git a/Scripts/Operations/Export-NonComplianceReports.ps1 b/Scripts/Operations/Export-NonComplianceReports.ps1 index 822c0c15..227d0e51 100644 --- a/Scripts/Operations/Export-NonComplianceReports.ps1 +++ b/Scripts/Operations/Export-NonComplianceReports.ps1 @@ -99,7 +99,7 @@ param( [Parameter(Mandatory = $false, HelpMessage = "Filter by Policy Effect")] [string[]] $PolicyEffectFilter = $null, - [Parameter(Mandatory = $false, HelpMessage = "Switch parmeter to filter out Policy Effect Manual")] + [Parameter(Mandatory = $false, HelpMessage = "Switch parameter to filter out Policy Effect Manual")] [switch] $ExcludeManualPolicyEffect, [Parameter(Mandatory = $false, HelpMessage = "Filter by Policy Effect `"deployifnotexists`" and `"modify`" and compliance status `"NonCompliant`"")] diff --git a/Scripts/Operations/Format-PolicyName.ps1 b/Scripts/Operations/Format-PolicyName.ps1 deleted file mode 100644 index 6cac68cc..00000000 --- a/Scripts/Operations/Format-PolicyName.ps1 +++ /dev/null @@ -1,16 +0,0 @@ -[CmdletBinding()] -param ( - [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] - [string] - $DisplayName -) - -. "$PSScriptRoot/../Helpers/Get-ScrubbedString.ps1" - -$invalidChars = [IO.Path]::GetInvalidFileNameChars() -$invalidChars += (":[]()$".ToCharArray()) - -$scrubbed = Get-ScrubbedString -String $DisplayName -InvalidChars $invalidChars -ReplaceWith "-" -ReplaceSpaces -ReplaceSpacesWith "-" -MaxLength 100 -TrimEnds -ToLower -SingleReplace - -Write-Output "referenceID = `"$scrubbed`"" -Write-Output "effectParam = `"effect-$scrubbed`"" \ No newline at end of file diff --git a/Scripts/Operations/Get-AzExemptions.ps1 b/Scripts/Operations/Get-AzExemptions.ps1 index 6ac86e5f..11a19d54 100644 --- a/Scripts/Operations/Get-AzExemptions.ps1 +++ b/Scripts/Operations/Get-AzExemptions.ps1 @@ -71,7 +71,7 @@ else { } Write-Information "" -$scopeTable = Get-AzScopeTree -PacEnvironment $pacEnvironment +$scopeTable = Build-ScopeTableForDeploymentRootScope -PacEnvironment $pacEnvironment $deployedPolicyResources = Get-AzPolicyResources -PacEnvironment $pacEnvironment -ScopeTable $scopeTable -SkipRoleAssignments $exemptions = $deployedPolicyResources.policyExemptions.managed diff --git a/Scripts/Operations/New-EPACGlobalSettings.ps1 b/Scripts/Operations/New-EPACGlobalSettings.ps1 index f1eb5f6d..9e84dcd7 100644 --- a/Scripts/Operations/New-EPACGlobalSettings.ps1 +++ b/Scripts/Operations/New-EPACGlobalSettings.ps1 @@ -43,7 +43,7 @@ if ($DeploymentRootScope.StartsWith('/providers/Microsoft.Management/managementG if (Get-AzLocation | Where-Object { $_.Location -eq $ManagedIdentityLocation }) { $jsonstrings = @("{""`$schema"": ""https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/main/Schemas/global-settings-schema.json"", ""pacOwnerId"": """, """, ""managedIdentityLocations"": { ""*"": """, - """}, ""globalNotScopes"": { ""*"": [""/resourceGroupPatterns/excluded-rg*""] }, ""pacEnvironments"": [{ ""pacSelector"": ""quick-start"",""cloud"": ""AzureCloud"", ""tenantId"": """, + """}, ""pacEnvironments"": [{ ""pacSelector"": ""quick-start"",""cloud"": ""AzureCloud"", ""tenantId"": """, """, ""deploymentRootScope"": ""$DeploymentRootScope""}]}" ) diff --git a/Scripts/Operations/New-PipelinesFromStarterKit.ps1 b/Scripts/Operations/New-PipelinesFromStarterKit.ps1 new file mode 100644 index 00000000..3d64c30f --- /dev/null +++ b/Scripts/Operations/New-PipelinesFromStarterKit.ps1 @@ -0,0 +1,107 @@ +<# +.SYNOPSIS + Copy pipelines and templates from starter kit to new folder + +.DESCRIPTION + This script copies pipelines and templates from the starter kit to a new folder. The script prompts for the type of pipeline to create, the branching flow to implement, and the type of script to use. + +.PARAMETER StarterKitFolder + Starter kit folder + +.PARAMETER PipelinesFolder + New pipeline folder + +.PARAMETER PipelineType + Type of DevOps pipeline to create AzureDevOps or GitHubActions? + +.PARAMETER BranchingFlow + Implementing branching flow Release or GitHub + +.PARAMETER ScriptType + Using Powershell module or script? + +#> + +[CmdletBinding()] +param ( + [Parameter(Mandatory = $false, HelpMessage = "Starter kit folder")] + [string] $StarterKitFolder = "./StarterKit", + + [Parameter(Mandatory = $false, HelpMessage = "New pipeline folder")] + [string] $PipelinesFolder = "", + + [Parameter(Mandatory = $false, HelpMessage = "Type of DevOps pipeline to create AzureDevOps or GitHubActions?")] + [ValidateSet("AzureDevOps", "GitHubActions")] + # [string] $PipelineType = "AzureDevOps", + [string] $PipelineType = "GitHubActions", + + [Parameter(Mandatory = $false, HelpMessage = "Implementing branching flow Release or GitHub")] + [ValidateSet("Release", "GitHub")] + [string] $BranchingFlow = "Release", + + [Parameter(Mandatory = $false, HelpMessage = "Using Powershell module or script?")] + [ValidateSet("Module", "Scripts")] + [string] $ScriptType = "Module" +) + +if (!(Test-Path $StarterKitFolder)) { + Write-Error "Starter kit folder not found" + return +} + +$starterPipelinesFolder = "" +$starterPipelinesSubfolder = "" +$starterTemplatesSubfolder = "" +$templatesFolder = "" +$pipelineTypeText = "" +$templateTypeText = "" +switch ($PipelineType) { + AzureDevOps { + if ($PipelinesFolder -eq "") { + $PipelinesFolder = "./Pipelines" + } + $templatesFolder = "$PipelinesFolder/templates" + $starterPipelinesFolder = "$StarterKitFolder/Pipelines/AzureDevOps" + $pipelineTypeText = "Azure DevOps pipelines" + $templateTypeText = "Azure DevOps templates" + } + GitHubActions { + if ($PipelinesFolder -eq "") { + $PipelinesFolder = "./.github/workflows" + } + $templatesFolder = $PipelinesFolder + $starterPipelinesFolder = "$StarterKitFolder/Pipelines/GitHubActions" + $pipelineTypeText = "GitHub Actions workflows" + $templateTypeText = "GitHub Actions reusable workflows" + } +} + +switch ($BranchingFlow) { + Release { + $starterPipelinesSubfolder = "Release-Flow" + } + GitHub { + $starterPipelinesSubfolder = "GitHub-Flow" + } +} +$starterPipelinesPath = "$starterPipelinesFolder/$starterPipelinesSubfolder/*.yml" + +switch ($ScriptType) { + Module { + $starterTemplatesSubfolder = "templates-ps1-module" + } + Scripts { + $starterTemplatesSubfolder = "templates-ps1-scripts" + } +} +$starterTemplatesPath = "$starterPipelinesFolder/$starterTemplatesSubfolder/*.yml" + +if (!(Test-Path $templatesFolder)) { + $null = New-Item -ItemType Directory -Name $templatesFolder +} + +Write-Information "Copying starter kit $pipelineTypeText ($starterPipelinesSubfolder) from '$starterPipelinesPath' to $PipelinesFolder" -InformationAction Continue +Write-Information "Copying starter kit $templateTypeText (use $ScriptType) from '$starterTemplatesPath' to $templatesFolder" -InformationAction Continue +Read-Host "Press Enter to continue" +Copy-Item -Path $starterPipelinesPath -Destination $PipelinesFolder +Copy-Item -Path $starterTemplatesPath -Destination $templatesFolder diff --git a/StarterKit/Definitions/policyDefinitions/Defender/mdc-workload-protection-enrollment.json b/StarterKit/Definitions-Common/policyDefinitions/Defender/mdc-workload-protection-enrollment.json similarity index 100% rename from StarterKit/Definitions/policyDefinitions/Defender/mdc-workload-protection-enrollment.json rename to StarterKit/Definitions-Common/policyDefinitions/Defender/mdc-workload-protection-enrollment.json diff --git a/StarterKit/Definitions/policyDefinitions/Tagging/resources-inherit-rg-tag-dynamic-notscope.json b/StarterKit/Definitions-Common/policyDefinitions/Tagging/resources-inherit-rg-tag-dynamic-notscope.json similarity index 100% rename from StarterKit/Definitions/policyDefinitions/Tagging/resources-inherit-rg-tag-dynamic-notscope.json rename to StarterKit/Definitions-Common/policyDefinitions/Tagging/resources-inherit-rg-tag-dynamic-notscope.json diff --git a/StarterKit/Definitions/policyDefinitions/Tagging/resources-required-tag-dynamic-notscope.jsonc b/StarterKit/Definitions-Common/policyDefinitions/Tagging/resources-required-tag-dynamic-notscope.jsonc similarity index 100% rename from StarterKit/Definitions/policyDefinitions/Tagging/resources-required-tag-dynamic-notscope.jsonc rename to StarterKit/Definitions-Common/policyDefinitions/Tagging/resources-required-tag-dynamic-notscope.jsonc diff --git a/StarterKit/Definitions/policyDefinitions/Tagging/rg-addreplace-tag-dynamic-notscope.json b/StarterKit/Definitions-Common/policyDefinitions/Tagging/rg-addreplace-tag-dynamic-notscope.json similarity index 100% rename from StarterKit/Definitions/policyDefinitions/Tagging/rg-addreplace-tag-dynamic-notscope.json rename to StarterKit/Definitions-Common/policyDefinitions/Tagging/rg-addreplace-tag-dynamic-notscope.json diff --git a/StarterKit/Definitions/policyDefinitions/Tagging/rg-required-tag-dynamic-notscope.json b/StarterKit/Definitions-Common/policyDefinitions/Tagging/rg-required-tag-dynamic-notscope.json similarity index 100% rename from StarterKit/Definitions/policyDefinitions/Tagging/rg-required-tag-dynamic-notscope.json rename to StarterKit/Definitions-Common/policyDefinitions/Tagging/rg-required-tag-dynamic-notscope.json diff --git a/StarterKit/Definitions/policySetDefinitions/allowed-locations-initiative.jsonc b/StarterKit/Definitions-Common/policySetDefinitions/allowed-locations-initiative.jsonc similarity index 100% rename from StarterKit/Definitions/policySetDefinitions/allowed-locations-initiative.jsonc rename to StarterKit/Definitions-Common/policySetDefinitions/allowed-locations-initiative.jsonc diff --git a/StarterKit/Definitions/policySetDefinitions/mdc-workload-protection-enrollment-policy-set.jsonc b/StarterKit/Definitions-Common/policySetDefinitions/mdc-workload-protection-enrollment-policy-set.jsonc similarity index 100% rename from StarterKit/Definitions/policySetDefinitions/mdc-workload-protection-enrollment-policy-set.jsonc rename to StarterKit/Definitions-Common/policySetDefinitions/mdc-workload-protection-enrollment-policy-set.jsonc diff --git a/StarterKit/Definitions/global-settings.jsonc b/StarterKit/Definitions-GitHub-Flow/global-settings.jsonc similarity index 69% rename from StarterKit/Definitions/global-settings.jsonc rename to StarterKit/Definitions-GitHub-Flow/global-settings.jsonc index f9df6cf6..3c075b0e 100644 --- a/StarterKit/Definitions/global-settings.jsonc +++ b/StarterKit/Definitions-GitHub-Flow/global-settings.jsonc @@ -6,27 +6,21 @@ "pacSelector": "epac-dev", "cloud": "AzureCloud", "tenantId": "77777777-8888-9999-1111-222222222222", - "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/EPAC-Dev" + "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/mg-epac-dev" }, { "pacSelector": "tenant", "cloud": "AzureCloud", "tenantId": "77777777-8888-9999-1111-222222222222", - "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/Contoso-Root", // replaces rootScope - "desiredState": { // [optional] - "strategy": "full", // default full - } + "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/mg-enterprise" } ], "managedIdentityLocations": { "*": "eastus2" }, "globalNotScopes": { - "*": [ - "/resourceGroupPatterns/excluded-rg*", - ], "tenant": [ - "/providers/Microsoft.Management/managementGroups/EPAC-Dev" + "/providers/Microsoft.Management/managementGroups/mg-epac-dev" ] } } \ No newline at end of file diff --git a/StarterKit/Definitions/policyAssignments/allowed-locations-assignments.jsonc b/StarterKit/Definitions-GitHub-Flow/policyAssignments/allowed-locations-assignments.jsonc similarity index 80% rename from StarterKit/Definitions/policyAssignments/allowed-locations-assignments.jsonc rename to StarterKit/Definitions-GitHub-Flow/policyAssignments/allowed-locations-assignments.jsonc index 384049c2..a2c68409 100644 --- a/StarterKit/Definitions/policyAssignments/allowed-locations-assignments.jsonc +++ b/StarterKit/Definitions-GitHub-Flow/policyAssignments/allowed-locations-assignments.jsonc @@ -17,10 +17,10 @@ }, "scope": { "epac-dev": [ - "/providers/Microsoft.Management/managementGroups/EPAC-Dev" + "/providers/Microsoft.Management/managementGroups/mg-epac-dev" ], "tenant": [ - "/providers/Microsoft.Management/managementGroups/Contoso-Root" + "/providers/Microsoft.Management/managementGroups/mg-enterprise" ] } } \ No newline at end of file diff --git a/StarterKit/Definitions/policyAssignments/security-baseline-assignments.jsonc b/StarterKit/Definitions-GitHub-Flow/policyAssignments/security-baseline-assignments.jsonc similarity index 58% rename from StarterKit/Definitions/policyAssignments/security-baseline-assignments.jsonc rename to StarterKit/Definitions-GitHub-Flow/policyAssignments/security-baseline-assignments.jsonc index f66eeac9..db5b8e90 100644 --- a/StarterKit/Definitions/policyAssignments/security-baseline-assignments.jsonc +++ b/StarterKit/Definitions-GitHub-Flow/policyAssignments/security-baseline-assignments.jsonc @@ -35,61 +35,27 @@ "parameterSelector": "prod", "scope": { "epac-dev": [ - "/providers/Microsoft.Management/managementGroups/epac-dev-prod" + "/providers/Microsoft.Management/managementGroups/mg-epac-dev-prod" ], "tenant": [ - "/providers/Microsoft.Management/managementGroups/Contoso-Prod" + "/providers/Microsoft.Management/managementGroups/mg-prod" ] } }, { - "nodeName": "Test/", + "nodeName": "Nonprod/", "assignment": { "name": "tst-", - "displayName": "Test ", - "description": "Test Environment controls enforcement with " + "displayName": "Nonprod ", + "description": "Nonprod Environment controls enforcement with " }, - "parameterSelector": "test", + "parameterSelector": "nonprod", "scope": { "epac-dev": [ - "/providers/Microsoft.Management/managementGroups/epac-dev-test" + "/providers/Microsoft.Management/managementGroups/epac-dev-nonprod" ], "tenant": [ - "/providers/Microsoft.Management/managementGroups/Contoso-Test" - ] - } - }, - { - "nodeName": "Dev/", - "assignment": { - "name": "dev-", - "displayName": "Dev ", - "description": "Dev Environment controls enforcement with " - }, - "parameterSelector": "dev", - "scope": { - "epac-dev": [ - "/providers/Microsoft.Management/managementGroups/epac-dev-dev" - ], - "tenant": [ - "/providers/Microsoft.Management/managementGroups/Contoso-Dev" - ] - } - }, - { - "nodeName": "Sandbox/", - "assignment": { - "name": "sbx-", - "displayName": "Sandbox ", - "description": "Sandbox Environment controls enforcement with " - }, - "parameterSelector": "sandbox", - "scope": { - "epac-dev": [ - "/providers/Microsoft.Management/managementGroups/epac-dev-sandbox" - ], - "tenant": [ - "/providers/Microsoft.Management/managementGroups/Contoso-Sandbox" + "/providers/Microsoft.Management/managementGroups/mg-nonprod" ] } } diff --git a/StarterKit/Definitions-GitHub-Flow/policyAssignments/security-baseline-parameters.csv b/StarterKit/Definitions-GitHub-Flow/policyAssignments/security-baseline-parameters.csv new file mode 100644 index 00000000..9b1e18fd --- /dev/null +++ b/StarterKit/Definitions-GitHub-Flow/policyAssignments/security-baseline-parameters.csv @@ -0,0 +1,1953 @@ +"name","referencePath","policyType","category","displayName","description","groupNames","policySets","allowedEffects","prodEffect","nonprodEffect","prodParameters","nonprodParameters" +"051cba44-2429-45b9-9649-46cec11c7119","","BuiltIn","API for FHIR","Azure API for FHIR should use a customer-managed key to encrypt data at rest","Use a customer-managed key to control the encryption at rest of the data stored in Azure API for FHIR when this is a regulatory or compliance requirement. Customer-managed keys also deliver double encryption by adding a second layer of encryption on top of the default one done with service-managed keys.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"1ee56206-5dd1-42ab-b02d-8aae8b1634ce","","BuiltIn","API for FHIR","Azure API for FHIR should use private link","Azure API for FHIR should have at least one approved private endpoint connection. Clients in a virtual network can securely access resources that have private endpoint connections through private links. For more information, visit: https://aka.ms/fhir-privatelink.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"ee7495e7-3ba7-40b6-bfee-c29e22cc75d4","","BuiltIn","API Management","API Management APIs should use only encrypted protocols","To ensure security of data in transit, APIs should be available only through encrypted protocols, like HTTPS or WSS. Avoid using unsecured protocols, such as HTTP or WS.","Azure_Security_Benchmark_v3.0_DP-3","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"c15dcc82-b93c-4dcb-9332-fbf121685b54","","BuiltIn","API Management","API Management calls to API backends should be authenticated","Calls from API Management to backends should use some form of authentication, whether via certificates or credentials. Does not apply to Service Fabric backends.","Azure_Security_Benchmark_v3.0_IM-4","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"92bb331d-ac71-416a-8c91-02f2cb734ce4","","BuiltIn","API Management","API Management calls to API backends should not bypass certificate thumbprint or name validation","To improve the API security, API Management should validate the backend server certificate for all API calls. Enable SSL certificate thumbprint and name validation.","Azure_Security_Benchmark_v3.0_IM-4","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"b741306c-968e-4b67-b916-5675e5c709f4","","BuiltIn","API Management","API Management direct management endpoint should not be enabled","The direct management REST API in Azure API Management bypasses Azure Resource Manager role-based access control, authorization, and throttling mechanisms, thus increasing the vulnerability of your service.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"549814b6-3212-4203-bdc8-1548d342fb67","","BuiltIn","API Management","API Management minimum API version should be set to 2019-12-01 or higher","To prevent service secrets from being shared with read-only users, the minimum API version should be set to 2019-12-01 or higher.","Azure_Security_Benchmark_v3.0_IM-8, +Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"f1cc7827-022c-473e-836e-5a51cae0b249","","BuiltIn","API Management","API Management secret named values should be stored in Azure Key Vault","Named values are a collection of name and value pairs in each API Management service. Secret values can be stored either as encrypted text in API Management (custom secrets) or by referencing secrets in Azure Key Vault. To improve security of API Management and secrets, reference secret named values from Azure Key Vault. Azure Key Vault supports granular access management and secret rotation policies.","Azure_Security_Benchmark_v3.0_IM-8, +Azure_Security_Benchmark_v3.0_DP-6","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"ef619a2c-cc4d-4d03-b2ba-8c94a834d85b","","BuiltIn","API Management","API Management services should use a virtual network","Azure Virtual Network deployment provides enhanced security, isolation and allows you to place your API Management service in a non-internet routable network that you control access to. These networks can then be connected to your on-premises networks using various VPN technologies, which enables access to your backend services within the network and/or on-premises. The developer portal and API gateway, can be configured to be accessible either from the Internet or only within the virtual network.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: aPIManagementServicesShouldUseAVirtualNetworkMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""aPIManagementServicesShouldUseAVirtualNetworkEvaluatedSkuNames"":[""Developer"",""Premium""],""evaluatedSkuNames-ef619a2c-cc4d-4d03-b2ba-8c94a834d85b"":[""Developer"",""Premium""]}","{""aPIManagementServicesShouldUseAVirtualNetworkEvaluatedSkuNames"":[""Developer"",""Premium""],""evaluatedSkuNames-ef619a2c-cc4d-4d03-b2ba-8c94a834d85b"":[""Developer"",""Premium""]}" +"df73bd95-24da-4a4f-96b9-4e8b94b402bd","","BuiltIn","API Management","API Management should disable public network access to the service configuration endpoints","To improve the security of API Management services, restrict connectivity to service configuration endpoints, like direct access management API, Git configuration management endpoint, or self-hosted gateways configuration endpoint.","Azure_Security_Benchmark_v3.0_NS-2","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"3aa03346-d8c5-4994-a5bc-7652c2a2aef1","","BuiltIn","API Management","API Management subscriptions should not be scoped to all APIs","API Management subscriptions should be scoped to a product or an individual API instead of all APIs, which could result in an excessive data exposure.","Azure_Security_Benchmark_v3.0_PA-7","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1dc2fc00-2245-4143-99f4-874c937f13ef","","BuiltIn","API Management","Azure API Management platform version should be stv2","Azure API Management stv1 compute platform version will be retired effective 31 August 2024, and these instances should be migrated to stv2 compute platform for continued support. Learn more at https://learn.microsoft.com/azure/api-management/breaking-changes/stv1-platform-retirement-august-2024","Azure_Security_Benchmark_v3.0_PV-2, +Azure_Security_Benchmark_v3.0_AM-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"ca610c1d-041c-4332-9d88-7ed3094967c7","","BuiltIn","App Configuration","App Configuration should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your app configuration instances instead of the entire service, you'll also be protected against data leakage risks. Learn more at: https://aka.ms/appconfig/private-endpoint.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: appConfigurationShouldUsePrivateLinkMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"af35e2a4-ef96-44e7-a9ae-853dd97032c4","","BuiltIn","App Platform","Azure Spring Cloud should use network injection","Azure Spring Cloud instances should use virtual network injection for the following purposes: 1. Isolate Azure Spring Cloud from Internet. 2. Enable Azure Spring Cloud to interact with systems in either on premises data centers or Azure service in other virtual networks. 3. Empower customers to control inbound and outbound network communications for Azure Spring Cloud.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1)","ASB: Audit (default: azureSpringCloudShouldUseNetworkInjectionMonitoringEffect), +NIST-800-53: Audit (default: effect-af35e2a4-ef96-44e7-a9ae-853dd97032c4)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""evaluatedSkuNames-af35e2a4-ef96-44e7-a9ae-853dd97032c4"":[""Standard""]}","{""evaluatedSkuNames-af35e2a4-ef96-44e7-a9ae-853dd97032c4"":[""Standard""]}" +"eaebaea7-8013-4ceb-9d14-7eb32271373c","","BuiltIn","App Service","[Deprecated]: Function apps should have 'Client Certificates (Incoming client certificates)' enabled","Client certificates allow for the app to request a certificate for incoming requests. Only clients with valid certificates will be able to reach the app. This policy has been replaced by a new policy with the same name because Http 2.0 doesn't support client certificates.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: functionAppsShouldHaveClientCertificatesEnabledMonitoringEffect), +NIST-800-53: Disabled (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"19dd1db6-f442-49cf-a838-b0786b4401ef","","BuiltIn","App Service","App Service apps should have Client Certificates (Incoming client certificates) enabled","Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app. This policy applies to apps with Http version set to 1.1.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (Policy Default), +NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"cb510bfd-1cba-4d9f-a230-cb0976f4bb71","","BuiltIn","App Service","App Service apps should have remote debugging turned off","Remote debugging requires inbound ports to be opened on an App Service app. Remote debugging should be turned off.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (default: webAppDisableRemoteDebuggingMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"91a78b24-f231-4a8a-8da9-02c35b2b6510","","BuiltIn","App Service","App Service apps should have resource logs enabled","Audit enabling of resource logs on the app. This enables you to recreate activity trails for investigation purposes if a security incident occurs or your network is compromised.","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticLogsInAppServicesShouldBeEnabledMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"5744710e-cc2f-4ee8-8809-3b11e89f4bc9","","BuiltIn","App Service","App Service apps should not have CORS configured to allow every resource to access your apps","Cross-Origin Resource Sharing (CORS) should not allow all domains to access your app. Allow only required domains to interact with your app.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (default: webAppRestrictCORSAccessMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"a4af4a39-4135-47fb-b175-47fbdf85311d","","BuiltIn","App Service","App Service apps should only be accessible over HTTPS","Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks.","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (default: webAppEnforceHttpsMonitoringEffectV2), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"4d24b6d4-5e53-4a4f-a7f4-618fa573ee4b","","BuiltIn","App Service","App Service apps should require FTPS only","Enable FTPS enforcement for enhanced security.","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (default: fTPSShouldBeRequiredInYourWebAppMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"8c122334-9d20-4eb8-89ea-ac9a705b74ae","","BuiltIn","App Service","App Service apps should use latest 'HTTP Version'","Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version.","NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-2(6)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"2b9ad585-36bc-4615-b300-fd4435808332","","BuiltIn","App Service","App Service apps should use managed identity","Use a managed identity for enhanced authentication security","Azure_Security_Benchmark_v3.0_IM-3, +NIST_SP_800-53_R5_AC-2, +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-4","ASB: AuditIfNotExists (default: managedIdentityShouldBeUsedInYourWebAppMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"f0e6e85b-9b9f-4a4b-b67b-f730d42f1b0b","","BuiltIn","App Service","App Service apps should use the latest TLS version","Periodically, newer versions are released for TLS either due to security flaws, include additional functionality, and enhance speed. Upgrade to the latest TLS version for App Service apps to take advantage of security fixes, if any, and/or new functionalities of the latest version.","Azure_Security_Benchmark_v3.0_NS-8, +Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (default: latestTLSVersionShouldBeUsedInYourWebAppMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"fb74e86f-d351-4b8d-b034-93da7391c01f","","BuiltIn","App Service","App Service Environment should have internal encryption enabled","Setting InternalEncryption to true encrypts the pagefile, worker disks, and internal network traffic between the front ends and workers in an App Service Environment. To learn more, refer to https://docs.microsoft.com/azure/app-service/environment/app-service-app-service-environment-custom-settings#enable-internal-encryption.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"0e60b895-3786-45da-8377-9c6b4b6ac5f9","","BuiltIn","App Service","Function apps should have remote debugging turned off","Remote debugging requires inbound ports to be opened on Function apps. Remote debugging should be turned off.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (default: functionAppDisableRemoteDebuggingMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0820b7b9-23aa-4725-a1ce-ae4558f718e5","","BuiltIn","App Service","Function apps should not have CORS configured to allow every resource to access your apps","Cross-Origin Resource Sharing (CORS) should not allow all domains to access your Function app. Allow only required domains to interact with your Function app.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (default: functionAppRestrictCORSAccessMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"6d555dd1-86f2-4f1c-8ed7-5abae7c6cbab","","BuiltIn","App Service","Function apps should only be accessible over HTTPS","Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks.","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (default: functionAppEnforceHttpsMonitoringEffectV2), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"399b2637-a50f-4f95-96f8-3a145476eb15","","BuiltIn","App Service","Function apps should require FTPS only","Enable FTPS enforcement for enhanced security.","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (default: fTPSOnlyShouldBeRequiredInYourFunctionAppMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"e2c1c086-2d84-4019-bff3-c44ccd95113c","","BuiltIn","App Service","Function apps should use latest 'HTTP Version'","Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version.","NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-2(6)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0da106f2-4ca3-48e8-bc85-c638fe6aea8f","","BuiltIn","App Service","Function apps should use managed identity","Use a managed identity for enhanced authentication security","Azure_Security_Benchmark_v3.0_IM-3, +NIST_SP_800-53_R5_AC-2, +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-4","ASB: AuditIfNotExists (default: managedIdentityShouldBeUsedInYourFunctionAppMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"f9d614c5-c173-4d56-95a7-b4437057d193","","BuiltIn","App Service","Function apps should use the latest TLS version","Periodically, newer versions are released for TLS either due to security flaws, include additional functionality, and enhance speed. Upgrade to the latest TLS version for Function apps to take advantage of security fixes, if any, and/or new functionalities of the latest version.","Azure_Security_Benchmark_v3.0_NS-8, +Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (default: latestTLSVersionShouldBeUsedInYourFunctionAppMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"3657f5a0-770e-44a3-b44e-9431ba1e9735","","BuiltIn","Automation","Automation account variables should be encrypted","It is important to enable encryption of Automation account variable assets when storing sensitive data","Azure_Security_Benchmark_v3.0_DP-4, +NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","ASB: Audit (default: encryptionOfAutomationAccountMonitoringEffect), +NIST-800-53: Audit (default: effect-3657f5a0-770e-44a3-b44e-9431ba1e9735)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"56a5ee18-2ae6-4810-86f7-18e39ce5629b","","BuiltIn","Automation","Azure Automation accounts should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your Azure Automation Accounts. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/automation-cmk.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-56a5ee18-2ae6-4810-86f7-18e39ce5629b)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"71ef260a-8f18-47b7-abcb-62d0673d94dc","","BuiltIn","Azure Ai Services","Azure AI Services resources should have key access disabled (disable local authentication)","Key access (local authentication) is recommended to be disabled for security. Azure OpenAI Studio, typically used in development/testing, requires key access and will not function if key access is disabled. After disabling, Microsoft Entra ID becomes the only access method, which allows maintaining minimum privilege principle and granular control. Learn more at: https://aka.ms/AI/auth","Azure_Security_Benchmark_v3.0_IM-1, +NIST_SP_800-53_R5_AC-2, +NIST_SP_800-53_R5_AC-2(1), +NIST_SP_800-53_R5_AC-2(7), +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-4","ASB: Audit (Policy Default), +NIST-800-53: Audit (default: effect-71ef260a-8f18-47b7-abcb-62d0673d94dc)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"037eea7a-bd0a-46c5-9a66-03aea78705d3","","BuiltIn","Azure Ai Services","Azure AI Services resources should restrict network access","By restricting network access, you can ensure that only allowed networks can access the service. This can be achieved by configuring network rules so that only applications from allowed networks can access the Azure AI service.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: cognitiveServicesAccountsShouldRestrictNetworkAccessMonitoringEffect), +NIST-800-53: Audit (default: effect-037eea7a-bd0a-46c5-9a66-03aea78705d3)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"81e74cea-30fd-40d5-802f-d72103c2aaaa","","BuiltIn","Azure Data Explorer","Azure Data Explorer encryption at rest should use a customer-managed key","Enabling encryption at rest using a customer-managed key on your Azure Data Explorer cluster provides additional control over the key being used by the encryption at rest. This feature is oftentimes applicable to customers with special compliance requirements and requires a Key Vault to managing the keys.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-81e74cea-30fd-40d5-802f-d72103c2aaaa)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"f4b53539-8df9-40e4-86c6-6b607703bd4e","","BuiltIn","Azure Data Explorer","Disk encryption should be enabled on Azure Data Explorer","Enabling disk encryption helps protect and safeguard your data to meet your organizational security and compliance commitments.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (default: effect-f4b53539-8df9-40e4-86c6-6b607703bd4e)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"ec068d99-e9c7-401f-8cef-5bdde4e6ccf1","","BuiltIn","Azure Data Explorer","Double encryption should be enabled on Azure Data Explorer","Enabling double encryption helps protect and safeguard your data to meet your organizational security and compliance commitments. When double encryption has been enabled, data in the storage account is encrypted twice, once at the service level and once at the infrastructure level, using two different encryption algorithms and two different keys.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (default: effect-ec068d99-e9c7-401f-8cef-5bdde4e6ccf1)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"51c1490f-3319-459c-bbbc-7f391bbed753","","BuiltIn","Azure Databricks","Azure Databricks Clusters should disable public IP","Disabling public IP of clusters in Azure Databricks Workspaces improves security by ensuring that the clusters aren't exposed on the public internet. Learn more at: https://learn.microsoft.com/azure/databricks/security/secure-cluster-connectivity.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"9c25c9e4-ee12-4882-afd2-11fb9d87893f","","BuiltIn","Azure Databricks","Azure Databricks Workspaces should be in a virtual network","Azure Virtual Networks provide enhanced security and isolation for your Azure Databricks Workspaces, as well as subnets, access control policies, and other features to further restrict access. Learn more at: https://docs.microsoft.com/azure/databricks/administration-guide/cloud-configurations/azure/vnet-inject.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"0e7849de-b939-4c50-ab48-fc6b0f5eeba2","","BuiltIn","Azure Databricks","Azure Databricks Workspaces should disable public network access","Disabling public network access improves security by ensuring that the resource isn't exposed on the public internet. You can control exposure of your resources by creating private endpoints instead. Learn more at: https://learn.microsoft.com/azure/databricks/administration-guide/cloud-configurations/azure/private-link. ","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"258823f2-4595-4b52-b333-cc96192710d8","","BuiltIn","Azure Databricks","Azure Databricks Workspaces should use private link","Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Databricks workspaces, you can reduce data leakage risks. Learn more about private links at: https://aka.ms/adbpe.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"138ff14d-b687-4faa-a81c-898c91a87fa2","","BuiltIn","Azure Databricks","Resource logs in Azure Databricks Workspaces should be enabled","Resource logs enable recreating activity trails to use for investigation purposes when a security incident occurs or when your network is compromised.","Azure_Security_Benchmark_v3.0_LT-3","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"b4ac1030-89c5-4697-8e00-28b5ba6a8811","","BuiltIn","Azure Stack Edge","Azure Stack Edge devices should use double-encryption","To secure the data at rest on the device, ensure it's double-encrypted, the access to data is controlled, and once the device is deactivated, the data is securely erased off the data disks. Double encryption is the use of two layers of encryption: BitLocker XTS-AES 256-bit encryption on the data volumes and built-in encryption of the hard drives. Learn more in the security overview documentation for the specific Stack Edge device.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: audit (default: effect-b4ac1030-89c5-4697-8e00-28b5ba6a8811)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"bd876905-5b84-4f73-ab2d-2e7a7c4568d9","","BuiltIn","Azure Update Manager","Machines should be configured to periodically check for missing system updates","To ensure periodic assessments for missing system updates are triggered automatically every 24 hours, the AssessmentMode property should be set to 'AutomaticByPlatform'. Learn more about AssessmentMode property for Windows: https://aka.ms/computevm-windowspatchassessmentmode, for Linux: https://aka.ms/computevm-linuxpatchassessmentmode.","Azure_Security_Benchmark_v3.0_PV-6","ASB: Audit (default: systemUpdatesAutoAssessmentModeEffect)","parameter: + Audit, + Disabled","Audit","Audit","","" +"2e94d99a-8a36-4563-bc77-810d8893b671","","BuiltIn","Backup","[Preview]: Azure Recovery Services vaults should use customer-managed keys for encrypting backup data","Use customer-managed keys to manage the encryption at rest of your backup data. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/AB-CmkEncryption.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-2e94d99a-8a36-4563-bc77-810d8893b671)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""enableDoubleEncryption-2e94d99a-8a36-4563-bc77-810d8893b671"":true}","{""enableDoubleEncryption-2e94d99a-8a36-4563-bc77-810d8893b671"":true}" +"013e242c-8828-4970-87b3-ab247555486d","","BuiltIn","Backup","Azure Backup should be enabled for Virtual Machines","Ensure protection of your Azure Virtual Machines by enabling Azure Backup. Azure Backup is a secure and cost effective data protection solution for Azure.","Azure_Security_Benchmark_v3.0_BR-1, +Azure_Security_Benchmark_v3.0_BR-2, +NIST_SP_800-53_R5_CP-9","ASB: AuditIfNotExists (default: azureBackupShouldBeEnabledForVirtualMachinesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"99e9ccd8-3db9-4592-b0d1-14b1715a4d8a","","BuiltIn","Batch","Azure Batch account should use customer-managed keys to encrypt data","Use customer-managed keys to manage the encryption at rest of your Batch account's data. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/Batch-CMK.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-99e9ccd8-3db9-4592-b0d1-14b1715a4d8a)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"428256e6-1fac-4f48-a757-df34c2b3336d","","BuiltIn","Batch","Resource logs in Batch accounts should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInBatchAccountMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInBatchAccountRetentionDays"":""1""}","{""diagnosticsLogsInBatchAccountRetentionDays"":""1""}" +"51522a96-0869-4791-82f3-981000c2c67f","","BuiltIn","Bot Service","Bot Service should be encrypted with a customer-managed key","Azure Bot Service automatically encrypts your resource to protect your data and meet organizational security and compliance commitments. By default, Microsoft-managed encryption keys are used. For greater flexibility in managing keys or controlling access to your subscription, select customer-managed keys, also known as bring your own key (BYOK). Learn more about Azure Bot Service encryption: https://docs.microsoft.com/azure/bot-service/bot-service-encryption.","NIST_SP_800-53_R5_SC-12","NIST-800-53: audit (default: effect-51522a96-0869-4791-82f3-981000c2c67f)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"7803067c-7d34-46e3-8c79-0ca68fc4036d","","BuiltIn","Cache","Azure Cache for Redis should use private link","Private endpoints lets you connect your virtual network to Azure services without a public IP address at the source or destination. By mapping private endpoints to your Azure Cache for Redis instances, data leakage risks are reduced. Learn more at: https://docs.microsoft.com/azure/azure-cache-for-redis/cache-private-link.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: azureCacheForRedisShouldUsePrivateEndpointMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"22bee202-a82f-4305-9a2a-6d7f44d4dedb","","BuiltIn","Cache","Only secure connections to your Azure Cache for Redis should be enabled","Audit enabling of only connections via SSL to Azure Cache for Redis. Use of secure connections ensures authentication between the server and the service and protects data in transit from network layer attacks such as man-in-the-middle, eavesdropping, and session-hijacking","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (default: diagnosticsLogsInRedisCacheMonitoringEffect), +NIST-800-53: Audit (default: effect-22bee202-a82f-4305-9a2a-6d7f44d4dedb)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"0725b4dd-7e76-479c-a735-68e7ee23d5ca","","BuiltIn","Cognitive Services","Cognitive Services accounts should disable public network access","To improve the security of Cognitive Services accounts, ensure that it isn't exposed to the public internet and can only be accessed from a private endpoint. Disable the public network access property as described in https://go.microsoft.com/fwlink/?linkid=2129800. This option disables access from any public address space outside the Azure IP range, and denies all logins that match IP or virtual network-based firewall rules. This reduces data leakage risks.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: publicNetworkAccessShouldBeDisabledForCognitiveServicesAccountsMonitoringEffect), +NIST-800-53: Audit (default: effect-0725b4dd-7e76-479c-a735-68e7ee23d5ca)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"67121cc7-ff39-4ab8-b7e3-95b84dab487d","","BuiltIn","Cognitive Services","Cognitive Services accounts should enable data encryption with a customer-managed key","Customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data stored in Cognitive Services to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more about customer-managed keys at https://go.microsoft.com/fwlink/?linkid=2121321.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: cognitiveServicesAccountsShouldEnableDataEncryptionWithACustomerManagedKeyMonitoringEffect), +NIST-800-53: Audit (default: effect-67121cc7-ff39-4ab8-b7e3-95b84dab487d)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"cddd188c-4b82-4c48-a19d-ddf74ee66a01","","BuiltIn","Cognitive Services","Cognitive Services should use private link","Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Cognitive Services, you'll reduce the potential for data leakage. Learn more about private links at: https://go.microsoft.com/fwlink/?linkid=2129800.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (Policy Default), +NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"0015ea4d-51ff-4ce3-8d8c-f3f8f0179a56","","BuiltIn","Compute","Audit virtual machines without disaster recovery configured","Audit virtual machines which do not have disaster recovery configured. To learn more about disaster recovery, visit https://aka.ms/asr-doc.","NIST_SP_800-53_R5_CP-7","NIST-800-53: auditIfNotExists (Policy Fixed)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"f39f5f49-4abf-44de-8c70-0756997bfb51","","BuiltIn","Compute","Disk access resources should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to diskAccesses, data leakage risks are reduced. Learn more about private links at: https://aka.ms/disksprivatelinksdoc. ","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"ca91455f-eace-4f96-be59-e6e2c35b4816","","BuiltIn","Compute","Managed disks should be double encrypted with both platform-managed and customer-managed keys","High security sensitive customers who are concerned of the risk associated with any particular encryption algorithm, implementation, or key being compromised can opt for additional layer of encryption using a different encryption algorithm/mode at the infrastructure layer using platform managed encryption keys. The disk encryption sets are required to use double encryption. Learn more at https://aka.ms/disks-doubleEncryption.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-ca91455f-eace-4f96-be59-e6e2c35b4816)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"702dd420-7fcc-42c5-afe8-4026edd20fe0","","BuiltIn","Compute","OS and data disks should be encrypted with a customer-managed key","Use customer-managed keys to manage the encryption at rest of the contents of your managed disks. By default, the data is encrypted at rest with platform-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/disks-cmk.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-702dd420-7fcc-42c5-afe8-4026edd20fe0)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"fc4d8e41-e223-45ea-9bf5-eada37891d87","","BuiltIn","Compute","Virtual machines and virtual machine scale sets should have encryption at host enabled","Use encryption at host to get end-to-end encryption for your virtual machine and virtual machine scale set data. Encryption at host enables encryption at rest for your temporary disk and OS/data disk caches. Temporary and ephemeral OS disks are encrypted with platform-managed keys when encryption at host is enabled. OS/data disk caches are encrypted at rest with either customer-managed or platform-managed key, depending on the encryption type selected on the disk. Learn more at https://aka.ms/vm-hbe.","Azure_Security_Benchmark_v3.0_DP-4, +NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","ASB: Audit (Policy Default), +NIST-800-53: Audit (default: effect-fc4d8e41-e223-45ea-9bf5-eada37891d87)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1d84d5fb-01f6-4d12-ba4f-4a26081d403d","","BuiltIn","Compute","Virtual machines should be migrated to new Azure Resource Manager resources","Use new Azure Resource Manager for your virtual machines to provide security enhancements such as: stronger access control (RBAC), better auditing, Azure Resource Manager based deployment and governance, access to managed identities, access to key vault for secrets, Azure AD-based authentication and support for tags and resource groups for easier security management","Azure_Security_Benchmark_v3.0_AM-2, +NIST_SP_800-53_R5_AC-3","ASB: Audit (default: classicComputeVMsMonitoringEffect), +NIST-800-53: Audit (default: effect-1d84d5fb-01f6-4d12-ba4f-4a26081d403d)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"0aa61e00-0a01-4a3c-9945-e93cffedf0e6","","BuiltIn","Container Instance","Azure Container Instance container group should use customer-managed key for encryption","Secure your containers with greater flexibility using customer-managed keys. When you specify a customer-managed key, that key is used to protect and control access to the key that encrypts your data. Using customer-managed keys provides additional capabilities to control rotation of the key encryption key or cryptographically erase data.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-0aa61e00-0a01-4a3c-9945-e93cffedf0e6)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"5b9159ae-1701-4a6f-9a7a-aa9c8ddd0580","","BuiltIn","Container Registry","Container registries should be encrypted with a customer-managed key","Use customer-managed keys to manage the encryption at rest of the contents of your registries. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/acr/CMK.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: containerRegistriesShouldBeEncryptedWithACustomerManagedKeyMonitoringEffect), +NIST-800-53: Audit (default: effect-5b9159ae-1701-4a6f-9a7a-aa9c8ddd0580)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"d0793b48-0edc-4296-a390-4c75d1bdfd71","","BuiltIn","Container Registry","Container registries should not allow unrestricted network access","Azure container registries by default accept connections over the internet from hosts on any network. To protect your registries from potential threats, allow access from only specific private endpoints, public IP addresses or address ranges. If your registry doesn't have network rules configured, it will appear in the unhealthy resources. Learn more about Container Registry network rules here: https://aka.ms/acr/privatelink, https://aka.ms/acr/portal/public-network and https://aka.ms/acr/vnet.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: containerRegistriesShouldNotAllowUnrestrictedNetworkAccessMonitoringEffect), +NIST-800-53: Audit (default: effect-d0793b48-0edc-4296-a390-4c75d1bdfd71)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"e8eef0a8-67cf-4eb4-9386-14b0e78733d4","","BuiltIn","Container Registry","Container registries should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network.By mapping private endpoints to your container registries instead of the entire service, you'll also be protected against data leakage risks. Learn more at: https://aka.ms/acr/private-link.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: containerRegistriesShouldUsePrivateLinkMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"862e97cf-49fc-4a5c-9de4-40d4e2e7c8eb","","BuiltIn","Cosmos DB","Azure Cosmos DB accounts should have firewall rules","Firewall rules should be defined on your Azure Cosmos DB accounts to prevent traffic from unauthorized sources. Accounts that have at least one IP rule defined with the virtual network filter enabled are deemed compliant. Accounts disabling public access are also deemed compliant.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: azureCosmosDBAccountsShouldHaveFirewallRulesMonitoringEffect), +NIST-800-53: Audit (default: effect-862e97cf-49fc-4a5c-9de4-40d4e2e7c8eb)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1f905d99-2ab7-462c-a6b0-f709acca6c8f","","BuiltIn","Cosmos DB","Azure Cosmos DB accounts should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your Azure Cosmos DB. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/cosmosdb-cmk.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: disabled (default: azureCosmosDbAccountsShouldUseCustomerManagedKeysToEncryptDataAtRestMonitoringEffect), +NIST-800-53: audit (default: effect-1f905d99-2ab7-462c-a6b0-f709acca6c8f)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"797b37f7-06b8-444c-b1ad-fc62867f335a","","BuiltIn","Cosmos DB","Azure Cosmos DB should disable public network access","Disabling public network access improves security by ensuring that your CosmosDB account isn't exposed on the public internet. Creating private endpoints can limit exposure of your CosmosDB account. Learn more at: https://docs.microsoft.com/azure/cosmos-db/how-to-configure-private-endpoints#blocking-public-network-access-during-account-creation.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"5450f5bd-9c72-4390-a9c4-a7aba4edfdd2","","BuiltIn","Cosmos DB","Cosmos DB database accounts should have local authentication methods disabled","Disabling local authentication methods improves security by ensuring that Cosmos DB database accounts exclusively require Azure Active Directory identities for authentication. Learn more at: https://docs.microsoft.com/azure/cosmos-db/how-to-setup-rbac#disable-local-auth.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (default: azureCosmosDbAccountsShouldHaveLocalAuthenticationMethodsDisabledMonitoringEffect)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"58440f8a-10c5-4151-bdce-dfbaad4a20b7","","BuiltIn","Cosmos DB","CosmosDB accounts should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your CosmosDB account, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/cosmos-db/how-to-configure-private-endpoints.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (Policy Default), +NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"c349d81b-9985-44ae-a8da-ff98d108ede8","","BuiltIn","Data Box","Azure Data Box jobs should enable double encryption for data at rest on the device","Enable a second layer of software-based encryption for data at rest on the device. The device is already protected via Advanced Encryption Standard 256-bit encryption for data at rest. This option adds a second layer of data encryption.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (default: effect-c349d81b-9985-44ae-a8da-ff98d108ede8)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""supportedSKUs-c349d81b-9985-44ae-a8da-ff98d108ede8"":[""DataBox"",""DataBoxHeavy""]}","{""supportedSKUs-c349d81b-9985-44ae-a8da-ff98d108ede8"":[""DataBox"",""DataBoxHeavy""]}" +"86efb160-8de7-451d-bc08-5d475b0aadae","","BuiltIn","Data Box","Azure Data Box jobs should use a customer-managed key to encrypt the device unlock password","Use a customer-managed key to control the encryption of the device unlock password for Azure Data Box. Customer-managed keys also help manage access to the device unlock password by the Data Box service in order to prepare the device and copy data in an automated manner. The data on the device itself is already encrypted at rest with Advanced Encryption Standard 256-bit encryption, and the device unlock password is encrypted by default with a Microsoft managed key.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-86efb160-8de7-451d-bc08-5d475b0aadae)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""supportedSKUs-86efb160-8de7-451d-bc08-5d475b0aadae"":[""DataBox"",""DataBoxHeavy""]}","{""supportedSKUs-86efb160-8de7-451d-bc08-5d475b0aadae"":[""DataBox"",""DataBoxHeavy""]}" +"4ec52d6d-beb7-40c4-9a9e-fe753254690e","","BuiltIn","Data Factory","Azure data factories should be encrypted with a customer-managed key","Use customer-managed keys to manage the encryption at rest of your Azure Data Factory. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/adf-cmk.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-4ec52d6d-beb7-40c4-9a9e-fe753254690e)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"8b0323be-cc25-4b61-935d-002c3798c6ea","","BuiltIn","Data Factory","Azure Data Factory should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Data Factory, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/data-factory/data-factory-private-link.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"057ef27e-665e-4328-8ea3-04b3122bd9fb","","BuiltIn","Data Lake","Resource logs in Azure Data Lake Store should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInDataLakeStoreMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInDataLakeStoreRetentionDays"":""1""}","{""diagnosticsLogsInDataLakeStoreRetentionDays"":""1""}" +"c95c74d9-38fe-4f0d-af86-0c7d626a315c","","BuiltIn","Data Lake","Resource logs in Data Lake Analytics should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInDataLakeAnalyticsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInDataLakeAnalyticsRetentionDays"":""1""}","{""diagnosticsLogsInDataLakeAnalyticsRetentionDays"":""1""}" +"9830b652-8523-49cc-b1b3-e17dce1127ca","","BuiltIn","Event Grid","Azure Event Grid domains should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Event Grid domain instead of the entire service, you'll also be protected against data leakage risks. Learn more at: https://aka.ms/privateendpoints.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: azureEventGridDomainsShouldUsePrivateLinkMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"4b90e17e-8448-49db-875e-bd83fb6f804f","","BuiltIn","Event Grid","Azure Event Grid topics should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Event Grid topic instead of the entire service, you'll also be protected against data leakage risks. Learn more at: https://aka.ms/privateendpoints.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: azureEventGridTopicsShouldUsePrivateLinkMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"a1ad735a-e96f-45d2-a7b2-9a4932cab7ec","","BuiltIn","Event Hub","Event Hub namespaces should use a customer-managed key for encryption","Azure Event Hubs supports the option of encrypting data at rest with either Microsoft-managed keys (default) or customer-managed keys. Choosing to encrypt data using customer-managed keys enables you to assign, rotate, disable, and revoke access to the keys that Event Hub will use to encrypt data in your namespace. Note that Event Hub only supports encryption with customer-managed keys for namespaces in dedicated clusters.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"b8564268-eb4a-4337-89be-a19db070c59d","","BuiltIn","Event Hub","Event Hub namespaces should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Event Hub namespaces, data leakage risks are reduced. Learn more at: https://docs.microsoft.com/azure/event-hubs/private-link-service.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"83a214f7-d01a-484b-91a9-ed54470c9a6a","","BuiltIn","Event Hub","Resource logs in Event Hub should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInEventHubMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInEventHubRetentionDays"":""1""}","{""diagnosticsLogsInEventHubRetentionDays"":""1""}" +"a451c1ef-c6ca-483d-87ed-f49761e3ffb5","","BuiltIn","General","Audit usage of custom RBAC roles","Audit built-in roles such as 'Owner, Contributer, Reader' instead of custom RBAC roles, which are error prone. Using custom roles is treated as an exception and requires a rigorous review and threat modeling","Azure_Security_Benchmark_v3.0_PA-7, +NIST_SP_800-53_R5_AC-2, +NIST_SP_800-53_R5_AC-2(7), +NIST_SP_800-53_R5_AC-6, +NIST_SP_800-53_R5_AC-6(7)","ASB: Audit (default: useRbacRulesMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"ca88aadc-6e2b-416c-9de2-5a0f01d1693f","","BuiltIn","Guest Configuration","[Preview]: Linux virtual machines should enable Azure Disk Encryption or EncryptionAtHost.","By default, a virtual machine's OS and data disks are encrypted-at-rest using platform-managed keys; temp disks and data caches aren't encrypted, and data isn't encrypted when flowing between compute and storage resources. Use Azure Disk Encryption or EncryptionAtHost to encrypt all this data.Visit https://aka.ms/diskencryptioncomparison to compare encryption offerings. This policy requires two prerequisites to be deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol.","Azure_Security_Benchmark_v3.0_DP-4","ASB: AuditIfNotExists (default: gcLinuxDiskEncryptionMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"3dc5edcd-002d-444c-b216-e123bbfa37c0","","BuiltIn","Guest Configuration","[Preview]: Windows virtual machines should enable Azure Disk Encryption or EncryptionAtHost.","By default, a virtual machine's OS and data disks are encrypted-at-rest using platform-managed keys; temp disks and data caches aren't encrypted, and data isn't encrypted when flowing between compute and storage resources. Use Azure Disk Encryption or EncryptionAtHost to encrypt all this data.Visit https://aka.ms/diskencryptioncomparison to compare encryption offerings. This policy requires two prerequisites to be deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol.","Azure_Security_Benchmark_v3.0_DP-4","ASB: AuditIfNotExists (default: gcWindowsDiskEncryptionMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"3cf2ab00-13f1-4d0c-8971-2ac904541a7e","","BuiltIn","Guest Configuration","Add system-assigned managed identity to enable Guest Configuration assignments on virtual machines with no identities","This policy adds a system-assigned managed identity to virtual machines hosted in Azure that are supported by Guest Configuration but do not have any managed identities. A system-assigned managed identity is a prerequisite for all Guest Configuration assignments and must be added to machines before using any Guest Configuration policy definitions. For more information on Guest Configuration, visit https://aka.ms/gcpol.","NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_IA-5, +NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: modify (Policy Fixed)","override: + Modify, + Audit, + Disabled","Modify","Modify","","" +"497dff13-db2a-4c0f-8603-28fa3b331ab6","","BuiltIn","Guest Configuration","Add system-assigned managed identity to enable Guest Configuration assignments on VMs with a user-assigned identity","This policy adds a system-assigned managed identity to virtual machines hosted in Azure that are supported by Guest Configuration and have at least one user-assigned identity but do not have a system-assigned managed identity. A system-assigned managed identity is a prerequisite for all Guest Configuration assignments and must be added to machines before using any Guest Configuration policy definitions. For more information on Guest Configuration, visit https://aka.ms/gcpol.","NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_IA-5, +NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: modify (Policy Fixed)","override: + Modify, + Audit, + Disabled","Modify","Modify","","" +"ea53dbee-c6c9-4f0e-9f9e-de0039b78023","","BuiltIn","Guest Configuration","Audit Linux machines that allow remote connections from accounts without passwords","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Linux machines that allow remote connections from accounts without passwords","NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"e6955644-301c-44b5-a4c4-528577de6861","","BuiltIn","Guest Configuration","Audit Linux machines that do not have the passwd file permissions set to 0644","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Linux machines that do not have the passwd file permissions set to 0644","NIST_SP_800-53_R5_IA-5, +NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"f6ec09a3-78bf-4f8f-99dc-6c77182d0f99","","BuiltIn","Guest Configuration","Audit Linux machines that have accounts without passwords","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Linux machines that have accounts without passwords","NIST_SP_800-53_R5_AC-3","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"5b054a0d-39e2-4d53-bea3-9734cad2c69b","","BuiltIn","Guest Configuration","Audit Windows machines that allow re-use of the passwords after the specified number of unique passwords","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that allow re-use of the passwords after the specified number of unique passwords. Default value for unique passwords is 24","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"4ceb8dc2-559c-478b-a15b-733fbf1e3738","","BuiltIn","Guest Configuration","Audit Windows machines that do not have the maximum password age set to specified number of days","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not have the maximum password age set to specified number of days. Default value for maximum password age is 70 days","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"237b38db-ca4d-4259-9e47-7882441ca2c0","","BuiltIn","Guest Configuration","Audit Windows machines that do not have the minimum password age set to specified number of days","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not have the minimum password age set to specified number of days. Default value for minimum password age is 1 day","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"bf16e0bb-31e1-4646-8202-60a235cc7e74","","BuiltIn","Guest Configuration","Audit Windows machines that do not have the password complexity setting enabled","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not have the password complexity setting enabled","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"a2d0e922-65d0-40c4-8f87-ea6da2d307a2","","BuiltIn","Guest Configuration","Audit Windows machines that do not restrict the minimum password length to specified number of characters","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not restrict the minimum password length to specified number of characters. Default value for minimum password length is 14 characters","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"da0f98fe-a24b-4ad5-af69-bd0400233661","","BuiltIn","Guest Configuration","Audit Windows machines that do not store passwords using reversible encryption","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not store passwords using reversible encryption","NIST_SP_800-53_R5_IA-5, +NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"630c64f9-8b6b-4c64-b511-6544ceff6fd6","","BuiltIn","Guest Configuration","Authentication to Linux machines should require SSH keys","Although SSH itself provides an encrypted connection, using passwords with SSH still leaves the VM vulnerable to brute-force attacks. The most secure option for authenticating to an Azure Linux virtual machine over SSH is with a public-private key pair, also known as SSH keys. Learn more: https://docs.microsoft.com/azure/virtual-machines/linux/create-ssh-keys-detailed.","Azure_Security_Benchmark_v3.0_IM-6, +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-5","ASB: AuditIfNotExists (default: authenticationToLinuxMachinesShouldRequireSSHKeysMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"331e8ea8-378a-410f-a2e5-ae22f38bb0da","","BuiltIn","Guest Configuration","Deploy the Linux Guest Configuration extension to enable Guest Configuration assignments on Linux VMs","This policy deploys the Linux Guest Configuration extension to Linux virtual machines hosted in Azure that are supported by Guest Configuration. The Linux Guest Configuration extension is a prerequisite for all Linux Guest Configuration assignments and must be deployed to machines before using any Linux Guest Configuration policy definition. For more information on Guest Configuration, visit https://aka.ms/gcpol.","NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_IA-5, +NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: deployIfNotExists (Policy Fixed)","override: + DeployIfNotExists, + AuditIfNotExists, + Disabled","DeployIfNotExists","DeployIfNotExists","","" +"385f5831-96d4-41db-9a3c-cd3af78aaae6","","BuiltIn","Guest Configuration","Deploy the Windows Guest Configuration extension to enable Guest Configuration assignments on Windows VMs","This policy deploys the Windows Guest Configuration extension to Windows virtual machines hosted in Azure that are supported by Guest Configuration. The Windows Guest Configuration extension is a prerequisite for all Windows Guest Configuration assignments and must be deployed to machines before using any Windows Guest Configuration policy definition. For more information on Guest Configuration, visit https://aka.ms/gcpol.","NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_IA-5, +NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: deployIfNotExists (Policy Fixed)","override: + DeployIfNotExists, + AuditIfNotExists, + Disabled","DeployIfNotExists","DeployIfNotExists","","" +"1e7fed80-8321-4605-b42c-65fc300f23a3","","BuiltIn","Guest Configuration","Linux machines should have Log Analytics agent installed on Azure Arc","Machines are non-compliant if Log Analytics agent is not installed on Azure Arc enabled Linux server.","Azure_Security_Benchmark_v3.0_LT-5","ASB: AuditIfNotExists (default: ArcLinuxMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"fc9b3da7-8347-4380-8e70-0a0361d8dedd","","BuiltIn","Guest Configuration","Linux machines should meet requirements for the Azure compute security baseline","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if the machine is not configured correctly for one of the recommendations in the Azure compute security baseline.","Azure_Security_Benchmark_v3.0_PV-4, +NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (default: linuxGuestConfigBaselinesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"bed48b13-6647-468e-aa2f-1af1d3f4dd40","","BuiltIn","Guest Configuration","Windows Defender Exploit Guard should be enabled on your machines","Windows Defender Exploit Guard uses the Azure Policy Guest Configuration agent. Exploit Guard has four components that are designed to lock down devices against a wide variety of attack vectors and block behaviors commonly used in malware attacks while enabling enterprises to balance their security risk and productivity requirements (Windows only).","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_ES-2, +NIST_SP_800-53_R5_SC-3, +NIST_SP_800-53_R5_SI-3, +NIST_SP_800-53_R5_SI-16","ASB: AuditIfNotExists (default: windowsDefenderExploitGuardMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsIncludeArcMachines"":""true"",""NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40"":""Compliant""}","{""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsIncludeArcMachines"":""true"",""NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40"":""Compliant""}" +"5752e6d6-1206-46d8-8ab1-ecc2f71a8112","","BuiltIn","Guest Configuration","Windows machines should be configured to use secure communication protocols","To protect the privacy of information communicated over the Internet, your machines should use the latest version of the industry-standard cryptographic protocol, Transport Layer Security (TLS). TLS secures communications over a network by encrypting a connection between machines.","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (default: windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""MinimumTLSVersion-5752e6d6-1206-46d8-8ab1-ecc2f71a8112"":""1.2"",""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsMinimumTLSVersion"":""1.2""}","{""MinimumTLSVersion-5752e6d6-1206-46d8-8ab1-ecc2f71a8112"":""1.2"",""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsMinimumTLSVersion"":""1.2""}" +"4078e558-bda6-41fb-9b3c-361e8875200d","","BuiltIn","Guest Configuration","Windows machines should have Log Analytics agent installed on Azure Arc","Machines are non-compliant if Log Analytics agent is not installed on Azure Arc enabled windows server.","Azure_Security_Benchmark_v3.0_LT-5","ASB: AuditIfNotExists (default: ArcWindowsMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"72650e9f-97bc-4b2a-ab5f-9781a9fcecbc","","BuiltIn","Guest Configuration","Windows machines should meet requirements of the Azure compute security baseline","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if the machine is not configured correctly for one of the recommendations in the Azure compute security baseline.","Azure_Security_Benchmark_v3.0_PV-4, +NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (default: windowsGuestConfigBaselinesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""IncludeArcMachines"":""false""}","{""IncludeArcMachines"":""false""}" +"64d314f6-6062-4780-a861-c23e8951bee5","","BuiltIn","HDInsight","Azure HDInsight clusters should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your Azure HDInsight clusters. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/hdi.cmk.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-64d314f6-6062-4780-a861-c23e8951bee5)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1fd32ebd-e4c3-4e13-a54a-d7422d4d95f6","","BuiltIn","HDInsight","Azure HDInsight clusters should use encryption at host to encrypt data at rest","Enabling encryption at host helps protect and safeguard your data to meet your organizational security and compliance commitments. When you enable encryption at host, data stored on the VM host is encrypted at rest and flows encrypted to the Storage service.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-1fd32ebd-e4c3-4e13-a54a-d7422d4d95f6)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"d9da03a1-f3c3-412a-9709-947156872263","","BuiltIn","HDInsight","Azure HDInsight clusters should use encryption in transit to encrypt communication between Azure HDInsight cluster nodes","Data can be tampered with during transmission between Azure HDInsight cluster nodes. Enabling encryption in transit addresses problems of misuse and tampering during this transmission.","NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","NIST-800-53: Audit (default: effect-d9da03a1-f3c3-412a-9709-947156872263)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"47031206-ce96-41f8-861b-6a915f3de284","","BuiltIn","Internet of Things","[Preview]: IoT Hub device provisioning service data should be encrypted using customer-managed keys (CMK)","Use customer-managed keys to manage the encryption at rest of your IoT Hub device provisioning service. The data is automatically encrypted at rest with service-managed keys, but customer-managed keys (CMK) are commonly required to meet regulatory compliance standards. CMKs enable the data to be encrypted with an Azure Key Vault key created and owned by you. Learn more about CMK encryption at https://aka.ms/dps/CMK.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-47031206-ce96-41f8-861b-6a915f3de284)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"df39c015-56a4-45de-b4a3-efe77bed320d","","BuiltIn","Internet of Things","IoT Hub device provisioning service instances should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to the IoT Hub device provisioning service, data leakage risks are reduced. Learn more about private links at: https://aka.ms/iotdpsvnet.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"383856f8-de7f-44a2-81fc-e5135b5c2aa4","","BuiltIn","Internet of Things","Resource logs in IoT Hub should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInIoTHubMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInIoTHubRetentionDays"":""1"",""requiredRetentionDays"":""365""}","{""diagnosticsLogsInIoTHubRetentionDays"":""1"",""requiredRetentionDays"":""365""}" +"55615ac9-af46-4a59-874e-391cc3dfb490","","BuiltIn","Key Vault","Azure Key Vault should have firewall enabled","Enable the key vault firewall so that the key vault is not accessible by default to any public IPs. Optionally, you can configure specific IP ranges to limit access to those networks. Learn more at: https://docs.microsoft.com/azure/key-vault/general/network-security","Azure_Security_Benchmark_v3.0_NS-2, +Azure_Security_Benchmark_v3.0_DP-8, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: firewallShouldBeEnabledOnKeyVaultMonitoringEffect), +NIST-800-53: Audit (default: effect-55615ac9-af46-4a59-874e-391cc3dfb490)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"a6abeaec-4d90-4a02-805f-6b26c4d3fbe9","","BuiltIn","Key Vault","Azure Key Vaults should use private link","Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to key vault, you can reduce data leakage risks. Learn more about private links at: https://aka.ms/akvprivatelink.","Azure_Security_Benchmark_v3.0_NS-2, +Azure_Security_Benchmark_v3.0_DP-8, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: privateEndpointShouldBeConfiguredForKeyVaultMonitoringEffect), +NIST-800-53: Audit (default: effect-a6abeaec-4d90-4a02-805f-6b26c4d3fbe9)","parameter: + Audit, + Disabled","Audit","Audit","","" +"0a075868-4c26-42ef-914c-5bc007359560","","BuiltIn","Key Vault","Certificates should have the specified maximum validity period","Manage your organizational compliance requirements by specifying the maximum amount of time that a certificate can be valid within your key vault.","Azure_Security_Benchmark_v3.0_DP-7, +NIST_SP_800-53_R5_IA-5","ASB: disabled (default: certificatesValidityPeriodMonitoringEffect), +NIST-800-53: audit (default: effect-0a075868-4c26-42ef-914c-5bc007359560)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","{""maximumValidityInMonths-0a075868-4c26-42ef-914c-5bc007359560"":12,""certificatesValidityPeriodInMonths"":12}","{""maximumValidityInMonths-0a075868-4c26-42ef-914c-5bc007359560"":12,""certificatesValidityPeriodInMonths"":12}" +"152b15f7-8e1f-4c1f-ab71-8c010ba5dbc0","","BuiltIn","Key Vault","Key Vault keys should have an expiration date","Cryptographic keys should have a defined expiration date and not be permanent. Keys that are valid forever provide a potential attacker with more time to compromise the key. It is a recommended security practice to set expiration dates on cryptographic keys.","Azure_Security_Benchmark_v3.0_DP-6, +NIST_SP_800-53_R5_IA-5","ASB: Disabled (default: keysExpirationSetEffect), +NIST-800-53: Audit (default: effect-152b15f7-8e1f-4c1f-ab71-8c010ba5dbc0)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"98728c90-32c7-4049-8429-847dc0f4fe37","","BuiltIn","Key Vault","Key Vault secrets should have an expiration date","Secrets should have a defined expiration date and not be permanent. Secrets that are valid forever provide a potential attacker with more time to compromise them. It is a recommended security practice to set expiration dates on secrets.","Azure_Security_Benchmark_v3.0_DP-6, +NIST_SP_800-53_R5_IA-5","ASB: Disabled (default: secretsExpirationSetEffect), +NIST-800-53: Audit (default: effect-98728c90-32c7-4049-8429-847dc0f4fe37)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"0b60c0b2-2dc2-4e1c-b5c9-abbed971de53","","BuiltIn","Key Vault","Key vaults should have deletion protection enabled","Malicious deletion of a key vault can lead to permanent data loss. You can prevent permanent data loss by enabling purge protection and soft delete. Purge protection protects you from insider attacks by enforcing a mandatory retention period for soft deleted key vaults. No one inside your organization or Microsoft will be able to purge your key vaults during the soft delete retention period. Keep in mind that key vaults created after September 1st 2019 have soft-delete enabled by default.","Azure_Security_Benchmark_v3.0_DP-8, +NIST_SP_800-53_R5_CP-9","ASB: Audit (default: keyVaultsShouldHavePurgeProtectionEnabledMonitoringEffect), +NIST-800-53: Audit (default: effect-0b60c0b2-2dc2-4e1c-b5c9-abbed971de53)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1e66c121-a66a-4b1f-9b83-0fd99bf0fc2d","","BuiltIn","Key Vault","Key vaults should have soft delete enabled","Deleting a key vault without soft delete enabled permanently deletes all secrets, keys, and certificates stored in the key vault. Accidental deletion of a key vault can lead to permanent data loss. Soft delete allows you to recover an accidentally deleted key vault for a configurable retention period.","Azure_Security_Benchmark_v3.0_DP-8, +NIST_SP_800-53_R5_CP-9","ASB: Audit (default: keyVaultsShouldHaveSoftDeleteEnabledMonitoringEffect), +NIST-800-53: Audit (default: effect-1e66c121-a66a-4b1f-9b83-0fd99bf0fc2d)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"cf820ca0-f99e-4f3e-84fb-66e913812d21","","BuiltIn","Key Vault","Resource logs in Key Vault should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_DP-8, +Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInKeyVaultMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInKeyVaultRetentionDays"":""1""}","{""diagnosticsLogsInKeyVaultRetentionDays"":""1""}" +"8dfab9c4-fe7b-49ad-85e4-1e9be085358f","","BuiltIn","Kubernetes","[Preview]: Azure Arc enabled Kubernetes clusters should have Microsoft Defender for Cloud extension installed","Microsoft Defender for Cloud extension for Azure Arc provides threat protection for your Arc enabled Kubernetes clusters. The extension collects data from all nodes in the cluster and sends it to the Azure Defender for Kubernetes backend in the cloud for further analysis. Learn more in https://docs.microsoft.com/azure/defender-for-cloud/defender-for-containers-enable?pivots=defender-for-container-arc.","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: arcEnabledKubernetesClustersShouldHaveAzureDefendersExtensionInstalled), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"6b2122c1-8120-4ff5-801b-17625a355590","","BuiltIn","Kubernetes","Azure Arc enabled Kubernetes clusters should have the Azure Policy extension installed","The Azure Policy extension for Azure Arc provides at-scale enforcements and safeguards on your Arc enabled Kubernetes clusters in a centralized, consistent manner. Learn more at https://aka.ms/akspolicydoc.","Azure_Security_Benchmark_v3.0_PV-2","ASB: AuditIfNotExists (default: arcEnabledKubernetesClustersShouldHaveAzurePolicyExtensionInstalledEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"a1840de2-8088-4ea8-b153-b4c723e9cb01","","BuiltIn","Kubernetes","Azure Kubernetes Service clusters should have Defender profile enabled","Microsoft Defender for Containers provides cloud-native Kubernetes security capabilities including environment hardening, workload protection, and run-time protection. When you enable the SecurityProfile.AzureDefender on your Azure Kubernetes Service cluster, an agent is deployed to your cluster to collect security event data. Learn more about Microsoft Defender for Containers in https://docs.microsoft.com/azure/defender-for-cloud/defender-for-containers-introduction?tabs=defender-for-container-arch-aks","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2","ASB: Audit (default: azureKubernetesServiceClustersShouldHaveSecurityProfileEnabled)","parameter: + Audit, + Disabled","Audit","Audit","","" +"0a15ec92-a229-4763-bb14-0ea34a568f8d","","BuiltIn","Kubernetes","Azure Policy Add-on for Kubernetes service (AKS) should be installed and enabled on your clusters","Azure Policy Add-on for Kubernetes service (AKS) extends Gatekeeper v3, an admission controller webhook for Open Policy Agent (OPA), to apply at-scale enforcements and safeguards on your clusters in a centralized, consistent manner.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: azurePolicyAddonStatusEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"7d7be79c-23ba-4033-84dd-45e2a5ccdd67","","BuiltIn","Kubernetes","Both operating systems and data disks in Azure Kubernetes Service clusters should be encrypted by customer-managed keys","Encrypting OS and data disks using customer-managed keys provides more control and greater flexibility in key management. This is a common requirement in many regulatory and industry compliance standards.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-7d7be79c-23ba-4033-84dd-45e2a5ccdd67)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"e345eecc-fa47-480f-9e88-67dcc122b164","","BuiltIn","Kubernetes","Kubernetes cluster containers CPU and memory resource limits should not exceed the specified limits","Enforce container CPU and memory resource limits to prevent resource exhaustion attacks in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: memoryAndCPULimitsInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-e345eecc-fa47-480f-9e88-67dcc122b164)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""memoryLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0"",""cpuLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0"",""memoryInKubernetesClusterLimit"":""64Gi"",""memoryAndCPULimitsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""memoryAndCPULimitsInKubernetesClusterLabelSelector"":{},""CPUInKubernetesClusterLimit"":""32""}","{""memoryLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0"",""cpuLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0"",""memoryInKubernetesClusterLimit"":""64Gi"",""memoryAndCPULimitsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""memoryAndCPULimitsInKubernetesClusterLabelSelector"":{},""CPUInKubernetesClusterLimit"":""32""}" +"47a1ee2f-2a2a-4576-bf2a-e0e36709c2b8","","BuiltIn","Kubernetes","Kubernetes cluster containers should not share host process ID or host IPC namespace","Block pod containers from sharing the host process ID namespace and host IPC namespace in a Kubernetes cluster. This recommendation is part of CIS 5.2.2 and CIS 5.2.3 which are intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: NoSharingSensitiveHostNamespacesInKubernetesEffect), +NIST-800-53: audit (default: effect-47a1ee2f-2a2a-4576-bf2a-e0e36709c2b8)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""NoSharingSensitiveHostNamespacesInKubernetesLabelSelector"":{},""NoSharingSensitiveHostNamespacesInKubernetesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""NoSharingSensitiveHostNamespacesInKubernetesLabelSelector"":{},""NoSharingSensitiveHostNamespacesInKubernetesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}" +"511f5417-5d12-434d-ab2e-816901e72a5e","","BuiltIn","Kubernetes","Kubernetes cluster containers should only use allowed AppArmor profiles","Containers should only use allowed AppArmor profiles in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: AllowedAppArmorProfilesInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-511f5417-5d12-434d-ab2e-816901e72a5e)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""AllowedAppArmorProfilesInKubernetesClusterList"":[""runtime/default""],""AllowedAppArmorProfilesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedProfiles-511f5417-5d12-434d-ab2e-816901e72a5e"":[],""AllowedAppArmorProfilesInKubernetesClusterLabelSelector"":{}}","{""AllowedAppArmorProfilesInKubernetesClusterList"":[""runtime/default""],""AllowedAppArmorProfilesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedProfiles-511f5417-5d12-434d-ab2e-816901e72a5e"":[],""AllowedAppArmorProfilesInKubernetesClusterLabelSelector"":{}}" +"c26596ff-4d70-4e6a-9a30-c2506bd2f80c","","BuiltIn","Kubernetes","Kubernetes cluster containers should only use allowed capabilities","Restrict the capabilities to reduce the attack surface of containers in a Kubernetes cluster. This recommendation is part of CIS 5.2.8 and CIS 5.2.9 which are intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: AllowedCapabilitiesInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-c26596ff-4d70-4e6a-9a30-c2506bd2f80c)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""requiredDropCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""AllowedCapabilitiesInKubernetesClusterList"":[],""AllowedCapabilitiesInKubernetesClusterLabelSelector"":{},""allowedCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""DropCapabilitiesInKubernetesClusterList"":[],""AllowedCapabilitiesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""requiredDropCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""AllowedCapabilitiesInKubernetesClusterList"":[],""AllowedCapabilitiesInKubernetesClusterLabelSelector"":{},""allowedCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""DropCapabilitiesInKubernetesClusterList"":[],""AllowedCapabilitiesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}" +"febd0533-8e55-448f-b837-bd0e06f16469","","BuiltIn","Kubernetes","Kubernetes cluster containers should only use allowed images","Use images from trusted registries to reduce the Kubernetes cluster's exposure risk to unknown vulnerabilities, security issues and malicious images. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: allowedContainerImagesInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-febd0533-8e55-448f-b837-bd0e06f16469)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""allowedContainerImagesRegex-febd0533-8e55-448f-b837-bd0e06f16469"":""^(.+){0}$"",""namespaces"":[],""allowedContainerImagesLabelSelector"":{},""allowedContainerImagesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""labelSelector"":{},""excludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc""],""allowedContainerImagesInKubernetesClusterRegex"":""^(.+){0}$""}","{""allowedContainerImagesRegex-febd0533-8e55-448f-b837-bd0e06f16469"":""^(.+){0}$"",""namespaces"":[],""allowedContainerImagesLabelSelector"":{},""allowedContainerImagesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""labelSelector"":{},""excludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc""],""allowedContainerImagesInKubernetesClusterRegex"":""^(.+){0}$""}" +"df49d893-a74c-421d-bc95-c663042e5b80","","BuiltIn","Kubernetes","Kubernetes cluster containers should run with a read only root file system","Run containers with a read only root file system to protect from changes at run-time with malicious binaries being added to PATH in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: ReadOnlyRootFileSystemInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-df49d893-a74c-421d-bc95-c663042e5b80)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""ReadOnlyRootFileSystemInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""ReadOnlyRootFileSystemInKubernetesClusterLabelSelector"":{}}","{""ReadOnlyRootFileSystemInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""ReadOnlyRootFileSystemInKubernetesClusterLabelSelector"":{}}" +"098fc59e-46c7-4d99-9b16-64990e543d75","","BuiltIn","Kubernetes","Kubernetes cluster pod hostPath volumes should only use allowed host paths","Limit pod HostPath volume mounts to the allowed host paths in a Kubernetes Cluster. This policy is generally available for Kubernetes Service (AKS), and Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: AllowedHostPathVolumesInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-098fc59e-46c7-4d99-9b16-64990e543d75)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""AllowedHostPathVolumesInKubernetesClusterLabelSelector"":{},""allowedHostPaths-098fc59e-46c7-4d99-9b16-64990e543d75"":{""paths"":[]},""AllowedHostPathVolumesInKubernetesClusterList"":{""paths"":[]},""AllowedHostPathVolumesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""AllowedHostPathVolumesInKubernetesClusterLabelSelector"":{},""allowedHostPaths-098fc59e-46c7-4d99-9b16-64990e543d75"":{""paths"":[]},""AllowedHostPathVolumesInKubernetesClusterList"":{""paths"":[]},""AllowedHostPathVolumesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}" +"f06ddb64-5fa3-4b77-b166-acb36f7f6042","","BuiltIn","Kubernetes","Kubernetes cluster pods and containers should only run with approved user and group IDs","Control the user, primary group, supplemental group and file system group IDs that pods and containers can use to run in a Kubernetes Cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: MustRunAsNonRootNamespaceEffect), +NIST-800-53: audit (default: effect-f06ddb64-5fa3-4b77-b166-acb36f7f6042)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""fsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""MustRunAsNonRootNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""runAsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""runAsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""MustRunAsNonRootLabelSelector"":{},""runAsUserRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""runAsUserRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""MustRunAsNonRoot"",""supplementalGroupsRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""fsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""supplementalGroupsRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]}}","{""fsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""MustRunAsNonRootNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""runAsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""runAsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""MustRunAsNonRootLabelSelector"":{},""runAsUserRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""runAsUserRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""MustRunAsNonRoot"",""supplementalGroupsRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""fsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""supplementalGroupsRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]}}" +"82985f06-dc18-4a48-bc1c-b9f4f0098cfe","","BuiltIn","Kubernetes","Kubernetes cluster pods should only use approved host network and port range","Restrict pod access to the host network and the allowable host port range in a Kubernetes cluster. This recommendation is part of CIS 5.2.4 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: AllowedHostNetworkingAndPortsInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-82985f06-dc18-4a48-bc1c-b9f4f0098cfe)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""AllowHostNetworkingInKubernetesCluster"":false,""maxPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""minPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""allowHostNetwork-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":false,""AllowedHostNetworkingAndPortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""AllowedHostMaxPortInKubernetesCluster"":0,""AllowedHostNetworkingAndPortsInKubernetesClusterLabelSelector"":{},""AllowedHostMinPortInKubernetesCluster"":0}","{""AllowHostNetworkingInKubernetesCluster"":false,""maxPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""minPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""allowHostNetwork-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":false,""AllowedHostNetworkingAndPortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""AllowedHostMaxPortInKubernetesCluster"":0,""AllowedHostNetworkingAndPortsInKubernetesClusterLabelSelector"":{},""AllowedHostMinPortInKubernetesCluster"":0}" +"233a2a17-77ca-4fb1-9b6b-69223d272a44","","BuiltIn","Kubernetes","Kubernetes cluster services should listen only on allowed ports","Restrict services to listen only on allowed ports to secure access to the Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: allowedServicePortsInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-233a2a17-77ca-4fb1-9b6b-69223d272a44)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""allowedServicePortsInKubernetesClusterLabelSelector"":{},""allowedServicePortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""allowedservicePortsInKubernetesClusterPorts"":[""-1""],""allowedServicePortsList-233a2a17-77ca-4fb1-9b6b-69223d272a44"":[]}","{""allowedServicePortsInKubernetesClusterLabelSelector"":{},""allowedServicePortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""allowedservicePortsInKubernetesClusterPorts"":[""-1""],""allowedServicePortsList-233a2a17-77ca-4fb1-9b6b-69223d272a44"":[]}" +"95edb821-ddaf-4404-9732-666045e056b4","","BuiltIn","Kubernetes","Kubernetes cluster should not allow privileged containers","Do not allow privileged containers creation in a Kubernetes cluster. This recommendation is part of CIS 5.2.1 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: privilegedContainersShouldBeAvoidedEffect), +NIST-800-53: audit (default: effect-95edb821-ddaf-4404-9732-666045e056b4)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""excludedImagesInKubernetesCluster"":[],""privilegedContainerNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""excludedContainers-95edb821-ddaf-4404-9732-666045e056b4"":[],""privilegedContainerLabelSelector"":{}}","{""excludedImagesInKubernetesCluster"":[],""privilegedContainerNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""excludedContainers-95edb821-ddaf-4404-9732-666045e056b4"":[],""privilegedContainerLabelSelector"":{}}" +"1a5b4dca-0b6f-4cf5-907c-56316bc1bf3d","","BuiltIn","Kubernetes","Kubernetes clusters should be accessible only over HTTPS","Use of HTTPS ensures authentication and protects data in transit from network layer eavesdropping attacks. This capability is currently generally available for Kubernetes Service (AKS), and in preview for Azure Arc enabled Kubernetes. For more info, visit https://aka.ms/kubepolicydoc","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (default: kubernetesClustersShouldBeAccessibleOnlyOverHTTPSMonitoringEffect), +NIST-800-53: audit (default: effect-1a5b4dca-0b6f-4cf5-907c-56316bc1bf3d)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""kubernetesClustersShouldBeAccessibleOnlyOverHTTPSExcludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""kubernetesClustersShouldBeAccessibleOnlyOverHTTPSLabelSelector"":{}}","{""kubernetesClustersShouldBeAccessibleOnlyOverHTTPSExcludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""kubernetesClustersShouldBeAccessibleOnlyOverHTTPSLabelSelector"":{}}" +"423dd1ba-798e-40e4-9c4d-b6902674b423","","BuiltIn","Kubernetes","Kubernetes clusters should disable automounting API credentials","Disable automounting API credentials to prevent a potentially compromised Pod resource to run API commands against Kubernetes clusters. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (default: KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringEffect)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringLabelSelector"":{}}","{""KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringLabelSelector"":{}}" +"1c6e92c9-99f0-4e55-9cf2-0c234dc48f99","","BuiltIn","Kubernetes","Kubernetes clusters should not allow container privilege escalation","Do not allow containers to run with privilege escalation to root in a Kubernetes cluster. This recommendation is part of CIS 5.2.5 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: NoPrivilegeEscalationInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-1c6e92c9-99f0-4e55-9cf2-0c234dc48f99)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""NoPrivilegeEscalationInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""NoPrivilegeEscalationInKubernetesClusterLabelSelector"":{}}","{""NoPrivilegeEscalationInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""NoPrivilegeEscalationInKubernetesClusterLabelSelector"":{}}" +"d2e7ea85-6b44-4317-a0be-1b951587f626","","BuiltIn","Kubernetes","Kubernetes clusters should not grant CAP_SYS_ADMIN security capabilities","To reduce the attack surface of your containers, restrict CAP_SYS_ADMIN Linux capabilities. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (default: KubernetesClustersShouldNotGrantCAPSYSADMINSecurityCapabilitiesMonitoringEffect)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""KubernetesClustersShouldNotGrantCAPSYSADMINSecurityCapabilitiesMonitoringLabelSelector"":{},""KubernetesClustersShouldNotGrantCAPSYSADMINSecurityCapabilitiesMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""KubernetesClustersShouldNotGrantCAPSYSADMINSecurityCapabilitiesMonitoringLabelSelector"":{},""KubernetesClustersShouldNotGrantCAPSYSADMINSecurityCapabilitiesMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}" +"9f061a12-e40d-4183-a00e-171812443373","","BuiltIn","Kubernetes","Kubernetes clusters should not use the default namespace","Prevent usage of the default namespace in Kubernetes clusters to protect against unauthorized access for ConfigMap, Pod, Secret, Service, and ServiceAccount resource types. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (default: KubernetesClustersShouldNotUseTheDefaultNamespaceMonitoringEffect)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""KubernetesClustersShouldNotUseTheDefaultNamespaceMonitoringLabelSelector"":{}}","{""KubernetesClustersShouldNotUseTheDefaultNamespaceMonitoringLabelSelector"":{}}" +"245fc9df-fa96-4414-9a0b-3738c2f7341c","","BuiltIn","Kubernetes","Resource logs in Azure Kubernetes Service should be enabled","Azure Kubernetes Service's resource logs can help recreate activity trails when investigating security incidents. Enable it to make sure the logs will exist when needed","Azure_Security_Benchmark_v3.0_LT-3","ASB: AuditIfNotExists (default: diagnosticsLogsInKubernetesMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInKubernetesRetentionDays"":""1""}","{""diagnosticsLogsInKubernetesRetentionDays"":""1""}" +"41425d9f-d1a5-499a-9932-f8ed8453932c","","BuiltIn","Kubernetes","Temp disks and cache for agent node pools in Azure Kubernetes Service clusters should be encrypted at host","To enhance data security, the data stored on the virtual machine (VM) host of your Azure Kubernetes Service nodes VMs should be encrypted at rest. This is a common requirement in many regulatory and industry compliance standards.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (default: effect-41425d9f-d1a5-499a-9932-f8ed8453932c)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1fafeaf6-7927-4059-a50a-8eb2a7a6f2b5","","BuiltIn","Logic Apps","Logic Apps Integration Service Environment should be encrypted with customer-managed keys","Deploy into Integration Service Environment to manage encryption at rest of Logic Apps data using customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-1fafeaf6-7927-4059-a50a-8eb2a7a6f2b5)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"34f95f76-5386-4de7-b824-0d8478470c9d","","BuiltIn","Logic Apps","Resource logs in Logic Apps should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInLogicAppsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInLogicAppsRetentionDays"":""1""}","{""diagnosticsLogsInLogicAppsRetentionDays"":""1""}" +"f110a506-2dcb-422e-bcea-d533fc8c35e2","","BuiltIn","Machine Learning","Azure Machine Learning compute instances should be recreated to get the latest software updates","Ensure Azure Machine Learning compute instances run on the latest available operating system. Security is improved and vulnerabilities reduced by running with the latest security patches. For more information, visit https://aka.ms/azureml-ci-updates/.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"7804b5c7-01dc-4723-969b-ae300cc07ff1","","BuiltIn","Machine Learning","Azure Machine Learning Computes should be in a virtual network","Azure Virtual Networks provide enhanced security and isolation for your Azure Machine Learning Compute Clusters and Instances, as well as subnets, access control policies, and other features to further restrict access. When a compute is configured with a virtual network, it is not publicly addressable and can only be accessed from virtual machines and applications within the virtual network.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"e96a9a5f-07ca-471b-9bc5-6a0f33cbd68f","","BuiltIn","Machine Learning","Azure Machine Learning Computes should have local authentication methods disabled","Disabling local authentication methods improves security by ensuring that Machine Learning Computes require Azure Active Directory identities exclusively for authentication. Learn more at: https://aka.ms/azure-ml-aad-policy.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"ba769a63-b8cc-4b2d-abf6-ac33c7204be8","","BuiltIn","Machine Learning","Azure Machine Learning workspaces should be encrypted with a customer-managed key","Manage encryption at rest of Azure Machine Learning workspace data with customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/azureml-workspaces-cmk.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: azureMachineLearningWorkspacesShouldBeEncryptedWithACustomerManagedKeyMonitoringEffect), +NIST-800-53: Audit (default: effect-ba769a63-b8cc-4b2d-abf6-ac33c7204be8)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"438c38d2-3772-465a-a9cc-7a6666a275ce","","BuiltIn","Machine Learning","Azure Machine Learning Workspaces should disable public network access","Disabling public network access improves security by ensuring that the Machine Learning Workspaces aren't exposed on the public internet. You can control exposure of your workspaces by creating private endpoints instead. Learn more at: https://learn.microsoft.com/azure/machine-learning/how-to-configure-private-link?view=azureml-api-2&tabs=azure-portal.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"45e05259-1eb5-4f70-9574-baf73e9d219b","","BuiltIn","Machine Learning","Azure Machine Learning workspaces should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Machine Learning workspaces, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/machine-learning/how-to-configure-private-link.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: azureMachineLearningWorkspacesShouldUsePrivateLinkMonitoringEffect), +NIST-800-53: Audit (default: effect-45e05259-1eb5-4f70-9574-baf73e9d219b)","parameter: + Audit, + Disabled","Audit","Audit","","" +"afe0c3be-ba3b-4544-ba52-0c99672a8ad6","","BuiltIn","Machine Learning","Resource logs in Azure Machine Learning Workspaces should be enabled","Resource logs enable recreating activity trails to use for investigation purposes when a security incident occurs or when your network is compromised.","Azure_Security_Benchmark_v3.0_LT-3","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"842c54e8-c2f9-4d79-ae8d-38d8b8019373","","BuiltIn","Monitoring","[Preview]: Log Analytics extension should be installed on your Linux Azure Arc machines","This policy audits Linux Azure Arc machines if the Log Analytics extension is not installed.","Azure_Security_Benchmark_v3.0_LT-5, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: ArcLinuxMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"d69b1763-b96d-40b8-a2d9-ca31e9fd0d3e","","BuiltIn","Monitoring","[Preview]: Log Analytics extension should be installed on your Windows Azure Arc machines","This policy audits Windows Azure Arc machines if the Log Analytics extension is not installed.","Azure_Security_Benchmark_v3.0_LT-5, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: ArcWindowsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"04c4380f-3fae-46e8-96c9-30193528f602","","BuiltIn","Monitoring","[Preview]: Network traffic data collection agent should be installed on Linux virtual machines","Security Center uses the Microsoft Dependency agent to collect network traffic data from your Azure virtual machines to enable advanced network protection features such as traffic visualization on the network map, network hardening recommendations and specific network threats.","Azure_Security_Benchmark_v3.0_LT-4, +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: ASCDependencyAgentAuditLinuxEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"2f2ee1de-44aa-4762-b6bd-0893fc3f306d","","BuiltIn","Monitoring","[Preview]: Network traffic data collection agent should be installed on Windows virtual machines","Security Center uses the Microsoft Dependency agent to collect network traffic data from your Azure virtual machines to enable advanced network protection features such as traffic visualization on the network map, network hardening recommendations and specific network threats.","Azure_Security_Benchmark_v3.0_LT-4, +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: ASCDependencyAgentAuditWindowsEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"ea0dfaed-95fb-448c-934e-d6e713ce393d","","BuiltIn","Monitoring","Azure Monitor Logs clusters should be created with infrastructure-encryption enabled (double encryption)","To ensure secure data encryption is enabled at the service level and the infrastructure level with two different encryption algorithms and two different keys, use an Azure Monitor dedicated cluster. This option is enabled by default when supported at the region, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys#customer-managed-key-overview.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: audit (default: effect-ea0dfaed-95fb-448c-934e-d6e713ce393d)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1f68a601-6e6d-4e42-babf-3f643a047ea2","","BuiltIn","Monitoring","Azure Monitor Logs clusters should be encrypted with customer-managed key","Create Azure Monitor logs cluster with customer-managed keys encryption. By default, the log data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance. Customer-managed key in Azure Monitor gives you more control over the access to you data, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys.","NIST_SP_800-53_R5_SC-12","NIST-800-53: audit (default: effect-1f68a601-6e6d-4e42-babf-3f643a047ea2)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"fa298e57-9444-42ba-bf04-86e8470e32c7","","BuiltIn","Monitoring","Saved-queries in Azure Monitor should be saved in customer storage account for logs encryption","Link storage account to Log Analytics workspace to protect saved-queries with storage account encryption. Customer-managed keys are commonly required to meet regulatory compliance and for more control over the access to your saved-queries in Azure Monitor. For more details on the above, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys?tabs=portal#customer-managed-key-for-saved-queries.","NIST_SP_800-53_R5_SC-12","NIST-800-53: audit (default: effect-fa298e57-9444-42ba-bf04-86e8470e32c7)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"fc5e4038-4584-4632-8c85-c0448d374b2c","","BuiltIn","Network","[Preview]: All Internet traffic should be routed via your deployed Azure Firewall","Azure Security Center has identified that some of your subnets aren't protected with a next generation firewall. Protect your subnets from potential threats by restricting access to them with Azure Firewall or a supported next generation firewall","Azure_Security_Benchmark_v3.0_NS-3, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: AzureFirewallEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"055aa869-bc98-4af8-bafc-23f1ab6ffe2c","","BuiltIn","Network","Azure Web Application Firewall should be enabled for Azure Front Door entry-points","Deploy Azure Web Application Firewall (WAF) in front of public facing web applications for additional inspection of incoming traffic. Web Application Firewall (WAF) provides centralized protection of your web applications from common exploits and vulnerabilities such as SQL injections, Cross-Site Scripting, local and remote file executions. You can also restrict access to your web applications by countries, IP address ranges, and other http(s) parameters via custom rules.","Azure_Security_Benchmark_v3.0_NS-6, +NIST_SP_800-53_R5_SC-5, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: webApplicationFirewallShouldBeEnabledForAzureFrontDoorServiceServiceMonitoringEffect), +NIST-800-53: Audit (default: effect-055aa869-bc98-4af8-bafc-23f1ab6ffe2c)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"b6e2945c-0b7b-40f5-9233-7a5323b5cdc6","","BuiltIn","Network","Network Watcher should be enabled","Network Watcher is a regional service that enables you to monitor and diagnose conditions at a network scenario level in, to, and from Azure. Scenario level monitoring enables you to diagnose problems at an end to end network level view. It is required to have a network watcher resource group to be created in every region where a virtual network is present. An alert is enabled if a network watcher resource group is not available in a particular region.","Azure_Security_Benchmark_v3.0_IR-4, +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: networkWatcherShouldBeEnabledMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""networkWatcherShouldBeEnabledResourceGroupName"":""NetworkWatcherRG"",""resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6"":""NetworkWatcherRG""}","{""networkWatcherShouldBeEnabledResourceGroupName"":""NetworkWatcherRG"",""resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6"":""NetworkWatcherRG""}" +"21a6bc25-125e-4d13-b82d-2e19b7208ab7","","BuiltIn","Network","VPN gateways should use only Azure Active Directory (Azure AD) authentication for point-to-site users","Disabling local authentication methods improves security by ensuring that VPN Gateways use only Azure Active Directory identities for authentication. Learn more about Azure AD authentication at https://docs.microsoft.com/azure/vpn-gateway/openvpn-azure-ad-tenant","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"564feb30-bf6a-4854-b4bb-0d2d2d1e6c66","","BuiltIn","Network","Web Application Firewall (WAF) should be enabled for Application Gateway","Deploy Azure Web Application Firewall (WAF) in front of public facing web applications for additional inspection of incoming traffic. Web Application Firewall (WAF) provides centralized protection of your web applications from common exploits and vulnerabilities such as SQL injections, Cross-Site Scripting, local and remote file executions. You can also restrict access to your web applications by countries, IP address ranges, and other http(s) parameters via custom rules.","Azure_Security_Benchmark_v3.0_NS-6, +NIST_SP_800-53_R5_SC-5, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: webApplicationFirewallShouldBeEnabledForApplicationGatewayMonitoringEffect), +NIST-800-53: Audit (default: effect-564feb30-bf6a-4854-b4bb-0d2d2d1e6c66)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"a049bf77-880b-470f-ba6d-9f21c530cf83","","BuiltIn","Search","Azure Cognitive Search service should use a SKU that supports private link","With supported SKUs of Azure Cognitive Search, Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Search service, data leakage risks are reduced. Learn more at: https://aka.ms/azure-cognitive-search/inbound-private-endpoints.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (default: effect-a049bf77-880b-470f-ba6d-9f21c530cf83)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"ee980b6d-0eca-4501-8d54-f6290fd512c3","","BuiltIn","Search","Azure Cognitive Search services should disable public network access","Disabling public network access improves security by ensuring that your Azure Cognitive Search service is not exposed on the public internet. Creating private endpoints can limit exposure of your Search service. Learn more at: https://aka.ms/azure-cognitive-search/inbound-private-endpoints.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (default: effect-ee980b6d-0eca-4501-8d54-f6290fd512c3)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"0fda3595-9f2b-4592-8675-4231d6fa82fe","","BuiltIn","Search","Azure Cognitive Search services should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Cognitive Search, data leakage risks are reduced. Learn more about private links at: https://aka.ms/azure-cognitive-search/inbound-private-endpoints.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"b4330a05-a843-4bc8-bf9a-cacce50c67f4","","BuiltIn","Search","Resource logs in Search services should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInSearchServiceMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInSearchServiceRetentionDays"":""1""}","{""diagnosticsLogsInSearchServiceRetentionDays"":""1""}" +"672fe5a1-2fcd-42d7-b85d-902b6e28c6ff","","BuiltIn","Security Center","[Preview]: Guest Attestation extension should be installed on supported Linux virtual machines","Install Guest Attestation extension on supported Linux virtual machines to allow Azure Security Center to proactively attest and monitor the boot integrity. Once installed, boot integrity will be attested via Remote Attestation. This assessment applies to Trusted Launch and Confidential Linux virtual machines.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (default: GuestAttestationExtensionShouldBeInstalledOnSupportedLinuxVirtualMachinesMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"a21f8c92-9e22-4f09-b759-50500d1d2dda","","BuiltIn","Security Center","[Preview]: Guest Attestation extension should be installed on supported Linux virtual machines scale sets","Install Guest Attestation extension on supported Linux virtual machines scale sets to allow Azure Security Center to proactively attest and monitor the boot integrity. Once installed, boot integrity will be attested via Remote Attestation. This assessment applies to Trusted Launch and Confidential Linux virtual machine scale sets.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (default: GuestAttestationExtensionShouldBeInstalledOnSupportedLinuxVirtualMachinesScaleSetsMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1cb4d9c2-f88f-4069-bee0-dba239a57b09","","BuiltIn","Security Center","[Preview]: Guest Attestation extension should be installed on supported Windows virtual machines","Install Guest Attestation extension on supported virtual machines to allow Azure Security Center to proactively attest and monitor the boot integrity. Once installed, boot integrity will be attested via Remote Attestation. This assessment applies to Trusted Launch and Confidential Windows virtual machines.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (default: GuestAttestationExtensionShouldBeInstalledOnSupportedWindowsVirtualMachinesMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"f655e522-adff-494d-95c2-52d4f6d56a42","","BuiltIn","Security Center","[Preview]: Guest Attestation extension should be installed on supported Windows virtual machines scale sets","Install Guest Attestation extension on supported virtual machines scale sets to allow Azure Security Center to proactively attest and monitor the boot integrity. Once installed, boot integrity will be attested via Remote Attestation. This assessment applies to Trusted Launch and Confidential Windows virtual machine scale sets.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (default: GuestAttestationExtensionShouldBeInstalledOnSupportedWindowsVirtualMachinesScaleSetsMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"13a6c84f-49a5-410a-b5df-5b880c3fe009","","BuiltIn","Security Center","[Preview]: Linux virtual machines should use only signed and trusted boot components","All OS boot components (boot loader, kernel, kernel drivers) must be signed by trusted publishers. Defender for Cloud has identified untrusted OS boot components on one or more of your Linux machines. To protect your machines from potentially malicious components, add them to your allow list or remove the identified components.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (default: LinuxVirtualMachineShouldUseSignedAndTrustedBootComponentEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"97566dd7-78ae-4997-8b36-1c7bfe0d8121","","BuiltIn","Security Center","[Preview]: Secure Boot should be enabled on supported Windows virtual machines","Enable Secure Boot on supported Windows virtual machines to mitigate against malicious and unauthorized changes to the boot chain. Once enabled, only trusted bootloaders, kernel and kernel drivers will be allowed to run. This assessment applies to Trusted Launch and Confidential Windows virtual machines.","Azure_Security_Benchmark_v3.0_PV-4","ASB: Audit (default: SecureBootShouldBeEnabledOnSupportedWindowsVirtualMachinesMonitoringEffect)","parameter: + Audit, + Disabled","Audit","Audit","","" +"f85bf3e0-d513-442e-89c3-1784ad63382b","","BuiltIn","Security Center","[Preview]: System updates should be installed on your machines (powered by Update Center)","Your machines are missing system, security, and critical updates. Software updates often include critical patches to security holes. Such holes are frequently exploited in malware attacks so it's vital to keep your software updated. To install all outstanding patches and secure your machines, follow the remediation steps.","Azure_Security_Benchmark_v3.0_PV-6","ASB: AuditIfNotExists (default: systemUpdatesV2MonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1c30f9cd-b84c-49cc-aa2c-9288447cc3b3","","BuiltIn","Security Center","[Preview]: vTPM should be enabled on supported virtual machines","Enable virtual TPM device on supported virtual machines to facilitate Measured Boot and other OS security features that require a TPM. Once enabled, vTPM can be used to attest boot integrity. This assessment only applies to trusted launch enabled virtual machines.","Azure_Security_Benchmark_v3.0_PV-4","ASB: Audit (default: VtpmShouldBeEnabledOnSupportedVirtualMachinesMonitoringEffect)","parameter: + Audit, + Disabled","Audit","Audit","","" +"4f11b553-d42e-4e3a-89be-32ca364cad4c","","BuiltIn","Security Center","A maximum of 3 owners should be designated for your subscription","It is recommended to designate up to 3 subscription owners in order to reduce the potential for breach by a compromised owner.","Azure_Security_Benchmark_v3.0_PA-1, +NIST_SP_800-53_R5_AC-2, +NIST_SP_800-53_R5_AC-6, +NIST_SP_800-53_R5_AC-6(7)","ASB: AuditIfNotExists (default: identityDesignateLessThanOwnersMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"501541f7-f7e7-4cd6-868c-4190fdad3ac9","","BuiltIn","Security Center","A vulnerability assessment solution should be enabled on your virtual machines","Audits virtual machines to detect whether they are running a supported vulnerability assessment solution. A core component of every cyber risk and security program is the identification and analysis of vulnerabilities. Azure Security Center's standard pricing tier includes vulnerability scanning for your virtual machines at no extra cost. Additionally, Security Center can automatically deploy this tool for you.","Azure_Security_Benchmark_v3.0_PV-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (default: serverVulnerabilityAssessmentEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"e3e008c3-56b9-4133-8fd7-d3347377402a","","BuiltIn","Security Center","Accounts with owner permissions on Azure resources should be MFA enabled","Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with owner permissions to prevent a breach of accounts or resources.","Azure_Security_Benchmark_v3.0_IM-6, +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-2(1)","ASB: AuditIfNotExists (default: identityEnableMFAForOwnerPermissionsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"81b3ccb4-e6e8-4e4a-8d05-5df25cd29fd4","","BuiltIn","Security Center","Accounts with read permissions on Azure resources should be MFA enabled","Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with read privileges to prevent a breach of accounts or resources.","Azure_Security_Benchmark_v3.0_IM-6, +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-2(2)","ASB: AuditIfNotExists (default: identityEnableMFAForReadPermissionsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"931e118d-50a1-4457-a5e4-78550e086c52","","BuiltIn","Security Center","Accounts with write permissions on Azure resources should be MFA enabled","Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with write privileges to prevent a breach of accounts or resources.","Azure_Security_Benchmark_v3.0_IM-6, +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-2(1)","ASB: AuditIfNotExists (default: identityEnableMFAForWritePermissionsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"47a6b606-51aa-4496-8bb7-64b11cf66adc","","BuiltIn","Security Center","Adaptive application controls for defining safe applications should be enabled on your machines","Enable application controls to define the list of known-safe applications running on your machines, and alert you when other applications run. This helps harden your machines against malware. To simplify the process of configuring and maintaining your rules, Security Center uses machine learning to analyze the applications running on each machine and suggest the list of known-safe applications.","Azure_Security_Benchmark_v3.0_AM-5, +NIST_SP_800-53_R5_CM-7, +NIST_SP_800-53_R5_CM-7(2), +NIST_SP_800-53_R5_CM-7(5), +NIST_SP_800-53_R5_CM-10, +NIST_SP_800-53_R5_CM-11","ASB: AuditIfNotExists (default: adaptiveApplicationControlsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"08e6af2d-db70-460a-bfe9-d5bd474ba9d6","","BuiltIn","Security Center","Adaptive network hardening recommendations should be applied on internet facing virtual machines","Azure Security Center analyzes the traffic patterns of Internet facing virtual machines and provides Network Security Group rule recommendations that reduce the potential attack surface","Azure_Security_Benchmark_v3.0_NS-1, +Azure_Security_Benchmark_v3.0_NS-7, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-4(3), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: adaptiveNetworkHardeningsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"9daedab3-fb2d-461e-b861-71790eead4f6","","BuiltIn","Security Center","All network ports should be restricted on network security groups associated to your virtual machine","Azure Security Center has identified some of your network security groups' inbound rules to be too permissive. Inbound rules should not allow access from 'Any' or 'Internet' ranges. This can potentially enable attackers to target your resources.","Azure_Security_Benchmark_v3.0_NS-1, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: nextGenerationFirewallMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"123a3936-f020-408a-ba0c-47873faf1534","","BuiltIn","Security Center","Allowlist rules in your adaptive application control policy should be updated","Monitor for changes in behavior on groups of machines configured for auditing by Azure Security Center's adaptive application controls. Security Center uses machine learning to analyze the running processes on your machines and suggest a list of known-safe applications. These are presented as recommended apps to allow in adaptive application control policies.","Azure_Security_Benchmark_v3.0_AM-5, +NIST_SP_800-53_R5_CM-7, +NIST_SP_800-53_R5_CM-7(2), +NIST_SP_800-53_R5_CM-7(5), +NIST_SP_800-53_R5_CM-10, +NIST_SP_800-53_R5_CM-11","ASB: AuditIfNotExists (default: adaptiveApplicationControlsUpdateMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"8ac833bd-f505-48d5-887e-c993a1d3eea0","","BuiltIn","Security Center","API endpoints in Azure API Management should be authenticated","API endpoints published within Azure API Management should enforce authentication to help minimize security risk. Authentication mechanisms are sometimes implemented incorrectly or are missing. This allows attackers to exploit implementation flaws and to access data. Learn More about the OWASP API Threat for Broken User Authentication here: https://learn.microsoft.com/azure/api-management/mitigate-owasp-api-threats#broken-user-authentication","Azure_Security_Benchmark_v3.0_IM-4","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"c8acafaf-3d23-44d1-9624-978ef0f8652c","","BuiltIn","Security Center","API endpoints that are unused should be disabled and removed from the Azure API Management service","As a security best practice, API endpoints that haven't received traffic for 30 days are considered unused and should be removed from the Azure API Management service. Keeping unused API endpoints may pose a security risk to your organization. These may be APIs that should have been deprecated from the Azure API Management service but may have been accidentally left active. Such APIs typically do not receive the most up to date security coverage.","Azure_Security_Benchmark_v3.0_AM-3","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0e246bcf-5f6f-4f87-bc6f-775d4712c7ea","","BuiltIn","Security Center","Authorized IP ranges should be defined on Kubernetes Services","Restrict access to the Kubernetes Service Management API by granting API access only to IP addresses in specific ranges. It is recommended to limit access to authorized IP ranges to ensure that only applications from allowed networks can access the cluster.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: kubernetesServiceAuthorizedIPRangesEnabledMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"475aae12-b88a-4572-8b36-9b712b2b3a17","","BuiltIn","Security Center","Auto provisioning of the Log Analytics agent should be enabled on your subscription","To monitor for security vulnerabilities and threats, Azure Security Center collects data from your Azure virtual machines. Data is collected by the Log Analytics agent, formerly known as the Microsoft Monitoring Agent (MMA), which reads various security-related configurations and event logs from the machine and copies the data to your Log Analytics workspace for analysis. We recommend enabling auto provisioning to automatically deploy the agent to all supported Azure VMs and any new ones that are created.","Azure_Security_Benchmark_v3.0_LT-5, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: autoProvisioningOfTheLogAnalyticsAgentShouldBeEnabledOnYourSubscriptionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"a7aca53f-2ed4-4466-a25e-0b45ade68efd","","BuiltIn","Security Center","Azure DDoS Protection should be enabled","DDoS protection should be enabled for all virtual networks with a subnet that is part of an application gateway with a public IP.","Azure_Security_Benchmark_v3.0_NS-5, +NIST_SP_800-53_R5_SC-5","ASB: AuditIfNotExists (default: vnetEnableDDoSProtectionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"2913021d-f2fd-4f3d-b958-22354e2bdbcb","","BuiltIn","Security Center","Azure Defender for App Service should be enabled","Azure Defender for App Service leverages the scale of the cloud, and the visibility that Azure has as a cloud provider, to monitor for common web app attacks.","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: appServicesAdvancedThreatProtectionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"7fe3b40f-802b-4cdd-8bd4-fd799c948cc2","","BuiltIn","Security Center","Azure Defender for Azure SQL Database servers should be enabled","Azure Defender for SQL provides functionality for surfacing and mitigating potential database vulnerabilities, detecting anomalous activities that could indicate threats to SQL databases, and discovering and classifying sensitive data.","Azure_Security_Benchmark_v3.0_DP-2, +Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: sqlServersAdvancedDataSecurityMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0e6763cc-5078-4e64-889d-ff4d9a839047","","BuiltIn","Security Center","Azure Defender for Key Vault should be enabled","Azure Defender for Key Vault provides an additional layer of protection and security intelligence by detecting unusual and potentially harmful attempts to access or exploit key vault accounts.","Azure_Security_Benchmark_v3.0_DP-8, +Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: keyVaultsAdvancedDataSecurityMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0a9fbe0d-c5c4-4da8-87d8-f4fd77338835","","BuiltIn","Security Center","Azure Defender for open-source relational databases should be enabled","Azure Defender for open-source relational databases detects anomalous activities indicating unusual and potentially harmful attempts to access or exploit databases. Learn more about the capabilities of Azure Defender for open-source relational databases at https://aka.ms/AzDforOpenSourceDBsDocu. Important: Enabling this plan will result in charges for protecting your open-source relational databases. Learn about the pricing on Security Center's pricing page: https://aka.ms/pricing-security-center","Azure_Security_Benchmark_v3.0_DP-2, +Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5","ASB: AuditIfNotExists (default: AzureDefenderForOpenSourceRelationalDatabasesShouldBeEnabledMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"c3d20c29-b36d-48fe-808b-99a87530ad99","","BuiltIn","Security Center","Azure Defender for Resource Manager should be enabled","Azure Defender for Resource Manager automatically monitors the resource management operations in your organization. Azure Defender detects threats and alerts you about suspicious activity. Learn more about the capabilities of Azure Defender for Resource Manager at https://aka.ms/defender-for-resource-manager . Enabling this Azure Defender plan results in charges. Learn about the pricing details per region on Security Center's pricing page: https://aka.ms/pricing-security-center .","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: AzureDefenderForResourceManagerShouldBeEnabledMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"4da35fc9-c9e7-4960-aec9-797fe7d9051d","","BuiltIn","Security Center","Azure Defender for servers should be enabled","Azure Defender for servers provides real-time threat protection for server workloads and generates hardening recommendations as well as alerts about suspicious activities.","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_ES-1, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_CM-7, +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SC-3, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-3, +NIST_SP_800-53_R5_SI-4, +NIST_SP_800-53_R5_SI-16","ASB: AuditIfNotExists (default: virtualMachinesAdvancedThreatProtectionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"6581d072-105e-4418-827f-bd446d56421b","","BuiltIn","Security Center","Azure Defender for SQL servers on machines should be enabled","Azure Defender for SQL provides functionality for surfacing and mitigating potential database vulnerabilities, detecting anomalous activities that could indicate threats to SQL databases, and discovering and classifying sensitive data.","Azure_Security_Benchmark_v3.0_DP-2, +Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: sqlServersVirtualMachinesAdvancedDataSecurityMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"d38668f5-d155-42c7-ab3d-9b57b50f8fbf","","BuiltIn","Security Center","Azure Defender for SQL should be enabled for unprotected PostgreSQL flexible servers","Audit PostgreSQL flexible servers without Advanced Data Security","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"090c7b07-b4ed-4561-ad20-e9075f3ccaff","","BuiltIn","Security Center","Azure registry container images should have vulnerabilities resolved (powered by Microsoft Defender Vulnerability Management)","Container image vulnerability assessment scans your registry for commonly known vulnerabilities (CVEs) and provides a detailed vulnerability report for each image. Resolving vulnerabilities can greatly improve your security posture, ensuring images are safe to use prior to deployment.","Azure_Security_Benchmark_v3.0_PV-6, +Azure_Security_Benchmark_v3.0_DS-6","ASB: AuditIfNotExists (default: azureContainerRegistryVulnerabilityAssessmentEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"ac4a19c2-fa67-49b4-8ae5-0b2e78c49457","","BuiltIn","Security Center","Azure Role-Based Access Control (RBAC) should be used on Kubernetes Services","To provide granular filtering on the actions that users can perform, use Azure Role-Based Access Control (RBAC) to manage permissions in Kubernetes Service Clusters and configure relevant authorization policies.","Azure_Security_Benchmark_v3.0_PA-7, +NIST_SP_800-53_R5_AC-3(7)","ASB: Audit (default: kubernetesServiceRbacEnabledMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"17f4b1cc-c55c-4d94-b1f9-2978f6ac2957","","BuiltIn","Security Center","Azure running container images should have vulnerabilities resolved (powered by Microsoft Defender Vulnerability Management)","Container image vulnerability assessment scans your registry for commonly known vulnerabilities (CVEs) and provides a detailed vulnerability report for each image. This recommendation provides visibility to vulnerable images currently running in your Kubernetes clusters. Remediating vulnerabilities in container images that are currently running is key to improving your security posture, significantly reducing the attack surface for your containerized workloads.","Azure_Security_Benchmark_v3.0_PV-6, +Azure_Security_Benchmark_v3.0_DS-6","ASB: AuditIfNotExists (default: kubernetesRunningImagesVulnerabilityMDVMAssessmentEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0cfea604-3201-4e14-88fc-fae4c427a6c5","","BuiltIn","Security Center","Blocked accounts with owner permissions on Azure resources should be removed","Deprecated accounts with owner permissions should be removed from your subscription. Deprecated accounts are accounts that have been blocked from signing in.","Azure_Security_Benchmark_v3.0_PA-1, +Azure_Security_Benchmark_v3.0_PA-4, +NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (default: identityRemoveDeprecatedAccountWithOwnerPermissionsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"8d7e1fde-fe26-4b5f-8108-f8e432cbc2be","","BuiltIn","Security Center","Blocked accounts with read and write permissions on Azure resources should be removed","Deprecated accounts should be removed from your subscriptions. Deprecated accounts are accounts that have been blocked from signing in.","Azure_Security_Benchmark_v3.0_PA-4, +NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (default: identityRemoveDeprecatedAccountMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"6e2593d9-add6-4083-9c9b-4b7d2188c899","","BuiltIn","Security Center","Email notification for high severity alerts should be enabled","To ensure the relevant people in your organization are notified when there is a potential security breach in one of your subscriptions, enable email notifications for high severity alerts in Security Center.","Azure_Security_Benchmark_v3.0_IR-2, +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_IR-6(2), +NIST_SP_800-53_R5_SI-4(12)","ASB: AuditIfNotExists (default: emailNotificationForHighSeverityAlertsShouldBeEnabledMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0b15565f-aa9e-48ba-8619-45960f2c314d","","BuiltIn","Security Center","Email notification to subscription owner for high severity alerts should be enabled","To ensure your subscription owners are notified when there is a potential security breach in their subscription, set email notifications to subscription owners for high severity alerts in Security Center.","Azure_Security_Benchmark_v3.0_IR-2, +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_IR-6(2), +NIST_SP_800-53_R5_SI-4(12)","ASB: AuditIfNotExists (default: emailNotificationToSubscriptionOwnerForHighSeverityAlertsShouldBeEnabledMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"8e42c1f2-a2ab-49bc-994a-12bcd0dc4ac2","","BuiltIn","Security Center","Endpoint protection health issues should be resolved on your machines","Resolve endpoint protection health issues on your virtual machines to protect them from latest threats and vulnerabilities. Azure Security Center supported endpoint protection solutions are documented here - https://docs.microsoft.com/azure/security-center/security-center-services?tabs=features-windows#supported-endpoint-protection-solutions. Endpoint protection assessment is documented here - https://docs.microsoft.com/azure/security-center/security-center-endpoint-protection.","Azure_Security_Benchmark_v3.0_ES-2, +Azure_Security_Benchmark_v3.0_ES-3","ASB: AuditIfNotExists (default: endpointProtectionHealthIssuesMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1f7c564c-0a90-4d44-b7e1-9d456cffaee8","","BuiltIn","Security Center","Endpoint protection should be installed on your machines","To protect your machines from threats and vulnerabilities, install a supported endpoint protection solution.","Azure_Security_Benchmark_v3.0_ES-2","ASB: AuditIfNotExists (default: installEndpointProtectionMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"26a828e1-e88f-464e-bbb3-c134a282b9de","","BuiltIn","Security Center","Endpoint protection solution should be installed on virtual machine scale sets","Audit the existence and health of an endpoint protection solution on your virtual machines scale sets, to protect them from threats and vulnerabilities.","Azure_Security_Benchmark_v3.0_ES-2, +NIST_SP_800-53_R5_SC-3, +NIST_SP_800-53_R5_SI-3","ASB: AuditIfNotExists (default: vmssEndpointProtectionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"339353f6-2387-4a45-abe4-7f529d121046","","BuiltIn","Security Center","Guest accounts with owner permissions on Azure resources should be removed","External accounts with owner permissions should be removed from your subscription in order to prevent unmonitored access.","Azure_Security_Benchmark_v3.0_PA-1, +Azure_Security_Benchmark_v3.0_PA-4, +NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (default: identityRemoveExternalAccountWithOwnerPermissionsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"e9ac8f8e-ce22-4355-8f04-99b911d6be52","","BuiltIn","Security Center","Guest accounts with read permissions on Azure resources should be removed","External accounts with read privileges should be removed from your subscription in order to prevent unmonitored access.","Azure_Security_Benchmark_v3.0_PA-4, +NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (default: identityRemoveExternalAccountWithReadPermissionsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"94e1c2ac-cbbe-4cac-a2b5-389c812dee87","","BuiltIn","Security Center","Guest accounts with write permissions on Azure resources should be removed","External accounts with write privileges should be removed from your subscription in order to prevent unmonitored access.","Azure_Security_Benchmark_v3.0_PA-4, +NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (default: identityRemoveExternalAccountWithWritePermissionsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"ae89ebca-1c92-4898-ac2c-9f63decb045c","","BuiltIn","Security Center","Guest Configuration extension should be installed on your machines","To ensure secure configurations of in-guest settings of your machine, install the Guest Configuration extension. In-guest settings that the extension monitors include the configuration of the operating system, application configuration or presence, and environment settings. Once installed, in-guest policies will be available such as 'Windows Exploit guard should be enabled'. Learn more at https://aka.ms/gcpol.","Azure_Security_Benchmark_v3.0_PV-4, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: azurePolicyforWindowsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"f6de0be7-9a8a-4b8a-b349-43cf02d22f7c","","BuiltIn","Security Center","Internet-facing virtual machines should be protected with network security groups","Protect your virtual machines from potential threats by restricting access to them with network security groups (NSG). Learn more about controlling traffic with NSGs at https://aka.ms/nsg-doc","Azure_Security_Benchmark_v3.0_NS-1, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: networkSecurityGroupsOnVirtualMachinesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"bd352bd5-2853-4985-bf0d-73806b4a5744","","BuiltIn","Security Center","IP Forwarding on your virtual machine should be disabled","Enabling IP forwarding on a virtual machine's NIC allows the machine to receive traffic addressed to other destinations. IP forwarding is rarely required (e.g., when using the VM as a network virtual appliance), and therefore, this should be reviewed by the network security team.","Azure_Security_Benchmark_v3.0_NS-3, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-5, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: disableIPForwardingMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"fb893a29-21bb-418c-a157-e99480ec364c","","BuiltIn","Security Center","Kubernetes Services should be upgraded to a non-vulnerable Kubernetes version","Upgrade your Kubernetes service cluster to a later Kubernetes version to protect against known vulnerabilities in your current Kubernetes version. Vulnerability CVE-2019-9946 has been patched in Kubernetes versions 1.11.9+, 1.12.7+, 1.13.5+, and 1.14.0+","NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-2(6)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"a4fe33eb-e377-4efb-ab31-0784311bc499","","BuiltIn","Security Center","Log Analytics agent should be installed on your virtual machine for Azure Security Center monitoring","This policy audits any Windows/Linux virtual machines (VMs) if the Log Analytics agent is not installed which Security Center uses to monitor for security vulnerabilities and threats","Azure_Security_Benchmark_v3.0_LT-5, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: installLogAnalyticsAgentOnVmMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"a3a6ea0c-e018-4933-9ef0-5aaa1501449b","","BuiltIn","Security Center","Log Analytics agent should be installed on your virtual machine scale sets for Azure Security Center monitoring","Security Center collects data from your Azure virtual machines (VMs) to monitor for security vulnerabilities and threats.","Azure_Security_Benchmark_v3.0_LT-5, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: installLogAnalyticsAgentOnVmssMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"3ac7c827-eea2-4bde-acc7-9568cd320efa","","BuiltIn","Security Center","Machines should have secret findings resolved","Audits virtual machines to detect whether they contain secret findings from the secret scanning solutions on your virtual machines.","Azure_Security_Benchmark_v3.0_PV-5, +Azure_Security_Benchmark_v3.0_IM-8","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"b0f33259-77d7-4c9e-aac6-3aabcfae693c","","BuiltIn","Security Center","Management ports of virtual machines should be protected with just-in-time network access control","Possible network Just In Time (JIT) access will be monitored by Azure Security Center as recommendations","Azure_Security_Benchmark_v3.0_NS-3, +Azure_Security_Benchmark_v3.0_PA-2, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-4(3), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: jitNetworkAccessMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"22730e10-96f6-4aac-ad84-9383d35b5917","","BuiltIn","Security Center","Management ports should be closed on your virtual machines","Open remote management ports are exposing your VM to a high level of risk from Internet-based attacks. These attacks attempt to brute force credentials to gain admin access to the machine.","Azure_Security_Benchmark_v3.0_NS-3, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: restrictAccessToManagementPortsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1f90fc71-a595-4066-8974-d4d0802e8ef0","","BuiltIn","Security Center","Microsoft Defender CSPM should be enabled","Defender Cloud Security Posture Management (CSPM) provides enhanced posture capabilities and a new intelligent cloud security graph to help identify, prioritize, and reduce risk. Defender CSPM is available in addition to the free foundational security posture capabilities turned on by default in Defender for Cloud.","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5","ASB: AuditIfNotExists (default: MicrosoftDefenderCSPMShouldBeEnabledMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"7926a6d1-b268-4586-8197-e8ae90c877d7","","BuiltIn","Security Center","Microsoft Defender for APIs should be enabled","Microsoft Defender for APIs brings new discovery, protection, detection, & response coverage to monitor for common API based attacks & security misconfigurations.","Azure_Security_Benchmark_v3.0_DP-1, +Azure_Security_Benchmark_v3.0_DP-2, +Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1c988dd6-ade4-430f-a608-2a3e5b0a6d38","","BuiltIn","Security Center","Microsoft Defender for Containers should be enabled","Microsoft Defender for Containers provides hardening, vulnerability assessment and run-time protections for your Azure, hybrid, and multi-cloud Kubernetes environments.","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: containersAdvancedThreatProtectionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"d31e5c31-63b2-4f12-887b-e49456834fa1","","BuiltIn","Security Center","Microsoft Defender for SQL should be enabled for unprotected Synapse workspaces","Enable Defender for SQL to protect your Synapse workspaces. Defender for SQL monitors your Synapse SQL to detect anomalous activities indicating unusual and potentially harmful attempts to access or exploit databases.","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"938c4981-c2c9-4168-9cd6-972b8675f906","","BuiltIn","Security Center","Microsoft Defender for SQL status should be protected for Arc-enabled SQL Servers","Microsoft Defender for SQL provides functionality for surfacing and mitigating potential database vulnerabilities, detecting anomalous activities that could indicate threats to SQL databases, discovering and classifying sensitive data. Once enabled, the protection status indicates that the resource is actively monitored. Even when Defender is enabled, multiple configuration settings should be validated on the agent, machine, workspace and SQL server to ensure active protection.","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5","ASB: Audit (default: arcEnabledSqlServerDefenderStatusEffect)","parameter: + Audit, + Disabled","Audit","Audit","","" +"640d2586-54d2-465f-877f-9ffc1d2109f4","","BuiltIn","Security Center","Microsoft Defender for Storage should be enabled","Microsoft Defender for Storage detects potential threats to your storage accounts. It helps prevent the three major impacts on your data and workload: malicious file uploads, sensitive data exfiltration, and data corruption. The new Defender for Storage plan includes Malware Scanning and Sensitive Data Threat Detection. This plan also provides a predictable pricing structure (per storage account) for control over coverage and costs.","Azure_Security_Benchmark_v3.0_DP-2, +Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (Policy Default), +NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"af6cd1bd-1635-48cb-bde7-5b15693900b9","","BuiltIn","Security Center","Monitor missing Endpoint Protection in Azure Security Center","Servers without an installed Endpoint Protection agent will be monitored by Azure Security Center as recommendations","Azure_Security_Benchmark_v3.0_ES-2, +NIST_SP_800-53_R5_SC-3, +NIST_SP_800-53_R5_SI-3","ASB: AuditIfNotExists (default: endpointProtectionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"bb91dfba-c30d-4263-9add-9c2384e659a6","","BuiltIn","Security Center","Non-internet-facing virtual machines should be protected with network security groups","Protect your non-internet-facing virtual machines from potential threats by restricting access with network security groups (NSG). Learn more about controlling traffic with NSGs at https://aka.ms/nsg-doc","Azure_Security_Benchmark_v3.0_NS-1, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: networkSecurityGroupsOnInternalVirtualMachinesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"feedbf84-6b99-488c-acc2-71c829aa5ffc","","BuiltIn","Security Center","SQL databases should have vulnerability findings resolved","Monitor vulnerability assessment scan results and recommendations for how to remediate database vulnerabilities.","Azure_Security_Benchmark_v3.0_PV-6, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (default: sqlDbVulnerabilityAssesmentMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"c6283572-73bb-4deb-bf2c-7a2b8f7462cb","","BuiltIn","Security Center","SQL server-targeted autoprovisioning should be enabled for SQL servers on machines plan","To ensure your SQL VMs and Arc-enabled SQL Servers are protected, ensure the SQL-targeted Azure Monitoring Agent is configured to automatically deploy. This is also necessary if you've previously configured autoprovisioning of the Microsoft Monitoring Agent, as that component is being deprecated. Learn more: https://aka.ms/SQLAMAMigration","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"6ba6d016-e7c3-4842-b8f2-4992ebc0d72d","","BuiltIn","Security Center","SQL servers on machines should have vulnerability findings resolved","SQL vulnerability assessment scans your database for security vulnerabilities, and exposes any deviations from best practices such as misconfigurations, excessive permissions, and unprotected sensitive data. Resolving the vulnerabilities found can greatly improve your database security posture.","Azure_Security_Benchmark_v3.0_PV-6, +NIST_SP_800-53_R5_RA-5","ASB: AuditIfNotExists (default: serverSqlDbVulnerabilityAssesmentMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"e71308d3-144b-4262-b144-efdc3cc90517","","BuiltIn","Security Center","Subnets should be associated with a Network Security Group","Protect your subnet from potential threats by restricting access to it with a Network Security Group (NSG). NSGs contain a list of Access Control List (ACL) rules that allow or deny network traffic to your subnet.","Azure_Security_Benchmark_v3.0_NS-1, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Disabled (default: networkSecurityGroupsOnSubnetsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","Disabled","Disabled","","" +"4f4f78b8-e367-4b10-a341-d9a4ad5cf1c7","","BuiltIn","Security Center","Subscriptions should have a contact email address for security issues","To ensure the relevant people in your organization are notified when there is a potential security breach in one of your subscriptions, set a security contact to receive email notifications from Security Center.","Azure_Security_Benchmark_v3.0_IR-2, +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_IR-6(2), +NIST_SP_800-53_R5_SI-4(12)","ASB: AuditIfNotExists (default: subscriptionsShouldHaveAContactEmailAddressForSecurityIssuesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"c3f317a7-a95c-4547-b7e7-11017ebdf2fe","","BuiltIn","Security Center","System updates on virtual machine scale sets should be installed","Audit whether there are any missing system security updates and critical updates that should be installed to ensure that your Windows and Linux virtual machine scale sets are secure.","Azure_Security_Benchmark_v3.0_PV-6, +NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (default: vmssSystemUpdatesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"86b3d65f-7626-441e-b690-81a8b71cff60","","BuiltIn","Security Center","System updates should be installed on your machines","Missing security system updates on your servers will be monitored by Azure Security Center as recommendations","Azure_Security_Benchmark_v3.0_PV-6, +NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (default: systemUpdatesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"09024ccc-0c5f-475e-9457-b7c0d9ed487b","","BuiltIn","Security Center","There should be more than one owner assigned to your subscription","It is recommended to designate more than one subscription owner in order to have administrator access redundancy.","Azure_Security_Benchmark_v3.0_PA-1, +NIST_SP_800-53_R5_AC-5","ASB: AuditIfNotExists (default: identityDesignateMoreThanOneOwnerMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0961003e-5a0a-4549-abde-af6a37f2724d","","BuiltIn","Security Center","Virtual machines should encrypt temp disks, caches, and data flows between Compute and Storage resources","By default, a virtual machine's OS and data disks are encrypted-at-rest using platform-managed keys. Temp disks, data caches and data flowing between compute and storage aren't encrypted. Disregard this recommendation if: 1. using encryption-at-host, or 2. server-side encryption on Managed Disks meets your security requirements. Learn more in: Server-side encryption of Azure Disk Storage: https://aka.ms/disksse, Different disk encryption offerings: https://aka.ms/diskencryptioncomparison","Azure_Security_Benchmark_v3.0_DP-4, +NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","ASB: AuditIfNotExists (default: diskEncryptionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"d26f7642-7545-4e18-9b75-8c9bbdee3a9a","","BuiltIn","Security Center","Virtual machines' Guest Configuration extension should be deployed with system-assigned managed identity","The Guest Configuration extension requires a system assigned managed identity. Azure virtual machines in the scope of this policy will be non-compliant when they have the Guest Configuration extension installed but do not have a system assigned managed identity. Learn more at https://aka.ms/gcpol","Azure_Security_Benchmark_v3.0_IM-3, +Azure_Security_Benchmark_v3.0_PV-4, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: gcExtOnVMWithNoSAMIMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"e8cbc669-f12d-49eb-93e7-9273119e9933","","BuiltIn","Security Center","Vulnerabilities in container security configurations should be remediated","Audit vulnerabilities in security configuration on machines with Docker installed and display as recommendations in Azure Security Center.","Azure_Security_Benchmark_v3.0_PV-6, +Azure_Security_Benchmark_v3.0_DS-6, +NIST_SP_800-53_R5_RA-5","ASB: AuditIfNotExists (default: containerBenchmarkMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"e1e5fd5d-3e4c-4ce1-8661-7d1873ae6b15","","BuiltIn","Security Center","Vulnerabilities in security configuration on your machines should be remediated","Servers which do not satisfy the configured baseline will be monitored by Azure Security Center as recommendations","Azure_Security_Benchmark_v3.0_PV-6, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (default: systemConfigurationsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"3c735d8a-a4ba-4a3a-b7cf-db7754cf57f4","","BuiltIn","Security Center","Vulnerabilities in security configuration on your virtual machine scale sets should be remediated","Audit the OS vulnerabilities on your virtual machine scale sets to protect them from attacks.","Azure_Security_Benchmark_v3.0_PV-6, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (default: vmssOsVulnerabilitiesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1c06e275-d63d-4540-b761-71f364c2111d","","BuiltIn","Service Bus","Azure Service Bus namespaces should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Service Bus namespaces, data leakage risks are reduced. Learn more at: https://docs.microsoft.com/azure/service-bus-messaging/private-link-service.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"f8d36e2f-389b-4ee4-898d-21aeb69a0f45","","BuiltIn","Service Bus","Resource logs in Service Bus should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInServiceBusMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInServiceBusRetentionDays"":""1""}","{""diagnosticsLogsInServiceBusRetentionDays"":""1""}" +"295fc8b1-dc9f-4f53-9c61-3f313ceab40a","","BuiltIn","Service Bus","Service Bus Premium namespaces should use a customer-managed key for encryption","Azure Service Bus supports the option of encrypting data at rest with either Microsoft-managed keys (default) or customer-managed keys. Choosing to encrypt data using customer-managed keys enables you to assign, rotate, disable, and revoke access to the keys that Service Bus will use to encrypt data in your namespace. Note that Service Bus only supports encryption with customer-managed keys for premium namespaces.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"617c02be-7f02-4efd-8836-3180d47b6c68","","BuiltIn","Service Fabric","Service Fabric clusters should have the ClusterProtectionLevel property set to EncryptAndSign","Service Fabric provides three levels of protection (None, Sign and EncryptAndSign) for node-to-node communication using a primary cluster certificate. Set the protection level to ensure that all node-to-node messages are encrypted and digitally signed","Azure_Security_Benchmark_v3.0_DP-4, +NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","ASB: Audit (default: clusterProtectionLevelInServiceFabricMonitoringEffect), +NIST-800-53: Audit (default: effect-617c02be-7f02-4efd-8836-3180d47b6c68)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"b54ed75b-3e1a-44ac-a333-05ba39b99ff0","","BuiltIn","Service Fabric","Service Fabric clusters should only use Azure Active Directory for client authentication","Audit usage of client authentication only via Azure Active Directory in Service Fabric","Azure_Security_Benchmark_v3.0_IM-1, +NIST_SP_800-53_R5_AC-2, +NIST_SP_800-53_R5_AC-2(1), +NIST_SP_800-53_R5_AC-2(7), +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-4","ASB: Audit (default: aadAuthenticationInServiceFabricMonitoringEffect), +NIST-800-53: Audit (default: effect-b54ed75b-3e1a-44ac-a333-05ba39b99ff0)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"2393d2cf-a342-44cd-a2e2-fe0188fd1234","","BuiltIn","SignalR","Azure SignalR Service should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Azure SignalR Service resource instead of the entire service, you'll reduce your data leakage risks. Learn more about private links at: https://aka.ms/asrs/privatelink.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: azureSignalRServiceShouldUsePrivateLinkMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"146412e9-005c-472b-9e48-c87b72ac229e","","BuiltIn","SQL","A Microsoft Entra administrator should be provisioned for MySQL servers","Audit provisioning of a Microsoft Entra administrator for your MySQL server to enable Microsoft Entra authentication. Microsoft Entra authentication enables simplified permission management and centralized identity management of database users and other Microsoft services","Azure_Security_Benchmark_v3.0_DP-4","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"b4dec045-250a-48c2-b5cc-e0c4eec8b5b4","","BuiltIn","SQL","A Microsoft Entra administrator should be provisioned for PostgreSQL servers","Audit provisioning of a Microsoft Entra administrator for your PostgreSQL server to enable Microsoft Entra authentication. Microsoft Entra authentication enables simplified permission management and centralized identity management of database users and other Microsoft services","Azure_Security_Benchmark_v3.0_IM-1","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1f314764-cb73-4fc9-b863-8eca98ac36e9","","BuiltIn","SQL","An Azure Active Directory administrator should be provisioned for SQL servers","Audit provisioning of an Azure Active Directory administrator for your SQL server to enable Azure AD authentication. Azure AD authentication enables simplified permission management and centralized identity management of database users and other Microsoft services","Azure_Security_Benchmark_v3.0_IM-1, +NIST_SP_800-53_R5_AC-2, +NIST_SP_800-53_R5_AC-2(1), +NIST_SP_800-53_R5_AC-2(7), +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-4","ASB: AuditIfNotExists (default: aadAuthenticationInSqlServerMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9","","BuiltIn","SQL","Auditing on SQL server should be enabled","Auditing on your SQL Server should be enabled to track database activities across all databases on the server and save them in an audit log.","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: sqlServerAuditingMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""setting-a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9"":""enabled""}","{""setting-a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9"":""enabled""}" +"abfb4388-5bf4-4ad7-ba82-2cd2f41ceae9","","BuiltIn","SQL","Azure Defender for SQL should be enabled for unprotected Azure SQL servers","Audit SQL servers without Advanced Data Security","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-16, +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: sqlServerAdvancedDataSecurityMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"abfb7388-5bf4-4ad7-ba99-2cd2f41cebb9","","BuiltIn","SQL","Azure Defender for SQL should be enabled for unprotected SQL Managed Instances","Audit each SQL Managed Instance without advanced data security.","Azure_Security_Benchmark_v3.0_DP-2, +Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AC-16, +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: sqlManagedInstanceAdvancedDataSecurityMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"40e85574-ef33-47e8-a854-7a65c7500560","","BuiltIn","SQL","Azure MySQL flexible server should have Microsoft Entra Only Authentication enabled","Disabling local authentication methods and allowing only Microsoft Entra Authentication improves security by ensuring that Azure MySQL flexible server can exclusively be accessed by Microsoft Entra identities.","Azure_Security_Benchmark_v3.0_DP-4","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"32e6bbec-16b6-44c2-be37-c5b672d103cf","","BuiltIn","SQL","Azure SQL Database should be running TLS version 1.2 or newer","Setting TLS version to 1.2 or newer improves security by ensuring your Azure SQL Database can only be accessed from clients using TLS 1.2 or newer. Using versions of TLS less than 1.2 is not recommended since they have well documented security vulnerabilities.","Azure_Security_Benchmark_v3.0_DP-3, +Azure_Security_Benchmark_v3.0_IM-4","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"b3a22bc9-66de-45fb-98fa-00f5df42f41a","","BuiltIn","SQL","Azure SQL Database should have Microsoft Entra-only authentication enabled","Require Azure SQL logical servers to use Microsoft Entra-only authentication. This policy doesn't block servers from being created with local authentication enabled. It does block local authentication from being enabled on resources after create. Consider using the 'Microsoft Entra-only authentication' initiative instead to require both. Learn more at: https://aka.ms/adonlycreate.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"abda6d70-9778-44e7-84a8-06713e6db027","","BuiltIn","SQL","Azure SQL Database should have Microsoft Entra-only authentication enabled during creation","Require Azure SQL logical servers to be created with Microsoft Entra-only authentication. This policy doesn't block local authentication from being re-enabled on resources after create. Consider using the 'Microsoft Entra-only authentication' initiative instead to require both. Learn more at: https://aka.ms/adonlycreate.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"0c28c3fb-c244-42d5-a9bf-f35f2999577b","","BuiltIn","SQL","Azure SQL Managed Instance should have Microsoft Entra-only authentication enabled","Require Azure SQL Managed Instance to use Microsoft Entra-only authentication. This policy doesn't block Azure SQL Managed instances from being created with local authentication enabled. It does block local authentication from being enabled on resources after create. Consider using the 'Microsoft Entra-only authentication' initiative instead to require both. Learn more at: https://aka.ms/adonlycreate.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"9dfea752-dd46-4766-aed1-c355fa93fb91","","BuiltIn","SQL","Azure SQL Managed Instances should disable public network access","Disabling public network access (public endpoint) on Azure SQL Managed Instances improves security by ensuring that they can only be accessed from inside their virtual networks or via Private Endpoints. To learn more about public network access, visit https://aka.ms/mi-public-endpoint.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"78215662-041e-49ed-a9dd-5385911b3a1f","","BuiltIn","SQL","Azure SQL Managed Instances should have Microsoft Entra-only authentication enabled during creation","Require Azure SQL Managed Instance to be created with Microsoft Entra-only authentication. This policy doesn't block local authentication from being re-enabled on resources after create. Consider using the 'Microsoft Entra-only authentication' initiative instead to require both. Learn more at: https://aka.ms/adonlycreate.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"e802a67a-daf5-4436-9ea6-f6d821dd0c5d","","BuiltIn","SQL","Enforce SSL connection should be enabled for MySQL database servers","Azure Database for MySQL supports connecting your Azure Database for MySQL server to client applications using Secure Sockets Layer (SSL). Enforcing SSL connections between your database server and your client applications helps protect against 'man in the middle' attacks by encrypting the data stream between the server and your application. This configuration enforces that SSL is always enabled for accessing your database server.","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (default: enforceSSLConnectionShouldBeEnabledForMysqlDatabaseServersMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"d158790f-bfb0-486c-8631-2dc6b4e8e6af","","BuiltIn","SQL","Enforce SSL connection should be enabled for PostgreSQL database servers","Azure Database for PostgreSQL supports connecting your Azure Database for PostgreSQL server to client applications using Secure Sockets Layer (SSL). Enforcing SSL connections between your database server and your client applications helps protect against 'man in the middle' attacks by encrypting the data stream between the server and your application. This configuration enforces that SSL is always enabled for accessing your database server.","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (default: enforceSSLConnectionShouldBeEnabledForPostgresqlDatabaseServersMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"0ec47710-77ff-4a3d-9181-6aa50af424d0","","BuiltIn","SQL","Geo-redundant backup should be enabled for Azure Database for MariaDB","Azure Database for MariaDB allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create.","Azure_Security_Benchmark_v3.0_BR-1, +Azure_Security_Benchmark_v3.0_BR-2, +NIST_SP_800-53_R5_CP-6, +NIST_SP_800-53_R5_CP-6(1), +NIST_SP_800-53_R5_CP-9","ASB: Audit (default: georedundantBackupShouldBeEnabledForAzureDatabaseForMariadbMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"82339799-d096-41ae-8538-b108becf0970","","BuiltIn","SQL","Geo-redundant backup should be enabled for Azure Database for MySQL","Azure Database for MySQL allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create.","Azure_Security_Benchmark_v3.0_BR-1, +Azure_Security_Benchmark_v3.0_BR-2, +NIST_SP_800-53_R5_CP-6, +NIST_SP_800-53_R5_CP-6(1), +NIST_SP_800-53_R5_CP-9","ASB: Audit (default: georedundantBackupShouldBeEnabledForAzureDatabaseForMysqlMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"48af4db5-9b8b-401c-8e74-076be876a430","","BuiltIn","SQL","Geo-redundant backup should be enabled for Azure Database for PostgreSQL","Azure Database for PostgreSQL allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create.","Azure_Security_Benchmark_v3.0_BR-1, +Azure_Security_Benchmark_v3.0_BR-2, +NIST_SP_800-53_R5_CP-6, +NIST_SP_800-53_R5_CP-6(1), +NIST_SP_800-53_R5_CP-9","ASB: Audit (default: georedundantBackupShouldBeEnabledForAzureDatabaseForPostgresqlMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"3a58212a-c829-4f13-9872-6371df2fd0b4","","BuiltIn","SQL","Infrastructure encryption should be enabled for Azure Database for MySQL servers","Enable infrastructure encryption for Azure Database for MySQL servers to have higher level of assurance that the data is secure. When infrastructure encryption is enabled, the data at rest is encrypted twice using FIPS 140-2 compliant Microsoft managed keys.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (default: effect-3a58212a-c829-4f13-9872-6371df2fd0b4)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"24fba194-95d6-48c0-aea7-f65bf859c598","","BuiltIn","SQL","Infrastructure encryption should be enabled for Azure Database for PostgreSQL servers","Enable infrastructure encryption for Azure Database for PostgreSQL servers to have higher level of assurance that the data is secure. When infrastructure encryption is enabled, the data at rest is encrypted twice using FIPS 140-2 compliant Microsoft managed keys","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (default: effect-24fba194-95d6-48c0-aea7-f65bf859c598)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"d38fc420-0735-4ef3-ac11-c806f651a570","","BuiltIn","SQL","Long-term geo-redundant backup should be enabled for Azure SQL Databases","This policy audits any Azure SQL Database with long-term geo-redundant backup not enabled.","NIST_SP_800-53_R5_CP-6, +NIST_SP_800-53_R5_CP-6(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"83cef61d-dbd1-4b20-a4fc-5fbc7da10833","","BuiltIn","SQL","MySQL servers should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your MySQL servers. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: bringYourOwnKeyDataProtectionShouldBeEnabledForMySqlServersMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","Disabled","Disabled","","" +"18adea5e-f416-4d0f-8aa8-d24321e3e274","","BuiltIn","SQL","PostgreSQL servers should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your PostgreSQL servers. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: bringYourOwnKeyDataProtectionShouldBeEnabledForPostgreSqlServersMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","Disabled","Disabled","","" +"7698e800-9299-47a6-b3b6-5a0fee576eed","","BuiltIn","SQL","Private endpoint connections on Azure SQL Database should be enabled","Private endpoint connections enforce secure communication by enabling private connectivity to Azure SQL Database.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: privateEndpointConnectionsOnAzureSQLDatabaseShouldBeEnabledMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"0a1302fb-a631-4106-9753-f3d494733990","","BuiltIn","SQL","Private endpoint should be enabled for MariaDB servers","Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for MariaDB. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: privateEndpointShouldBeEnabledForMariadbServersMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"7595c971-233d-4bcf-bd18-596129188c49","","BuiltIn","SQL","Private endpoint should be enabled for MySQL servers","Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for MySQL. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: privateEndpointShouldBeEnabledForMysqlServersMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0564d078-92f5-4f97-8398-b9f58a51f70b","","BuiltIn","SQL","Private endpoint should be enabled for PostgreSQL servers","Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for PostgreSQL. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: privateEndpointShouldBeEnabledForPostgresqlServersMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1b8ca024-1d5c-4dec-8995-b1a932b41780","","BuiltIn","SQL","Public network access on Azure SQL Database should be disabled","Disabling the public network access property improves security by ensuring your Azure SQL Database can only be accessed from a private endpoint. This configuration denies all logins that match IP or virtual network based firewall rules.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: publicNetworkAccessOnAzureSQLDatabaseShouldBeDisabledMonitoringEffect), +NIST-800-53: Audit (default: effect-1b8ca024-1d5c-4dec-8995-b1a932b41780)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"fdccbe47-f3e3-4213-ad5d-ea459b2fa077","","BuiltIn","SQL","Public network access should be disabled for MariaDB servers","Disable the public network access property to improve security and ensure your Azure Database for MariaDB can only be accessed from a private endpoint. This configuration strictly disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: publicNetworkAccessShouldBeDisabledForMariaDbServersMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"d9844e8a-1437-4aeb-a32c-0c992f056095","","BuiltIn","SQL","Public network access should be disabled for MySQL servers","Disable the public network access property to improve security and ensure your Azure Database for MySQL can only be accessed from a private endpoint. This configuration strictly disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: publicNetworkAccessShouldBeDisabledForMySqlServersMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"b52376f7-9612-48a1-81cd-1ffe4b61032c","","BuiltIn","SQL","Public network access should be disabled for PostgreSQL servers","Disable the public network access property to improve security and ensure your Azure Database for PostgreSQL can only be accessed from a private endpoint. This configuration disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: publicNetworkAccessShouldBeDisabledForPostgreSqlServersMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"ac01ad65-10e5-46df-bdd9-6b0cad13e1d2","","BuiltIn","SQL","SQL managed instances should use customer-managed keys to encrypt data at rest","Implementing Transparent Data Encryption (TDE) with your own key provides you with increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. This recommendation applies to organizations with a related compliance requirement.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: ensureManagedInstanceTDEIsEncryptedWithYourOwnKeyWithDenyMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"0a370ff3-6cab-4e85-8995-295fd854c5b8","","BuiltIn","SQL","SQL servers should use customer-managed keys to encrypt data at rest","Implementing Transparent Data Encryption (TDE) with your own key provides increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. This recommendation applies to organizations with a related compliance requirement.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: ensureServerTDEIsEncryptedWithYourOwnKeyWithDenyMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"89099bee-89e0-4b26-a5f4-165451757743","","BuiltIn","SQL","SQL servers with auditing to storage account destination should be configured with 90 days retention or higher","For incident investigation purposes, we recommend setting the data retention for your SQL Server' auditing to storage account destination to at least 90 days. Confirm that you are meeting the necessary retention rules for the regions in which you are operating. This is sometimes required for compliance with regulatory standards.","Azure_Security_Benchmark_v3.0_LT-6, +NIST_SP_800-53_R5_AU-11","ASB: AuditIfNotExists (default: sQLServersShouldBeConfiguredWithAuditingRetentionDaysGreaterThan90DaysMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"17k78e20-9358-41c9-923c-fb736d382a12","","BuiltIn","SQL","Transparent Data Encryption on SQL databases should be enabled","Transparent data encryption should be enabled to protect data-at-rest and meet compliance requirements","Azure_Security_Benchmark_v3.0_DP-4, +NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","ASB: AuditIfNotExists (default: sqlDbEncryptionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1b7aa243-30e4-4c9e-bca8-d0d3022b634a","","BuiltIn","SQL","Vulnerability assessment should be enabled on SQL Managed Instance","Audit each SQL Managed Instance which doesn't have recurring vulnerability assessment scans enabled. Vulnerability assessment can discover, track, and help you remediate potential database vulnerabilities.","Azure_Security_Benchmark_v3.0_PV-5, +NIST_SP_800-53_R5_RA-5","ASB: AuditIfNotExists (default: vulnerabilityAssessmentOnManagedInstanceMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"ef2a8f2a-b3d9-49cd-a8a8-9a3aaaf647d9","","BuiltIn","SQL","Vulnerability assessment should be enabled on your SQL servers","Audit Azure SQL servers which do not have vulnerability assessment properly configured. Vulnerability assessment can discover, track, and help you remediate potential database vulnerabilities.","Azure_Security_Benchmark_v3.0_PV-5, +NIST_SP_800-53_R5_RA-5","ASB: AuditIfNotExists (default: vulnerabilityAssessmentOnServerMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"dad3a6b9-4451-492f-a95c-69efc6f3fada","","BuiltIn","Stack HCI","[Preview]: Azure Stack HCI servers should have consistently enforced application control policies","At a minimum, apply the Microsoft WDAC base policy in enforced mode on all Azure Stack HCI servers. Applied Windows Defender Application Control (WDAC) policies must be consistent across servers in the same cluster.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (Policy Default)","override: + Audit, + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"5e6bf724-0154-49bc-985f-27b2e07e636b","","BuiltIn","Stack HCI","[Preview]: Azure Stack HCI servers should meet Secured-core requirements","Ensure that all Azure Stack HCI servers meet the Secured-core requirements. To enable the Secured-core server requirements: 1. From the Azure Stack HCI clusters page, go to Windows Admin Center and select Connect. 2. Go to the Security extension and select Secured-core. 3. Select any setting that is not enabled and click Enable.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (Policy Default)","override: + Audit, + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"ee8ca833-1583-4d24-837e-96c2af9488a4","","BuiltIn","Stack HCI","[Preview]: Azure Stack HCI systems should have encrypted volumes","Use BitLocker to encrypt the OS and data volumes on Azure Stack HCI systems.","Azure_Security_Benchmark_v3.0_DP-5","ASB: AuditIfNotExists (Policy Default)","override: + Audit, + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"36f0d6bc-a253-4df8-b25b-c3a5023ff443","","BuiltIn","Stack HCI","[Preview]: Host and VM networking should be protected on Azure Stack HCI systems","Protect data on the Azure Stack HCI hosts network and on virtual machine network connections.","Azure_Security_Benchmark_v3.0_DP-3","ASB: AuditIfNotExists (Policy Default)","override: + Audit, + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"4fa4b6c0-31ca-4c0d-b10d-24b96f62a751","","BuiltIn","Storage","[Preview]: Storage account public access should be disallowed","Anonymous public read access to containers and blobs in Azure Storage is a convenient way to share data but might present security risks. To prevent data breaches caused by undesired anonymous access, Microsoft recommends preventing public access to a storage account unless your scenario requires it.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: audit (default: disallowPublicBlobAccessEffect), +NIST-800-53: audit (default: effect-4fa4b6c0-31ca-4c0d-b10d-24b96f62a751)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1d320205-c6a1-4ac6-873d-46224024e8e2","","BuiltIn","Storage","Azure File Sync should use private link","Creating a private endpoint for the indicated Storage Sync Service resource allows you to address your Storage Sync Service resource from within the private IP address space of your organization's network, rather than through the internet-accessible public endpoint. Creating a private endpoint by itself does not disable the public endpoint.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"bf045164-79ba-4215-8f95-f8048dc1780b","","BuiltIn","Storage","Geo-redundant storage should be enabled for Storage Accounts","Use geo-redundancy to create highly available applications","NIST_SP_800-53_R5_CP-6, +NIST_SP_800-53_R5_CP-6(1)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"970f84d8-71b6-4091-9979-ace7e3fb6dbb","","BuiltIn","Storage","HPC Cache accounts should use customer-managed key for encryption","Manage encryption at rest of Azure HPC Cache with customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-970f84d8-71b6-4091-9979-ace7e3fb6dbb)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"404c3081-a854-4457-ae30-26a93ef643f9","","BuiltIn","Storage","Secure transfer to storage accounts should be enabled","Audit requirement of Secure transfer in your storage account. Secure transfer is an option that forces your storage account to accept requests only from secure connections (HTTPS). Use of HTTPS ensures authentication between the server and the service and protects data in transit from network layer attacks such as man-in-the-middle, eavesdropping, and session-hijacking","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (default: secureTransferToStorageAccountMonitoringEffect), +NIST-800-53: Audit (default: effect-404c3081-a854-4457-ae30-26a93ef643f9)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"b5ec538c-daa0-4006-8596-35468b9148e8","","BuiltIn","Storage","Storage account encryption scopes should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your storage account encryption scopes. Customer-managed keys enable the data to be encrypted with an Azure key-vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more about storage account encryption scopes at https://aka.ms/encryption-scopes-overview.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-b5ec538c-daa0-4006-8596-35468b9148e8)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"37e0d2fe-28a5-43d6-a273-67d37d1f5606","","BuiltIn","Storage","Storage accounts should be migrated to new Azure Resource Manager resources","Use new Azure Resource Manager for your storage accounts to provide security enhancements such as: stronger access control (RBAC), better auditing, Azure Resource Manager based deployment and governance, access to managed identities, access to key vault for secrets, Azure AD-based authentication and support for tags and resource groups for easier security management","Azure_Security_Benchmark_v3.0_AM-2, +NIST_SP_800-53_R5_AC-3","ASB: Audit (default: classicStorageAccountsMonitoringEffect), +NIST-800-53: Audit (default: effect-37e0d2fe-28a5-43d6-a273-67d37d1f5606)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"4733ea7b-a883-42fe-8cac-97454c2a9e4a","","BuiltIn","Storage","Storage accounts should have infrastructure encryption","Enable infrastructure encryption for higher level of assurance that the data is secure. When infrastructure encryption is enabled, data in a storage account is encrypted twice.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (default: effect-4733ea7b-a883-42fe-8cac-97454c2a9e4a)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"8c6a50c6-9ffd-4ae7-986f-5fa6111f9a54","","BuiltIn","Storage","Storage accounts should prevent shared key access","Audit requirement of Azure Active Directory (Azure AD) to authorize requests for your storage account. By default, requests can be authorized with either Azure Active Directory credentials, or by using the account access key for Shared Key authorization. Of these two types of authorization, Azure AD provides superior security and ease of use over Shared Key, and is recommended by Microsoft.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"34c877ad-507e-4c82-993e-3452a6e0ad3c","","BuiltIn","Storage","Storage accounts should restrict network access","Network access to storage accounts should be restricted. Configure network rules so only applications from allowed networks can access the storage account. To allow connections from specific internet or on-premises clients, access can be granted to traffic from specific Azure virtual networks or to public internet IP address ranges","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Disabled (default: disableUnrestrictedNetworkToStorageAccountMonitoringEffect), +NIST-800-53: Audit (default: effect-34c877ad-507e-4c82-993e-3452a6e0ad3c)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"2a1a9cdf-e04d-429a-8416-3bfb72a1b26f","","BuiltIn","Storage","Storage accounts should restrict network access using virtual network rules","Protect your storage accounts from potential threats using virtual network rules as a preferred method instead of IP-based filtering. Disabling IP-based filtering prevents public IPs from accessing your storage accounts.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: storageAccountsShouldRestrictNetworkAccessUsingVirtualNetworkRulesMonitoringEffect), +NIST-800-53: Audit (default: effect-2a1a9cdf-e04d-429a-8416-3bfb72a1b26f)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"6fac406b-40ca-413b-bf8e-0bf964659c25","","BuiltIn","Storage","Storage accounts should use customer-managed key for encryption","Secure your blob and file storage account with greater flexibility using customer-managed keys. When you specify a customer-managed key, that key is used to protect and control access to the key that encrypts your data. Using customer-managed keys provides additional capabilities to control rotation of the key encryption key or cryptographically erase data.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: storageAccountsShouldUseCustomerManagedKeyForEncryptionMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Disabled","Disabled","","" +"6edd7eda-6dd8-40f7-810d-67160c639cd9","","BuiltIn","Storage","Storage accounts should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your storage account, data leakage risks are reduced. Learn more about private links at - https://aka.ms/azureprivatelinkoverview","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: storageAccountShouldUseAPrivateLinkConnectionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"87ba29ef-1ab3-4d82-b763-87fcd4f531f7","","BuiltIn","Stream Analytics","Azure Stream Analytics jobs should use customer-managed keys to encrypt data","Use customer-managed keys when you want to securely store any metadata and private data assets of your Stream Analytics jobs in your storage account. This gives you total control over how your Stream Analytics data is encrypted.","NIST_SP_800-53_R5_SC-12","NIST-800-53: audit (default: effect-87ba29ef-1ab3-4d82-b763-87fcd4f531f7)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"f9be5368-9bf5-4b84-9e0a-7850da98bb46","","BuiltIn","Stream Analytics","Resource logs in Azure Stream Analytics should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInStreamAnalyticsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInStreamAnalyticsRetentionDays"":""1""}","{""diagnosticsLogsInStreamAnalyticsRetentionDays"":""1""}" +"f7d52b2d-e161-4dfa-a82b-55e564167385","","BuiltIn","Synapse","Azure Synapse workspaces should use customer-managed keys to encrypt data at rest","Use customer-managed keys to control the encryption at rest of the data stored in Azure Synapse workspaces. Customer-managed keys deliver double encryption by adding a second layer of encryption on top of the default encryption with service-managed keys.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-f7d52b2d-e161-4dfa-a82b-55e564167385)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"72d11df1-dd8a-41f7-8925-b05b960ebafc","","BuiltIn","Synapse","Azure Synapse workspaces should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Synapse workspace, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/synapse-analytics/security/how-to-connect-to-workspace-with-private-links.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"6ea81a52-5ca7-4575-9669-eaa910b7edf8","","BuiltIn","Synapse","Synapse Workspaces should have Microsoft Entra-only authentication enabled","Require Synapse Workspaces to use Microsoft Entra-only authentication. This policy doesn't block workspaces from being created with local authentication enabled. It does block local authentication from being enabled on resources after create. Consider using the 'Microsoft Entra-only authentication' initiative instead to require both. Learn more at: https://aka.ms/Synapse.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"2158ddbe-fefa-408e-b43f-d4faef8ff3b8","","BuiltIn","Synapse","Synapse Workspaces should use only Microsoft Entra identities for authentication during workspace creation","Require Synapse Workspaces to be created with Microsoft Entra-only authentication. This policy doesn't block local authentication from being re-enabled on resources after create. Consider using the 'Microsoft Entra-only authentication' initiative instead to require both. Learn more at: https://aka.ms/Synapse.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"0049a6b3-a662-4f3e-8635-39cf44ace45a","","BuiltIn","Synapse","Vulnerability assessment should be enabled on your Synapse workspaces","Discover, track, and remediate potential vulnerabilities by configuring recurring SQL vulnerability assessment scans on your Synapse workspaces.","NIST_SP_800-53_R5_RA-5","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"2154edb9-244f-4741-9970-660785bccdaa","","BuiltIn","VM Image Builder","VM Image Builder templates should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your VM Image Builder building resources, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/virtual-machines/linux/image-builder-networking#deploy-using-an-existing-vnet.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: vmImageBuilderTemplatesShouldUsePrivateLinkMonitoringEffect), +NIST-800-53: Audit (default: effect-2154edb9-244f-4741-9970-660785bccdaa)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"eb907f70-7514-460d-92b3-a5ae93b4f917","","BuiltIn","Web PubSub","Azure Web PubSub Service should use private link","Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Azure Web PubSub Service, you can reduce data leakage risks. Learn more about private links at: https://aka.ms/awps/privatelink.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" diff --git a/StarterKit/Definitions/policyAssignments/tag-assignments.jsonc b/StarterKit/Definitions-GitHub-Flow/policyAssignments/tag-assignments.jsonc similarity index 92% rename from StarterKit/Definitions/policyAssignments/tag-assignments.jsonc rename to StarterKit/Definitions-GitHub-Flow/policyAssignments/tag-assignments.jsonc index a8b6b07e..11a9b008 100644 --- a/StarterKit/Definitions/policyAssignments/tag-assignments.jsonc +++ b/StarterKit/Definitions-GitHub-Flow/policyAssignments/tag-assignments.jsonc @@ -20,10 +20,10 @@ "nodeName": "required-and-inherit/", "scope": { "epac-dev": [ - "/providers/Microsoft.Management/managementGroups/EPAC-Dev" + "/providers/Microsoft.Management/managementGroups/mg-epac-dev" ], "tenant": [ - "/providers/Microsoft.Management/managementGroups/Contoso-Root" + "/providers/Microsoft.Management/managementGroups/mg-enterprise" ] }, "definitionEntryList": [ @@ -48,14 +48,14 @@ ], "children": [ { - "nodeName": "Project", + "nodeName": "Example", "assignment": { - "name": "Project", - "displayName": "Project", - "description": "Project" + "name": "Example", + "displayName": "Example", + "description": "Example" }, "parameters": { - "tagName": "Project" + "tagName": "Example" } }, { @@ -93,10 +93,10 @@ }, "scope": { "epac-dev": [ - "/providers/Microsoft.Management/managementGroups/EPAC-DEv-Prod" + "/providers/Microsoft.Management/managementGroups/mg-epac-dev-prod" ], "tenant": [ - "/providers/Microsoft.Management/managementGroups/Contoso-Prod" + "/providers/Microsoft.Management/managementGroups/mg-prod" ] } }, @@ -112,10 +112,10 @@ }, "scope": { "epac-dev": [ - "/providers/Microsoft.Management/managementGroups/EPAC-Dev-NonProd" + "/providers/Microsoft.Management/managementGroups/mg-epac-dev-nonprod" ], "tenant": [ - "/providers/Microsoft.Management/managementGroups/Contoso-NonProd" + "/providers/Microsoft.Management/managementGroups/mg-nonprod" ] } } diff --git a/StarterKit/Definitions-GitHub-Flow/policyDocumentations/contoso.jsonc b/StarterKit/Definitions-GitHub-Flow/policyDocumentations/contoso.jsonc new file mode 100644 index 00000000..44715e0b --- /dev/null +++ b/StarterKit/Definitions-GitHub-Flow/policyDocumentations/contoso.jsonc @@ -0,0 +1,72 @@ +{ + "$schema": "https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/main/Schemas/policy-documentation-schema.json", + "documentAssignments": { + "environmentCategories": [ + { + "pacEnvironment": "tenant", + "environmentCategory": "prod", + "scopes": [ + "Management Group: Contoso-Prod" + ], + "representativeAssignments": [ + { + "shortName": "ASB", + "id": "/providers/Microsoft.Management/managementGroups/mg-prod/providers/Microsoft.Authorization/policyAssignments/pr-asb" + }, + { + "shortName": "NIST-800-53", + "id": "/providers/Microsoft.Management/managementGroups/mg-prod/providers/Microsoft.Authorization/policyAssignments/pr-nist-800-53-r5" + } + ] + }, + { + "pacEnvironment": "tenant", + "environmentCategory": "nonprod", + "scopes": [ + "Management Group: Contoso-NonProd" + ], + "representativeAssignments": [ + { + "shortName": "ASB", + "id": "/providers/Microsoft.Management/managementGroups/mg-nonprod/providers/Microsoft.Authorization/policyAssignments/np-asb" + }, + { + "shortName": "NIST-800-53", + "id": "/providers/Microsoft.Management/managementGroups/mg-nonprod/providers/Microsoft.Authorization/policyAssignments/np-nist-800-53-r5" + } + ] + } + ], + "documentationSpecifications": [ + { + "fileNameStem": "contoso-policy-effects", + "environmentCategories": [ + "prod", + "nonprod" + ], + "title": "Contoso Policy effects" + } + ] + }, + "documentPolicySets": [ + { + "pacEnvironment": "epac-dev", + "fileNameStem": "contoso-compliance-initiatives", + "title": "Document Initiatives", + "policySets": [ + { + "shortName": "ASB", + "id": "/providers/Microsoft.Authorization/policySetDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8" + }, + { + "shortName": "NIST-800-53", + "id": "/providers/Microsoft.Authorization/policySetDefinitions/179d1daa-458f-4e47-8086-2a68d0d6c38f" + } + ], + "environmentColumnsInCsv": [ + "prod", + "nonprod" + ] + } + ] +} \ No newline at end of file diff --git a/StarterKit/Definitions-Microsoft-Release-Flow/global-settings.jsonc b/StarterKit/Definitions-Microsoft-Release-Flow/global-settings.jsonc new file mode 100644 index 00000000..66837a64 --- /dev/null +++ b/StarterKit/Definitions-Microsoft-Release-Flow/global-settings.jsonc @@ -0,0 +1,35 @@ +{ + "$schema": "https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/main/Schemas/global-settings-schema.json", + "pacOwnerId": "11111111-2222-3333-4444-555555555555", + "pacEnvironments": [ + { + "pacSelector": "epac-dev", + "cloud": "AzureCloud", + "tenantId": "77777777-8888-9999-1111-222222222222", + "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/mg-epac-dev" + }, + { + "pacSelector": "nonprod", + "cloud": "AzureCloud", + "tenantId": "77777777-8888-9999-1111-222222222222", + "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/mg-nonprod" + }, + { + "pacSelector": "tenant", + "cloud": "AzureCloud", + "tenantId": "77777777-8888-9999-1111-222222222222", + "deploymentRootScope": "/providers/Microsoft.Management/managementGroups/mg-enterprise" + } + ], + "managedIdentityLocations": { + "*": "eastus2" + }, + "globalNotScopes": { + "nonprod": [ + "/providers/Microsoft.Management/managementGroups/mg-epac-dev" + ], + "tenant": [ + "/providers/Microsoft.Management/managementGroups/mg-nonprod" + ] + } +} \ No newline at end of file diff --git a/StarterKit/Definitions-Microsoft-Release-Flow/policyAssignments/allowed-locations-assignments.jsonc b/StarterKit/Definitions-Microsoft-Release-Flow/policyAssignments/allowed-locations-assignments.jsonc new file mode 100644 index 00000000..586e497d --- /dev/null +++ b/StarterKit/Definitions-Microsoft-Release-Flow/policyAssignments/allowed-locations-assignments.jsonc @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/main/Schemas/policy-assignment-schema.json", + "nodeName": "/Loc/", + "assignment": { + "name": "allowed-locations", + "displayName": "Allowed Locations", + "description": "Sets the allowed locations" + }, + "definitionEntry": { + "policySetName": "e14e5d7c-9551-4ae2-b8fa-b5d6b9b3c677", + "displayName": "Allowed Locations Initiative" + }, + "parameters": { + "AllowedLocations": [ + "eastus2" + ] + }, + "scope": { + "epac-dev": [ + "/providers/Microsoft.Management/managementGroups/mg-epac-dev" + ], + "nonprod": [ + "/providers/Microsoft.Management/managementGroups/mg-nonprod" + ], + "prod": [ + "/providers/Microsoft.Management/managementGroups/mg-prod" + ] + } +} \ No newline at end of file diff --git a/StarterKit/Definitions-Microsoft-Release-Flow/policyAssignments/security-baseline-assignments.jsonc b/StarterKit/Definitions-Microsoft-Release-Flow/policyAssignments/security-baseline-assignments.jsonc new file mode 100644 index 00000000..1da5a062 --- /dev/null +++ b/StarterKit/Definitions-Microsoft-Release-Flow/policyAssignments/security-baseline-assignments.jsonc @@ -0,0 +1,63 @@ +{ + "$schema": "https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/main/Schemas/policy-assignment-schema.json", + "nodeName": "/Security/", + "parameterFile": "security-baseline-parameters.csv", + "definitionEntryList": [ + { + "policySetId": "/providers/Microsoft.Authorization/policySetDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8", + "displayName": "Azure Security Benchmark", + "assignment": { + "append": true, + "name": "asb", + "displayName": "Azure Security Benchmark", + "description": "Azure Security Benchmark Initiative." + } + }, + { + "policySetId": "/providers/Microsoft.Authorization/policySetDefinitions/179d1daa-458f-4e47-8086-2a68d0d6c38f", + "displayName": "NIST SP 800-53 Rev. 5", + "assignment": { + "append": true, + "name": "nist-800-53-r5", + "displayName": "NIST SP 800-53 Rev. 5", + "description": "NIST SP 800-53 Rev. 5 Initiative." + } + } + ], + "children": [ + { + "nodeName": "Prod/", + "assignment": { + "name": "pr-", + "displayName": "Prod ", + "description": "Prod Environment controls enforcement with " + }, + "parameterSelector": "prod", + "scope": { + "epac-dev": [ + "/providers/Microsoft.Management/managementGroups/mg-epac-dev-prod" + ], + "prod": [ + "/providers/Microsoft.Management/managementGroups/mg-prod" + ] + } + }, + { + "nodeName": "Nonprod", + "assignment": { + "name": "np-", + "displayName": "Nonprod ", + "description": "Nonprod Environment controls enforcement with " + }, + "parameterSelector": "nonprod", + "scope": { + "epac-dev": [ + "/providers/Microsoft.Management/managementGroups/mg-epac-dev-nonprod" + ], + "nonprod": [ + "/providers/Microsoft.Management/managementGroups/mg-nonprod" + ] + } + } + ] +} \ No newline at end of file diff --git a/StarterKit/Definitions-Microsoft-Release-Flow/policyAssignments/security-baseline-parameters.csv b/StarterKit/Definitions-Microsoft-Release-Flow/policyAssignments/security-baseline-parameters.csv new file mode 100644 index 00000000..9b1e18fd --- /dev/null +++ b/StarterKit/Definitions-Microsoft-Release-Flow/policyAssignments/security-baseline-parameters.csv @@ -0,0 +1,1953 @@ +"name","referencePath","policyType","category","displayName","description","groupNames","policySets","allowedEffects","prodEffect","nonprodEffect","prodParameters","nonprodParameters" +"051cba44-2429-45b9-9649-46cec11c7119","","BuiltIn","API for FHIR","Azure API for FHIR should use a customer-managed key to encrypt data at rest","Use a customer-managed key to control the encryption at rest of the data stored in Azure API for FHIR when this is a regulatory or compliance requirement. Customer-managed keys also deliver double encryption by adding a second layer of encryption on top of the default one done with service-managed keys.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"1ee56206-5dd1-42ab-b02d-8aae8b1634ce","","BuiltIn","API for FHIR","Azure API for FHIR should use private link","Azure API for FHIR should have at least one approved private endpoint connection. Clients in a virtual network can securely access resources that have private endpoint connections through private links. For more information, visit: https://aka.ms/fhir-privatelink.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"ee7495e7-3ba7-40b6-bfee-c29e22cc75d4","","BuiltIn","API Management","API Management APIs should use only encrypted protocols","To ensure security of data in transit, APIs should be available only through encrypted protocols, like HTTPS or WSS. Avoid using unsecured protocols, such as HTTP or WS.","Azure_Security_Benchmark_v3.0_DP-3","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"c15dcc82-b93c-4dcb-9332-fbf121685b54","","BuiltIn","API Management","API Management calls to API backends should be authenticated","Calls from API Management to backends should use some form of authentication, whether via certificates or credentials. Does not apply to Service Fabric backends.","Azure_Security_Benchmark_v3.0_IM-4","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"92bb331d-ac71-416a-8c91-02f2cb734ce4","","BuiltIn","API Management","API Management calls to API backends should not bypass certificate thumbprint or name validation","To improve the API security, API Management should validate the backend server certificate for all API calls. Enable SSL certificate thumbprint and name validation.","Azure_Security_Benchmark_v3.0_IM-4","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"b741306c-968e-4b67-b916-5675e5c709f4","","BuiltIn","API Management","API Management direct management endpoint should not be enabled","The direct management REST API in Azure API Management bypasses Azure Resource Manager role-based access control, authorization, and throttling mechanisms, thus increasing the vulnerability of your service.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"549814b6-3212-4203-bdc8-1548d342fb67","","BuiltIn","API Management","API Management minimum API version should be set to 2019-12-01 or higher","To prevent service secrets from being shared with read-only users, the minimum API version should be set to 2019-12-01 or higher.","Azure_Security_Benchmark_v3.0_IM-8, +Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"f1cc7827-022c-473e-836e-5a51cae0b249","","BuiltIn","API Management","API Management secret named values should be stored in Azure Key Vault","Named values are a collection of name and value pairs in each API Management service. Secret values can be stored either as encrypted text in API Management (custom secrets) or by referencing secrets in Azure Key Vault. To improve security of API Management and secrets, reference secret named values from Azure Key Vault. Azure Key Vault supports granular access management and secret rotation policies.","Azure_Security_Benchmark_v3.0_IM-8, +Azure_Security_Benchmark_v3.0_DP-6","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"ef619a2c-cc4d-4d03-b2ba-8c94a834d85b","","BuiltIn","API Management","API Management services should use a virtual network","Azure Virtual Network deployment provides enhanced security, isolation and allows you to place your API Management service in a non-internet routable network that you control access to. These networks can then be connected to your on-premises networks using various VPN technologies, which enables access to your backend services within the network and/or on-premises. The developer portal and API gateway, can be configured to be accessible either from the Internet or only within the virtual network.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: aPIManagementServicesShouldUseAVirtualNetworkMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""aPIManagementServicesShouldUseAVirtualNetworkEvaluatedSkuNames"":[""Developer"",""Premium""],""evaluatedSkuNames-ef619a2c-cc4d-4d03-b2ba-8c94a834d85b"":[""Developer"",""Premium""]}","{""aPIManagementServicesShouldUseAVirtualNetworkEvaluatedSkuNames"":[""Developer"",""Premium""],""evaluatedSkuNames-ef619a2c-cc4d-4d03-b2ba-8c94a834d85b"":[""Developer"",""Premium""]}" +"df73bd95-24da-4a4f-96b9-4e8b94b402bd","","BuiltIn","API Management","API Management should disable public network access to the service configuration endpoints","To improve the security of API Management services, restrict connectivity to service configuration endpoints, like direct access management API, Git configuration management endpoint, or self-hosted gateways configuration endpoint.","Azure_Security_Benchmark_v3.0_NS-2","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"3aa03346-d8c5-4994-a5bc-7652c2a2aef1","","BuiltIn","API Management","API Management subscriptions should not be scoped to all APIs","API Management subscriptions should be scoped to a product or an individual API instead of all APIs, which could result in an excessive data exposure.","Azure_Security_Benchmark_v3.0_PA-7","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1dc2fc00-2245-4143-99f4-874c937f13ef","","BuiltIn","API Management","Azure API Management platform version should be stv2","Azure API Management stv1 compute platform version will be retired effective 31 August 2024, and these instances should be migrated to stv2 compute platform for continued support. Learn more at https://learn.microsoft.com/azure/api-management/breaking-changes/stv1-platform-retirement-august-2024","Azure_Security_Benchmark_v3.0_PV-2, +Azure_Security_Benchmark_v3.0_AM-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"ca610c1d-041c-4332-9d88-7ed3094967c7","","BuiltIn","App Configuration","App Configuration should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your app configuration instances instead of the entire service, you'll also be protected against data leakage risks. Learn more at: https://aka.ms/appconfig/private-endpoint.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: appConfigurationShouldUsePrivateLinkMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"af35e2a4-ef96-44e7-a9ae-853dd97032c4","","BuiltIn","App Platform","Azure Spring Cloud should use network injection","Azure Spring Cloud instances should use virtual network injection for the following purposes: 1. Isolate Azure Spring Cloud from Internet. 2. Enable Azure Spring Cloud to interact with systems in either on premises data centers or Azure service in other virtual networks. 3. Empower customers to control inbound and outbound network communications for Azure Spring Cloud.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1)","ASB: Audit (default: azureSpringCloudShouldUseNetworkInjectionMonitoringEffect), +NIST-800-53: Audit (default: effect-af35e2a4-ef96-44e7-a9ae-853dd97032c4)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""evaluatedSkuNames-af35e2a4-ef96-44e7-a9ae-853dd97032c4"":[""Standard""]}","{""evaluatedSkuNames-af35e2a4-ef96-44e7-a9ae-853dd97032c4"":[""Standard""]}" +"eaebaea7-8013-4ceb-9d14-7eb32271373c","","BuiltIn","App Service","[Deprecated]: Function apps should have 'Client Certificates (Incoming client certificates)' enabled","Client certificates allow for the app to request a certificate for incoming requests. Only clients with valid certificates will be able to reach the app. This policy has been replaced by a new policy with the same name because Http 2.0 doesn't support client certificates.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: functionAppsShouldHaveClientCertificatesEnabledMonitoringEffect), +NIST-800-53: Disabled (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"19dd1db6-f442-49cf-a838-b0786b4401ef","","BuiltIn","App Service","App Service apps should have Client Certificates (Incoming client certificates) enabled","Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app. This policy applies to apps with Http version set to 1.1.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (Policy Default), +NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"cb510bfd-1cba-4d9f-a230-cb0976f4bb71","","BuiltIn","App Service","App Service apps should have remote debugging turned off","Remote debugging requires inbound ports to be opened on an App Service app. Remote debugging should be turned off.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (default: webAppDisableRemoteDebuggingMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"91a78b24-f231-4a8a-8da9-02c35b2b6510","","BuiltIn","App Service","App Service apps should have resource logs enabled","Audit enabling of resource logs on the app. This enables you to recreate activity trails for investigation purposes if a security incident occurs or your network is compromised.","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticLogsInAppServicesShouldBeEnabledMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"5744710e-cc2f-4ee8-8809-3b11e89f4bc9","","BuiltIn","App Service","App Service apps should not have CORS configured to allow every resource to access your apps","Cross-Origin Resource Sharing (CORS) should not allow all domains to access your app. Allow only required domains to interact with your app.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (default: webAppRestrictCORSAccessMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"a4af4a39-4135-47fb-b175-47fbdf85311d","","BuiltIn","App Service","App Service apps should only be accessible over HTTPS","Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks.","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (default: webAppEnforceHttpsMonitoringEffectV2), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"4d24b6d4-5e53-4a4f-a7f4-618fa573ee4b","","BuiltIn","App Service","App Service apps should require FTPS only","Enable FTPS enforcement for enhanced security.","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (default: fTPSShouldBeRequiredInYourWebAppMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"8c122334-9d20-4eb8-89ea-ac9a705b74ae","","BuiltIn","App Service","App Service apps should use latest 'HTTP Version'","Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version.","NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-2(6)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"2b9ad585-36bc-4615-b300-fd4435808332","","BuiltIn","App Service","App Service apps should use managed identity","Use a managed identity for enhanced authentication security","Azure_Security_Benchmark_v3.0_IM-3, +NIST_SP_800-53_R5_AC-2, +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-4","ASB: AuditIfNotExists (default: managedIdentityShouldBeUsedInYourWebAppMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"f0e6e85b-9b9f-4a4b-b67b-f730d42f1b0b","","BuiltIn","App Service","App Service apps should use the latest TLS version","Periodically, newer versions are released for TLS either due to security flaws, include additional functionality, and enhance speed. Upgrade to the latest TLS version for App Service apps to take advantage of security fixes, if any, and/or new functionalities of the latest version.","Azure_Security_Benchmark_v3.0_NS-8, +Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (default: latestTLSVersionShouldBeUsedInYourWebAppMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"fb74e86f-d351-4b8d-b034-93da7391c01f","","BuiltIn","App Service","App Service Environment should have internal encryption enabled","Setting InternalEncryption to true encrypts the pagefile, worker disks, and internal network traffic between the front ends and workers in an App Service Environment. To learn more, refer to https://docs.microsoft.com/azure/app-service/environment/app-service-app-service-environment-custom-settings#enable-internal-encryption.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"0e60b895-3786-45da-8377-9c6b4b6ac5f9","","BuiltIn","App Service","Function apps should have remote debugging turned off","Remote debugging requires inbound ports to be opened on Function apps. Remote debugging should be turned off.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (default: functionAppDisableRemoteDebuggingMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0820b7b9-23aa-4725-a1ce-ae4558f718e5","","BuiltIn","App Service","Function apps should not have CORS configured to allow every resource to access your apps","Cross-Origin Resource Sharing (CORS) should not allow all domains to access your Function app. Allow only required domains to interact with your Function app.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (default: functionAppRestrictCORSAccessMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"6d555dd1-86f2-4f1c-8ed7-5abae7c6cbab","","BuiltIn","App Service","Function apps should only be accessible over HTTPS","Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks.","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (default: functionAppEnforceHttpsMonitoringEffectV2), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"399b2637-a50f-4f95-96f8-3a145476eb15","","BuiltIn","App Service","Function apps should require FTPS only","Enable FTPS enforcement for enhanced security.","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (default: fTPSOnlyShouldBeRequiredInYourFunctionAppMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"e2c1c086-2d84-4019-bff3-c44ccd95113c","","BuiltIn","App Service","Function apps should use latest 'HTTP Version'","Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version.","NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-2(6)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0da106f2-4ca3-48e8-bc85-c638fe6aea8f","","BuiltIn","App Service","Function apps should use managed identity","Use a managed identity for enhanced authentication security","Azure_Security_Benchmark_v3.0_IM-3, +NIST_SP_800-53_R5_AC-2, +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-4","ASB: AuditIfNotExists (default: managedIdentityShouldBeUsedInYourFunctionAppMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"f9d614c5-c173-4d56-95a7-b4437057d193","","BuiltIn","App Service","Function apps should use the latest TLS version","Periodically, newer versions are released for TLS either due to security flaws, include additional functionality, and enhance speed. Upgrade to the latest TLS version for Function apps to take advantage of security fixes, if any, and/or new functionalities of the latest version.","Azure_Security_Benchmark_v3.0_NS-8, +Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (default: latestTLSVersionShouldBeUsedInYourFunctionAppMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"3657f5a0-770e-44a3-b44e-9431ba1e9735","","BuiltIn","Automation","Automation account variables should be encrypted","It is important to enable encryption of Automation account variable assets when storing sensitive data","Azure_Security_Benchmark_v3.0_DP-4, +NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","ASB: Audit (default: encryptionOfAutomationAccountMonitoringEffect), +NIST-800-53: Audit (default: effect-3657f5a0-770e-44a3-b44e-9431ba1e9735)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"56a5ee18-2ae6-4810-86f7-18e39ce5629b","","BuiltIn","Automation","Azure Automation accounts should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your Azure Automation Accounts. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/automation-cmk.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-56a5ee18-2ae6-4810-86f7-18e39ce5629b)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"71ef260a-8f18-47b7-abcb-62d0673d94dc","","BuiltIn","Azure Ai Services","Azure AI Services resources should have key access disabled (disable local authentication)","Key access (local authentication) is recommended to be disabled for security. Azure OpenAI Studio, typically used in development/testing, requires key access and will not function if key access is disabled. After disabling, Microsoft Entra ID becomes the only access method, which allows maintaining minimum privilege principle and granular control. Learn more at: https://aka.ms/AI/auth","Azure_Security_Benchmark_v3.0_IM-1, +NIST_SP_800-53_R5_AC-2, +NIST_SP_800-53_R5_AC-2(1), +NIST_SP_800-53_R5_AC-2(7), +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-4","ASB: Audit (Policy Default), +NIST-800-53: Audit (default: effect-71ef260a-8f18-47b7-abcb-62d0673d94dc)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"037eea7a-bd0a-46c5-9a66-03aea78705d3","","BuiltIn","Azure Ai Services","Azure AI Services resources should restrict network access","By restricting network access, you can ensure that only allowed networks can access the service. This can be achieved by configuring network rules so that only applications from allowed networks can access the Azure AI service.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: cognitiveServicesAccountsShouldRestrictNetworkAccessMonitoringEffect), +NIST-800-53: Audit (default: effect-037eea7a-bd0a-46c5-9a66-03aea78705d3)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"81e74cea-30fd-40d5-802f-d72103c2aaaa","","BuiltIn","Azure Data Explorer","Azure Data Explorer encryption at rest should use a customer-managed key","Enabling encryption at rest using a customer-managed key on your Azure Data Explorer cluster provides additional control over the key being used by the encryption at rest. This feature is oftentimes applicable to customers with special compliance requirements and requires a Key Vault to managing the keys.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-81e74cea-30fd-40d5-802f-d72103c2aaaa)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"f4b53539-8df9-40e4-86c6-6b607703bd4e","","BuiltIn","Azure Data Explorer","Disk encryption should be enabled on Azure Data Explorer","Enabling disk encryption helps protect and safeguard your data to meet your organizational security and compliance commitments.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (default: effect-f4b53539-8df9-40e4-86c6-6b607703bd4e)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"ec068d99-e9c7-401f-8cef-5bdde4e6ccf1","","BuiltIn","Azure Data Explorer","Double encryption should be enabled on Azure Data Explorer","Enabling double encryption helps protect and safeguard your data to meet your organizational security and compliance commitments. When double encryption has been enabled, data in the storage account is encrypted twice, once at the service level and once at the infrastructure level, using two different encryption algorithms and two different keys.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (default: effect-ec068d99-e9c7-401f-8cef-5bdde4e6ccf1)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"51c1490f-3319-459c-bbbc-7f391bbed753","","BuiltIn","Azure Databricks","Azure Databricks Clusters should disable public IP","Disabling public IP of clusters in Azure Databricks Workspaces improves security by ensuring that the clusters aren't exposed on the public internet. Learn more at: https://learn.microsoft.com/azure/databricks/security/secure-cluster-connectivity.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"9c25c9e4-ee12-4882-afd2-11fb9d87893f","","BuiltIn","Azure Databricks","Azure Databricks Workspaces should be in a virtual network","Azure Virtual Networks provide enhanced security and isolation for your Azure Databricks Workspaces, as well as subnets, access control policies, and other features to further restrict access. Learn more at: https://docs.microsoft.com/azure/databricks/administration-guide/cloud-configurations/azure/vnet-inject.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"0e7849de-b939-4c50-ab48-fc6b0f5eeba2","","BuiltIn","Azure Databricks","Azure Databricks Workspaces should disable public network access","Disabling public network access improves security by ensuring that the resource isn't exposed on the public internet. You can control exposure of your resources by creating private endpoints instead. Learn more at: https://learn.microsoft.com/azure/databricks/administration-guide/cloud-configurations/azure/private-link. ","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"258823f2-4595-4b52-b333-cc96192710d8","","BuiltIn","Azure Databricks","Azure Databricks Workspaces should use private link","Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Databricks workspaces, you can reduce data leakage risks. Learn more about private links at: https://aka.ms/adbpe.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"138ff14d-b687-4faa-a81c-898c91a87fa2","","BuiltIn","Azure Databricks","Resource logs in Azure Databricks Workspaces should be enabled","Resource logs enable recreating activity trails to use for investigation purposes when a security incident occurs or when your network is compromised.","Azure_Security_Benchmark_v3.0_LT-3","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"b4ac1030-89c5-4697-8e00-28b5ba6a8811","","BuiltIn","Azure Stack Edge","Azure Stack Edge devices should use double-encryption","To secure the data at rest on the device, ensure it's double-encrypted, the access to data is controlled, and once the device is deactivated, the data is securely erased off the data disks. Double encryption is the use of two layers of encryption: BitLocker XTS-AES 256-bit encryption on the data volumes and built-in encryption of the hard drives. Learn more in the security overview documentation for the specific Stack Edge device.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: audit (default: effect-b4ac1030-89c5-4697-8e00-28b5ba6a8811)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"bd876905-5b84-4f73-ab2d-2e7a7c4568d9","","BuiltIn","Azure Update Manager","Machines should be configured to periodically check for missing system updates","To ensure periodic assessments for missing system updates are triggered automatically every 24 hours, the AssessmentMode property should be set to 'AutomaticByPlatform'. Learn more about AssessmentMode property for Windows: https://aka.ms/computevm-windowspatchassessmentmode, for Linux: https://aka.ms/computevm-linuxpatchassessmentmode.","Azure_Security_Benchmark_v3.0_PV-6","ASB: Audit (default: systemUpdatesAutoAssessmentModeEffect)","parameter: + Audit, + Disabled","Audit","Audit","","" +"2e94d99a-8a36-4563-bc77-810d8893b671","","BuiltIn","Backup","[Preview]: Azure Recovery Services vaults should use customer-managed keys for encrypting backup data","Use customer-managed keys to manage the encryption at rest of your backup data. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/AB-CmkEncryption.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-2e94d99a-8a36-4563-bc77-810d8893b671)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""enableDoubleEncryption-2e94d99a-8a36-4563-bc77-810d8893b671"":true}","{""enableDoubleEncryption-2e94d99a-8a36-4563-bc77-810d8893b671"":true}" +"013e242c-8828-4970-87b3-ab247555486d","","BuiltIn","Backup","Azure Backup should be enabled for Virtual Machines","Ensure protection of your Azure Virtual Machines by enabling Azure Backup. Azure Backup is a secure and cost effective data protection solution for Azure.","Azure_Security_Benchmark_v3.0_BR-1, +Azure_Security_Benchmark_v3.0_BR-2, +NIST_SP_800-53_R5_CP-9","ASB: AuditIfNotExists (default: azureBackupShouldBeEnabledForVirtualMachinesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"99e9ccd8-3db9-4592-b0d1-14b1715a4d8a","","BuiltIn","Batch","Azure Batch account should use customer-managed keys to encrypt data","Use customer-managed keys to manage the encryption at rest of your Batch account's data. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/Batch-CMK.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-99e9ccd8-3db9-4592-b0d1-14b1715a4d8a)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"428256e6-1fac-4f48-a757-df34c2b3336d","","BuiltIn","Batch","Resource logs in Batch accounts should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInBatchAccountMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInBatchAccountRetentionDays"":""1""}","{""diagnosticsLogsInBatchAccountRetentionDays"":""1""}" +"51522a96-0869-4791-82f3-981000c2c67f","","BuiltIn","Bot Service","Bot Service should be encrypted with a customer-managed key","Azure Bot Service automatically encrypts your resource to protect your data and meet organizational security and compliance commitments. By default, Microsoft-managed encryption keys are used. For greater flexibility in managing keys or controlling access to your subscription, select customer-managed keys, also known as bring your own key (BYOK). Learn more about Azure Bot Service encryption: https://docs.microsoft.com/azure/bot-service/bot-service-encryption.","NIST_SP_800-53_R5_SC-12","NIST-800-53: audit (default: effect-51522a96-0869-4791-82f3-981000c2c67f)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"7803067c-7d34-46e3-8c79-0ca68fc4036d","","BuiltIn","Cache","Azure Cache for Redis should use private link","Private endpoints lets you connect your virtual network to Azure services without a public IP address at the source or destination. By mapping private endpoints to your Azure Cache for Redis instances, data leakage risks are reduced. Learn more at: https://docs.microsoft.com/azure/azure-cache-for-redis/cache-private-link.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: azureCacheForRedisShouldUsePrivateEndpointMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"22bee202-a82f-4305-9a2a-6d7f44d4dedb","","BuiltIn","Cache","Only secure connections to your Azure Cache for Redis should be enabled","Audit enabling of only connections via SSL to Azure Cache for Redis. Use of secure connections ensures authentication between the server and the service and protects data in transit from network layer attacks such as man-in-the-middle, eavesdropping, and session-hijacking","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (default: diagnosticsLogsInRedisCacheMonitoringEffect), +NIST-800-53: Audit (default: effect-22bee202-a82f-4305-9a2a-6d7f44d4dedb)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"0725b4dd-7e76-479c-a735-68e7ee23d5ca","","BuiltIn","Cognitive Services","Cognitive Services accounts should disable public network access","To improve the security of Cognitive Services accounts, ensure that it isn't exposed to the public internet and can only be accessed from a private endpoint. Disable the public network access property as described in https://go.microsoft.com/fwlink/?linkid=2129800. This option disables access from any public address space outside the Azure IP range, and denies all logins that match IP or virtual network-based firewall rules. This reduces data leakage risks.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: publicNetworkAccessShouldBeDisabledForCognitiveServicesAccountsMonitoringEffect), +NIST-800-53: Audit (default: effect-0725b4dd-7e76-479c-a735-68e7ee23d5ca)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"67121cc7-ff39-4ab8-b7e3-95b84dab487d","","BuiltIn","Cognitive Services","Cognitive Services accounts should enable data encryption with a customer-managed key","Customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data stored in Cognitive Services to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more about customer-managed keys at https://go.microsoft.com/fwlink/?linkid=2121321.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: cognitiveServicesAccountsShouldEnableDataEncryptionWithACustomerManagedKeyMonitoringEffect), +NIST-800-53: Audit (default: effect-67121cc7-ff39-4ab8-b7e3-95b84dab487d)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"cddd188c-4b82-4c48-a19d-ddf74ee66a01","","BuiltIn","Cognitive Services","Cognitive Services should use private link","Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Cognitive Services, you'll reduce the potential for data leakage. Learn more about private links at: https://go.microsoft.com/fwlink/?linkid=2129800.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (Policy Default), +NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"0015ea4d-51ff-4ce3-8d8c-f3f8f0179a56","","BuiltIn","Compute","Audit virtual machines without disaster recovery configured","Audit virtual machines which do not have disaster recovery configured. To learn more about disaster recovery, visit https://aka.ms/asr-doc.","NIST_SP_800-53_R5_CP-7","NIST-800-53: auditIfNotExists (Policy Fixed)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"f39f5f49-4abf-44de-8c70-0756997bfb51","","BuiltIn","Compute","Disk access resources should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to diskAccesses, data leakage risks are reduced. Learn more about private links at: https://aka.ms/disksprivatelinksdoc. ","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"ca91455f-eace-4f96-be59-e6e2c35b4816","","BuiltIn","Compute","Managed disks should be double encrypted with both platform-managed and customer-managed keys","High security sensitive customers who are concerned of the risk associated with any particular encryption algorithm, implementation, or key being compromised can opt for additional layer of encryption using a different encryption algorithm/mode at the infrastructure layer using platform managed encryption keys. The disk encryption sets are required to use double encryption. Learn more at https://aka.ms/disks-doubleEncryption.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-ca91455f-eace-4f96-be59-e6e2c35b4816)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"702dd420-7fcc-42c5-afe8-4026edd20fe0","","BuiltIn","Compute","OS and data disks should be encrypted with a customer-managed key","Use customer-managed keys to manage the encryption at rest of the contents of your managed disks. By default, the data is encrypted at rest with platform-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/disks-cmk.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-702dd420-7fcc-42c5-afe8-4026edd20fe0)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"fc4d8e41-e223-45ea-9bf5-eada37891d87","","BuiltIn","Compute","Virtual machines and virtual machine scale sets should have encryption at host enabled","Use encryption at host to get end-to-end encryption for your virtual machine and virtual machine scale set data. Encryption at host enables encryption at rest for your temporary disk and OS/data disk caches. Temporary and ephemeral OS disks are encrypted with platform-managed keys when encryption at host is enabled. OS/data disk caches are encrypted at rest with either customer-managed or platform-managed key, depending on the encryption type selected on the disk. Learn more at https://aka.ms/vm-hbe.","Azure_Security_Benchmark_v3.0_DP-4, +NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","ASB: Audit (Policy Default), +NIST-800-53: Audit (default: effect-fc4d8e41-e223-45ea-9bf5-eada37891d87)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1d84d5fb-01f6-4d12-ba4f-4a26081d403d","","BuiltIn","Compute","Virtual machines should be migrated to new Azure Resource Manager resources","Use new Azure Resource Manager for your virtual machines to provide security enhancements such as: stronger access control (RBAC), better auditing, Azure Resource Manager based deployment and governance, access to managed identities, access to key vault for secrets, Azure AD-based authentication and support for tags and resource groups for easier security management","Azure_Security_Benchmark_v3.0_AM-2, +NIST_SP_800-53_R5_AC-3","ASB: Audit (default: classicComputeVMsMonitoringEffect), +NIST-800-53: Audit (default: effect-1d84d5fb-01f6-4d12-ba4f-4a26081d403d)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"0aa61e00-0a01-4a3c-9945-e93cffedf0e6","","BuiltIn","Container Instance","Azure Container Instance container group should use customer-managed key for encryption","Secure your containers with greater flexibility using customer-managed keys. When you specify a customer-managed key, that key is used to protect and control access to the key that encrypts your data. Using customer-managed keys provides additional capabilities to control rotation of the key encryption key or cryptographically erase data.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-0aa61e00-0a01-4a3c-9945-e93cffedf0e6)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"5b9159ae-1701-4a6f-9a7a-aa9c8ddd0580","","BuiltIn","Container Registry","Container registries should be encrypted with a customer-managed key","Use customer-managed keys to manage the encryption at rest of the contents of your registries. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/acr/CMK.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: containerRegistriesShouldBeEncryptedWithACustomerManagedKeyMonitoringEffect), +NIST-800-53: Audit (default: effect-5b9159ae-1701-4a6f-9a7a-aa9c8ddd0580)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"d0793b48-0edc-4296-a390-4c75d1bdfd71","","BuiltIn","Container Registry","Container registries should not allow unrestricted network access","Azure container registries by default accept connections over the internet from hosts on any network. To protect your registries from potential threats, allow access from only specific private endpoints, public IP addresses or address ranges. If your registry doesn't have network rules configured, it will appear in the unhealthy resources. Learn more about Container Registry network rules here: https://aka.ms/acr/privatelink, https://aka.ms/acr/portal/public-network and https://aka.ms/acr/vnet.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: containerRegistriesShouldNotAllowUnrestrictedNetworkAccessMonitoringEffect), +NIST-800-53: Audit (default: effect-d0793b48-0edc-4296-a390-4c75d1bdfd71)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"e8eef0a8-67cf-4eb4-9386-14b0e78733d4","","BuiltIn","Container Registry","Container registries should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network.By mapping private endpoints to your container registries instead of the entire service, you'll also be protected against data leakage risks. Learn more at: https://aka.ms/acr/private-link.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: containerRegistriesShouldUsePrivateLinkMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"862e97cf-49fc-4a5c-9de4-40d4e2e7c8eb","","BuiltIn","Cosmos DB","Azure Cosmos DB accounts should have firewall rules","Firewall rules should be defined on your Azure Cosmos DB accounts to prevent traffic from unauthorized sources. Accounts that have at least one IP rule defined with the virtual network filter enabled are deemed compliant. Accounts disabling public access are also deemed compliant.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: azureCosmosDBAccountsShouldHaveFirewallRulesMonitoringEffect), +NIST-800-53: Audit (default: effect-862e97cf-49fc-4a5c-9de4-40d4e2e7c8eb)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1f905d99-2ab7-462c-a6b0-f709acca6c8f","","BuiltIn","Cosmos DB","Azure Cosmos DB accounts should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your Azure Cosmos DB. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/cosmosdb-cmk.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: disabled (default: azureCosmosDbAccountsShouldUseCustomerManagedKeysToEncryptDataAtRestMonitoringEffect), +NIST-800-53: audit (default: effect-1f905d99-2ab7-462c-a6b0-f709acca6c8f)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"797b37f7-06b8-444c-b1ad-fc62867f335a","","BuiltIn","Cosmos DB","Azure Cosmos DB should disable public network access","Disabling public network access improves security by ensuring that your CosmosDB account isn't exposed on the public internet. Creating private endpoints can limit exposure of your CosmosDB account. Learn more at: https://docs.microsoft.com/azure/cosmos-db/how-to-configure-private-endpoints#blocking-public-network-access-during-account-creation.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"5450f5bd-9c72-4390-a9c4-a7aba4edfdd2","","BuiltIn","Cosmos DB","Cosmos DB database accounts should have local authentication methods disabled","Disabling local authentication methods improves security by ensuring that Cosmos DB database accounts exclusively require Azure Active Directory identities for authentication. Learn more at: https://docs.microsoft.com/azure/cosmos-db/how-to-setup-rbac#disable-local-auth.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (default: azureCosmosDbAccountsShouldHaveLocalAuthenticationMethodsDisabledMonitoringEffect)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"58440f8a-10c5-4151-bdce-dfbaad4a20b7","","BuiltIn","Cosmos DB","CosmosDB accounts should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your CosmosDB account, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/cosmos-db/how-to-configure-private-endpoints.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (Policy Default), +NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"c349d81b-9985-44ae-a8da-ff98d108ede8","","BuiltIn","Data Box","Azure Data Box jobs should enable double encryption for data at rest on the device","Enable a second layer of software-based encryption for data at rest on the device. The device is already protected via Advanced Encryption Standard 256-bit encryption for data at rest. This option adds a second layer of data encryption.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (default: effect-c349d81b-9985-44ae-a8da-ff98d108ede8)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""supportedSKUs-c349d81b-9985-44ae-a8da-ff98d108ede8"":[""DataBox"",""DataBoxHeavy""]}","{""supportedSKUs-c349d81b-9985-44ae-a8da-ff98d108ede8"":[""DataBox"",""DataBoxHeavy""]}" +"86efb160-8de7-451d-bc08-5d475b0aadae","","BuiltIn","Data Box","Azure Data Box jobs should use a customer-managed key to encrypt the device unlock password","Use a customer-managed key to control the encryption of the device unlock password for Azure Data Box. Customer-managed keys also help manage access to the device unlock password by the Data Box service in order to prepare the device and copy data in an automated manner. The data on the device itself is already encrypted at rest with Advanced Encryption Standard 256-bit encryption, and the device unlock password is encrypted by default with a Microsoft managed key.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-86efb160-8de7-451d-bc08-5d475b0aadae)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""supportedSKUs-86efb160-8de7-451d-bc08-5d475b0aadae"":[""DataBox"",""DataBoxHeavy""]}","{""supportedSKUs-86efb160-8de7-451d-bc08-5d475b0aadae"":[""DataBox"",""DataBoxHeavy""]}" +"4ec52d6d-beb7-40c4-9a9e-fe753254690e","","BuiltIn","Data Factory","Azure data factories should be encrypted with a customer-managed key","Use customer-managed keys to manage the encryption at rest of your Azure Data Factory. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/adf-cmk.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-4ec52d6d-beb7-40c4-9a9e-fe753254690e)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"8b0323be-cc25-4b61-935d-002c3798c6ea","","BuiltIn","Data Factory","Azure Data Factory should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Data Factory, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/data-factory/data-factory-private-link.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"057ef27e-665e-4328-8ea3-04b3122bd9fb","","BuiltIn","Data Lake","Resource logs in Azure Data Lake Store should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInDataLakeStoreMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInDataLakeStoreRetentionDays"":""1""}","{""diagnosticsLogsInDataLakeStoreRetentionDays"":""1""}" +"c95c74d9-38fe-4f0d-af86-0c7d626a315c","","BuiltIn","Data Lake","Resource logs in Data Lake Analytics should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInDataLakeAnalyticsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInDataLakeAnalyticsRetentionDays"":""1""}","{""diagnosticsLogsInDataLakeAnalyticsRetentionDays"":""1""}" +"9830b652-8523-49cc-b1b3-e17dce1127ca","","BuiltIn","Event Grid","Azure Event Grid domains should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Event Grid domain instead of the entire service, you'll also be protected against data leakage risks. Learn more at: https://aka.ms/privateendpoints.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: azureEventGridDomainsShouldUsePrivateLinkMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"4b90e17e-8448-49db-875e-bd83fb6f804f","","BuiltIn","Event Grid","Azure Event Grid topics should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Event Grid topic instead of the entire service, you'll also be protected against data leakage risks. Learn more at: https://aka.ms/privateendpoints.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: azureEventGridTopicsShouldUsePrivateLinkMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"a1ad735a-e96f-45d2-a7b2-9a4932cab7ec","","BuiltIn","Event Hub","Event Hub namespaces should use a customer-managed key for encryption","Azure Event Hubs supports the option of encrypting data at rest with either Microsoft-managed keys (default) or customer-managed keys. Choosing to encrypt data using customer-managed keys enables you to assign, rotate, disable, and revoke access to the keys that Event Hub will use to encrypt data in your namespace. Note that Event Hub only supports encryption with customer-managed keys for namespaces in dedicated clusters.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"b8564268-eb4a-4337-89be-a19db070c59d","","BuiltIn","Event Hub","Event Hub namespaces should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Event Hub namespaces, data leakage risks are reduced. Learn more at: https://docs.microsoft.com/azure/event-hubs/private-link-service.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"83a214f7-d01a-484b-91a9-ed54470c9a6a","","BuiltIn","Event Hub","Resource logs in Event Hub should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInEventHubMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInEventHubRetentionDays"":""1""}","{""diagnosticsLogsInEventHubRetentionDays"":""1""}" +"a451c1ef-c6ca-483d-87ed-f49761e3ffb5","","BuiltIn","General","Audit usage of custom RBAC roles","Audit built-in roles such as 'Owner, Contributer, Reader' instead of custom RBAC roles, which are error prone. Using custom roles is treated as an exception and requires a rigorous review and threat modeling","Azure_Security_Benchmark_v3.0_PA-7, +NIST_SP_800-53_R5_AC-2, +NIST_SP_800-53_R5_AC-2(7), +NIST_SP_800-53_R5_AC-6, +NIST_SP_800-53_R5_AC-6(7)","ASB: Audit (default: useRbacRulesMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"ca88aadc-6e2b-416c-9de2-5a0f01d1693f","","BuiltIn","Guest Configuration","[Preview]: Linux virtual machines should enable Azure Disk Encryption or EncryptionAtHost.","By default, a virtual machine's OS and data disks are encrypted-at-rest using platform-managed keys; temp disks and data caches aren't encrypted, and data isn't encrypted when flowing between compute and storage resources. Use Azure Disk Encryption or EncryptionAtHost to encrypt all this data.Visit https://aka.ms/diskencryptioncomparison to compare encryption offerings. This policy requires two prerequisites to be deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol.","Azure_Security_Benchmark_v3.0_DP-4","ASB: AuditIfNotExists (default: gcLinuxDiskEncryptionMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"3dc5edcd-002d-444c-b216-e123bbfa37c0","","BuiltIn","Guest Configuration","[Preview]: Windows virtual machines should enable Azure Disk Encryption or EncryptionAtHost.","By default, a virtual machine's OS and data disks are encrypted-at-rest using platform-managed keys; temp disks and data caches aren't encrypted, and data isn't encrypted when flowing between compute and storage resources. Use Azure Disk Encryption or EncryptionAtHost to encrypt all this data.Visit https://aka.ms/diskencryptioncomparison to compare encryption offerings. This policy requires two prerequisites to be deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol.","Azure_Security_Benchmark_v3.0_DP-4","ASB: AuditIfNotExists (default: gcWindowsDiskEncryptionMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"3cf2ab00-13f1-4d0c-8971-2ac904541a7e","","BuiltIn","Guest Configuration","Add system-assigned managed identity to enable Guest Configuration assignments on virtual machines with no identities","This policy adds a system-assigned managed identity to virtual machines hosted in Azure that are supported by Guest Configuration but do not have any managed identities. A system-assigned managed identity is a prerequisite for all Guest Configuration assignments and must be added to machines before using any Guest Configuration policy definitions. For more information on Guest Configuration, visit https://aka.ms/gcpol.","NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_IA-5, +NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: modify (Policy Fixed)","override: + Modify, + Audit, + Disabled","Modify","Modify","","" +"497dff13-db2a-4c0f-8603-28fa3b331ab6","","BuiltIn","Guest Configuration","Add system-assigned managed identity to enable Guest Configuration assignments on VMs with a user-assigned identity","This policy adds a system-assigned managed identity to virtual machines hosted in Azure that are supported by Guest Configuration and have at least one user-assigned identity but do not have a system-assigned managed identity. A system-assigned managed identity is a prerequisite for all Guest Configuration assignments and must be added to machines before using any Guest Configuration policy definitions. For more information on Guest Configuration, visit https://aka.ms/gcpol.","NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_IA-5, +NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: modify (Policy Fixed)","override: + Modify, + Audit, + Disabled","Modify","Modify","","" +"ea53dbee-c6c9-4f0e-9f9e-de0039b78023","","BuiltIn","Guest Configuration","Audit Linux machines that allow remote connections from accounts without passwords","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Linux machines that allow remote connections from accounts without passwords","NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"e6955644-301c-44b5-a4c4-528577de6861","","BuiltIn","Guest Configuration","Audit Linux machines that do not have the passwd file permissions set to 0644","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Linux machines that do not have the passwd file permissions set to 0644","NIST_SP_800-53_R5_IA-5, +NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"f6ec09a3-78bf-4f8f-99dc-6c77182d0f99","","BuiltIn","Guest Configuration","Audit Linux machines that have accounts without passwords","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Linux machines that have accounts without passwords","NIST_SP_800-53_R5_AC-3","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"5b054a0d-39e2-4d53-bea3-9734cad2c69b","","BuiltIn","Guest Configuration","Audit Windows machines that allow re-use of the passwords after the specified number of unique passwords","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that allow re-use of the passwords after the specified number of unique passwords. Default value for unique passwords is 24","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"4ceb8dc2-559c-478b-a15b-733fbf1e3738","","BuiltIn","Guest Configuration","Audit Windows machines that do not have the maximum password age set to specified number of days","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not have the maximum password age set to specified number of days. Default value for maximum password age is 70 days","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"237b38db-ca4d-4259-9e47-7882441ca2c0","","BuiltIn","Guest Configuration","Audit Windows machines that do not have the minimum password age set to specified number of days","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not have the minimum password age set to specified number of days. Default value for minimum password age is 1 day","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"bf16e0bb-31e1-4646-8202-60a235cc7e74","","BuiltIn","Guest Configuration","Audit Windows machines that do not have the password complexity setting enabled","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not have the password complexity setting enabled","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"a2d0e922-65d0-40c4-8f87-ea6da2d307a2","","BuiltIn","Guest Configuration","Audit Windows machines that do not restrict the minimum password length to specified number of characters","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not restrict the minimum password length to specified number of characters. Default value for minimum password length is 14 characters","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"da0f98fe-a24b-4ad5-af69-bd0400233661","","BuiltIn","Guest Configuration","Audit Windows machines that do not store passwords using reversible encryption","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not store passwords using reversible encryption","NIST_SP_800-53_R5_IA-5, +NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"630c64f9-8b6b-4c64-b511-6544ceff6fd6","","BuiltIn","Guest Configuration","Authentication to Linux machines should require SSH keys","Although SSH itself provides an encrypted connection, using passwords with SSH still leaves the VM vulnerable to brute-force attacks. The most secure option for authenticating to an Azure Linux virtual machine over SSH is with a public-private key pair, also known as SSH keys. Learn more: https://docs.microsoft.com/azure/virtual-machines/linux/create-ssh-keys-detailed.","Azure_Security_Benchmark_v3.0_IM-6, +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-5","ASB: AuditIfNotExists (default: authenticationToLinuxMachinesShouldRequireSSHKeysMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"331e8ea8-378a-410f-a2e5-ae22f38bb0da","","BuiltIn","Guest Configuration","Deploy the Linux Guest Configuration extension to enable Guest Configuration assignments on Linux VMs","This policy deploys the Linux Guest Configuration extension to Linux virtual machines hosted in Azure that are supported by Guest Configuration. The Linux Guest Configuration extension is a prerequisite for all Linux Guest Configuration assignments and must be deployed to machines before using any Linux Guest Configuration policy definition. For more information on Guest Configuration, visit https://aka.ms/gcpol.","NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_IA-5, +NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: deployIfNotExists (Policy Fixed)","override: + DeployIfNotExists, + AuditIfNotExists, + Disabled","DeployIfNotExists","DeployIfNotExists","","" +"385f5831-96d4-41db-9a3c-cd3af78aaae6","","BuiltIn","Guest Configuration","Deploy the Windows Guest Configuration extension to enable Guest Configuration assignments on Windows VMs","This policy deploys the Windows Guest Configuration extension to Windows virtual machines hosted in Azure that are supported by Guest Configuration. The Windows Guest Configuration extension is a prerequisite for all Windows Guest Configuration assignments and must be deployed to machines before using any Windows Guest Configuration policy definition. For more information on Guest Configuration, visit https://aka.ms/gcpol.","NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_IA-5, +NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: deployIfNotExists (Policy Fixed)","override: + DeployIfNotExists, + AuditIfNotExists, + Disabled","DeployIfNotExists","DeployIfNotExists","","" +"1e7fed80-8321-4605-b42c-65fc300f23a3","","BuiltIn","Guest Configuration","Linux machines should have Log Analytics agent installed on Azure Arc","Machines are non-compliant if Log Analytics agent is not installed on Azure Arc enabled Linux server.","Azure_Security_Benchmark_v3.0_LT-5","ASB: AuditIfNotExists (default: ArcLinuxMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"fc9b3da7-8347-4380-8e70-0a0361d8dedd","","BuiltIn","Guest Configuration","Linux machines should meet requirements for the Azure compute security baseline","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if the machine is not configured correctly for one of the recommendations in the Azure compute security baseline.","Azure_Security_Benchmark_v3.0_PV-4, +NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (default: linuxGuestConfigBaselinesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"bed48b13-6647-468e-aa2f-1af1d3f4dd40","","BuiltIn","Guest Configuration","Windows Defender Exploit Guard should be enabled on your machines","Windows Defender Exploit Guard uses the Azure Policy Guest Configuration agent. Exploit Guard has four components that are designed to lock down devices against a wide variety of attack vectors and block behaviors commonly used in malware attacks while enabling enterprises to balance their security risk and productivity requirements (Windows only).","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_ES-2, +NIST_SP_800-53_R5_SC-3, +NIST_SP_800-53_R5_SI-3, +NIST_SP_800-53_R5_SI-16","ASB: AuditIfNotExists (default: windowsDefenderExploitGuardMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsIncludeArcMachines"":""true"",""NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40"":""Compliant""}","{""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsIncludeArcMachines"":""true"",""NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40"":""Compliant""}" +"5752e6d6-1206-46d8-8ab1-ecc2f71a8112","","BuiltIn","Guest Configuration","Windows machines should be configured to use secure communication protocols","To protect the privacy of information communicated over the Internet, your machines should use the latest version of the industry-standard cryptographic protocol, Transport Layer Security (TLS). TLS secures communications over a network by encrypting a connection between machines.","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (default: windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""MinimumTLSVersion-5752e6d6-1206-46d8-8ab1-ecc2f71a8112"":""1.2"",""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsMinimumTLSVersion"":""1.2""}","{""MinimumTLSVersion-5752e6d6-1206-46d8-8ab1-ecc2f71a8112"":""1.2"",""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsMinimumTLSVersion"":""1.2""}" +"4078e558-bda6-41fb-9b3c-361e8875200d","","BuiltIn","Guest Configuration","Windows machines should have Log Analytics agent installed on Azure Arc","Machines are non-compliant if Log Analytics agent is not installed on Azure Arc enabled windows server.","Azure_Security_Benchmark_v3.0_LT-5","ASB: AuditIfNotExists (default: ArcWindowsMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"72650e9f-97bc-4b2a-ab5f-9781a9fcecbc","","BuiltIn","Guest Configuration","Windows machines should meet requirements of the Azure compute security baseline","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if the machine is not configured correctly for one of the recommendations in the Azure compute security baseline.","Azure_Security_Benchmark_v3.0_PV-4, +NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (default: windowsGuestConfigBaselinesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""IncludeArcMachines"":""false""}","{""IncludeArcMachines"":""false""}" +"64d314f6-6062-4780-a861-c23e8951bee5","","BuiltIn","HDInsight","Azure HDInsight clusters should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your Azure HDInsight clusters. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/hdi.cmk.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-64d314f6-6062-4780-a861-c23e8951bee5)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1fd32ebd-e4c3-4e13-a54a-d7422d4d95f6","","BuiltIn","HDInsight","Azure HDInsight clusters should use encryption at host to encrypt data at rest","Enabling encryption at host helps protect and safeguard your data to meet your organizational security and compliance commitments. When you enable encryption at host, data stored on the VM host is encrypted at rest and flows encrypted to the Storage service.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-1fd32ebd-e4c3-4e13-a54a-d7422d4d95f6)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"d9da03a1-f3c3-412a-9709-947156872263","","BuiltIn","HDInsight","Azure HDInsight clusters should use encryption in transit to encrypt communication between Azure HDInsight cluster nodes","Data can be tampered with during transmission between Azure HDInsight cluster nodes. Enabling encryption in transit addresses problems of misuse and tampering during this transmission.","NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","NIST-800-53: Audit (default: effect-d9da03a1-f3c3-412a-9709-947156872263)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"47031206-ce96-41f8-861b-6a915f3de284","","BuiltIn","Internet of Things","[Preview]: IoT Hub device provisioning service data should be encrypted using customer-managed keys (CMK)","Use customer-managed keys to manage the encryption at rest of your IoT Hub device provisioning service. The data is automatically encrypted at rest with service-managed keys, but customer-managed keys (CMK) are commonly required to meet regulatory compliance standards. CMKs enable the data to be encrypted with an Azure Key Vault key created and owned by you. Learn more about CMK encryption at https://aka.ms/dps/CMK.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-47031206-ce96-41f8-861b-6a915f3de284)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"df39c015-56a4-45de-b4a3-efe77bed320d","","BuiltIn","Internet of Things","IoT Hub device provisioning service instances should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to the IoT Hub device provisioning service, data leakage risks are reduced. Learn more about private links at: https://aka.ms/iotdpsvnet.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"383856f8-de7f-44a2-81fc-e5135b5c2aa4","","BuiltIn","Internet of Things","Resource logs in IoT Hub should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInIoTHubMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInIoTHubRetentionDays"":""1"",""requiredRetentionDays"":""365""}","{""diagnosticsLogsInIoTHubRetentionDays"":""1"",""requiredRetentionDays"":""365""}" +"55615ac9-af46-4a59-874e-391cc3dfb490","","BuiltIn","Key Vault","Azure Key Vault should have firewall enabled","Enable the key vault firewall so that the key vault is not accessible by default to any public IPs. Optionally, you can configure specific IP ranges to limit access to those networks. Learn more at: https://docs.microsoft.com/azure/key-vault/general/network-security","Azure_Security_Benchmark_v3.0_NS-2, +Azure_Security_Benchmark_v3.0_DP-8, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: firewallShouldBeEnabledOnKeyVaultMonitoringEffect), +NIST-800-53: Audit (default: effect-55615ac9-af46-4a59-874e-391cc3dfb490)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"a6abeaec-4d90-4a02-805f-6b26c4d3fbe9","","BuiltIn","Key Vault","Azure Key Vaults should use private link","Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to key vault, you can reduce data leakage risks. Learn more about private links at: https://aka.ms/akvprivatelink.","Azure_Security_Benchmark_v3.0_NS-2, +Azure_Security_Benchmark_v3.0_DP-8, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: privateEndpointShouldBeConfiguredForKeyVaultMonitoringEffect), +NIST-800-53: Audit (default: effect-a6abeaec-4d90-4a02-805f-6b26c4d3fbe9)","parameter: + Audit, + Disabled","Audit","Audit","","" +"0a075868-4c26-42ef-914c-5bc007359560","","BuiltIn","Key Vault","Certificates should have the specified maximum validity period","Manage your organizational compliance requirements by specifying the maximum amount of time that a certificate can be valid within your key vault.","Azure_Security_Benchmark_v3.0_DP-7, +NIST_SP_800-53_R5_IA-5","ASB: disabled (default: certificatesValidityPeriodMonitoringEffect), +NIST-800-53: audit (default: effect-0a075868-4c26-42ef-914c-5bc007359560)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","{""maximumValidityInMonths-0a075868-4c26-42ef-914c-5bc007359560"":12,""certificatesValidityPeriodInMonths"":12}","{""maximumValidityInMonths-0a075868-4c26-42ef-914c-5bc007359560"":12,""certificatesValidityPeriodInMonths"":12}" +"152b15f7-8e1f-4c1f-ab71-8c010ba5dbc0","","BuiltIn","Key Vault","Key Vault keys should have an expiration date","Cryptographic keys should have a defined expiration date and not be permanent. Keys that are valid forever provide a potential attacker with more time to compromise the key. It is a recommended security practice to set expiration dates on cryptographic keys.","Azure_Security_Benchmark_v3.0_DP-6, +NIST_SP_800-53_R5_IA-5","ASB: Disabled (default: keysExpirationSetEffect), +NIST-800-53: Audit (default: effect-152b15f7-8e1f-4c1f-ab71-8c010ba5dbc0)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"98728c90-32c7-4049-8429-847dc0f4fe37","","BuiltIn","Key Vault","Key Vault secrets should have an expiration date","Secrets should have a defined expiration date and not be permanent. Secrets that are valid forever provide a potential attacker with more time to compromise them. It is a recommended security practice to set expiration dates on secrets.","Azure_Security_Benchmark_v3.0_DP-6, +NIST_SP_800-53_R5_IA-5","ASB: Disabled (default: secretsExpirationSetEffect), +NIST-800-53: Audit (default: effect-98728c90-32c7-4049-8429-847dc0f4fe37)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"0b60c0b2-2dc2-4e1c-b5c9-abbed971de53","","BuiltIn","Key Vault","Key vaults should have deletion protection enabled","Malicious deletion of a key vault can lead to permanent data loss. You can prevent permanent data loss by enabling purge protection and soft delete. Purge protection protects you from insider attacks by enforcing a mandatory retention period for soft deleted key vaults. No one inside your organization or Microsoft will be able to purge your key vaults during the soft delete retention period. Keep in mind that key vaults created after September 1st 2019 have soft-delete enabled by default.","Azure_Security_Benchmark_v3.0_DP-8, +NIST_SP_800-53_R5_CP-9","ASB: Audit (default: keyVaultsShouldHavePurgeProtectionEnabledMonitoringEffect), +NIST-800-53: Audit (default: effect-0b60c0b2-2dc2-4e1c-b5c9-abbed971de53)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1e66c121-a66a-4b1f-9b83-0fd99bf0fc2d","","BuiltIn","Key Vault","Key vaults should have soft delete enabled","Deleting a key vault without soft delete enabled permanently deletes all secrets, keys, and certificates stored in the key vault. Accidental deletion of a key vault can lead to permanent data loss. Soft delete allows you to recover an accidentally deleted key vault for a configurable retention period.","Azure_Security_Benchmark_v3.0_DP-8, +NIST_SP_800-53_R5_CP-9","ASB: Audit (default: keyVaultsShouldHaveSoftDeleteEnabledMonitoringEffect), +NIST-800-53: Audit (default: effect-1e66c121-a66a-4b1f-9b83-0fd99bf0fc2d)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"cf820ca0-f99e-4f3e-84fb-66e913812d21","","BuiltIn","Key Vault","Resource logs in Key Vault should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_DP-8, +Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInKeyVaultMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInKeyVaultRetentionDays"":""1""}","{""diagnosticsLogsInKeyVaultRetentionDays"":""1""}" +"8dfab9c4-fe7b-49ad-85e4-1e9be085358f","","BuiltIn","Kubernetes","[Preview]: Azure Arc enabled Kubernetes clusters should have Microsoft Defender for Cloud extension installed","Microsoft Defender for Cloud extension for Azure Arc provides threat protection for your Arc enabled Kubernetes clusters. The extension collects data from all nodes in the cluster and sends it to the Azure Defender for Kubernetes backend in the cloud for further analysis. Learn more in https://docs.microsoft.com/azure/defender-for-cloud/defender-for-containers-enable?pivots=defender-for-container-arc.","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: arcEnabledKubernetesClustersShouldHaveAzureDefendersExtensionInstalled), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"6b2122c1-8120-4ff5-801b-17625a355590","","BuiltIn","Kubernetes","Azure Arc enabled Kubernetes clusters should have the Azure Policy extension installed","The Azure Policy extension for Azure Arc provides at-scale enforcements and safeguards on your Arc enabled Kubernetes clusters in a centralized, consistent manner. Learn more at https://aka.ms/akspolicydoc.","Azure_Security_Benchmark_v3.0_PV-2","ASB: AuditIfNotExists (default: arcEnabledKubernetesClustersShouldHaveAzurePolicyExtensionInstalledEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"a1840de2-8088-4ea8-b153-b4c723e9cb01","","BuiltIn","Kubernetes","Azure Kubernetes Service clusters should have Defender profile enabled","Microsoft Defender for Containers provides cloud-native Kubernetes security capabilities including environment hardening, workload protection, and run-time protection. When you enable the SecurityProfile.AzureDefender on your Azure Kubernetes Service cluster, an agent is deployed to your cluster to collect security event data. Learn more about Microsoft Defender for Containers in https://docs.microsoft.com/azure/defender-for-cloud/defender-for-containers-introduction?tabs=defender-for-container-arch-aks","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2","ASB: Audit (default: azureKubernetesServiceClustersShouldHaveSecurityProfileEnabled)","parameter: + Audit, + Disabled","Audit","Audit","","" +"0a15ec92-a229-4763-bb14-0ea34a568f8d","","BuiltIn","Kubernetes","Azure Policy Add-on for Kubernetes service (AKS) should be installed and enabled on your clusters","Azure Policy Add-on for Kubernetes service (AKS) extends Gatekeeper v3, an admission controller webhook for Open Policy Agent (OPA), to apply at-scale enforcements and safeguards on your clusters in a centralized, consistent manner.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: azurePolicyAddonStatusEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"7d7be79c-23ba-4033-84dd-45e2a5ccdd67","","BuiltIn","Kubernetes","Both operating systems and data disks in Azure Kubernetes Service clusters should be encrypted by customer-managed keys","Encrypting OS and data disks using customer-managed keys provides more control and greater flexibility in key management. This is a common requirement in many regulatory and industry compliance standards.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-7d7be79c-23ba-4033-84dd-45e2a5ccdd67)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"e345eecc-fa47-480f-9e88-67dcc122b164","","BuiltIn","Kubernetes","Kubernetes cluster containers CPU and memory resource limits should not exceed the specified limits","Enforce container CPU and memory resource limits to prevent resource exhaustion attacks in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: memoryAndCPULimitsInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-e345eecc-fa47-480f-9e88-67dcc122b164)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""memoryLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0"",""cpuLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0"",""memoryInKubernetesClusterLimit"":""64Gi"",""memoryAndCPULimitsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""memoryAndCPULimitsInKubernetesClusterLabelSelector"":{},""CPUInKubernetesClusterLimit"":""32""}","{""memoryLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0"",""cpuLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0"",""memoryInKubernetesClusterLimit"":""64Gi"",""memoryAndCPULimitsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""memoryAndCPULimitsInKubernetesClusterLabelSelector"":{},""CPUInKubernetesClusterLimit"":""32""}" +"47a1ee2f-2a2a-4576-bf2a-e0e36709c2b8","","BuiltIn","Kubernetes","Kubernetes cluster containers should not share host process ID or host IPC namespace","Block pod containers from sharing the host process ID namespace and host IPC namespace in a Kubernetes cluster. This recommendation is part of CIS 5.2.2 and CIS 5.2.3 which are intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: NoSharingSensitiveHostNamespacesInKubernetesEffect), +NIST-800-53: audit (default: effect-47a1ee2f-2a2a-4576-bf2a-e0e36709c2b8)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""NoSharingSensitiveHostNamespacesInKubernetesLabelSelector"":{},""NoSharingSensitiveHostNamespacesInKubernetesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""NoSharingSensitiveHostNamespacesInKubernetesLabelSelector"":{},""NoSharingSensitiveHostNamespacesInKubernetesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}" +"511f5417-5d12-434d-ab2e-816901e72a5e","","BuiltIn","Kubernetes","Kubernetes cluster containers should only use allowed AppArmor profiles","Containers should only use allowed AppArmor profiles in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: AllowedAppArmorProfilesInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-511f5417-5d12-434d-ab2e-816901e72a5e)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""AllowedAppArmorProfilesInKubernetesClusterList"":[""runtime/default""],""AllowedAppArmorProfilesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedProfiles-511f5417-5d12-434d-ab2e-816901e72a5e"":[],""AllowedAppArmorProfilesInKubernetesClusterLabelSelector"":{}}","{""AllowedAppArmorProfilesInKubernetesClusterList"":[""runtime/default""],""AllowedAppArmorProfilesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedProfiles-511f5417-5d12-434d-ab2e-816901e72a5e"":[],""AllowedAppArmorProfilesInKubernetesClusterLabelSelector"":{}}" +"c26596ff-4d70-4e6a-9a30-c2506bd2f80c","","BuiltIn","Kubernetes","Kubernetes cluster containers should only use allowed capabilities","Restrict the capabilities to reduce the attack surface of containers in a Kubernetes cluster. This recommendation is part of CIS 5.2.8 and CIS 5.2.9 which are intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: AllowedCapabilitiesInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-c26596ff-4d70-4e6a-9a30-c2506bd2f80c)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""requiredDropCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""AllowedCapabilitiesInKubernetesClusterList"":[],""AllowedCapabilitiesInKubernetesClusterLabelSelector"":{},""allowedCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""DropCapabilitiesInKubernetesClusterList"":[],""AllowedCapabilitiesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""requiredDropCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""AllowedCapabilitiesInKubernetesClusterList"":[],""AllowedCapabilitiesInKubernetesClusterLabelSelector"":{},""allowedCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""DropCapabilitiesInKubernetesClusterList"":[],""AllowedCapabilitiesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}" +"febd0533-8e55-448f-b837-bd0e06f16469","","BuiltIn","Kubernetes","Kubernetes cluster containers should only use allowed images","Use images from trusted registries to reduce the Kubernetes cluster's exposure risk to unknown vulnerabilities, security issues and malicious images. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: allowedContainerImagesInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-febd0533-8e55-448f-b837-bd0e06f16469)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""allowedContainerImagesRegex-febd0533-8e55-448f-b837-bd0e06f16469"":""^(.+){0}$"",""namespaces"":[],""allowedContainerImagesLabelSelector"":{},""allowedContainerImagesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""labelSelector"":{},""excludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc""],""allowedContainerImagesInKubernetesClusterRegex"":""^(.+){0}$""}","{""allowedContainerImagesRegex-febd0533-8e55-448f-b837-bd0e06f16469"":""^(.+){0}$"",""namespaces"":[],""allowedContainerImagesLabelSelector"":{},""allowedContainerImagesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""labelSelector"":{},""excludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc""],""allowedContainerImagesInKubernetesClusterRegex"":""^(.+){0}$""}" +"df49d893-a74c-421d-bc95-c663042e5b80","","BuiltIn","Kubernetes","Kubernetes cluster containers should run with a read only root file system","Run containers with a read only root file system to protect from changes at run-time with malicious binaries being added to PATH in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: ReadOnlyRootFileSystemInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-df49d893-a74c-421d-bc95-c663042e5b80)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""ReadOnlyRootFileSystemInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""ReadOnlyRootFileSystemInKubernetesClusterLabelSelector"":{}}","{""ReadOnlyRootFileSystemInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""ReadOnlyRootFileSystemInKubernetesClusterLabelSelector"":{}}" +"098fc59e-46c7-4d99-9b16-64990e543d75","","BuiltIn","Kubernetes","Kubernetes cluster pod hostPath volumes should only use allowed host paths","Limit pod HostPath volume mounts to the allowed host paths in a Kubernetes Cluster. This policy is generally available for Kubernetes Service (AKS), and Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: AllowedHostPathVolumesInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-098fc59e-46c7-4d99-9b16-64990e543d75)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""AllowedHostPathVolumesInKubernetesClusterLabelSelector"":{},""allowedHostPaths-098fc59e-46c7-4d99-9b16-64990e543d75"":{""paths"":[]},""AllowedHostPathVolumesInKubernetesClusterList"":{""paths"":[]},""AllowedHostPathVolumesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""AllowedHostPathVolumesInKubernetesClusterLabelSelector"":{},""allowedHostPaths-098fc59e-46c7-4d99-9b16-64990e543d75"":{""paths"":[]},""AllowedHostPathVolumesInKubernetesClusterList"":{""paths"":[]},""AllowedHostPathVolumesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}" +"f06ddb64-5fa3-4b77-b166-acb36f7f6042","","BuiltIn","Kubernetes","Kubernetes cluster pods and containers should only run with approved user and group IDs","Control the user, primary group, supplemental group and file system group IDs that pods and containers can use to run in a Kubernetes Cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: MustRunAsNonRootNamespaceEffect), +NIST-800-53: audit (default: effect-f06ddb64-5fa3-4b77-b166-acb36f7f6042)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""fsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""MustRunAsNonRootNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""runAsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""runAsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""MustRunAsNonRootLabelSelector"":{},""runAsUserRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""runAsUserRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""MustRunAsNonRoot"",""supplementalGroupsRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""fsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""supplementalGroupsRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]}}","{""fsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""MustRunAsNonRootNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""runAsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""runAsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""MustRunAsNonRootLabelSelector"":{},""runAsUserRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""runAsUserRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""MustRunAsNonRoot"",""supplementalGroupsRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""fsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""supplementalGroupsRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]}}" +"82985f06-dc18-4a48-bc1c-b9f4f0098cfe","","BuiltIn","Kubernetes","Kubernetes cluster pods should only use approved host network and port range","Restrict pod access to the host network and the allowable host port range in a Kubernetes cluster. This recommendation is part of CIS 5.2.4 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: AllowedHostNetworkingAndPortsInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-82985f06-dc18-4a48-bc1c-b9f4f0098cfe)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""AllowHostNetworkingInKubernetesCluster"":false,""maxPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""minPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""allowHostNetwork-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":false,""AllowedHostNetworkingAndPortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""AllowedHostMaxPortInKubernetesCluster"":0,""AllowedHostNetworkingAndPortsInKubernetesClusterLabelSelector"":{},""AllowedHostMinPortInKubernetesCluster"":0}","{""AllowHostNetworkingInKubernetesCluster"":false,""maxPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""minPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""allowHostNetwork-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":false,""AllowedHostNetworkingAndPortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""AllowedHostMaxPortInKubernetesCluster"":0,""AllowedHostNetworkingAndPortsInKubernetesClusterLabelSelector"":{},""AllowedHostMinPortInKubernetesCluster"":0}" +"233a2a17-77ca-4fb1-9b6b-69223d272a44","","BuiltIn","Kubernetes","Kubernetes cluster services should listen only on allowed ports","Restrict services to listen only on allowed ports to secure access to the Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: allowedServicePortsInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-233a2a17-77ca-4fb1-9b6b-69223d272a44)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""allowedServicePortsInKubernetesClusterLabelSelector"":{},""allowedServicePortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""allowedservicePortsInKubernetesClusterPorts"":[""-1""],""allowedServicePortsList-233a2a17-77ca-4fb1-9b6b-69223d272a44"":[]}","{""allowedServicePortsInKubernetesClusterLabelSelector"":{},""allowedServicePortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""allowedservicePortsInKubernetesClusterPorts"":[""-1""],""allowedServicePortsList-233a2a17-77ca-4fb1-9b6b-69223d272a44"":[]}" +"95edb821-ddaf-4404-9732-666045e056b4","","BuiltIn","Kubernetes","Kubernetes cluster should not allow privileged containers","Do not allow privileged containers creation in a Kubernetes cluster. This recommendation is part of CIS 5.2.1 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: privilegedContainersShouldBeAvoidedEffect), +NIST-800-53: audit (default: effect-95edb821-ddaf-4404-9732-666045e056b4)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""excludedImagesInKubernetesCluster"":[],""privilegedContainerNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""excludedContainers-95edb821-ddaf-4404-9732-666045e056b4"":[],""privilegedContainerLabelSelector"":{}}","{""excludedImagesInKubernetesCluster"":[],""privilegedContainerNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""excludedContainers-95edb821-ddaf-4404-9732-666045e056b4"":[],""privilegedContainerLabelSelector"":{}}" +"1a5b4dca-0b6f-4cf5-907c-56316bc1bf3d","","BuiltIn","Kubernetes","Kubernetes clusters should be accessible only over HTTPS","Use of HTTPS ensures authentication and protects data in transit from network layer eavesdropping attacks. This capability is currently generally available for Kubernetes Service (AKS), and in preview for Azure Arc enabled Kubernetes. For more info, visit https://aka.ms/kubepolicydoc","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (default: kubernetesClustersShouldBeAccessibleOnlyOverHTTPSMonitoringEffect), +NIST-800-53: audit (default: effect-1a5b4dca-0b6f-4cf5-907c-56316bc1bf3d)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""kubernetesClustersShouldBeAccessibleOnlyOverHTTPSExcludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""kubernetesClustersShouldBeAccessibleOnlyOverHTTPSLabelSelector"":{}}","{""kubernetesClustersShouldBeAccessibleOnlyOverHTTPSExcludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""kubernetesClustersShouldBeAccessibleOnlyOverHTTPSLabelSelector"":{}}" +"423dd1ba-798e-40e4-9c4d-b6902674b423","","BuiltIn","Kubernetes","Kubernetes clusters should disable automounting API credentials","Disable automounting API credentials to prevent a potentially compromised Pod resource to run API commands against Kubernetes clusters. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (default: KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringEffect)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringLabelSelector"":{}}","{""KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringLabelSelector"":{}}" +"1c6e92c9-99f0-4e55-9cf2-0c234dc48f99","","BuiltIn","Kubernetes","Kubernetes clusters should not allow container privilege escalation","Do not allow containers to run with privilege escalation to root in a Kubernetes cluster. This recommendation is part of CIS 5.2.5 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, +NIST_SP_800-53_R5_CM-6","ASB: Audit (default: NoPrivilegeEscalationInKubernetesClusterEffect), +NIST-800-53: audit (default: effect-1c6e92c9-99f0-4e55-9cf2-0c234dc48f99)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""NoPrivilegeEscalationInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""NoPrivilegeEscalationInKubernetesClusterLabelSelector"":{}}","{""NoPrivilegeEscalationInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""],""NoPrivilegeEscalationInKubernetesClusterLabelSelector"":{}}" +"d2e7ea85-6b44-4317-a0be-1b951587f626","","BuiltIn","Kubernetes","Kubernetes clusters should not grant CAP_SYS_ADMIN security capabilities","To reduce the attack surface of your containers, restrict CAP_SYS_ADMIN Linux capabilities. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (default: KubernetesClustersShouldNotGrantCAPSYSADMINSecurityCapabilitiesMonitoringEffect)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""KubernetesClustersShouldNotGrantCAPSYSADMINSecurityCapabilitiesMonitoringLabelSelector"":{},""KubernetesClustersShouldNotGrantCAPSYSADMINSecurityCapabilitiesMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""KubernetesClustersShouldNotGrantCAPSYSADMINSecurityCapabilitiesMonitoringLabelSelector"":{},""KubernetesClustersShouldNotGrantCAPSYSADMINSecurityCapabilitiesMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}" +"9f061a12-e40d-4183-a00e-171812443373","","BuiltIn","Kubernetes","Kubernetes clusters should not use the default namespace","Prevent usage of the default namespace in Kubernetes clusters to protect against unauthorized access for ConfigMap, Pod, Secret, Service, and ServiceAccount resource types. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (default: KubernetesClustersShouldNotUseTheDefaultNamespaceMonitoringEffect)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","{""KubernetesClustersShouldNotUseTheDefaultNamespaceMonitoringLabelSelector"":{}}","{""KubernetesClustersShouldNotUseTheDefaultNamespaceMonitoringLabelSelector"":{}}" +"245fc9df-fa96-4414-9a0b-3738c2f7341c","","BuiltIn","Kubernetes","Resource logs in Azure Kubernetes Service should be enabled","Azure Kubernetes Service's resource logs can help recreate activity trails when investigating security incidents. Enable it to make sure the logs will exist when needed","Azure_Security_Benchmark_v3.0_LT-3","ASB: AuditIfNotExists (default: diagnosticsLogsInKubernetesMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInKubernetesRetentionDays"":""1""}","{""diagnosticsLogsInKubernetesRetentionDays"":""1""}" +"41425d9f-d1a5-499a-9932-f8ed8453932c","","BuiltIn","Kubernetes","Temp disks and cache for agent node pools in Azure Kubernetes Service clusters should be encrypted at host","To enhance data security, the data stored on the virtual machine (VM) host of your Azure Kubernetes Service nodes VMs should be encrypted at rest. This is a common requirement in many regulatory and industry compliance standards.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (default: effect-41425d9f-d1a5-499a-9932-f8ed8453932c)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1fafeaf6-7927-4059-a50a-8eb2a7a6f2b5","","BuiltIn","Logic Apps","Logic Apps Integration Service Environment should be encrypted with customer-managed keys","Deploy into Integration Service Environment to manage encryption at rest of Logic Apps data using customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-1fafeaf6-7927-4059-a50a-8eb2a7a6f2b5)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"34f95f76-5386-4de7-b824-0d8478470c9d","","BuiltIn","Logic Apps","Resource logs in Logic Apps should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInLogicAppsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInLogicAppsRetentionDays"":""1""}","{""diagnosticsLogsInLogicAppsRetentionDays"":""1""}" +"f110a506-2dcb-422e-bcea-d533fc8c35e2","","BuiltIn","Machine Learning","Azure Machine Learning compute instances should be recreated to get the latest software updates","Ensure Azure Machine Learning compute instances run on the latest available operating system. Security is improved and vulnerabilities reduced by running with the latest security patches. For more information, visit https://aka.ms/azureml-ci-updates/.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"7804b5c7-01dc-4723-969b-ae300cc07ff1","","BuiltIn","Machine Learning","Azure Machine Learning Computes should be in a virtual network","Azure Virtual Networks provide enhanced security and isolation for your Azure Machine Learning Compute Clusters and Instances, as well as subnets, access control policies, and other features to further restrict access. When a compute is configured with a virtual network, it is not publicly addressable and can only be accessed from virtual machines and applications within the virtual network.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"e96a9a5f-07ca-471b-9bc5-6a0f33cbd68f","","BuiltIn","Machine Learning","Azure Machine Learning Computes should have local authentication methods disabled","Disabling local authentication methods improves security by ensuring that Machine Learning Computes require Azure Active Directory identities exclusively for authentication. Learn more at: https://aka.ms/azure-ml-aad-policy.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"ba769a63-b8cc-4b2d-abf6-ac33c7204be8","","BuiltIn","Machine Learning","Azure Machine Learning workspaces should be encrypted with a customer-managed key","Manage encryption at rest of Azure Machine Learning workspace data with customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/azureml-workspaces-cmk.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: azureMachineLearningWorkspacesShouldBeEncryptedWithACustomerManagedKeyMonitoringEffect), +NIST-800-53: Audit (default: effect-ba769a63-b8cc-4b2d-abf6-ac33c7204be8)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"438c38d2-3772-465a-a9cc-7a6666a275ce","","BuiltIn","Machine Learning","Azure Machine Learning Workspaces should disable public network access","Disabling public network access improves security by ensuring that the Machine Learning Workspaces aren't exposed on the public internet. You can control exposure of your workspaces by creating private endpoints instead. Learn more at: https://learn.microsoft.com/azure/machine-learning/how-to-configure-private-link?view=azureml-api-2&tabs=azure-portal.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"45e05259-1eb5-4f70-9574-baf73e9d219b","","BuiltIn","Machine Learning","Azure Machine Learning workspaces should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Machine Learning workspaces, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/machine-learning/how-to-configure-private-link.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: azureMachineLearningWorkspacesShouldUsePrivateLinkMonitoringEffect), +NIST-800-53: Audit (default: effect-45e05259-1eb5-4f70-9574-baf73e9d219b)","parameter: + Audit, + Disabled","Audit","Audit","","" +"afe0c3be-ba3b-4544-ba52-0c99672a8ad6","","BuiltIn","Machine Learning","Resource logs in Azure Machine Learning Workspaces should be enabled","Resource logs enable recreating activity trails to use for investigation purposes when a security incident occurs or when your network is compromised.","Azure_Security_Benchmark_v3.0_LT-3","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"842c54e8-c2f9-4d79-ae8d-38d8b8019373","","BuiltIn","Monitoring","[Preview]: Log Analytics extension should be installed on your Linux Azure Arc machines","This policy audits Linux Azure Arc machines if the Log Analytics extension is not installed.","Azure_Security_Benchmark_v3.0_LT-5, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: ArcLinuxMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"d69b1763-b96d-40b8-a2d9-ca31e9fd0d3e","","BuiltIn","Monitoring","[Preview]: Log Analytics extension should be installed on your Windows Azure Arc machines","This policy audits Windows Azure Arc machines if the Log Analytics extension is not installed.","Azure_Security_Benchmark_v3.0_LT-5, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: ArcWindowsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"04c4380f-3fae-46e8-96c9-30193528f602","","BuiltIn","Monitoring","[Preview]: Network traffic data collection agent should be installed on Linux virtual machines","Security Center uses the Microsoft Dependency agent to collect network traffic data from your Azure virtual machines to enable advanced network protection features such as traffic visualization on the network map, network hardening recommendations and specific network threats.","Azure_Security_Benchmark_v3.0_LT-4, +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: ASCDependencyAgentAuditLinuxEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"2f2ee1de-44aa-4762-b6bd-0893fc3f306d","","BuiltIn","Monitoring","[Preview]: Network traffic data collection agent should be installed on Windows virtual machines","Security Center uses the Microsoft Dependency agent to collect network traffic data from your Azure virtual machines to enable advanced network protection features such as traffic visualization on the network map, network hardening recommendations and specific network threats.","Azure_Security_Benchmark_v3.0_LT-4, +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: ASCDependencyAgentAuditWindowsEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"ea0dfaed-95fb-448c-934e-d6e713ce393d","","BuiltIn","Monitoring","Azure Monitor Logs clusters should be created with infrastructure-encryption enabled (double encryption)","To ensure secure data encryption is enabled at the service level and the infrastructure level with two different encryption algorithms and two different keys, use an Azure Monitor dedicated cluster. This option is enabled by default when supported at the region, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys#customer-managed-key-overview.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: audit (default: effect-ea0dfaed-95fb-448c-934e-d6e713ce393d)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1f68a601-6e6d-4e42-babf-3f643a047ea2","","BuiltIn","Monitoring","Azure Monitor Logs clusters should be encrypted with customer-managed key","Create Azure Monitor logs cluster with customer-managed keys encryption. By default, the log data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance. Customer-managed key in Azure Monitor gives you more control over the access to you data, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys.","NIST_SP_800-53_R5_SC-12","NIST-800-53: audit (default: effect-1f68a601-6e6d-4e42-babf-3f643a047ea2)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"fa298e57-9444-42ba-bf04-86e8470e32c7","","BuiltIn","Monitoring","Saved-queries in Azure Monitor should be saved in customer storage account for logs encryption","Link storage account to Log Analytics workspace to protect saved-queries with storage account encryption. Customer-managed keys are commonly required to meet regulatory compliance and for more control over the access to your saved-queries in Azure Monitor. For more details on the above, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys?tabs=portal#customer-managed-key-for-saved-queries.","NIST_SP_800-53_R5_SC-12","NIST-800-53: audit (default: effect-fa298e57-9444-42ba-bf04-86e8470e32c7)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"fc5e4038-4584-4632-8c85-c0448d374b2c","","BuiltIn","Network","[Preview]: All Internet traffic should be routed via your deployed Azure Firewall","Azure Security Center has identified that some of your subnets aren't protected with a next generation firewall. Protect your subnets from potential threats by restricting access to them with Azure Firewall or a supported next generation firewall","Azure_Security_Benchmark_v3.0_NS-3, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: AzureFirewallEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"055aa869-bc98-4af8-bafc-23f1ab6ffe2c","","BuiltIn","Network","Azure Web Application Firewall should be enabled for Azure Front Door entry-points","Deploy Azure Web Application Firewall (WAF) in front of public facing web applications for additional inspection of incoming traffic. Web Application Firewall (WAF) provides centralized protection of your web applications from common exploits and vulnerabilities such as SQL injections, Cross-Site Scripting, local and remote file executions. You can also restrict access to your web applications by countries, IP address ranges, and other http(s) parameters via custom rules.","Azure_Security_Benchmark_v3.0_NS-6, +NIST_SP_800-53_R5_SC-5, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: webApplicationFirewallShouldBeEnabledForAzureFrontDoorServiceServiceMonitoringEffect), +NIST-800-53: Audit (default: effect-055aa869-bc98-4af8-bafc-23f1ab6ffe2c)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"b6e2945c-0b7b-40f5-9233-7a5323b5cdc6","","BuiltIn","Network","Network Watcher should be enabled","Network Watcher is a regional service that enables you to monitor and diagnose conditions at a network scenario level in, to, and from Azure. Scenario level monitoring enables you to diagnose problems at an end to end network level view. It is required to have a network watcher resource group to be created in every region where a virtual network is present. An alert is enabled if a network watcher resource group is not available in a particular region.","Azure_Security_Benchmark_v3.0_IR-4, +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: networkWatcherShouldBeEnabledMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""networkWatcherShouldBeEnabledResourceGroupName"":""NetworkWatcherRG"",""resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6"":""NetworkWatcherRG""}","{""networkWatcherShouldBeEnabledResourceGroupName"":""NetworkWatcherRG"",""resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6"":""NetworkWatcherRG""}" +"21a6bc25-125e-4d13-b82d-2e19b7208ab7","","BuiltIn","Network","VPN gateways should use only Azure Active Directory (Azure AD) authentication for point-to-site users","Disabling local authentication methods improves security by ensuring that VPN Gateways use only Azure Active Directory identities for authentication. Learn more about Azure AD authentication at https://docs.microsoft.com/azure/vpn-gateway/openvpn-azure-ad-tenant","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"564feb30-bf6a-4854-b4bb-0d2d2d1e6c66","","BuiltIn","Network","Web Application Firewall (WAF) should be enabled for Application Gateway","Deploy Azure Web Application Firewall (WAF) in front of public facing web applications for additional inspection of incoming traffic. Web Application Firewall (WAF) provides centralized protection of your web applications from common exploits and vulnerabilities such as SQL injections, Cross-Site Scripting, local and remote file executions. You can also restrict access to your web applications by countries, IP address ranges, and other http(s) parameters via custom rules.","Azure_Security_Benchmark_v3.0_NS-6, +NIST_SP_800-53_R5_SC-5, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: webApplicationFirewallShouldBeEnabledForApplicationGatewayMonitoringEffect), +NIST-800-53: Audit (default: effect-564feb30-bf6a-4854-b4bb-0d2d2d1e6c66)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"a049bf77-880b-470f-ba6d-9f21c530cf83","","BuiltIn","Search","Azure Cognitive Search service should use a SKU that supports private link","With supported SKUs of Azure Cognitive Search, Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Search service, data leakage risks are reduced. Learn more at: https://aka.ms/azure-cognitive-search/inbound-private-endpoints.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (default: effect-a049bf77-880b-470f-ba6d-9f21c530cf83)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"ee980b6d-0eca-4501-8d54-f6290fd512c3","","BuiltIn","Search","Azure Cognitive Search services should disable public network access","Disabling public network access improves security by ensuring that your Azure Cognitive Search service is not exposed on the public internet. Creating private endpoints can limit exposure of your Search service. Learn more at: https://aka.ms/azure-cognitive-search/inbound-private-endpoints.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (default: effect-ee980b6d-0eca-4501-8d54-f6290fd512c3)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"0fda3595-9f2b-4592-8675-4231d6fa82fe","","BuiltIn","Search","Azure Cognitive Search services should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Cognitive Search, data leakage risks are reduced. Learn more about private links at: https://aka.ms/azure-cognitive-search/inbound-private-endpoints.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"b4330a05-a843-4bc8-bf9a-cacce50c67f4","","BuiltIn","Search","Resource logs in Search services should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInSearchServiceMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInSearchServiceRetentionDays"":""1""}","{""diagnosticsLogsInSearchServiceRetentionDays"":""1""}" +"672fe5a1-2fcd-42d7-b85d-902b6e28c6ff","","BuiltIn","Security Center","[Preview]: Guest Attestation extension should be installed on supported Linux virtual machines","Install Guest Attestation extension on supported Linux virtual machines to allow Azure Security Center to proactively attest and monitor the boot integrity. Once installed, boot integrity will be attested via Remote Attestation. This assessment applies to Trusted Launch and Confidential Linux virtual machines.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (default: GuestAttestationExtensionShouldBeInstalledOnSupportedLinuxVirtualMachinesMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"a21f8c92-9e22-4f09-b759-50500d1d2dda","","BuiltIn","Security Center","[Preview]: Guest Attestation extension should be installed on supported Linux virtual machines scale sets","Install Guest Attestation extension on supported Linux virtual machines scale sets to allow Azure Security Center to proactively attest and monitor the boot integrity. Once installed, boot integrity will be attested via Remote Attestation. This assessment applies to Trusted Launch and Confidential Linux virtual machine scale sets.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (default: GuestAttestationExtensionShouldBeInstalledOnSupportedLinuxVirtualMachinesScaleSetsMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1cb4d9c2-f88f-4069-bee0-dba239a57b09","","BuiltIn","Security Center","[Preview]: Guest Attestation extension should be installed on supported Windows virtual machines","Install Guest Attestation extension on supported virtual machines to allow Azure Security Center to proactively attest and monitor the boot integrity. Once installed, boot integrity will be attested via Remote Attestation. This assessment applies to Trusted Launch and Confidential Windows virtual machines.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (default: GuestAttestationExtensionShouldBeInstalledOnSupportedWindowsVirtualMachinesMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"f655e522-adff-494d-95c2-52d4f6d56a42","","BuiltIn","Security Center","[Preview]: Guest Attestation extension should be installed on supported Windows virtual machines scale sets","Install Guest Attestation extension on supported virtual machines scale sets to allow Azure Security Center to proactively attest and monitor the boot integrity. Once installed, boot integrity will be attested via Remote Attestation. This assessment applies to Trusted Launch and Confidential Windows virtual machine scale sets.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (default: GuestAttestationExtensionShouldBeInstalledOnSupportedWindowsVirtualMachinesScaleSetsMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"13a6c84f-49a5-410a-b5df-5b880c3fe009","","BuiltIn","Security Center","[Preview]: Linux virtual machines should use only signed and trusted boot components","All OS boot components (boot loader, kernel, kernel drivers) must be signed by trusted publishers. Defender for Cloud has identified untrusted OS boot components on one or more of your Linux machines. To protect your machines from potentially malicious components, add them to your allow list or remove the identified components.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (default: LinuxVirtualMachineShouldUseSignedAndTrustedBootComponentEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"97566dd7-78ae-4997-8b36-1c7bfe0d8121","","BuiltIn","Security Center","[Preview]: Secure Boot should be enabled on supported Windows virtual machines","Enable Secure Boot on supported Windows virtual machines to mitigate against malicious and unauthorized changes to the boot chain. Once enabled, only trusted bootloaders, kernel and kernel drivers will be allowed to run. This assessment applies to Trusted Launch and Confidential Windows virtual machines.","Azure_Security_Benchmark_v3.0_PV-4","ASB: Audit (default: SecureBootShouldBeEnabledOnSupportedWindowsVirtualMachinesMonitoringEffect)","parameter: + Audit, + Disabled","Audit","Audit","","" +"f85bf3e0-d513-442e-89c3-1784ad63382b","","BuiltIn","Security Center","[Preview]: System updates should be installed on your machines (powered by Update Center)","Your machines are missing system, security, and critical updates. Software updates often include critical patches to security holes. Such holes are frequently exploited in malware attacks so it's vital to keep your software updated. To install all outstanding patches and secure your machines, follow the remediation steps.","Azure_Security_Benchmark_v3.0_PV-6","ASB: AuditIfNotExists (default: systemUpdatesV2MonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1c30f9cd-b84c-49cc-aa2c-9288447cc3b3","","BuiltIn","Security Center","[Preview]: vTPM should be enabled on supported virtual machines","Enable virtual TPM device on supported virtual machines to facilitate Measured Boot and other OS security features that require a TPM. Once enabled, vTPM can be used to attest boot integrity. This assessment only applies to trusted launch enabled virtual machines.","Azure_Security_Benchmark_v3.0_PV-4","ASB: Audit (default: VtpmShouldBeEnabledOnSupportedVirtualMachinesMonitoringEffect)","parameter: + Audit, + Disabled","Audit","Audit","","" +"4f11b553-d42e-4e3a-89be-32ca364cad4c","","BuiltIn","Security Center","A maximum of 3 owners should be designated for your subscription","It is recommended to designate up to 3 subscription owners in order to reduce the potential for breach by a compromised owner.","Azure_Security_Benchmark_v3.0_PA-1, +NIST_SP_800-53_R5_AC-2, +NIST_SP_800-53_R5_AC-6, +NIST_SP_800-53_R5_AC-6(7)","ASB: AuditIfNotExists (default: identityDesignateLessThanOwnersMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"501541f7-f7e7-4cd6-868c-4190fdad3ac9","","BuiltIn","Security Center","A vulnerability assessment solution should be enabled on your virtual machines","Audits virtual machines to detect whether they are running a supported vulnerability assessment solution. A core component of every cyber risk and security program is the identification and analysis of vulnerabilities. Azure Security Center's standard pricing tier includes vulnerability scanning for your virtual machines at no extra cost. Additionally, Security Center can automatically deploy this tool for you.","Azure_Security_Benchmark_v3.0_PV-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (default: serverVulnerabilityAssessmentEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"e3e008c3-56b9-4133-8fd7-d3347377402a","","BuiltIn","Security Center","Accounts with owner permissions on Azure resources should be MFA enabled","Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with owner permissions to prevent a breach of accounts or resources.","Azure_Security_Benchmark_v3.0_IM-6, +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-2(1)","ASB: AuditIfNotExists (default: identityEnableMFAForOwnerPermissionsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"81b3ccb4-e6e8-4e4a-8d05-5df25cd29fd4","","BuiltIn","Security Center","Accounts with read permissions on Azure resources should be MFA enabled","Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with read privileges to prevent a breach of accounts or resources.","Azure_Security_Benchmark_v3.0_IM-6, +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-2(2)","ASB: AuditIfNotExists (default: identityEnableMFAForReadPermissionsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"931e118d-50a1-4457-a5e4-78550e086c52","","BuiltIn","Security Center","Accounts with write permissions on Azure resources should be MFA enabled","Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with write privileges to prevent a breach of accounts or resources.","Azure_Security_Benchmark_v3.0_IM-6, +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-2(1)","ASB: AuditIfNotExists (default: identityEnableMFAForWritePermissionsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"47a6b606-51aa-4496-8bb7-64b11cf66adc","","BuiltIn","Security Center","Adaptive application controls for defining safe applications should be enabled on your machines","Enable application controls to define the list of known-safe applications running on your machines, and alert you when other applications run. This helps harden your machines against malware. To simplify the process of configuring and maintaining your rules, Security Center uses machine learning to analyze the applications running on each machine and suggest the list of known-safe applications.","Azure_Security_Benchmark_v3.0_AM-5, +NIST_SP_800-53_R5_CM-7, +NIST_SP_800-53_R5_CM-7(2), +NIST_SP_800-53_R5_CM-7(5), +NIST_SP_800-53_R5_CM-10, +NIST_SP_800-53_R5_CM-11","ASB: AuditIfNotExists (default: adaptiveApplicationControlsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"08e6af2d-db70-460a-bfe9-d5bd474ba9d6","","BuiltIn","Security Center","Adaptive network hardening recommendations should be applied on internet facing virtual machines","Azure Security Center analyzes the traffic patterns of Internet facing virtual machines and provides Network Security Group rule recommendations that reduce the potential attack surface","Azure_Security_Benchmark_v3.0_NS-1, +Azure_Security_Benchmark_v3.0_NS-7, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-4(3), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: adaptiveNetworkHardeningsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"9daedab3-fb2d-461e-b861-71790eead4f6","","BuiltIn","Security Center","All network ports should be restricted on network security groups associated to your virtual machine","Azure Security Center has identified some of your network security groups' inbound rules to be too permissive. Inbound rules should not allow access from 'Any' or 'Internet' ranges. This can potentially enable attackers to target your resources.","Azure_Security_Benchmark_v3.0_NS-1, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: nextGenerationFirewallMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"123a3936-f020-408a-ba0c-47873faf1534","","BuiltIn","Security Center","Allowlist rules in your adaptive application control policy should be updated","Monitor for changes in behavior on groups of machines configured for auditing by Azure Security Center's adaptive application controls. Security Center uses machine learning to analyze the running processes on your machines and suggest a list of known-safe applications. These are presented as recommended apps to allow in adaptive application control policies.","Azure_Security_Benchmark_v3.0_AM-5, +NIST_SP_800-53_R5_CM-7, +NIST_SP_800-53_R5_CM-7(2), +NIST_SP_800-53_R5_CM-7(5), +NIST_SP_800-53_R5_CM-10, +NIST_SP_800-53_R5_CM-11","ASB: AuditIfNotExists (default: adaptiveApplicationControlsUpdateMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"8ac833bd-f505-48d5-887e-c993a1d3eea0","","BuiltIn","Security Center","API endpoints in Azure API Management should be authenticated","API endpoints published within Azure API Management should enforce authentication to help minimize security risk. Authentication mechanisms are sometimes implemented incorrectly or are missing. This allows attackers to exploit implementation flaws and to access data. Learn More about the OWASP API Threat for Broken User Authentication here: https://learn.microsoft.com/azure/api-management/mitigate-owasp-api-threats#broken-user-authentication","Azure_Security_Benchmark_v3.0_IM-4","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"c8acafaf-3d23-44d1-9624-978ef0f8652c","","BuiltIn","Security Center","API endpoints that are unused should be disabled and removed from the Azure API Management service","As a security best practice, API endpoints that haven't received traffic for 30 days are considered unused and should be removed from the Azure API Management service. Keeping unused API endpoints may pose a security risk to your organization. These may be APIs that should have been deprecated from the Azure API Management service but may have been accidentally left active. Such APIs typically do not receive the most up to date security coverage.","Azure_Security_Benchmark_v3.0_AM-3","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0e246bcf-5f6f-4f87-bc6f-775d4712c7ea","","BuiltIn","Security Center","Authorized IP ranges should be defined on Kubernetes Services","Restrict access to the Kubernetes Service Management API by granting API access only to IP addresses in specific ranges. It is recommended to limit access to authorized IP ranges to ensure that only applications from allowed networks can access the cluster.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: kubernetesServiceAuthorizedIPRangesEnabledMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"475aae12-b88a-4572-8b36-9b712b2b3a17","","BuiltIn","Security Center","Auto provisioning of the Log Analytics agent should be enabled on your subscription","To monitor for security vulnerabilities and threats, Azure Security Center collects data from your Azure virtual machines. Data is collected by the Log Analytics agent, formerly known as the Microsoft Monitoring Agent (MMA), which reads various security-related configurations and event logs from the machine and copies the data to your Log Analytics workspace for analysis. We recommend enabling auto provisioning to automatically deploy the agent to all supported Azure VMs and any new ones that are created.","Azure_Security_Benchmark_v3.0_LT-5, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: autoProvisioningOfTheLogAnalyticsAgentShouldBeEnabledOnYourSubscriptionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"a7aca53f-2ed4-4466-a25e-0b45ade68efd","","BuiltIn","Security Center","Azure DDoS Protection should be enabled","DDoS protection should be enabled for all virtual networks with a subnet that is part of an application gateway with a public IP.","Azure_Security_Benchmark_v3.0_NS-5, +NIST_SP_800-53_R5_SC-5","ASB: AuditIfNotExists (default: vnetEnableDDoSProtectionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"2913021d-f2fd-4f3d-b958-22354e2bdbcb","","BuiltIn","Security Center","Azure Defender for App Service should be enabled","Azure Defender for App Service leverages the scale of the cloud, and the visibility that Azure has as a cloud provider, to monitor for common web app attacks.","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: appServicesAdvancedThreatProtectionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"7fe3b40f-802b-4cdd-8bd4-fd799c948cc2","","BuiltIn","Security Center","Azure Defender for Azure SQL Database servers should be enabled","Azure Defender for SQL provides functionality for surfacing and mitigating potential database vulnerabilities, detecting anomalous activities that could indicate threats to SQL databases, and discovering and classifying sensitive data.","Azure_Security_Benchmark_v3.0_DP-2, +Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: sqlServersAdvancedDataSecurityMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0e6763cc-5078-4e64-889d-ff4d9a839047","","BuiltIn","Security Center","Azure Defender for Key Vault should be enabled","Azure Defender for Key Vault provides an additional layer of protection and security intelligence by detecting unusual and potentially harmful attempts to access or exploit key vault accounts.","Azure_Security_Benchmark_v3.0_DP-8, +Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: keyVaultsAdvancedDataSecurityMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0a9fbe0d-c5c4-4da8-87d8-f4fd77338835","","BuiltIn","Security Center","Azure Defender for open-source relational databases should be enabled","Azure Defender for open-source relational databases detects anomalous activities indicating unusual and potentially harmful attempts to access or exploit databases. Learn more about the capabilities of Azure Defender for open-source relational databases at https://aka.ms/AzDforOpenSourceDBsDocu. Important: Enabling this plan will result in charges for protecting your open-source relational databases. Learn about the pricing on Security Center's pricing page: https://aka.ms/pricing-security-center","Azure_Security_Benchmark_v3.0_DP-2, +Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5","ASB: AuditIfNotExists (default: AzureDefenderForOpenSourceRelationalDatabasesShouldBeEnabledMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"c3d20c29-b36d-48fe-808b-99a87530ad99","","BuiltIn","Security Center","Azure Defender for Resource Manager should be enabled","Azure Defender for Resource Manager automatically monitors the resource management operations in your organization. Azure Defender detects threats and alerts you about suspicious activity. Learn more about the capabilities of Azure Defender for Resource Manager at https://aka.ms/defender-for-resource-manager . Enabling this Azure Defender plan results in charges. Learn about the pricing details per region on Security Center's pricing page: https://aka.ms/pricing-security-center .","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: AzureDefenderForResourceManagerShouldBeEnabledMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"4da35fc9-c9e7-4960-aec9-797fe7d9051d","","BuiltIn","Security Center","Azure Defender for servers should be enabled","Azure Defender for servers provides real-time threat protection for server workloads and generates hardening recommendations as well as alerts about suspicious activities.","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_ES-1, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_CM-7, +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SC-3, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-3, +NIST_SP_800-53_R5_SI-4, +NIST_SP_800-53_R5_SI-16","ASB: AuditIfNotExists (default: virtualMachinesAdvancedThreatProtectionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"6581d072-105e-4418-827f-bd446d56421b","","BuiltIn","Security Center","Azure Defender for SQL servers on machines should be enabled","Azure Defender for SQL provides functionality for surfacing and mitigating potential database vulnerabilities, detecting anomalous activities that could indicate threats to SQL databases, and discovering and classifying sensitive data.","Azure_Security_Benchmark_v3.0_DP-2, +Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: sqlServersVirtualMachinesAdvancedDataSecurityMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"d38668f5-d155-42c7-ab3d-9b57b50f8fbf","","BuiltIn","Security Center","Azure Defender for SQL should be enabled for unprotected PostgreSQL flexible servers","Audit PostgreSQL flexible servers without Advanced Data Security","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"090c7b07-b4ed-4561-ad20-e9075f3ccaff","","BuiltIn","Security Center","Azure registry container images should have vulnerabilities resolved (powered by Microsoft Defender Vulnerability Management)","Container image vulnerability assessment scans your registry for commonly known vulnerabilities (CVEs) and provides a detailed vulnerability report for each image. Resolving vulnerabilities can greatly improve your security posture, ensuring images are safe to use prior to deployment.","Azure_Security_Benchmark_v3.0_PV-6, +Azure_Security_Benchmark_v3.0_DS-6","ASB: AuditIfNotExists (default: azureContainerRegistryVulnerabilityAssessmentEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"ac4a19c2-fa67-49b4-8ae5-0b2e78c49457","","BuiltIn","Security Center","Azure Role-Based Access Control (RBAC) should be used on Kubernetes Services","To provide granular filtering on the actions that users can perform, use Azure Role-Based Access Control (RBAC) to manage permissions in Kubernetes Service Clusters and configure relevant authorization policies.","Azure_Security_Benchmark_v3.0_PA-7, +NIST_SP_800-53_R5_AC-3(7)","ASB: Audit (default: kubernetesServiceRbacEnabledMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"17f4b1cc-c55c-4d94-b1f9-2978f6ac2957","","BuiltIn","Security Center","Azure running container images should have vulnerabilities resolved (powered by Microsoft Defender Vulnerability Management)","Container image vulnerability assessment scans your registry for commonly known vulnerabilities (CVEs) and provides a detailed vulnerability report for each image. This recommendation provides visibility to vulnerable images currently running in your Kubernetes clusters. Remediating vulnerabilities in container images that are currently running is key to improving your security posture, significantly reducing the attack surface for your containerized workloads.","Azure_Security_Benchmark_v3.0_PV-6, +Azure_Security_Benchmark_v3.0_DS-6","ASB: AuditIfNotExists (default: kubernetesRunningImagesVulnerabilityMDVMAssessmentEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0cfea604-3201-4e14-88fc-fae4c427a6c5","","BuiltIn","Security Center","Blocked accounts with owner permissions on Azure resources should be removed","Deprecated accounts with owner permissions should be removed from your subscription. Deprecated accounts are accounts that have been blocked from signing in.","Azure_Security_Benchmark_v3.0_PA-1, +Azure_Security_Benchmark_v3.0_PA-4, +NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (default: identityRemoveDeprecatedAccountWithOwnerPermissionsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"8d7e1fde-fe26-4b5f-8108-f8e432cbc2be","","BuiltIn","Security Center","Blocked accounts with read and write permissions on Azure resources should be removed","Deprecated accounts should be removed from your subscriptions. Deprecated accounts are accounts that have been blocked from signing in.","Azure_Security_Benchmark_v3.0_PA-4, +NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (default: identityRemoveDeprecatedAccountMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"6e2593d9-add6-4083-9c9b-4b7d2188c899","","BuiltIn","Security Center","Email notification for high severity alerts should be enabled","To ensure the relevant people in your organization are notified when there is a potential security breach in one of your subscriptions, enable email notifications for high severity alerts in Security Center.","Azure_Security_Benchmark_v3.0_IR-2, +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_IR-6(2), +NIST_SP_800-53_R5_SI-4(12)","ASB: AuditIfNotExists (default: emailNotificationForHighSeverityAlertsShouldBeEnabledMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0b15565f-aa9e-48ba-8619-45960f2c314d","","BuiltIn","Security Center","Email notification to subscription owner for high severity alerts should be enabled","To ensure your subscription owners are notified when there is a potential security breach in their subscription, set email notifications to subscription owners for high severity alerts in Security Center.","Azure_Security_Benchmark_v3.0_IR-2, +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_IR-6(2), +NIST_SP_800-53_R5_SI-4(12)","ASB: AuditIfNotExists (default: emailNotificationToSubscriptionOwnerForHighSeverityAlertsShouldBeEnabledMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"8e42c1f2-a2ab-49bc-994a-12bcd0dc4ac2","","BuiltIn","Security Center","Endpoint protection health issues should be resolved on your machines","Resolve endpoint protection health issues on your virtual machines to protect them from latest threats and vulnerabilities. Azure Security Center supported endpoint protection solutions are documented here - https://docs.microsoft.com/azure/security-center/security-center-services?tabs=features-windows#supported-endpoint-protection-solutions. Endpoint protection assessment is documented here - https://docs.microsoft.com/azure/security-center/security-center-endpoint-protection.","Azure_Security_Benchmark_v3.0_ES-2, +Azure_Security_Benchmark_v3.0_ES-3","ASB: AuditIfNotExists (default: endpointProtectionHealthIssuesMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1f7c564c-0a90-4d44-b7e1-9d456cffaee8","","BuiltIn","Security Center","Endpoint protection should be installed on your machines","To protect your machines from threats and vulnerabilities, install a supported endpoint protection solution.","Azure_Security_Benchmark_v3.0_ES-2","ASB: AuditIfNotExists (default: installEndpointProtectionMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"26a828e1-e88f-464e-bbb3-c134a282b9de","","BuiltIn","Security Center","Endpoint protection solution should be installed on virtual machine scale sets","Audit the existence and health of an endpoint protection solution on your virtual machines scale sets, to protect them from threats and vulnerabilities.","Azure_Security_Benchmark_v3.0_ES-2, +NIST_SP_800-53_R5_SC-3, +NIST_SP_800-53_R5_SI-3","ASB: AuditIfNotExists (default: vmssEndpointProtectionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"339353f6-2387-4a45-abe4-7f529d121046","","BuiltIn","Security Center","Guest accounts with owner permissions on Azure resources should be removed","External accounts with owner permissions should be removed from your subscription in order to prevent unmonitored access.","Azure_Security_Benchmark_v3.0_PA-1, +Azure_Security_Benchmark_v3.0_PA-4, +NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (default: identityRemoveExternalAccountWithOwnerPermissionsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"e9ac8f8e-ce22-4355-8f04-99b911d6be52","","BuiltIn","Security Center","Guest accounts with read permissions on Azure resources should be removed","External accounts with read privileges should be removed from your subscription in order to prevent unmonitored access.","Azure_Security_Benchmark_v3.0_PA-4, +NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (default: identityRemoveExternalAccountWithReadPermissionsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"94e1c2ac-cbbe-4cac-a2b5-389c812dee87","","BuiltIn","Security Center","Guest accounts with write permissions on Azure resources should be removed","External accounts with write privileges should be removed from your subscription in order to prevent unmonitored access.","Azure_Security_Benchmark_v3.0_PA-4, +NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (default: identityRemoveExternalAccountWithWritePermissionsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"ae89ebca-1c92-4898-ac2c-9f63decb045c","","BuiltIn","Security Center","Guest Configuration extension should be installed on your machines","To ensure secure configurations of in-guest settings of your machine, install the Guest Configuration extension. In-guest settings that the extension monitors include the configuration of the operating system, application configuration or presence, and environment settings. Once installed, in-guest policies will be available such as 'Windows Exploit guard should be enabled'. Learn more at https://aka.ms/gcpol.","Azure_Security_Benchmark_v3.0_PV-4, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: azurePolicyforWindowsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"f6de0be7-9a8a-4b8a-b349-43cf02d22f7c","","BuiltIn","Security Center","Internet-facing virtual machines should be protected with network security groups","Protect your virtual machines from potential threats by restricting access to them with network security groups (NSG). Learn more about controlling traffic with NSGs at https://aka.ms/nsg-doc","Azure_Security_Benchmark_v3.0_NS-1, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: networkSecurityGroupsOnVirtualMachinesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"bd352bd5-2853-4985-bf0d-73806b4a5744","","BuiltIn","Security Center","IP Forwarding on your virtual machine should be disabled","Enabling IP forwarding on a virtual machine's NIC allows the machine to receive traffic addressed to other destinations. IP forwarding is rarely required (e.g., when using the VM as a network virtual appliance), and therefore, this should be reviewed by the network security team.","Azure_Security_Benchmark_v3.0_NS-3, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-5, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: disableIPForwardingMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"fb893a29-21bb-418c-a157-e99480ec364c","","BuiltIn","Security Center","Kubernetes Services should be upgraded to a non-vulnerable Kubernetes version","Upgrade your Kubernetes service cluster to a later Kubernetes version to protect against known vulnerabilities in your current Kubernetes version. Vulnerability CVE-2019-9946 has been patched in Kubernetes versions 1.11.9+, 1.12.7+, 1.13.5+, and 1.14.0+","NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-2(6)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"a4fe33eb-e377-4efb-ab31-0784311bc499","","BuiltIn","Security Center","Log Analytics agent should be installed on your virtual machine for Azure Security Center monitoring","This policy audits any Windows/Linux virtual machines (VMs) if the Log Analytics agent is not installed which Security Center uses to monitor for security vulnerabilities and threats","Azure_Security_Benchmark_v3.0_LT-5, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: installLogAnalyticsAgentOnVmMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"a3a6ea0c-e018-4933-9ef0-5aaa1501449b","","BuiltIn","Security Center","Log Analytics agent should be installed on your virtual machine scale sets for Azure Security Center monitoring","Security Center collects data from your Azure virtual machines (VMs) to monitor for security vulnerabilities and threats.","Azure_Security_Benchmark_v3.0_LT-5, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: installLogAnalyticsAgentOnVmssMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"3ac7c827-eea2-4bde-acc7-9568cd320efa","","BuiltIn","Security Center","Machines should have secret findings resolved","Audits virtual machines to detect whether they contain secret findings from the secret scanning solutions on your virtual machines.","Azure_Security_Benchmark_v3.0_PV-5, +Azure_Security_Benchmark_v3.0_IM-8","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"b0f33259-77d7-4c9e-aac6-3aabcfae693c","","BuiltIn","Security Center","Management ports of virtual machines should be protected with just-in-time network access control","Possible network Just In Time (JIT) access will be monitored by Azure Security Center as recommendations","Azure_Security_Benchmark_v3.0_NS-3, +Azure_Security_Benchmark_v3.0_PA-2, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-4(3), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: jitNetworkAccessMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"22730e10-96f6-4aac-ad84-9383d35b5917","","BuiltIn","Security Center","Management ports should be closed on your virtual machines","Open remote management ports are exposing your VM to a high level of risk from Internet-based attacks. These attacks attempt to brute force credentials to gain admin access to the machine.","Azure_Security_Benchmark_v3.0_NS-3, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: restrictAccessToManagementPortsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1f90fc71-a595-4066-8974-d4d0802e8ef0","","BuiltIn","Security Center","Microsoft Defender CSPM should be enabled","Defender Cloud Security Posture Management (CSPM) provides enhanced posture capabilities and a new intelligent cloud security graph to help identify, prioritize, and reduce risk. Defender CSPM is available in addition to the free foundational security posture capabilities turned on by default in Defender for Cloud.","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5","ASB: AuditIfNotExists (default: MicrosoftDefenderCSPMShouldBeEnabledMonitoringEffect)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"7926a6d1-b268-4586-8197-e8ae90c877d7","","BuiltIn","Security Center","Microsoft Defender for APIs should be enabled","Microsoft Defender for APIs brings new discovery, protection, detection, & response coverage to monitor for common API based attacks & security misconfigurations.","Azure_Security_Benchmark_v3.0_DP-1, +Azure_Security_Benchmark_v3.0_DP-2, +Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1c988dd6-ade4-430f-a608-2a3e5b0a6d38","","BuiltIn","Security Center","Microsoft Defender for Containers should be enabled","Microsoft Defender for Containers provides hardening, vulnerability assessment and run-time protections for your Azure, hybrid, and multi-cloud Kubernetes environments.","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: containersAdvancedThreatProtectionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"d31e5c31-63b2-4f12-887b-e49456834fa1","","BuiltIn","Security Center","Microsoft Defender for SQL should be enabled for unprotected Synapse workspaces","Enable Defender for SQL to protect your Synapse workspaces. Defender for SQL monitors your Synapse SQL to detect anomalous activities indicating unusual and potentially harmful attempts to access or exploit databases.","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"938c4981-c2c9-4168-9cd6-972b8675f906","","BuiltIn","Security Center","Microsoft Defender for SQL status should be protected for Arc-enabled SQL Servers","Microsoft Defender for SQL provides functionality for surfacing and mitigating potential database vulnerabilities, detecting anomalous activities that could indicate threats to SQL databases, discovering and classifying sensitive data. Once enabled, the protection status indicates that the resource is actively monitored. Even when Defender is enabled, multiple configuration settings should be validated on the agent, machine, workspace and SQL server to ensure active protection.","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5","ASB: Audit (default: arcEnabledSqlServerDefenderStatusEffect)","parameter: + Audit, + Disabled","Audit","Audit","","" +"640d2586-54d2-465f-877f-9ffc1d2109f4","","BuiltIn","Security Center","Microsoft Defender for Storage should be enabled","Microsoft Defender for Storage detects potential threats to your storage accounts. It helps prevent the three major impacts on your data and workload: malicious file uploads, sensitive data exfiltration, and data corruption. The new Defender for Storage plan includes Malware Scanning and Sensitive Data Threat Detection. This plan also provides a predictable pricing structure (per storage account) for control over coverage and costs.","Azure_Security_Benchmark_v3.0_DP-2, +Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (Policy Default), +NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"af6cd1bd-1635-48cb-bde7-5b15693900b9","","BuiltIn","Security Center","Monitor missing Endpoint Protection in Azure Security Center","Servers without an installed Endpoint Protection agent will be monitored by Azure Security Center as recommendations","Azure_Security_Benchmark_v3.0_ES-2, +NIST_SP_800-53_R5_SC-3, +NIST_SP_800-53_R5_SI-3","ASB: AuditIfNotExists (default: endpointProtectionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"bb91dfba-c30d-4263-9add-9c2384e659a6","","BuiltIn","Security Center","Non-internet-facing virtual machines should be protected with network security groups","Protect your non-internet-facing virtual machines from potential threats by restricting access with network security groups (NSG). Learn more about controlling traffic with NSGs at https://aka.ms/nsg-doc","Azure_Security_Benchmark_v3.0_NS-1, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: networkSecurityGroupsOnInternalVirtualMachinesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"feedbf84-6b99-488c-acc2-71c829aa5ffc","","BuiltIn","Security Center","SQL databases should have vulnerability findings resolved","Monitor vulnerability assessment scan results and recommendations for how to remediate database vulnerabilities.","Azure_Security_Benchmark_v3.0_PV-6, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (default: sqlDbVulnerabilityAssesmentMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"c6283572-73bb-4deb-bf2c-7a2b8f7462cb","","BuiltIn","Security Center","SQL server-targeted autoprovisioning should be enabled for SQL servers on machines plan","To ensure your SQL VMs and Arc-enabled SQL Servers are protected, ensure the SQL-targeted Azure Monitoring Agent is configured to automatically deploy. This is also necessary if you've previously configured autoprovisioning of the Microsoft Monitoring Agent, as that component is being deprecated. Learn more: https://aka.ms/SQLAMAMigration","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"6ba6d016-e7c3-4842-b8f2-4992ebc0d72d","","BuiltIn","Security Center","SQL servers on machines should have vulnerability findings resolved","SQL vulnerability assessment scans your database for security vulnerabilities, and exposes any deviations from best practices such as misconfigurations, excessive permissions, and unprotected sensitive data. Resolving the vulnerabilities found can greatly improve your database security posture.","Azure_Security_Benchmark_v3.0_PV-6, +NIST_SP_800-53_R5_RA-5","ASB: AuditIfNotExists (default: serverSqlDbVulnerabilityAssesmentMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"e71308d3-144b-4262-b144-efdc3cc90517","","BuiltIn","Security Center","Subnets should be associated with a Network Security Group","Protect your subnet from potential threats by restricting access to it with a Network Security Group (NSG). NSGs contain a list of Access Control List (ACL) rules that allow or deny network traffic to your subnet.","Azure_Security_Benchmark_v3.0_NS-1, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Disabled (default: networkSecurityGroupsOnSubnetsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","Disabled","Disabled","","" +"4f4f78b8-e367-4b10-a341-d9a4ad5cf1c7","","BuiltIn","Security Center","Subscriptions should have a contact email address for security issues","To ensure the relevant people in your organization are notified when there is a potential security breach in one of your subscriptions, set a security contact to receive email notifications from Security Center.","Azure_Security_Benchmark_v3.0_IR-2, +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_IR-6(2), +NIST_SP_800-53_R5_SI-4(12)","ASB: AuditIfNotExists (default: subscriptionsShouldHaveAContactEmailAddressForSecurityIssuesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"c3f317a7-a95c-4547-b7e7-11017ebdf2fe","","BuiltIn","Security Center","System updates on virtual machine scale sets should be installed","Audit whether there are any missing system security updates and critical updates that should be installed to ensure that your Windows and Linux virtual machine scale sets are secure.","Azure_Security_Benchmark_v3.0_PV-6, +NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (default: vmssSystemUpdatesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"86b3d65f-7626-441e-b690-81a8b71cff60","","BuiltIn","Security Center","System updates should be installed on your machines","Missing security system updates on your servers will be monitored by Azure Security Center as recommendations","Azure_Security_Benchmark_v3.0_PV-6, +NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (default: systemUpdatesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"09024ccc-0c5f-475e-9457-b7c0d9ed487b","","BuiltIn","Security Center","There should be more than one owner assigned to your subscription","It is recommended to designate more than one subscription owner in order to have administrator access redundancy.","Azure_Security_Benchmark_v3.0_PA-1, +NIST_SP_800-53_R5_AC-5","ASB: AuditIfNotExists (default: identityDesignateMoreThanOneOwnerMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0961003e-5a0a-4549-abde-af6a37f2724d","","BuiltIn","Security Center","Virtual machines should encrypt temp disks, caches, and data flows between Compute and Storage resources","By default, a virtual machine's OS and data disks are encrypted-at-rest using platform-managed keys. Temp disks, data caches and data flowing between compute and storage aren't encrypted. Disregard this recommendation if: 1. using encryption-at-host, or 2. server-side encryption on Managed Disks meets your security requirements. Learn more in: Server-side encryption of Azure Disk Storage: https://aka.ms/disksse, Different disk encryption offerings: https://aka.ms/diskencryptioncomparison","Azure_Security_Benchmark_v3.0_DP-4, +NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","ASB: AuditIfNotExists (default: diskEncryptionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"d26f7642-7545-4e18-9b75-8c9bbdee3a9a","","BuiltIn","Security Center","Virtual machines' Guest Configuration extension should be deployed with system-assigned managed identity","The Guest Configuration extension requires a system assigned managed identity. Azure virtual machines in the scope of this policy will be non-compliant when they have the Guest Configuration extension installed but do not have a system assigned managed identity. Learn more at https://aka.ms/gcpol","Azure_Security_Benchmark_v3.0_IM-3, +Azure_Security_Benchmark_v3.0_PV-4, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: gcExtOnVMWithNoSAMIMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"e8cbc669-f12d-49eb-93e7-9273119e9933","","BuiltIn","Security Center","Vulnerabilities in container security configurations should be remediated","Audit vulnerabilities in security configuration on machines with Docker installed and display as recommendations in Azure Security Center.","Azure_Security_Benchmark_v3.0_PV-6, +Azure_Security_Benchmark_v3.0_DS-6, +NIST_SP_800-53_R5_RA-5","ASB: AuditIfNotExists (default: containerBenchmarkMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"e1e5fd5d-3e4c-4ce1-8661-7d1873ae6b15","","BuiltIn","Security Center","Vulnerabilities in security configuration on your machines should be remediated","Servers which do not satisfy the configured baseline will be monitored by Azure Security Center as recommendations","Azure_Security_Benchmark_v3.0_PV-6, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (default: systemConfigurationsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"3c735d8a-a4ba-4a3a-b7cf-db7754cf57f4","","BuiltIn","Security Center","Vulnerabilities in security configuration on your virtual machine scale sets should be remediated","Audit the OS vulnerabilities on your virtual machine scale sets to protect them from attacks.","Azure_Security_Benchmark_v3.0_PV-6, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (default: vmssOsVulnerabilitiesMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1c06e275-d63d-4540-b761-71f364c2111d","","BuiltIn","Service Bus","Azure Service Bus namespaces should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Service Bus namespaces, data leakage risks are reduced. Learn more at: https://docs.microsoft.com/azure/service-bus-messaging/private-link-service.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"f8d36e2f-389b-4ee4-898d-21aeb69a0f45","","BuiltIn","Service Bus","Resource logs in Service Bus should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInServiceBusMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInServiceBusRetentionDays"":""1""}","{""diagnosticsLogsInServiceBusRetentionDays"":""1""}" +"295fc8b1-dc9f-4f53-9c61-3f313ceab40a","","BuiltIn","Service Bus","Service Bus Premium namespaces should use a customer-managed key for encryption","Azure Service Bus supports the option of encrypting data at rest with either Microsoft-managed keys (default) or customer-managed keys. Choosing to encrypt data using customer-managed keys enables you to assign, rotate, disable, and revoke access to the keys that Service Bus will use to encrypt data in your namespace. Note that Service Bus only supports encryption with customer-managed keys for premium namespaces.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"617c02be-7f02-4efd-8836-3180d47b6c68","","BuiltIn","Service Fabric","Service Fabric clusters should have the ClusterProtectionLevel property set to EncryptAndSign","Service Fabric provides three levels of protection (None, Sign and EncryptAndSign) for node-to-node communication using a primary cluster certificate. Set the protection level to ensure that all node-to-node messages are encrypted and digitally signed","Azure_Security_Benchmark_v3.0_DP-4, +NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","ASB: Audit (default: clusterProtectionLevelInServiceFabricMonitoringEffect), +NIST-800-53: Audit (default: effect-617c02be-7f02-4efd-8836-3180d47b6c68)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"b54ed75b-3e1a-44ac-a333-05ba39b99ff0","","BuiltIn","Service Fabric","Service Fabric clusters should only use Azure Active Directory for client authentication","Audit usage of client authentication only via Azure Active Directory in Service Fabric","Azure_Security_Benchmark_v3.0_IM-1, +NIST_SP_800-53_R5_AC-2, +NIST_SP_800-53_R5_AC-2(1), +NIST_SP_800-53_R5_AC-2(7), +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-4","ASB: Audit (default: aadAuthenticationInServiceFabricMonitoringEffect), +NIST-800-53: Audit (default: effect-b54ed75b-3e1a-44ac-a333-05ba39b99ff0)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"2393d2cf-a342-44cd-a2e2-fe0188fd1234","","BuiltIn","SignalR","Azure SignalR Service should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Azure SignalR Service resource instead of the entire service, you'll reduce your data leakage risks. Learn more about private links at: https://aka.ms/asrs/privatelink.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: azureSignalRServiceShouldUsePrivateLinkMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"146412e9-005c-472b-9e48-c87b72ac229e","","BuiltIn","SQL","A Microsoft Entra administrator should be provisioned for MySQL servers","Audit provisioning of a Microsoft Entra administrator for your MySQL server to enable Microsoft Entra authentication. Microsoft Entra authentication enables simplified permission management and centralized identity management of database users and other Microsoft services","Azure_Security_Benchmark_v3.0_DP-4","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"b4dec045-250a-48c2-b5cc-e0c4eec8b5b4","","BuiltIn","SQL","A Microsoft Entra administrator should be provisioned for PostgreSQL servers","Audit provisioning of a Microsoft Entra administrator for your PostgreSQL server to enable Microsoft Entra authentication. Microsoft Entra authentication enables simplified permission management and centralized identity management of database users and other Microsoft services","Azure_Security_Benchmark_v3.0_IM-1","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1f314764-cb73-4fc9-b863-8eca98ac36e9","","BuiltIn","SQL","An Azure Active Directory administrator should be provisioned for SQL servers","Audit provisioning of an Azure Active Directory administrator for your SQL server to enable Azure AD authentication. Azure AD authentication enables simplified permission management and centralized identity management of database users and other Microsoft services","Azure_Security_Benchmark_v3.0_IM-1, +NIST_SP_800-53_R5_AC-2, +NIST_SP_800-53_R5_AC-2(1), +NIST_SP_800-53_R5_AC-2(7), +NIST_SP_800-53_R5_AC-3, +NIST_SP_800-53_R5_IA-2, +NIST_SP_800-53_R5_IA-4","ASB: AuditIfNotExists (default: aadAuthenticationInSqlServerMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9","","BuiltIn","SQL","Auditing on SQL server should be enabled","Auditing on your SQL Server should be enabled to track database activities across all databases on the server and save them in an audit log.","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: sqlServerAuditingMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""setting-a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9"":""enabled""}","{""setting-a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9"":""enabled""}" +"abfb4388-5bf4-4ad7-ba82-2cd2f41ceae9","","BuiltIn","SQL","Azure Defender for SQL should be enabled for unprotected Azure SQL servers","Audit SQL servers without Advanced Data Security","Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-16, +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: sqlServerAdvancedDataSecurityMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"abfb7388-5bf4-4ad7-ba99-2cd2f41cebb9","","BuiltIn","SQL","Azure Defender for SQL should be enabled for unprotected SQL Managed Instances","Audit each SQL Managed Instance without advanced data security.","Azure_Security_Benchmark_v3.0_DP-2, +Azure_Security_Benchmark_v3.0_LT-1, +Azure_Security_Benchmark_v3.0_LT-2, +Azure_Security_Benchmark_v3.0_IR-3, +Azure_Security_Benchmark_v3.0_IR-5, +NIST_SP_800-53_R5_AC-2(12), +NIST_SP_800-53_R5_AC-16, +NIST_SP_800-53_R5_AU-6, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1), +NIST_SP_800-53_R5_IR-4, +NIST_SP_800-53_R5_IR-5, +NIST_SP_800-53_R5_RA-5, +NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (default: sqlManagedInstanceAdvancedDataSecurityMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"40e85574-ef33-47e8-a854-7a65c7500560","","BuiltIn","SQL","Azure MySQL flexible server should have Microsoft Entra Only Authentication enabled","Disabling local authentication methods and allowing only Microsoft Entra Authentication improves security by ensuring that Azure MySQL flexible server can exclusively be accessed by Microsoft Entra identities.","Azure_Security_Benchmark_v3.0_DP-4","ASB: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"32e6bbec-16b6-44c2-be37-c5b672d103cf","","BuiltIn","SQL","Azure SQL Database should be running TLS version 1.2 or newer","Setting TLS version to 1.2 or newer improves security by ensuring your Azure SQL Database can only be accessed from clients using TLS 1.2 or newer. Using versions of TLS less than 1.2 is not recommended since they have well documented security vulnerabilities.","Azure_Security_Benchmark_v3.0_DP-3, +Azure_Security_Benchmark_v3.0_IM-4","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"b3a22bc9-66de-45fb-98fa-00f5df42f41a","","BuiltIn","SQL","Azure SQL Database should have Microsoft Entra-only authentication enabled","Require Azure SQL logical servers to use Microsoft Entra-only authentication. This policy doesn't block servers from being created with local authentication enabled. It does block local authentication from being enabled on resources after create. Consider using the 'Microsoft Entra-only authentication' initiative instead to require both. Learn more at: https://aka.ms/adonlycreate.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"abda6d70-9778-44e7-84a8-06713e6db027","","BuiltIn","SQL","Azure SQL Database should have Microsoft Entra-only authentication enabled during creation","Require Azure SQL logical servers to be created with Microsoft Entra-only authentication. This policy doesn't block local authentication from being re-enabled on resources after create. Consider using the 'Microsoft Entra-only authentication' initiative instead to require both. Learn more at: https://aka.ms/adonlycreate.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"0c28c3fb-c244-42d5-a9bf-f35f2999577b","","BuiltIn","SQL","Azure SQL Managed Instance should have Microsoft Entra-only authentication enabled","Require Azure SQL Managed Instance to use Microsoft Entra-only authentication. This policy doesn't block Azure SQL Managed instances from being created with local authentication enabled. It does block local authentication from being enabled on resources after create. Consider using the 'Microsoft Entra-only authentication' initiative instead to require both. Learn more at: https://aka.ms/adonlycreate.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"9dfea752-dd46-4766-aed1-c355fa93fb91","","BuiltIn","SQL","Azure SQL Managed Instances should disable public network access","Disabling public network access (public endpoint) on Azure SQL Managed Instances improves security by ensuring that they can only be accessed from inside their virtual networks or via Private Endpoints. To learn more about public network access, visit https://aka.ms/mi-public-endpoint.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"78215662-041e-49ed-a9dd-5385911b3a1f","","BuiltIn","SQL","Azure SQL Managed Instances should have Microsoft Entra-only authentication enabled during creation","Require Azure SQL Managed Instance to be created with Microsoft Entra-only authentication. This policy doesn't block local authentication from being re-enabled on resources after create. Consider using the 'Microsoft Entra-only authentication' initiative instead to require both. Learn more at: https://aka.ms/adonlycreate.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"e802a67a-daf5-4436-9ea6-f6d821dd0c5d","","BuiltIn","SQL","Enforce SSL connection should be enabled for MySQL database servers","Azure Database for MySQL supports connecting your Azure Database for MySQL server to client applications using Secure Sockets Layer (SSL). Enforcing SSL connections between your database server and your client applications helps protect against 'man in the middle' attacks by encrypting the data stream between the server and your application. This configuration enforces that SSL is always enabled for accessing your database server.","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (default: enforceSSLConnectionShouldBeEnabledForMysqlDatabaseServersMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"d158790f-bfb0-486c-8631-2dc6b4e8e6af","","BuiltIn","SQL","Enforce SSL connection should be enabled for PostgreSQL database servers","Azure Database for PostgreSQL supports connecting your Azure Database for PostgreSQL server to client applications using Secure Sockets Layer (SSL). Enforcing SSL connections between your database server and your client applications helps protect against 'man in the middle' attacks by encrypting the data stream between the server and your application. This configuration enforces that SSL is always enabled for accessing your database server.","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (default: enforceSSLConnectionShouldBeEnabledForPostgresqlDatabaseServersMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"0ec47710-77ff-4a3d-9181-6aa50af424d0","","BuiltIn","SQL","Geo-redundant backup should be enabled for Azure Database for MariaDB","Azure Database for MariaDB allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create.","Azure_Security_Benchmark_v3.0_BR-1, +Azure_Security_Benchmark_v3.0_BR-2, +NIST_SP_800-53_R5_CP-6, +NIST_SP_800-53_R5_CP-6(1), +NIST_SP_800-53_R5_CP-9","ASB: Audit (default: georedundantBackupShouldBeEnabledForAzureDatabaseForMariadbMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"82339799-d096-41ae-8538-b108becf0970","","BuiltIn","SQL","Geo-redundant backup should be enabled for Azure Database for MySQL","Azure Database for MySQL allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create.","Azure_Security_Benchmark_v3.0_BR-1, +Azure_Security_Benchmark_v3.0_BR-2, +NIST_SP_800-53_R5_CP-6, +NIST_SP_800-53_R5_CP-6(1), +NIST_SP_800-53_R5_CP-9","ASB: Audit (default: georedundantBackupShouldBeEnabledForAzureDatabaseForMysqlMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"48af4db5-9b8b-401c-8e74-076be876a430","","BuiltIn","SQL","Geo-redundant backup should be enabled for Azure Database for PostgreSQL","Azure Database for PostgreSQL allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create.","Azure_Security_Benchmark_v3.0_BR-1, +Azure_Security_Benchmark_v3.0_BR-2, +NIST_SP_800-53_R5_CP-6, +NIST_SP_800-53_R5_CP-6(1), +NIST_SP_800-53_R5_CP-9","ASB: Audit (default: georedundantBackupShouldBeEnabledForAzureDatabaseForPostgresqlMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"3a58212a-c829-4f13-9872-6371df2fd0b4","","BuiltIn","SQL","Infrastructure encryption should be enabled for Azure Database for MySQL servers","Enable infrastructure encryption for Azure Database for MySQL servers to have higher level of assurance that the data is secure. When infrastructure encryption is enabled, the data at rest is encrypted twice using FIPS 140-2 compliant Microsoft managed keys.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (default: effect-3a58212a-c829-4f13-9872-6371df2fd0b4)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"24fba194-95d6-48c0-aea7-f65bf859c598","","BuiltIn","SQL","Infrastructure encryption should be enabled for Azure Database for PostgreSQL servers","Enable infrastructure encryption for Azure Database for PostgreSQL servers to have higher level of assurance that the data is secure. When infrastructure encryption is enabled, the data at rest is encrypted twice using FIPS 140-2 compliant Microsoft managed keys","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (default: effect-24fba194-95d6-48c0-aea7-f65bf859c598)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"d38fc420-0735-4ef3-ac11-c806f651a570","","BuiltIn","SQL","Long-term geo-redundant backup should be enabled for Azure SQL Databases","This policy audits any Azure SQL Database with long-term geo-redundant backup not enabled.","NIST_SP_800-53_R5_CP-6, +NIST_SP_800-53_R5_CP-6(1)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"83cef61d-dbd1-4b20-a4fc-5fbc7da10833","","BuiltIn","SQL","MySQL servers should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your MySQL servers. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: bringYourOwnKeyDataProtectionShouldBeEnabledForMySqlServersMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","Disabled","Disabled","","" +"18adea5e-f416-4d0f-8aa8-d24321e3e274","","BuiltIn","SQL","PostgreSQL servers should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your PostgreSQL servers. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: bringYourOwnKeyDataProtectionShouldBeEnabledForPostgreSqlServersMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","Disabled","Disabled","","" +"7698e800-9299-47a6-b3b6-5a0fee576eed","","BuiltIn","SQL","Private endpoint connections on Azure SQL Database should be enabled","Private endpoint connections enforce secure communication by enabling private connectivity to Azure SQL Database.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: privateEndpointConnectionsOnAzureSQLDatabaseShouldBeEnabledMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Audit","Audit","","" +"0a1302fb-a631-4106-9753-f3d494733990","","BuiltIn","SQL","Private endpoint should be enabled for MariaDB servers","Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for MariaDB. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: privateEndpointShouldBeEnabledForMariadbServersMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"7595c971-233d-4bcf-bd18-596129188c49","","BuiltIn","SQL","Private endpoint should be enabled for MySQL servers","Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for MySQL. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: privateEndpointShouldBeEnabledForMysqlServersMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"0564d078-92f5-4f97-8398-b9f58a51f70b","","BuiltIn","SQL","Private endpoint should be enabled for PostgreSQL servers","Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for PostgreSQL. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: privateEndpointShouldBeEnabledForPostgresqlServersMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1b8ca024-1d5c-4dec-8995-b1a932b41780","","BuiltIn","SQL","Public network access on Azure SQL Database should be disabled","Disabling the public network access property improves security by ensuring your Azure SQL Database can only be accessed from a private endpoint. This configuration denies all logins that match IP or virtual network based firewall rules.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: publicNetworkAccessOnAzureSQLDatabaseShouldBeDisabledMonitoringEffect), +NIST-800-53: Audit (default: effect-1b8ca024-1d5c-4dec-8995-b1a932b41780)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"fdccbe47-f3e3-4213-ad5d-ea459b2fa077","","BuiltIn","SQL","Public network access should be disabled for MariaDB servers","Disable the public network access property to improve security and ensure your Azure Database for MariaDB can only be accessed from a private endpoint. This configuration strictly disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: publicNetworkAccessShouldBeDisabledForMariaDbServersMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"d9844e8a-1437-4aeb-a32c-0c992f056095","","BuiltIn","SQL","Public network access should be disabled for MySQL servers","Disable the public network access property to improve security and ensure your Azure Database for MySQL can only be accessed from a private endpoint. This configuration strictly disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: publicNetworkAccessShouldBeDisabledForMySqlServersMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"b52376f7-9612-48a1-81cd-1ffe4b61032c","","BuiltIn","SQL","Public network access should be disabled for PostgreSQL servers","Disable the public network access property to improve security and ensure your Azure Database for PostgreSQL can only be accessed from a private endpoint. This configuration disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: publicNetworkAccessShouldBeDisabledForPostgreSqlServersMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"ac01ad65-10e5-46df-bdd9-6b0cad13e1d2","","BuiltIn","SQL","SQL managed instances should use customer-managed keys to encrypt data at rest","Implementing Transparent Data Encryption (TDE) with your own key provides you with increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. This recommendation applies to organizations with a related compliance requirement.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: ensureManagedInstanceTDEIsEncryptedWithYourOwnKeyWithDenyMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"0a370ff3-6cab-4e85-8995-295fd854c5b8","","BuiltIn","SQL","SQL servers should use customer-managed keys to encrypt data at rest","Implementing Transparent Data Encryption (TDE) with your own key provides increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. This recommendation applies to organizations with a related compliance requirement.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: ensureServerTDEIsEncryptedWithYourOwnKeyWithDenyMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"89099bee-89e0-4b26-a5f4-165451757743","","BuiltIn","SQL","SQL servers with auditing to storage account destination should be configured with 90 days retention or higher","For incident investigation purposes, we recommend setting the data retention for your SQL Server' auditing to storage account destination to at least 90 days. Confirm that you are meeting the necessary retention rules for the regions in which you are operating. This is sometimes required for compliance with regulatory standards.","Azure_Security_Benchmark_v3.0_LT-6, +NIST_SP_800-53_R5_AU-11","ASB: AuditIfNotExists (default: sQLServersShouldBeConfiguredWithAuditingRetentionDaysGreaterThan90DaysMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"17k78e20-9358-41c9-923c-fb736d382a12","","BuiltIn","SQL","Transparent Data Encryption on SQL databases should be enabled","Transparent data encryption should be enabled to protect data-at-rest and meet compliance requirements","Azure_Security_Benchmark_v3.0_DP-4, +NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","ASB: AuditIfNotExists (default: sqlDbEncryptionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"1b7aa243-30e4-4c9e-bca8-d0d3022b634a","","BuiltIn","SQL","Vulnerability assessment should be enabled on SQL Managed Instance","Audit each SQL Managed Instance which doesn't have recurring vulnerability assessment scans enabled. Vulnerability assessment can discover, track, and help you remediate potential database vulnerabilities.","Azure_Security_Benchmark_v3.0_PV-5, +NIST_SP_800-53_R5_RA-5","ASB: AuditIfNotExists (default: vulnerabilityAssessmentOnManagedInstanceMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"ef2a8f2a-b3d9-49cd-a8a8-9a3aaaf647d9","","BuiltIn","SQL","Vulnerability assessment should be enabled on your SQL servers","Audit Azure SQL servers which do not have vulnerability assessment properly configured. Vulnerability assessment can discover, track, and help you remediate potential database vulnerabilities.","Azure_Security_Benchmark_v3.0_PV-5, +NIST_SP_800-53_R5_RA-5","ASB: AuditIfNotExists (default: vulnerabilityAssessmentOnServerMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"dad3a6b9-4451-492f-a95c-69efc6f3fada","","BuiltIn","Stack HCI","[Preview]: Azure Stack HCI servers should have consistently enforced application control policies","At a minimum, apply the Microsoft WDAC base policy in enforced mode on all Azure Stack HCI servers. Applied Windows Defender Application Control (WDAC) policies must be consistent across servers in the same cluster.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (Policy Default)","override: + Audit, + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"5e6bf724-0154-49bc-985f-27b2e07e636b","","BuiltIn","Stack HCI","[Preview]: Azure Stack HCI servers should meet Secured-core requirements","Ensure that all Azure Stack HCI servers meet the Secured-core requirements. To enable the Secured-core server requirements: 1. From the Azure Stack HCI clusters page, go to Windows Admin Center and select Connect. 2. Go to the Security extension and select Secured-core. 3. Select any setting that is not enabled and click Enable.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (Policy Default)","override: + Audit, + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"ee8ca833-1583-4d24-837e-96c2af9488a4","","BuiltIn","Stack HCI","[Preview]: Azure Stack HCI systems should have encrypted volumes","Use BitLocker to encrypt the OS and data volumes on Azure Stack HCI systems.","Azure_Security_Benchmark_v3.0_DP-5","ASB: AuditIfNotExists (Policy Default)","override: + Audit, + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"36f0d6bc-a253-4df8-b25b-c3a5023ff443","","BuiltIn","Stack HCI","[Preview]: Host and VM networking should be protected on Azure Stack HCI systems","Protect data on the Azure Stack HCI hosts network and on virtual machine network connections.","Azure_Security_Benchmark_v3.0_DP-3","ASB: AuditIfNotExists (Policy Default)","override: + Audit, + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"4fa4b6c0-31ca-4c0d-b10d-24b96f62a751","","BuiltIn","Storage","[Preview]: Storage account public access should be disallowed","Anonymous public read access to containers and blobs in Azure Storage is a convenient way to share data but might present security risks. To prevent data breaches caused by undesired anonymous access, Microsoft recommends preventing public access to a storage account unless your scenario requires it.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: audit (default: disallowPublicBlobAccessEffect), +NIST-800-53: audit (default: effect-4fa4b6c0-31ca-4c0d-b10d-24b96f62a751)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"1d320205-c6a1-4ac6-873d-46224024e8e2","","BuiltIn","Storage","Azure File Sync should use private link","Creating a private endpoint for the indicated Storage Sync Service resource allows you to address your Storage Sync Service resource from within the private IP address space of your organization's network, rather than through the internet-accessible public endpoint. Creating a private endpoint by itself does not disable the public endpoint.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"bf045164-79ba-4215-8f95-f8048dc1780b","","BuiltIn","Storage","Geo-redundant storage should be enabled for Storage Accounts","Use geo-redundancy to create highly available applications","NIST_SP_800-53_R5_CP-6, +NIST_SP_800-53_R5_CP-6(1)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"970f84d8-71b6-4091-9979-ace7e3fb6dbb","","BuiltIn","Storage","HPC Cache accounts should use customer-managed key for encryption","Manage encryption at rest of Azure HPC Cache with customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-970f84d8-71b6-4091-9979-ace7e3fb6dbb)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"404c3081-a854-4457-ae30-26a93ef643f9","","BuiltIn","Storage","Secure transfer to storage accounts should be enabled","Audit requirement of Secure transfer in your storage account. Secure transfer is an option that forces your storage account to accept requests only from secure connections (HTTPS). Use of HTTPS ensures authentication between the server and the service and protects data in transit from network layer attacks such as man-in-the-middle, eavesdropping, and session-hijacking","Azure_Security_Benchmark_v3.0_DP-3, +NIST_SP_800-53_R5_SC-8, +NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (default: secureTransferToStorageAccountMonitoringEffect), +NIST-800-53: Audit (default: effect-404c3081-a854-4457-ae30-26a93ef643f9)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"b5ec538c-daa0-4006-8596-35468b9148e8","","BuiltIn","Storage","Storage account encryption scopes should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your storage account encryption scopes. Customer-managed keys enable the data to be encrypted with an Azure key-vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more about storage account encryption scopes at https://aka.ms/encryption-scopes-overview.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-b5ec538c-daa0-4006-8596-35468b9148e8)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"37e0d2fe-28a5-43d6-a273-67d37d1f5606","","BuiltIn","Storage","Storage accounts should be migrated to new Azure Resource Manager resources","Use new Azure Resource Manager for your storage accounts to provide security enhancements such as: stronger access control (RBAC), better auditing, Azure Resource Manager based deployment and governance, access to managed identities, access to key vault for secrets, Azure AD-based authentication and support for tags and resource groups for easier security management","Azure_Security_Benchmark_v3.0_AM-2, +NIST_SP_800-53_R5_AC-3","ASB: Audit (default: classicStorageAccountsMonitoringEffect), +NIST-800-53: Audit (default: effect-37e0d2fe-28a5-43d6-a273-67d37d1f5606)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"4733ea7b-a883-42fe-8cac-97454c2a9e4a","","BuiltIn","Storage","Storage accounts should have infrastructure encryption","Enable infrastructure encryption for higher level of assurance that the data is secure. When infrastructure encryption is enabled, data in a storage account is encrypted twice.","NIST_SP_800-53_R5_SC-28, +NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (default: effect-4733ea7b-a883-42fe-8cac-97454c2a9e4a)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"8c6a50c6-9ffd-4ae7-986f-5fa6111f9a54","","BuiltIn","Storage","Storage accounts should prevent shared key access","Audit requirement of Azure Active Directory (Azure AD) to authorize requests for your storage account. By default, requests can be authorized with either Azure Active Directory credentials, or by using the account access key for Shared Key authorization. Of these two types of authorization, Azure AD provides superior security and ease of use over Shared Key, and is recommended by Microsoft.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"34c877ad-507e-4c82-993e-3452a6e0ad3c","","BuiltIn","Storage","Storage accounts should restrict network access","Network access to storage accounts should be restricted. Configure network rules so only applications from allowed networks can access the storage account. To allow connections from specific internet or on-premises clients, access can be granted to traffic from specific Azure virtual networks or to public internet IP address ranges","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Disabled (default: disableUnrestrictedNetworkToStorageAccountMonitoringEffect), +NIST-800-53: Audit (default: effect-34c877ad-507e-4c82-993e-3452a6e0ad3c)","parameter: + Deny, + Audit, + Disabled","Disabled","Disabled","","" +"2a1a9cdf-e04d-429a-8416-3bfb72a1b26f","","BuiltIn","Storage","Storage accounts should restrict network access using virtual network rules","Protect your storage accounts from potential threats using virtual network rules as a preferred method instead of IP-based filtering. Disabling IP-based filtering prevents public IPs from accessing your storage accounts.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: storageAccountsShouldRestrictNetworkAccessUsingVirtualNetworkRulesMonitoringEffect), +NIST-800-53: Audit (default: effect-2a1a9cdf-e04d-429a-8416-3bfb72a1b26f)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"6fac406b-40ca-413b-bf8e-0bf964659c25","","BuiltIn","Storage","Storage accounts should use customer-managed key for encryption","Secure your blob and file storage account with greater flexibility using customer-managed keys. When you specify a customer-managed key, that key is used to protect and control access to the key that encrypts your data. Using customer-managed keys provides additional capabilities to control rotation of the key encryption key or cryptographically erase data.","Azure_Security_Benchmark_v3.0_DP-5, +NIST_SP_800-53_R5_SC-12","ASB: Disabled (default: storageAccountsShouldUseCustomerManagedKeyForEncryptionMonitoringEffect), +NIST-800-53: Audit (Policy Default)","parameter: + Audit, + Disabled","Disabled","Disabled","","" +"6edd7eda-6dd8-40f7-810d-67160c639cd9","","BuiltIn","Storage","Storage accounts should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your storage account, data leakage risks are reduced. Learn more about private links at - https://aka.ms/azureprivatelinkoverview","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (default: storageAccountShouldUseAPrivateLinkConnectionMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"87ba29ef-1ab3-4d82-b763-87fcd4f531f7","","BuiltIn","Stream Analytics","Azure Stream Analytics jobs should use customer-managed keys to encrypt data","Use customer-managed keys when you want to securely store any metadata and private data assets of your Stream Analytics jobs in your storage account. This gives you total control over how your Stream Analytics data is encrypted.","NIST_SP_800-53_R5_SC-12","NIST-800-53: audit (default: effect-87ba29ef-1ab3-4d82-b763-87fcd4f531f7)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"f9be5368-9bf5-4b84-9e0a-7850da98bb46","","BuiltIn","Stream Analytics","Resource logs in Azure Stream Analytics should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, +NIST_SP_800-53_R5_AU-6(4), +NIST_SP_800-53_R5_AU-6(5), +NIST_SP_800-53_R5_AU-12, +NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (default: diagnosticsLogsInStreamAnalyticsMonitoringEffect), +NIST-800-53: AuditIfNotExists (Policy Default)","parameter: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInStreamAnalyticsRetentionDays"":""1""}","{""diagnosticsLogsInStreamAnalyticsRetentionDays"":""1""}" +"f7d52b2d-e161-4dfa-a82b-55e564167385","","BuiltIn","Synapse","Azure Synapse workspaces should use customer-managed keys to encrypt data at rest","Use customer-managed keys to control the encryption at rest of the data stored in Azure Synapse workspaces. Customer-managed keys deliver double encryption by adding a second layer of encryption on top of the default encryption with service-managed keys.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (default: effect-f7d52b2d-e161-4dfa-a82b-55e564167385)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"72d11df1-dd8a-41f7-8925-b05b960ebafc","","BuiltIn","Synapse","Azure Synapse workspaces should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Synapse workspace, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/synapse-analytics/security/how-to-connect-to-workspace-with-private-links.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" +"6ea81a52-5ca7-4575-9669-eaa910b7edf8","","BuiltIn","Synapse","Synapse Workspaces should have Microsoft Entra-only authentication enabled","Require Synapse Workspaces to use Microsoft Entra-only authentication. This policy doesn't block workspaces from being created with local authentication enabled. It does block local authentication from being enabled on resources after create. Consider using the 'Microsoft Entra-only authentication' initiative instead to require both. Learn more at: https://aka.ms/Synapse.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"2158ddbe-fefa-408e-b43f-d4faef8ff3b8","","BuiltIn","Synapse","Synapse Workspaces should use only Microsoft Entra identities for authentication during workspace creation","Require Synapse Workspaces to be created with Microsoft Entra-only authentication. This policy doesn't block local authentication from being re-enabled on resources after create. Consider using the 'Microsoft Entra-only authentication' initiative instead to require both. Learn more at: https://aka.ms/Synapse.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","override: + Deny, + Audit, + Disabled","Audit","Audit","","" +"0049a6b3-a662-4f3e-8635-39cf44ace45a","","BuiltIn","Synapse","Vulnerability assessment should be enabled on your Synapse workspaces","Discover, track, and remediate potential vulnerabilities by configuring recurring SQL vulnerability assessment scans on your Synapse workspaces.","NIST_SP_800-53_R5_RA-5","NIST-800-53: AuditIfNotExists (Policy Default)","override: + AuditIfNotExists, + Disabled","AuditIfNotExists","AuditIfNotExists","","" +"2154edb9-244f-4741-9970-660785bccdaa","","BuiltIn","VM Image Builder","VM Image Builder templates should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your VM Image Builder building resources, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/virtual-machines/linux/image-builder-networking#deploy-using-an-existing-vnet.","Azure_Security_Benchmark_v3.0_NS-2, +NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (default: vmImageBuilderTemplatesShouldUsePrivateLinkMonitoringEffect), +NIST-800-53: Audit (default: effect-2154edb9-244f-4741-9970-660785bccdaa)","parameter: + Deny, + Audit, + Disabled","Audit","Audit","","" +"eb907f70-7514-460d-92b3-a5ae93b4f917","","BuiltIn","Web PubSub","Azure Web PubSub Service should use private link","Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Azure Web PubSub Service, you can reduce data leakage risks. Learn more about private links at: https://aka.ms/awps/privatelink.","NIST_SP_800-53_R5_AC-4, +NIST_SP_800-53_R5_AC-17, +NIST_SP_800-53_R5_AC-17(1), +NIST_SP_800-53_R5_SC-7, +NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","override: + Audit, + Disabled","Audit","Audit","","" diff --git a/StarterKit/Definitions-Microsoft-Release-Flow/policyAssignments/tag-assignments.jsonc b/StarterKit/Definitions-Microsoft-Release-Flow/policyAssignments/tag-assignments.jsonc new file mode 100644 index 00000000..bffa4d4c --- /dev/null +++ b/StarterKit/Definitions-Microsoft-Release-Flow/policyAssignments/tag-assignments.jsonc @@ -0,0 +1,128 @@ +{ + "$schema": "https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/main/Schemas/policy-assignment-schema.json", + // Modify Policies for required tags --- use this comment to trigger deployment + "nodeName": "/Tags/", + "parameters": { + "excludedRG": [ + "synapseworkspace-managedrg-*", + "databricks-rg-*", + "managed*", + "DefaultResourceGroup*", + "NetworkWatcherRG*", + "LogAnalyticsDefaultR*", + "Orca-Security*", + "rg-terraform*", + "cloud-shell-storage*" + ] + }, + "children": [ + { + "nodeName": "required-and-inherit/", + "scope": { + "epac-dev": [ + "/providers/Microsoft.Management/managementGroups/mg-epac-dev" + ], + "nonprod": [ + "/providers/Microsoft.Management/managementGroups/mg-nonprod" + ], + "prod": [ + "/providers/Microsoft.Management/managementGroups/mg-prod" + ] + }, + "definitionEntryList": [ + { + "policyName": "7ce92201-8036-4d55-938e-0dce0a5bc475", + "displayName": "Require Tag on Resource Group with dynamic notScope", + "assignment": { + "name": "rgtag-", + "displayName": "Require Tag on Resource Group - ", + "description": "Require Tag for Resource Groups when any resource group (not listed in in excludedRg) is created or updated - " + } + }, + { + "policyName": "5cc2cbfc-e306-4ec6-a141-eea3c79bb2ae", + "displayName": "Inherit Tag from Resource Group with dynamic notScope", + "assignment": { + "name": "taginh-", + "displayName": "Inherit Tag from Resource Group - ", + "description": "Modify Tag to comply with governance goal of enforcing Tags by inheriting Tags from RG - " + } + } + ], + "children": [ + { + "nodeName": "Example", + "assignment": { + "name": "Example", + "displayName": "Example", + "description": "Example" + }, + "parameters": { + "tagName": "Example" + } + }, + { + "nodeName": "Environment", + "assignment": { + "name": "Environment", + "displayName": "Environment", + "description": "Environment" + }, + "parameters": { + "tagName": "Environment" + } + } + ] + }, + { + "nodeName": "Environment/", + "definitionEntry": { + "policyName": "2076e19d-45f9-4564-a459-bb5a0aeaff85", + "displayName": "Add/Replace Tag on Resource Group with dynamic notScope" + }, + "parameters": { + "tagName": "Environment" + }, + "children": [ + { + "nodeName": "PROD", + "assignment": { + "name": "prod-env-tag", + "displayName": "Prod Environment Tag", + "description": "Set Tag Environment to PROD" + }, + "parameters": { + "tagValue": "PROD" + }, + "scope": { + "epac-dev": [ + "providers/Microsoft.Management/managementGroups/mg-epac-dev-prod" + ], + "prod": [ + "/providers/Microsoft.Management/managementGroups/mg-prod" + ] + } + }, + { + "nodeName": "NONPROD", + "assignment": { + "name": "prod-env-tag", + "displayName": "NonProd Environment Tag", + "description": "Set Tag Environment to NONPROD" + }, + "parameters": { + "tagValue": "NONPROD" + }, + "scope": { + "epac-dev": [ + "/providers/Microsoft.Management/managementGroups/mg-epac-dev-nonprod" + ], + "nonprod": [ + "/providers/Microsoft.Management/managementGroups/mg-nonprod" + ] + } + } + ] + } + ] +} \ No newline at end of file diff --git a/StarterKit/Definitions/policyDocumentations/contoso.jsonc b/StarterKit/Definitions-Microsoft-Release-Flow/policyDocumentations/contoso.jsonc similarity index 100% rename from StarterKit/Definitions/policyDocumentations/contoso.jsonc rename to StarterKit/Definitions-Microsoft-Release-Flow/policyDocumentations/contoso.jsonc diff --git a/StarterKit/Definitions/policyAssignments/security-baseline-parameters.csv b/StarterKit/Definitions/policyAssignments/security-baseline-parameters.csv deleted file mode 100644 index bdc71f04..00000000 --- a/StarterKit/Definitions/policyAssignments/security-baseline-parameters.csv +++ /dev/null @@ -1,2815 +0,0 @@ -"name","referencePath","policyType","category","displayName","description","groupNames","policySets","allowedEffects","prodEffect","testEffect","devEffect","sandboxEffect","prodParameters","testParameters","devParameters","sandboxParameters" -"051cba44-2429-45b9-9649-46cec11c7119","","BuiltIn","API for FHIR","Azure API for FHIR should use a customer-managed key to encrypt data at rest","Use a customer-managed key to control the encryption at rest of the data stored in Azure API for FHIR when this is a regulatory or compliance requirement. Customer-managed keys also deliver double encryption by adding a second layer of encryption on top of the default one done with service-managed keys.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (Policy Default)","audit, -Audit, -disabled, -Disabled","Audit","Audit","Audit","Audit","","","","" -"1ee56206-5dd1-42ab-b02d-8aae8b1634ce","","BuiltIn","API for FHIR","Azure API for FHIR should use private link","Azure API for FHIR should have at least one approved private endpoint connection. Clients in a virtual network can securely access resources that have private endpoint connections through private links. For more information, visit: https://aka.ms/fhir-privatelink.","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" -"ee7495e7-3ba7-40b6-bfee-c29e22cc75d4","","BuiltIn","API Management","API Management APIs should use only encrypted protocols","To ensure security of data in transit, APIs should be available only through encrypted protocols, like HTTPS or WSS. Avoid using unsecured protocols, such as HTTP or WS.","Azure_Security_Benchmark_v3.0_DP-3","ASB: Audit (Policy Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"c15dcc82-b93c-4dcb-9332-fbf121685b54","","BuiltIn","API Management","API Management calls to API backends should be authenticated","Calls from API Management to backends should use some form of authentication, whether via certificates or credentials. Does not apply to Service Fabric backends.","Azure_Security_Benchmark_v3.0_IM-4","ASB: Audit (Policy Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"92bb331d-ac71-416a-8c91-02f2cb734ce4","","BuiltIn","API Management","API Management calls to API backends should not bypass certificate thumbprint or name validation","To improve the API security, API Management should validate the backend server certificate for all API calls. Enable SSL certificate thumbprint and name validation.","Azure_Security_Benchmark_v3.0_IM-4","ASB: Audit (Policy Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"b741306c-968e-4b67-b916-5675e5c709f4","","BuiltIn","API Management","API Management direct management endpoint should not be enabled","The direct management REST API in Azure API Management bypasses Azure Resource Manager role-based access control, authorization, and throttling mechanisms, thus increasing the vulnerability of your service.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (Policy Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"549814b6-3212-4203-bdc8-1548d342fb67","","BuiltIn","API Management","API Management minimum API version should be set to 2019-12-01 or higher","To prevent service secrets from being shared with read-only users, the minimum API version should be set to 2019-12-01 or higher.","Azure_Security_Benchmark_v3.0_IM-8, -Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (Policy Default)","Audit, -Deny, -Disabled","Audit","Audit","Audit","Audit","","","","" -"f1cc7827-022c-473e-836e-5a51cae0b249","","BuiltIn","API Management","API Management secret named values should be stored in Azure Key Vault","Named values are a collection of name and value pairs in each API Management service. Secret values can be stored either as encrypted text in API Management (custom secrets) or by referencing secrets in Azure Key Vault. To improve security of API Management and secrets, reference secret named values from Azure Key Vault. Azure Key Vault supports granular access management and secret rotation policies.","Azure_Security_Benchmark_v3.0_IM-8, -Azure_Security_Benchmark_v3.0_DP-6","ASB: Audit (Policy Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"ef619a2c-cc4d-4d03-b2ba-8c94a834d85b","","BuiltIn","API Management","API Management services should use a virtual network","Azure Virtual Network deployment provides enhanced security, isolation and allows you to place your API Management service in a non-internet routable network that you control access to. These networks can then be connected to your on-premises networks using various VPN technologies, which enables access to your backend services within the network and/or on-premises. The developer portal and API gateway, can be configured to be accessible either from the Internet or only within the virtual network.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","{""evaluatedSkuNames-ef619a2c-cc4d-4d03-b2ba-8c94a834d85b"":[""Developer"",""Premium""],""aPIManagementServicesShouldUseAVirtualNetworkEvaluatedSkuNames"":[""Developer"",""Premium""]}","{""evaluatedSkuNames-ef619a2c-cc4d-4d03-b2ba-8c94a834d85b"":[""Developer"",""Premium""],""aPIManagementServicesShouldUseAVirtualNetworkEvaluatedSkuNames"":[""Developer"",""Premium""]}","{""evaluatedSkuNames-ef619a2c-cc4d-4d03-b2ba-8c94a834d85b"":[""Developer"",""Premium""],""aPIManagementServicesShouldUseAVirtualNetworkEvaluatedSkuNames"":[""Developer"",""Premium""]}","{""evaluatedSkuNames-ef619a2c-cc4d-4d03-b2ba-8c94a834d85b"":[""Developer"",""Premium""],""aPIManagementServicesShouldUseAVirtualNetworkEvaluatedSkuNames"":[""Developer"",""Premium""]}" -"df73bd95-24da-4a4f-96b9-4e8b94b402bd","","BuiltIn","API Management","API Management should disable public network access to the service configuration endpoints","To improve the security of API Management services, restrict connectivity to service configuration endpoints, like direct access management API, Git configuration management endpoint, or self-hosted gateways configuration endpoint.","Azure_Security_Benchmark_v3.0_NS-2","ASB: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"3aa03346-d8c5-4994-a5bc-7652c2a2aef1","","BuiltIn","API Management","API Management subscriptions should not be scoped to all APIs","API Management subscriptions should be scoped to a product or an individual API instead of all APIs, which could result in an excessive data exposure.","Azure_Security_Benchmark_v3.0_PA-7","ASB: Audit (Policy Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"ca610c1d-041c-4332-9d88-7ed3094967c7","","BuiltIn","App Configuration","App Configuration should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your app configuration instances instead of the entire service, you'll also be protected against data leakage risks. Learn more at: https://aka.ms/appconfig/private-endpoint.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"af35e2a4-ef96-44e7-a9ae-853dd97032c4","","BuiltIn","App Platform","Azure Spring Cloud should use network injection","Azure Spring Cloud instances should use virtual network injection for the following purposes: 1. Isolate Azure Spring Cloud from Internet. 2. Enable Azure Spring Cloud to interact with systems in either on premises data centers or Azure service in other virtual networks. 3. Empower customers to control inbound and outbound network communications for Azure Spring Cloud.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","{""evaluatedSkuNames-af35e2a4-ef96-44e7-a9ae-853dd97032c4"":[""Standard""]}","{""evaluatedSkuNames-af35e2a4-ef96-44e7-a9ae-853dd97032c4"":[""Standard""]}","{""evaluatedSkuNames-af35e2a4-ef96-44e7-a9ae-853dd97032c4"":[""Standard""]}","{""evaluatedSkuNames-af35e2a4-ef96-44e7-a9ae-853dd97032c4"":[""Standard""]}" -"5bb220d9-2698-4ee4-8404-b9c30c9df609","","BuiltIn","App Service","App Service apps should have 'Client Certificates (Incoming client certificates)' enabled","Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"cb510bfd-1cba-4d9f-a230-cb0976f4bb71","","BuiltIn","App Service","App Service apps should have remote debugging turned off","Remote debugging requires inbound ports to be opened on an App Service app. Remote debugging should be turned off.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"91a78b24-f231-4a8a-8da9-02c35b2b6510","","BuiltIn","App Service","App Service apps should have resource logs enabled","Audit enabling of resource logs on the app. This enables you to recreate activity trails for investigation purposes if a security incident occurs or your network is compromised.","Azure_Security_Benchmark_v3.0_LT-3, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"5744710e-cc2f-4ee8-8809-3b11e89f4bc9","","BuiltIn","App Service","App Service apps should not have CORS configured to allow every resource to access your apps","Cross-Origin Resource Sharing (CORS) should not allow all domains to access your app. Allow only required domains to interact with your app.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"a4af4a39-4135-47fb-b175-47fbdf85311d","","BuiltIn","App Service","App Service apps should only be accessible over HTTPS","Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks.","Azure_Security_Benchmark_v3.0_DP-3, -NIST_SP_800-53_R5_SC-8, -NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"4d24b6d4-5e53-4a4f-a7f4-618fa573ee4b","","BuiltIn","App Service","App Service apps should require FTPS only","Enable FTPS enforcement for enhanced security.","Azure_Security_Benchmark_v3.0_DP-3, -NIST_SP_800-53_R5_SC-8, -NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"8c122334-9d20-4eb8-89ea-ac9a705b74ae","","BuiltIn","App Service","App Service apps should use latest 'HTTP Version'","Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version.","NIST_SP_800-53_R5_SI-2, -NIST_SP_800-53_R5_SI-2(6)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"2b9ad585-36bc-4615-b300-fd4435808332","","BuiltIn","App Service","App Service apps should use managed identity","Use a managed identity for enhanced authentication security","Azure_Security_Benchmark_v3.0_IM-3, -NIST_SP_800-53_R5_AC-2, -NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_IA-2, -NIST_SP_800-53_R5_IA-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"f0e6e85b-9b9f-4a4b-b67b-f730d42f1b0b","","BuiltIn","App Service","App Service apps should use the latest TLS version","Periodically, newer versions are released for TLS either due to security flaws, include additional functionality, and enhance speed. Upgrade to the latest TLS version for App Service apps to take advantage of security fixes, if any, and/or new functionalities of the latest version.","Azure_Security_Benchmark_v3.0_NS-8, -Azure_Security_Benchmark_v3.0_DP-3, -NIST_SP_800-53_R5_SC-8, -NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"fb74e86f-d351-4b8d-b034-93da7391c01f","","BuiltIn","App Service","App Service Environment should have internal encryption enabled","Setting InternalEncryption to true encrypts the pagefile, worker disks, and internal network traffic between the front ends and workers in an App Service Environment. To learn more, refer to https://docs.microsoft.com/azure/app-service/environment/app-service-app-service-environment-custom-settings#enable-internal-encryption.","NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" -"eaebaea7-8013-4ceb-9d14-7eb32271373c","","BuiltIn","App Service","Function apps should have 'Client Certificates (Incoming client certificates)' enabled","Client certificates allow for the app to request a certificate for incoming requests. Only clients with valid certificates will be able to reach the app.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"0e60b895-3786-45da-8377-9c6b4b6ac5f9","","BuiltIn","App Service","Function apps should have remote debugging turned off","Remote debugging requires inbound ports to be opened on Function apps. Remote debugging should be turned off.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"0820b7b9-23aa-4725-a1ce-ae4558f718e5","","BuiltIn","App Service","Function apps should not have CORS configured to allow every resource to access your apps","Cross-Origin Resource Sharing (CORS) should not allow all domains to access your Function app. Allow only required domains to interact with your Function app.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"6d555dd1-86f2-4f1c-8ed7-5abae7c6cbab","","BuiltIn","App Service","Function apps should only be accessible over HTTPS","Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks.","Azure_Security_Benchmark_v3.0_DP-3, -NIST_SP_800-53_R5_SC-8, -NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"399b2637-a50f-4f95-96f8-3a145476eb15","","BuiltIn","App Service","Function apps should require FTPS only","Enable FTPS enforcement for enhanced security.","Azure_Security_Benchmark_v3.0_DP-3, -NIST_SP_800-53_R5_SC-8, -NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"e2c1c086-2d84-4019-bff3-c44ccd95113c","","BuiltIn","App Service","Function apps should use latest 'HTTP Version'","Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version.","NIST_SP_800-53_R5_SI-2, -NIST_SP_800-53_R5_SI-2(6)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"0da106f2-4ca3-48e8-bc85-c638fe6aea8f","","BuiltIn","App Service","Function apps should use managed identity","Use a managed identity for enhanced authentication security","Azure_Security_Benchmark_v3.0_IM-3, -NIST_SP_800-53_R5_AC-2, -NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_IA-2, -NIST_SP_800-53_R5_IA-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"f9d614c5-c173-4d56-95a7-b4437057d193","","BuiltIn","App Service","Function apps should use the latest TLS version","Periodically, newer versions are released for TLS either due to security flaws, include additional functionality, and enhance speed. Upgrade to the latest TLS version for Function apps to take advantage of security fixes, if any, and/or new functionalities of the latest version.","Azure_Security_Benchmark_v3.0_NS-8, -Azure_Security_Benchmark_v3.0_DP-3, -NIST_SP_800-53_R5_SC-8, -NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"3657f5a0-770e-44a3-b44e-9431ba1e9735","","BuiltIn","Automation","Automation account variables should be encrypted","It is important to enable encryption of Automation account variable assets when storing sensitive data","Azure_Security_Benchmark_v3.0_DP-4, -NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"56a5ee18-2ae6-4810-86f7-18e39ce5629b","","BuiltIn","Automation","Azure Automation accounts should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your Azure Automation Accounts. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/automation-cmk.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"81e74cea-30fd-40d5-802f-d72103c2aaaa","","BuiltIn","Azure Data Explorer","Azure Data Explorer encryption at rest should use a customer-managed key","Enabling encryption at rest using a customer-managed key on your Azure Data Explorer cluster provides additional control over the key being used by the encryption at rest. This feature is oftentimes applicable to customers with special compliance requirements and requires a Key Vault to managing the keys.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"f4b53539-8df9-40e4-86c6-6b607703bd4e","","BuiltIn","Azure Data Explorer","Disk encryption should be enabled on Azure Data Explorer","Enabling disk encryption helps protect and safeguard your data to meet your organizational security and compliance commitments.","NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"ec068d99-e9c7-401f-8cef-5bdde4e6ccf1","","BuiltIn","Azure Data Explorer","Double encryption should be enabled on Azure Data Explorer","Enabling double encryption helps protect and safeguard your data to meet your organizational security and compliance commitments. When double encryption has been enabled, data in the storage account is encrypted twice, once at the service level and once at the infrastructure level, using two different encryption algorithms and two different keys.","NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"51c1490f-3319-459c-bbbc-7f391bbed753","","BuiltIn","Azure Databricks","Azure Databricks Clusters should disable public IP","Disabling public IP of clusters in Azure Databricks Workspaces improves security by ensuring that the clusters aren't exposed on the public internet. Learn more at: https://learn.microsoft.com/azure/databricks/security/secure-cluster-connectivity.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","Audit, -Deny, -Disabled","Audit","Audit","Audit","Audit","","","","" -"9c25c9e4-ee12-4882-afd2-11fb9d87893f","","BuiltIn","Azure Databricks","Azure Databricks Workspaces should be in a virtual network","Azure Virtual Networks provide enhanced security and isolation for your Azure Databricks Workspaces, as well as subnets, access control policies, and other features to further restrict access. Learn more at: https://docs.microsoft.com/azure/databricks/administration-guide/cloud-configurations/azure/vnet-inject.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","Audit, -Deny, -Disabled","Audit","Audit","Audit","Audit","","","","" -"0e7849de-b939-4c50-ab48-fc6b0f5eeba2","","BuiltIn","Azure Databricks","Azure Databricks Workspaces should disable public network access","Disabling public network access improves security by ensuring that the resource isn't exposed on the public internet. You can control exposure of your resources by creating private endpoints instead. Learn more at: https://learn.microsoft.com/azure/databricks/administration-guide/cloud-configurations/azure/private-link. ","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","Audit, -Deny, -Disabled","Audit","Audit","Audit","Audit","","","","" -"258823f2-4595-4b52-b333-cc96192710d8","","BuiltIn","Azure Databricks","Azure Databricks Workspaces should use private link","Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Databricks workspaces, you can reduce data leakage risks. Learn more about private links at: https://aka.ms/adbpe.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" -"138ff14d-b687-4faa-a81c-898c91a87fa2","","BuiltIn","Azure Databricks","Resource logs in Azure Databricks Workspaces should be enabled","Resource logs enable recreating activity trails to use for investigation purposes when a security incident occurs or when your network is compromised.","Azure_Security_Benchmark_v3.0_LT-3","ASB: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"b4ac1030-89c5-4697-8e00-28b5ba6a8811","","BuiltIn","Azure Stack Edge","Azure Stack Edge devices should use double-encryption","To secure the data at rest on the device, ensure it's double-encrypted, the access to data is controlled, and once the device is deactivated, the data is securely erased off the data disks. Double encryption is the use of two layers of encryption: BitLocker XTS-AES 256-bit encryption on the data volumes and built-in encryption of the hard drives. Learn more in the security overview documentation for the specific Stack Edge device.","NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","audit","audit","audit","audit","","","","" -"2e94d99a-8a36-4563-bc77-810d8893b671","","BuiltIn","Backup","[Preview]: Azure Recovery Services vaults should use customer-managed keys for encrypting backup data","Use customer-managed keys to manage the encryption at rest of your backup data. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/AB-CmkEncryption.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","{""enableDoubleEncryption-2e94d99a-8a36-4563-bc77-810d8893b671"":true}","{""enableDoubleEncryption-2e94d99a-8a36-4563-bc77-810d8893b671"":true}","{""enableDoubleEncryption-2e94d99a-8a36-4563-bc77-810d8893b671"":true}","{""enableDoubleEncryption-2e94d99a-8a36-4563-bc77-810d8893b671"":true}" -"013e242c-8828-4970-87b3-ab247555486d","","BuiltIn","Backup","Azure Backup should be enabled for Virtual Machines","Ensure protection of your Azure Virtual Machines by enabling Azure Backup. Azure Backup is a secure and cost effective data protection solution for Azure.","Azure_Security_Benchmark_v3.0_BR-1, -Azure_Security_Benchmark_v3.0_BR-2, -NIST_SP_800-53_R5_CP-9","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"99e9ccd8-3db9-4592-b0d1-14b1715a4d8a","","BuiltIn","Batch","Azure Batch account should use customer-managed keys to encrypt data","Use customer-managed keys to manage the encryption at rest of your Batch account's data. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/Batch-CMK.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"428256e6-1fac-4f48-a757-df34c2b3336d","","BuiltIn","Batch","Resource logs in Batch accounts should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInBatchAccountRetentionDays"":""1""}","{""diagnosticsLogsInBatchAccountRetentionDays"":""1""}","{""diagnosticsLogsInBatchAccountRetentionDays"":""1""}","{""diagnosticsLogsInBatchAccountRetentionDays"":""1""}" -"51522a96-0869-4791-82f3-981000c2c67f","","BuiltIn","Bot Service","Bot Service should be encrypted with a customer-managed key","Azure Bot Service automatically encrypts your resource to protect your data and meet organizational security and compliance commitments. By default, Microsoft-managed encryption keys are used. For greater flexibility in managing keys or controlling access to your subscription, select customer-managed keys, also known as bring your own key (BYOK). Learn more about Azure Bot Service encryption: https://docs.microsoft.com/azure/bot-service/bot-service-encryption.","NIST_SP_800-53_R5_SC-12","NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","audit","audit","audit","audit","","","","" -"7803067c-7d34-46e3-8c79-0ca68fc4036d","","BuiltIn","Cache","Azure Cache for Redis should use private link","Private endpoints lets you connect your virtual network to Azure services without a public IP address at the source or destination. By mapping private endpoints to your Azure Cache for Redis instances, data leakage risks are reduced. Learn more at: https://docs.microsoft.com/azure/azure-cache-for-redis/cache-private-link.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"22bee202-a82f-4305-9a2a-6d7f44d4dedb","","BuiltIn","Cache","Only secure connections to your Azure Cache for Redis should be enabled","Audit enabling of only connections via SSL to Azure Cache for Redis. Use of secure connections ensures authentication between the server and the service and protects data in transit from network layer attacks such as man-in-the-middle, eavesdropping, and session-hijacking","Azure_Security_Benchmark_v3.0_DP-3, -NIST_SP_800-53_R5_SC-8, -NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"0725b4dd-7e76-479c-a735-68e7ee23d5ca","","BuiltIn","Cognitive Services","Cognitive Services accounts should disable public network access","To improve the security of Cognitive Services accounts, ensure that it isn't exposed to the public internet and can only be accessed from a private endpoint. Disable the public network access property as described in https://go.microsoft.com/fwlink/?linkid=2129800. This option disables access from any public address space outside the Azure IP range, and denies all logins that match IP or virtual network-based firewall rules. This reduces data leakage risks.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"67121cc7-ff39-4ab8-b7e3-95b84dab487d","","BuiltIn","Cognitive Services","Cognitive Services accounts should enable data encryption with a customer-managed key","Customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data stored in Cognitive Services to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more about customer-managed keys at https://go.microsoft.com/fwlink/?linkid=2121321.","Azure_Security_Benchmark_v3.0_DP-5, -NIST_SP_800-53_R5_SC-12","ASB: Disabled (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Disabled","Disabled","Disabled","Disabled","","","","" -"71ef260a-8f18-47b7-abcb-62d0673d94dc","","BuiltIn","Cognitive Services","Cognitive Services accounts should have local authentication methods disabled","Disabling local authentication methods improves security by ensuring that Cognitive Services accounts require Azure Active Directory identities exclusively for authentication. Learn more at: https://aka.ms/cs/auth.","NIST_SP_800-53_R5_AC-2, -NIST_SP_800-53_R5_AC-2(1), -NIST_SP_800-53_R5_AC-2(7), -NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_IA-2, -NIST_SP_800-53_R5_IA-4","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"037eea7a-bd0a-46c5-9a66-03aea78705d3","","BuiltIn","Cognitive Services","Cognitive Services accounts should restrict network access","Network access to Cognitive Services accounts should be restricted. Configure network rules so only applications from allowed networks can access the Cognitive Services account. To allow connections from specific internet or on-premises clients, access can be granted to traffic from specific Azure virtual networks or to public internet IP address ranges.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"cddd188c-4b82-4c48-a19d-ddf74ee66a01","","BuiltIn","Cognitive Services","Cognitive Services should use private link","Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Cognitive Services, you'll reduce the potential for data leakage. Learn more about private links at: https://go.microsoft.com/fwlink/?linkid=2129800.","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" -"0015ea4d-51ff-4ce3-8d8c-f3f8f0179a56","","BuiltIn","Compute","Audit virtual machines without disaster recovery configured","Audit virtual machines which do not have disaster recovery configured. To learn more about disaster recovery, visit https://aka.ms/asr-doc.","NIST_SP_800-53_R5_CP-7","NIST-800-53: auditIfNotExists (Policy Fixed)","Disabled, -AuditIfNotExists","auditIfNotExists","auditIfNotExists","auditIfNotExists","auditIfNotExists","","","","" -"f39f5f49-4abf-44de-8c70-0756997bfb51","","BuiltIn","Compute","Disk access resources should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to diskAccesses, data leakage risks are reduced. Learn more about private links at: https://aka.ms/disksprivatelinksdoc. ","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"ca91455f-eace-4f96-be59-e6e2c35b4816","","BuiltIn","Compute","Managed disks should be double encrypted with both platform-managed and customer-managed keys","High security sensitive customers who are concerned of the risk associated with any particular encryption algorithm, implementation, or key being compromised can opt for additional layer of encryption using a different encryption algorithm/mode at the infrastructure layer using platform managed encryption keys. The disk encryption sets are required to use double encryption. Learn more at https://aka.ms/disks-doubleEncryption.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"702dd420-7fcc-42c5-afe8-4026edd20fe0","","BuiltIn","Compute","OS and data disks should be encrypted with a customer-managed key","Use customer-managed keys to manage the encryption at rest of the contents of your managed disks. By default, the data is encrypted at rest with platform-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/disks-cmk.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"fc4d8e41-e223-45ea-9bf5-eada37891d87","","BuiltIn","Compute","Virtual machines and virtual machine scale sets should have encryption at host enabled","Use encryption at host to get end-to-end encryption for your virtual machine and virtual machine scale set data. Encryption at host enables encryption at rest for your temporary disk and OS/data disk caches. Temporary and ephemeral OS disks are encrypted with platform-managed keys when encryption at host is enabled. OS/data disk caches are encrypted at rest with either customer-managed or platform-managed key, depending on the encryption type selected on the disk. Learn more at https://aka.ms/vm-hbe.","NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"1d84d5fb-01f6-4d12-ba4f-4a26081d403d","","BuiltIn","Compute","Virtual machines should be migrated to new Azure Resource Manager resources","Use new Azure Resource Manager for your virtual machines to provide security enhancements such as: stronger access control (RBAC), better auditing, Azure Resource Manager based deployment and governance, access to managed identities, access to key vault for secrets, Azure AD-based authentication and support for tags and resource groups for easier security management","Azure_Security_Benchmark_v3.0_AM-2, -NIST_SP_800-53_R5_AC-3","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"0aa61e00-0a01-4a3c-9945-e93cffedf0e6","","BuiltIn","Container Instance","Azure Container Instance container group should use customer-managed key for encryption","Secure your containers with greater flexibility using customer-managed keys. When you specify a customer-managed key, that key is used to protect and control access to the key that encrypts your data. Using customer-managed keys provides additional capabilities to control rotation of the key encryption key or cryptographically erase data.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"5b9159ae-1701-4a6f-9a7a-aa9c8ddd0580","","BuiltIn","Container Registry","Container registries should be encrypted with a customer-managed key","Use customer-managed keys to manage the encryption at rest of the contents of your registries. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/acr/CMK.","Azure_Security_Benchmark_v3.0_DP-5, -NIST_SP_800-53_R5_SC-12","ASB: Disabled (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Disabled","Disabled","Disabled","Disabled","","","","" -"d0793b48-0edc-4296-a390-4c75d1bdfd71","","BuiltIn","Container Registry","Container registries should not allow unrestricted network access","Azure container registries by default accept connections over the internet from hosts on any network. To protect your registries from potential threats, allow access from only specific private endpoints, public IP addresses or address ranges. If your registry doesn't have network rules configured, it will appear in the unhealthy resources. Learn more about Container Registry network rules here: https://aka.ms/acr/privatelink, https://aka.ms/acr/portal/public-network and https://aka.ms/acr/vnet.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"e8eef0a8-67cf-4eb4-9386-14b0e78733d4","","BuiltIn","Container Registry","Container registries should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network.By mapping private endpoints to your container registries instead of the entire service, you'll also be protected against data leakage risks. Learn more at: https://aka.ms/acr/private-link.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"862e97cf-49fc-4a5c-9de4-40d4e2e7c8eb","","BuiltIn","Cosmos DB","Azure Cosmos DB accounts should have firewall rules","Firewall rules should be defined on your Azure Cosmos DB accounts to prevent traffic from unauthorized sources. Accounts that have at least one IP rule defined with the virtual network filter enabled are deemed compliant. Accounts disabling public access are also deemed compliant.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"1f905d99-2ab7-462c-a6b0-f709acca6c8f","","BuiltIn","Cosmos DB","Azure Cosmos DB accounts should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your Azure Cosmos DB. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/cosmosdb-cmk.","Azure_Security_Benchmark_v3.0_DP-5, -NIST_SP_800-53_R5_SC-12","ASB: disabled (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","disabled","disabled","disabled","disabled","","","","" -"5450f5bd-9c72-4390-a9c4-a7aba4edfdd2","","BuiltIn","Cosmos DB","Cosmos DB database accounts should have local authentication methods disabled","Disabling local authentication methods improves security by ensuring that Cosmos DB database accounts exclusively require Azure Active Directory identities for authentication. Learn more at: https://docs.microsoft.com/azure/cosmos-db/how-to-setup-rbac#disable-local-auth.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"58440f8a-10c5-4151-bdce-dfbaad4a20b7","","BuiltIn","Cosmos DB","CosmosDB accounts should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your CosmosDB account, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/cosmos-db/how-to-configure-private-endpoints.","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" -"c349d81b-9985-44ae-a8da-ff98d108ede8","","BuiltIn","Data Box","Azure Data Box jobs should enable double encryption for data at rest on the device","Enable a second layer of software-based encryption for data at rest on the device. The device is already protected via Advanced Encryption Standard 256-bit encryption for data at rest. This option adds a second layer of data encryption.","NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","{""supportedSKUs-c349d81b-9985-44ae-a8da-ff98d108ede8"":[""DataBox"",""DataBoxHeavy""]}","{""supportedSKUs-c349d81b-9985-44ae-a8da-ff98d108ede8"":[""DataBox"",""DataBoxHeavy""]}","{""supportedSKUs-c349d81b-9985-44ae-a8da-ff98d108ede8"":[""DataBox"",""DataBoxHeavy""]}","{""supportedSKUs-c349d81b-9985-44ae-a8da-ff98d108ede8"":[""DataBox"",""DataBoxHeavy""]}" -"86efb160-8de7-451d-bc08-5d475b0aadae","","BuiltIn","Data Box","Azure Data Box jobs should use a customer-managed key to encrypt the device unlock password","Use a customer-managed key to control the encryption of the device unlock password for Azure Data Box. Customer-managed keys also help manage access to the device unlock password by the Data Box service in order to prepare the device and copy data in an automated manner. The data on the device itself is already encrypted at rest with Advanced Encryption Standard 256-bit encryption, and the device unlock password is encrypted by default with a Microsoft managed key.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","{""supportedSKUs-86efb160-8de7-451d-bc08-5d475b0aadae"":[""DataBox"",""DataBoxHeavy""]}","{""supportedSKUs-86efb160-8de7-451d-bc08-5d475b0aadae"":[""DataBox"",""DataBoxHeavy""]}","{""supportedSKUs-86efb160-8de7-451d-bc08-5d475b0aadae"":[""DataBox"",""DataBoxHeavy""]}","{""supportedSKUs-86efb160-8de7-451d-bc08-5d475b0aadae"":[""DataBox"",""DataBoxHeavy""]}" -"4ec52d6d-beb7-40c4-9a9e-fe753254690e","","BuiltIn","Data Factory","Azure data factories should be encrypted with a customer-managed key","Use customer-managed keys to manage the encryption at rest of your Azure Data Factory. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/adf-cmk.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"8b0323be-cc25-4b61-935d-002c3798c6ea","","BuiltIn","Data Factory","Azure Data Factory should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Data Factory, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/data-factory/data-factory-private-link.","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"057ef27e-665e-4328-8ea3-04b3122bd9fb","","BuiltIn","Data Lake","Resource logs in Azure Data Lake Store should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInDataLakeStoreRetentionDays"":""1""}","{""diagnosticsLogsInDataLakeStoreRetentionDays"":""1""}","{""diagnosticsLogsInDataLakeStoreRetentionDays"":""1""}","{""diagnosticsLogsInDataLakeStoreRetentionDays"":""1""}" -"c95c74d9-38fe-4f0d-af86-0c7d626a315c","","BuiltIn","Data Lake","Resource logs in Data Lake Analytics should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInDataLakeAnalyticsRetentionDays"":""1""}","{""diagnosticsLogsInDataLakeAnalyticsRetentionDays"":""1""}","{""diagnosticsLogsInDataLakeAnalyticsRetentionDays"":""1""}","{""diagnosticsLogsInDataLakeAnalyticsRetentionDays"":""1""}" -"9830b652-8523-49cc-b1b3-e17dce1127ca","","BuiltIn","Event Grid","Azure Event Grid domains should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Event Grid domain instead of the entire service, you'll also be protected against data leakage risks. Learn more at: https://aka.ms/privateendpoints.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"4b90e17e-8448-49db-875e-bd83fb6f804f","","BuiltIn","Event Grid","Azure Event Grid topics should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Event Grid topic instead of the entire service, you'll also be protected against data leakage risks. Learn more at: https://aka.ms/privateendpoints.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"a1ad735a-e96f-45d2-a7b2-9a4932cab7ec","","BuiltIn","Event Hub","Event Hub namespaces should use a customer-managed key for encryption","Azure Event Hubs supports the option of encrypting data at rest with either Microsoft-managed keys (default) or customer-managed keys. Choosing to encrypt data using customer-managed keys enables you to assign, rotate, disable, and revoke access to the keys that Event Hub will use to encrypt data in your namespace. Note that Event Hub only supports encryption with customer-managed keys for namespaces in dedicated clusters.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" -"b8564268-eb4a-4337-89be-a19db070c59d","","BuiltIn","Event Hub","Event Hub namespaces should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Event Hub namespaces, data leakage risks are reduced. Learn more at: https://docs.microsoft.com/azure/event-hubs/private-link-service.","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"83a214f7-d01a-484b-91a9-ed54470c9a6a","","BuiltIn","Event Hub","Resource logs in Event Hub should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInEventHubRetentionDays"":""1""}","{""diagnosticsLogsInEventHubRetentionDays"":""1""}","{""diagnosticsLogsInEventHubRetentionDays"":""1""}","{""diagnosticsLogsInEventHubRetentionDays"":""1""}" -"a451c1ef-c6ca-483d-87ed-f49761e3ffb5","","BuiltIn","General","Audit usage of custom RBAC roles","Audit built-in roles such as 'Owner, Contributer, Reader' instead of custom RBAC roles, which are error prone. Using custom roles is treated as an exception and requires a rigorous review and threat modeling","Azure_Security_Benchmark_v3.0_PA-7, -NIST_SP_800-53_R5_AC-2, -NIST_SP_800-53_R5_AC-2(7), -NIST_SP_800-53_R5_AC-6, -NIST_SP_800-53_R5_AC-6(7)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"ca88aadc-6e2b-416c-9de2-5a0f01d1693f","","BuiltIn","Guest Configuration","[Preview]: Linux virtual machines should enable Azure Disk Encryption or EncryptionAtHost.","By default, a virtual machine's OS and data disks are encrypted-at-rest using platform-managed keys; temp disks and data caches aren't encrypted, and data isn't encrypted when flowing between compute and storage resources. Use Azure Disk Encryption or EncryptionAtHost to encrypt all this data.Visit https://aka.ms/diskencryptioncomparison to compare encryption offerings. This policy requires two prerequisites to be deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol.","Azure_Security_Benchmark_v3.0_DP-4","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"3dc5edcd-002d-444c-b216-e123bbfa37c0","","BuiltIn","Guest Configuration","[Preview]: Windows virtual machines should enable Azure Disk Encryption or EncryptionAtHost.","By default, a virtual machine's OS and data disks are encrypted-at-rest using platform-managed keys; temp disks and data caches aren't encrypted, and data isn't encrypted when flowing between compute and storage resources. Use Azure Disk Encryption or EncryptionAtHost to encrypt all this data.Visit https://aka.ms/diskencryptioncomparison to compare encryption offerings. This policy requires two prerequisites to be deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol.","Azure_Security_Benchmark_v3.0_DP-4","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"3cf2ab00-13f1-4d0c-8971-2ac904541a7e","","BuiltIn","Guest Configuration","Add system-assigned managed identity to enable Guest Configuration assignments on virtual machines with no identities","This policy adds a system-assigned managed identity to virtual machines hosted in Azure that are supported by Guest Configuration but do not have any managed identities. A system-assigned managed identity is a prerequisite for all Guest Configuration assignments and must be added to machines before using any Guest Configuration policy definitions. For more information on Guest Configuration, visit https://aka.ms/gcpol.","NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_IA-5, -NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: modify (Policy Fixed)","Disabled, -Audit, -Modify","modify","modify","modify","modify","","","","" -"497dff13-db2a-4c0f-8603-28fa3b331ab6","","BuiltIn","Guest Configuration","Add system-assigned managed identity to enable Guest Configuration assignments on VMs with a user-assigned identity","This policy adds a system-assigned managed identity to virtual machines hosted in Azure that are supported by Guest Configuration and have at least one user-assigned identity but do not have a system-assigned managed identity. A system-assigned managed identity is a prerequisite for all Guest Configuration assignments and must be added to machines before using any Guest Configuration policy definitions. For more information on Guest Configuration, visit https://aka.ms/gcpol.","NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_IA-5, -NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: modify (Policy Fixed)","Disabled, -Audit, -Modify","modify","modify","modify","modify","","","","" -"ea53dbee-c6c9-4f0e-9f9e-de0039b78023","","BuiltIn","Guest Configuration","Audit Linux machines that allow remote connections from accounts without passwords","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Linux machines that allow remote connections from accounts without passwords","NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"e6955644-301c-44b5-a4c4-528577de6861","","BuiltIn","Guest Configuration","Audit Linux machines that do not have the passwd file permissions set to 0644","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Linux machines that do not have the passwd file permissions set to 0644","NIST_SP_800-53_R5_IA-5, -NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"f6ec09a3-78bf-4f8f-99dc-6c77182d0f99","","BuiltIn","Guest Configuration","Audit Linux machines that have accounts without passwords","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Linux machines that have accounts without passwords","NIST_SP_800-53_R5_AC-3","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"5b054a0d-39e2-4d53-bea3-9734cad2c69b","","BuiltIn","Guest Configuration","Audit Windows machines that allow re-use of the passwords after the specified number of unique passwords","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that allow re-use of the passwords after the specified number of unique passwords. Default value for unique passwords is 24","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"4ceb8dc2-559c-478b-a15b-733fbf1e3738","","BuiltIn","Guest Configuration","Audit Windows machines that do not have the maximum password age set to specified number of days","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not have the maximum password age set to specified number of days. Default value for maximum password age is 70 days","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"237b38db-ca4d-4259-9e47-7882441ca2c0","","BuiltIn","Guest Configuration","Audit Windows machines that do not have the minimum password age set to specified number of days","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not have the minimum password age set to specified number of days. Default value for minimum password age is 1 day","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"bf16e0bb-31e1-4646-8202-60a235cc7e74","","BuiltIn","Guest Configuration","Audit Windows machines that do not have the password complexity setting enabled","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not have the password complexity setting enabled","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"a2d0e922-65d0-40c4-8f87-ea6da2d307a2","","BuiltIn","Guest Configuration","Audit Windows machines that do not restrict the minimum password length to specified number of characters","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not restrict the minimum password length to specified number of characters. Default value for minimum password length is 14 characters","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"da0f98fe-a24b-4ad5-af69-bd0400233661","","BuiltIn","Guest Configuration","Audit Windows machines that do not store passwords using reversible encryption","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if Windows machines that do not store passwords using reversible encryption","NIST_SP_800-53_R5_IA-5, -NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"630c64f9-8b6b-4c64-b511-6544ceff6fd6","","BuiltIn","Guest Configuration","Authentication to Linux machines should require SSH keys","Although SSH itself provides an encrypted connection, using passwords with SSH still leaves the VM vulnerable to brute-force attacks. The most secure option for authenticating to an Azure Linux virtual machine over SSH is with a public-private key pair, also known as SSH keys. Learn more: https://docs.microsoft.com/azure/virtual-machines/linux/create-ssh-keys-detailed.","Azure_Security_Benchmark_v3.0_IM-6, -NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_IA-5","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"331e8ea8-378a-410f-a2e5-ae22f38bb0da","","BuiltIn","Guest Configuration","Deploy the Linux Guest Configuration extension to enable Guest Configuration assignments on Linux VMs","This policy deploys the Linux Guest Configuration extension to Linux virtual machines hosted in Azure that are supported by Guest Configuration. The Linux Guest Configuration extension is a prerequisite for all Linux Guest Configuration assignments and must be deployed to machines before using any Linux Guest Configuration policy definition. For more information on Guest Configuration, visit https://aka.ms/gcpol.","NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_IA-5, -NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: deployIfNotExists (Policy Fixed)","Disabled, -AuditIfNotExists, -DeployIfNotExists","deployIfNotExists","deployIfNotExists","deployIfNotExists","deployIfNotExists","","","","" -"385f5831-96d4-41db-9a3c-cd3af78aaae6","","BuiltIn","Guest Configuration","Deploy the Windows Guest Configuration extension to enable Guest Configuration assignments on Windows VMs","This policy deploys the Windows Guest Configuration extension to Windows virtual machines hosted in Azure that are supported by Guest Configuration. The Windows Guest Configuration extension is a prerequisite for all Windows Guest Configuration assignments and must be deployed to machines before using any Windows Guest Configuration policy definition. For more information on Guest Configuration, visit https://aka.ms/gcpol.","NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_IA-5, -NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: deployIfNotExists (Policy Fixed)","Disabled, -AuditIfNotExists, -DeployIfNotExists","deployIfNotExists","deployIfNotExists","deployIfNotExists","deployIfNotExists","","","","" -"1e7fed80-8321-4605-b42c-65fc300f23a3","","BuiltIn","Guest Configuration","Linux machines should have Log Analytics agent installed on Azure Arc","Machines are non-compliant if Log Analytics agent is not installed on Azure Arc enabled Linux server.","Azure_Security_Benchmark_v3.0_LT-5","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"fc9b3da7-8347-4380-8e70-0a0361d8dedd","","BuiltIn","Guest Configuration","Linux machines should meet requirements for the Azure compute security baseline","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if the machine is not configured correctly for one of the recommendations in the Azure compute security baseline.","Azure_Security_Benchmark_v3.0_PV-4, -NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"bed48b13-6647-468e-aa2f-1af1d3f4dd40","","BuiltIn","Guest Configuration","Windows Defender Exploit Guard should be enabled on your machines","Windows Defender Exploit Guard uses the Azure Policy Guest Configuration agent. Exploit Guard has four components that are designed to lock down devices against a wide variety of attack vectors and block behaviors commonly used in malware attacks while enabling enterprises to balance their security risk and productivity requirements (Windows only).","Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_ES-2, -NIST_SP_800-53_R5_SC-3, -NIST_SP_800-53_R5_SI-3, -NIST_SP_800-53_R5_SI-16","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsIncludeArcMachines"":""true"",""NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40"":""Compliant""}","{""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsIncludeArcMachines"":""true"",""NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40"":""Compliant""}","{""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsIncludeArcMachines"":""true"",""NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40"":""Compliant""}","{""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsIncludeArcMachines"":""true"",""NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40"":""Compliant""}" -"4078e558-bda6-41fb-9b3c-361e8875200d","","BuiltIn","Guest Configuration","Windows machines should have Log Analytics agent installed on Azure Arc","Machines are non-compliant if Log Analytics agent is not installed on Azure Arc enabled windows server.","Azure_Security_Benchmark_v3.0_LT-5","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"72650e9f-97bc-4b2a-ab5f-9781a9fcecbc","","BuiltIn","Guest Configuration","Windows machines should meet requirements of the Azure compute security baseline","Requires that prerequisites are deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. Machines are non-compliant if the machine is not configured correctly for one of the recommendations in the Azure compute security baseline.","Azure_Security_Benchmark_v3.0_PV-4, -NIST_SP_800-53_R5_CM-6","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""IncludeArcMachines"":""false""}","{""IncludeArcMachines"":""false""}","{""IncludeArcMachines"":""false""}","{""IncludeArcMachines"":""false""}" -"5752e6d6-1206-46d8-8ab1-ecc2f71a8112","","BuiltIn","Guest Configuration","Windows web servers should be configured to use secure communication protocols","To protect the privacy of information communicated over the Internet, your web servers should use the latest version of the industry-standard cryptographic protocol, Transport Layer Security (TLS). TLS secures communications over a network by using security certificates to encrypt a connection between machines.","Azure_Security_Benchmark_v3.0_DP-3, -NIST_SP_800-53_R5_SC-8, -NIST_SP_800-53_R5_SC-8(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""MinimumTLSVersion-5752e6d6-1206-46d8-8ab1-ecc2f71a8112"":""1.2"",""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsMinimumTLSVersion"":""1.2""}","{""MinimumTLSVersion-5752e6d6-1206-46d8-8ab1-ecc2f71a8112"":""1.2"",""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsMinimumTLSVersion"":""1.2""}","{""MinimumTLSVersion-5752e6d6-1206-46d8-8ab1-ecc2f71a8112"":""1.2"",""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsMinimumTLSVersion"":""1.2""}","{""MinimumTLSVersion-5752e6d6-1206-46d8-8ab1-ecc2f71a8112"":""1.2"",""windowsWebServersShouldBeConfiguredToUseSecureCommunicationProtocolsMinimumTLSVersion"":""1.2""}" -"64d314f6-6062-4780-a861-c23e8951bee5","","BuiltIn","HDInsight","Azure HDInsight clusters should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your Azure HDInsight clusters. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/hdi.cmk.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"1fd32ebd-e4c3-4e13-a54a-d7422d4d95f6","","BuiltIn","HDInsight","Azure HDInsight clusters should use encryption at host to encrypt data at rest","Enabling encryption at host helps protect and safeguard your data to meet your organizational security and compliance commitments. When you enable encryption at host, data stored on the VM host is encrypted at rest and flows encrypted to the Storage service.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"d9da03a1-f3c3-412a-9709-947156872263","","BuiltIn","HDInsight","Azure HDInsight clusters should use encryption in transit to encrypt communication between Azure HDInsight cluster nodes","Data can be tampered with during transmission between Azure HDInsight cluster nodes. Enabling encryption in transit addresses problems of misuse and tampering during this transmission.","NIST_SP_800-53_R5_SC-8, -NIST_SP_800-53_R5_SC-8(1)","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"47031206-ce96-41f8-861b-6a915f3de284","","BuiltIn","Internet of Things","[Preview]: IoT Hub device provisioning service data should be encrypted using customer-managed keys (CMK)","Use customer-managed keys to manage the encryption at rest of your IoT Hub device provisioning service. The data is automatically encrypted at rest with service-managed keys, but customer-managed keys (CMK) are commonly required to meet regulatory compliance standards. CMKs enable the data to be encrypted with an Azure Key Vault key created and owned by you. Learn more about CMK encryption at https://aka.ms/dps/CMK.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"df39c015-56a4-45de-b4a3-efe77bed320d","","BuiltIn","Internet of Things","IoT Hub device provisioning service instances should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to the IoT Hub device provisioning service, data leakage risks are reduced. Learn more about private links at: https://aka.ms/iotdpsvnet.","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" -"383856f8-de7f-44a2-81fc-e5135b5c2aa4","","BuiltIn","Internet of Things","Resource logs in IoT Hub should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""requiredRetentionDays"":""365"",""diagnosticsLogsInIoTHubRetentionDays"":""1""}","{""requiredRetentionDays"":""365"",""diagnosticsLogsInIoTHubRetentionDays"":""1""}","{""requiredRetentionDays"":""365"",""diagnosticsLogsInIoTHubRetentionDays"":""1""}","{""requiredRetentionDays"":""365"",""diagnosticsLogsInIoTHubRetentionDays"":""1""}" -"0a075868-4c26-42ef-914c-5bc007359560","","BuiltIn","Key Vault","[Preview]: Certificates should have the specified maximum validity period","Manage your organizational compliance requirements by specifying the maximum amount of time that a certificate can be valid within your key vault.","Azure_Security_Benchmark_v3.0_DP-7, -NIST_SP_800-53_R5_IA-5","ASB: disabled (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","disabled","disabled","disabled","disabled","{""maximumValidityInMonths-0a075868-4c26-42ef-914c-5bc007359560"":12,""certificatesValidityPeriodInMonths"":12}","{""maximumValidityInMonths-0a075868-4c26-42ef-914c-5bc007359560"":12,""certificatesValidityPeriodInMonths"":12}","{""maximumValidityInMonths-0a075868-4c26-42ef-914c-5bc007359560"":12,""certificatesValidityPeriodInMonths"":12}","{""maximumValidityInMonths-0a075868-4c26-42ef-914c-5bc007359560"":12,""certificatesValidityPeriodInMonths"":12}" -"55615ac9-af46-4a59-874e-391cc3dfb490","","BuiltIn","Key Vault","Azure Key Vault should have firewall enabled","Enable the key vault firewall so that the key vault is not accessible by default to any public IPs. Optionally, you can configure specific IP ranges to limit access to those networks. Learn more at: https://docs.microsoft.com/azure/key-vault/general/network-security","Azure_Security_Benchmark_v3.0_NS-2, -Azure_Security_Benchmark_v3.0_DP-8, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"a6abeaec-4d90-4a02-805f-6b26c4d3fbe9","","BuiltIn","Key Vault","Azure Key Vaults should use private link","Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to key vault, you can reduce data leakage risks. Learn more about private links at: https://aka.ms/akvprivatelink.","Azure_Security_Benchmark_v3.0_NS-2, -Azure_Security_Benchmark_v3.0_DP-8, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"152b15f7-8e1f-4c1f-ab71-8c010ba5dbc0","","BuiltIn","Key Vault","Key Vault keys should have an expiration date","Cryptographic keys should have a defined expiration date and not be permanent. Keys that are valid forever provide a potential attacker with more time to compromise the key. It is a recommended security practice to set expiration dates on cryptographic keys.","Azure_Security_Benchmark_v3.0_DP-6, -NIST_SP_800-53_R5_IA-5","ASB: Disabled (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Disabled","Disabled","Disabled","Disabled","","","","" -"98728c90-32c7-4049-8429-847dc0f4fe37","","BuiltIn","Key Vault","Key Vault secrets should have an expiration date","Secrets should have a defined expiration date and not be permanent. Secrets that are valid forever provide a potential attacker with more time to compromise them. It is a recommended security practice to set expiration dates on secrets.","Azure_Security_Benchmark_v3.0_DP-6, -NIST_SP_800-53_R5_IA-5","ASB: Disabled (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Disabled","Disabled","Disabled","Disabled","","","","" -"0b60c0b2-2dc2-4e1c-b5c9-abbed971de53","","BuiltIn","Key Vault","Key vaults should have deletion protection enabled","Malicious deletion of a key vault can lead to permanent data loss. You can prevent permanent data loss by enabling purge protection and soft delete. Purge protection protects you from insider attacks by enforcing a mandatory retention period for soft deleted key vaults. No one inside your organization or Microsoft will be able to purge your key vaults during the soft delete retention period. Keep in mind that key vaults created after September 1st 2019 have soft-delete enabled by default.","Azure_Security_Benchmark_v3.0_DP-8, -NIST_SP_800-53_R5_CP-9","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"1e66c121-a66a-4b1f-9b83-0fd99bf0fc2d","","BuiltIn","Key Vault","Key vaults should have soft delete enabled","Deleting a key vault without soft delete enabled permanently deletes all secrets, keys, and certificates stored in the key vault. Accidental deletion of a key vault can lead to permanent data loss. Soft delete allows you to recover an accidentally deleted key vault for a configurable retention period.","Azure_Security_Benchmark_v3.0_DP-8, -NIST_SP_800-53_R5_CP-9","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"cf820ca0-f99e-4f3e-84fb-66e913812d21","","BuiltIn","Key Vault","Resource logs in Key Vault should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_DP-8, -Azure_Security_Benchmark_v3.0_LT-3, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInKeyVaultRetentionDays"":""1""}","{""diagnosticsLogsInKeyVaultRetentionDays"":""1""}","{""diagnosticsLogsInKeyVaultRetentionDays"":""1""}","{""diagnosticsLogsInKeyVaultRetentionDays"":""1""}" -"8dfab9c4-fe7b-49ad-85e4-1e9be085358f","","BuiltIn","Kubernetes","[Preview]: Azure Arc enabled Kubernetes clusters should have Microsoft Defender for Cloud extension installed","Microsoft Defender for Cloud extension for Azure Arc provides threat protection for your Arc enabled Kubernetes clusters. The extension collects data from all nodes in the cluster and sends it to the Azure Defender for Kubernetes backend in the cloud for further analysis. Learn more in https://docs.microsoft.com/azure/defender-for-cloud/defender-for-containers-enable?pivots=defender-for-container-arc.","Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -NIST_SP_800-53_R5_AC-2(12), -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"6b2122c1-8120-4ff5-801b-17625a355590","","BuiltIn","Kubernetes","Azure Arc enabled Kubernetes clusters should have the Azure Policy extension installed","The Azure Policy extension for Azure Arc provides at-scale enforcements and safeguards on your Arc enabled Kubernetes clusters in a centralized, consistent manner. Learn more at https://aka.ms/akspolicydoc.","Azure_Security_Benchmark_v3.0_PV-2","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"a1840de2-8088-4ea8-b153-b4c723e9cb01","","BuiltIn","Kubernetes","Azure Kubernetes Service clusters should have Defender profile enabled","Microsoft Defender for Containers provides cloud-native Kubernetes security capabilities including environment hardening, workload protection, and run-time protection. When you enable the SecurityProfile.AzureDefender on your Azure Kubernetes Service cluster, an agent is deployed to your cluster to collect security event data. Learn more about Microsoft Defender for Containers in https://docs.microsoft.com/azure/defender-for-cloud/defender-for-containers-introduction?tabs=defender-for-container-arch-aks","Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2","ASB: Audit (PolicySet Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"0a15ec92-a229-4763-bb14-0ea34a568f8d","","BuiltIn","Kubernetes","Azure Policy Add-on for Kubernetes service (AKS) should be installed and enabled on your clusters","Azure Policy Add-on for Kubernetes service (AKS) extends Gatekeeper v3, an admission controller webhook for Open Policy Agent (OPA), to apply at-scale enforcements and safeguards on your clusters in a centralized, consistent manner.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"7d7be79c-23ba-4033-84dd-45e2a5ccdd67","","BuiltIn","Kubernetes","Both operating systems and data disks in Azure Kubernetes Service clusters should be encrypted by customer-managed keys","Encrypting OS and data disks using customer-managed keys provides more control and greater flexibility in key management. This is a common requirement in many regulatory and industry compliance standards.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"e345eecc-fa47-480f-9e88-67dcc122b164","","BuiltIn","Kubernetes","Kubernetes cluster containers CPU and memory resource limits should not exceed the specified limits","Enforce container CPU and memory resource limits to prevent resource exhaustion attacks in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""CPUInKubernetesClusterLimit"":""32"",""memoryLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0"",""memoryInKubernetesClusterLimit"":""64Gi"",""memoryAndCPULimitsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""cpuLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0""}","{""CPUInKubernetesClusterLimit"":""32"",""memoryLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0"",""memoryInKubernetesClusterLimit"":""64Gi"",""memoryAndCPULimitsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""cpuLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0""}","{""CPUInKubernetesClusterLimit"":""32"",""memoryLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0"",""memoryInKubernetesClusterLimit"":""64Gi"",""memoryAndCPULimitsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""cpuLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0""}","{""CPUInKubernetesClusterLimit"":""32"",""memoryLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0"",""memoryInKubernetesClusterLimit"":""64Gi"",""memoryAndCPULimitsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""cpuLimit-e345eecc-fa47-480f-9e88-67dcc122b164"":""0""}" -"47a1ee2f-2a2a-4576-bf2a-e0e36709c2b8","","BuiltIn","Kubernetes","Kubernetes cluster containers should not share host process ID or host IPC namespace","Block pod containers from sharing the host process ID namespace and host IPC namespace in a Kubernetes cluster. This recommendation is part of CIS 5.2.2 and CIS 5.2.3 which are intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""NoSharingSensitiveHostNamespacesInKubernetesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""NoSharingSensitiveHostNamespacesInKubernetesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""NoSharingSensitiveHostNamespacesInKubernetesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""NoSharingSensitiveHostNamespacesInKubernetesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}" -"511f5417-5d12-434d-ab2e-816901e72a5e","","BuiltIn","Kubernetes","Kubernetes cluster containers should only use allowed AppArmor profiles","Containers should only use allowed AppArmor profiles in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""AllowedAppArmorProfilesInKubernetesClusterList"":[""runtime/default""],""AllowedAppArmorProfilesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedProfiles-511f5417-5d12-434d-ab2e-816901e72a5e"":[]}","{""AllowedAppArmorProfilesInKubernetesClusterList"":[""runtime/default""],""AllowedAppArmorProfilesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedProfiles-511f5417-5d12-434d-ab2e-816901e72a5e"":[]}","{""AllowedAppArmorProfilesInKubernetesClusterList"":[""runtime/default""],""AllowedAppArmorProfilesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedProfiles-511f5417-5d12-434d-ab2e-816901e72a5e"":[]}","{""AllowedAppArmorProfilesInKubernetesClusterList"":[""runtime/default""],""AllowedAppArmorProfilesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedProfiles-511f5417-5d12-434d-ab2e-816901e72a5e"":[]}" -"c26596ff-4d70-4e6a-9a30-c2506bd2f80c","","BuiltIn","Kubernetes","Kubernetes cluster containers should only use allowed capabilities","Restrict the capabilities to reduce the attack surface of containers in a Kubernetes cluster. This recommendation is part of CIS 5.2.8 and CIS 5.2.9 which are intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""AllowedCapabilitiesInKubernetesClusterList"":[],""requiredDropCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""AllowedCapabilitiesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""DropCapabilitiesInKubernetesClusterList"":[]}","{""AllowedCapabilitiesInKubernetesClusterList"":[],""requiredDropCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""AllowedCapabilitiesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""DropCapabilitiesInKubernetesClusterList"":[]}","{""AllowedCapabilitiesInKubernetesClusterList"":[],""requiredDropCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""AllowedCapabilitiesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""DropCapabilitiesInKubernetesClusterList"":[]}","{""AllowedCapabilitiesInKubernetesClusterList"":[],""requiredDropCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""AllowedCapabilitiesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedCapabilities-c26596ff-4d70-4e6a-9a30-c2506bd2f80c"":[],""DropCapabilitiesInKubernetesClusterList"":[]}" -"febd0533-8e55-448f-b837-bd0e06f16469","","BuiltIn","Kubernetes","Kubernetes cluster containers should only use allowed images","Use images from trusted registries to reduce the Kubernetes cluster's exposure risk to unknown vulnerabilities, security issues and malicious images. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""allowedContainerImagesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""labelSelector"":{},""allowedContainerImagesInKubernetesClusterRegex"":""^(.+){0}$"",""excludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc""],""allowedContainerImagesRegex-febd0533-8e55-448f-b837-bd0e06f16469"":""^(.+){0}$"",""namespaces"":[]}","{""allowedContainerImagesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""labelSelector"":{},""allowedContainerImagesInKubernetesClusterRegex"":""^(.+){0}$"",""excludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc""],""allowedContainerImagesRegex-febd0533-8e55-448f-b837-bd0e06f16469"":""^(.+){0}$"",""namespaces"":[]}","{""allowedContainerImagesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""labelSelector"":{},""allowedContainerImagesInKubernetesClusterRegex"":""^(.+){0}$"",""excludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc""],""allowedContainerImagesRegex-febd0533-8e55-448f-b837-bd0e06f16469"":""^(.+){0}$"",""namespaces"":[]}","{""allowedContainerImagesNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""labelSelector"":{},""allowedContainerImagesInKubernetesClusterRegex"":""^(.+){0}$"",""excludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc""],""allowedContainerImagesRegex-febd0533-8e55-448f-b837-bd0e06f16469"":""^(.+){0}$"",""namespaces"":[]}" -"df49d893-a74c-421d-bc95-c663042e5b80","","BuiltIn","Kubernetes","Kubernetes cluster containers should run with a read only root file system","Run containers with a read only root file system to protect from changes at run-time with malicious binaries being added to PATH in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""ReadOnlyRootFileSystemInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""ReadOnlyRootFileSystemInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""ReadOnlyRootFileSystemInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""ReadOnlyRootFileSystemInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}" -"098fc59e-46c7-4d99-9b16-64990e543d75","","BuiltIn","Kubernetes","Kubernetes cluster pod hostPath volumes should only use allowed host paths","Limit pod HostPath volume mounts to the allowed host paths in a Kubernetes Cluster. This policy is generally available for Kubernetes Service (AKS), and Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""AllowedHostPathVolumesInKubernetesClusterList"":{""paths"":[]},""AllowedHostPathVolumesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedHostPaths-098fc59e-46c7-4d99-9b16-64990e543d75"":{""paths"":[]}}","{""AllowedHostPathVolumesInKubernetesClusterList"":{""paths"":[]},""AllowedHostPathVolumesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedHostPaths-098fc59e-46c7-4d99-9b16-64990e543d75"":{""paths"":[]}}","{""AllowedHostPathVolumesInKubernetesClusterList"":{""paths"":[]},""AllowedHostPathVolumesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedHostPaths-098fc59e-46c7-4d99-9b16-64990e543d75"":{""paths"":[]}}","{""AllowedHostPathVolumesInKubernetesClusterList"":{""paths"":[]},""AllowedHostPathVolumesInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""allowedHostPaths-098fc59e-46c7-4d99-9b16-64990e543d75"":{""paths"":[]}}" -"f06ddb64-5fa3-4b77-b166-acb36f7f6042","","BuiltIn","Kubernetes","Kubernetes cluster pods and containers should only run with approved user and group IDs","Control the user, primary group, supplemental group and file system group IDs that pods and containers can use to run in a Kubernetes Cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""MustRunAsNonRootNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""runAsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""runAsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""supplementalGroupsRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""fsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""fsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""supplementalGroupsRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""runAsUserRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""runAsUserRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""MustRunAsNonRoot""}","{""MustRunAsNonRootNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""runAsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""runAsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""supplementalGroupsRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""fsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""fsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""supplementalGroupsRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""runAsUserRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""runAsUserRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""MustRunAsNonRoot""}","{""MustRunAsNonRootNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""runAsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""runAsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""supplementalGroupsRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""fsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""fsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""supplementalGroupsRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""runAsUserRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""runAsUserRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""MustRunAsNonRoot""}","{""MustRunAsNonRootNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""],""runAsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""runAsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""supplementalGroupsRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""fsGroupRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""fsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""supplementalGroupsRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""RunAsAny"",""runAsUserRanges-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":{""ranges"":[]},""runAsUserRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042"":""MustRunAsNonRoot""}" -"82985f06-dc18-4a48-bc1c-b9f4f0098cfe","","BuiltIn","Kubernetes","Kubernetes cluster pods should only use approved host network and port range","Restrict pod access to the host network and the allowable host port range in a Kubernetes cluster. This recommendation is part of CIS 5.2.4 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""maxPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""AllowedHostMinPortInKubernetesCluster"":0,""allowHostNetwork-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":false,""AllowHostNetworkingInKubernetesCluster"":false,""minPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""AllowedHostMaxPortInKubernetesCluster"":0,""AllowedHostNetworkingAndPortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""maxPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""AllowedHostMinPortInKubernetesCluster"":0,""allowHostNetwork-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":false,""AllowHostNetworkingInKubernetesCluster"":false,""minPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""AllowedHostMaxPortInKubernetesCluster"":0,""AllowedHostNetworkingAndPortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""maxPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""AllowedHostMinPortInKubernetesCluster"":0,""allowHostNetwork-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":false,""AllowHostNetworkingInKubernetesCluster"":false,""minPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""AllowedHostMaxPortInKubernetesCluster"":0,""AllowedHostNetworkingAndPortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""maxPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""AllowedHostMinPortInKubernetesCluster"":0,""allowHostNetwork-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":false,""AllowHostNetworkingInKubernetesCluster"":false,""minPort-82985f06-dc18-4a48-bc1c-b9f4f0098cfe"":0,""AllowedHostMaxPortInKubernetesCluster"":0,""AllowedHostNetworkingAndPortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}" -"233a2a17-77ca-4fb1-9b6b-69223d272a44","","BuiltIn","Kubernetes","Kubernetes cluster services should listen only on allowed ports","Restrict services to listen only on allowed ports to secure access to the Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""allowedServicePortsList-233a2a17-77ca-4fb1-9b6b-69223d272a44"":[],""allowedservicePortsInKubernetesClusterPorts"":[""-1""],""allowedServicePortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""allowedServicePortsList-233a2a17-77ca-4fb1-9b6b-69223d272a44"":[],""allowedservicePortsInKubernetesClusterPorts"":[""-1""],""allowedServicePortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""allowedServicePortsList-233a2a17-77ca-4fb1-9b6b-69223d272a44"":[],""allowedservicePortsInKubernetesClusterPorts"":[""-1""],""allowedServicePortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""allowedServicePortsList-233a2a17-77ca-4fb1-9b6b-69223d272a44"":[],""allowedservicePortsInKubernetesClusterPorts"":[""-1""],""allowedServicePortsInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}" -"95edb821-ddaf-4404-9732-666045e056b4","","BuiltIn","Kubernetes","Kubernetes cluster should not allow privileged containers","Do not allow privileged containers creation in a Kubernetes cluster. This recommendation is part of CIS 5.2.1 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""excludedContainers-95edb821-ddaf-4404-9732-666045e056b4"":[],""excludedImagesInKubernetesCluster"":[],""privilegedContainerNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""excludedContainers-95edb821-ddaf-4404-9732-666045e056b4"":[],""excludedImagesInKubernetesCluster"":[],""privilegedContainerNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""excludedContainers-95edb821-ddaf-4404-9732-666045e056b4"":[],""excludedImagesInKubernetesCluster"":[],""privilegedContainerNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""excludedContainers-95edb821-ddaf-4404-9732-666045e056b4"":[],""excludedImagesInKubernetesCluster"":[],""privilegedContainerNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}" -"1a5b4dca-0b6f-4cf5-907c-56316bc1bf3d","","BuiltIn","Kubernetes","Kubernetes clusters should be accessible only over HTTPS","Use of HTTPS ensures authentication and protects data in transit from network layer eavesdropping attacks. This capability is currently generally available for Kubernetes Service (AKS), and in preview for Azure Arc enabled Kubernetes. For more info, visit https://aka.ms/kubepolicydoc","Azure_Security_Benchmark_v3.0_DP-3, -NIST_SP_800-53_R5_SC-8, -NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""kubernetesClustersShouldBeAccessibleOnlyOverHTTPSExcludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""kubernetesClustersShouldBeAccessibleOnlyOverHTTPSExcludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""kubernetesClustersShouldBeAccessibleOnlyOverHTTPSExcludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""kubernetesClustersShouldBeAccessibleOnlyOverHTTPSExcludedNamespaces"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}" -"423dd1ba-798e-40e4-9c4d-b6902674b423","","BuiltIn","Kubernetes","Kubernetes clusters should disable automounting API credentials","Disable automounting API credentials to prevent a potentially compromised Pod resource to run API commands against Kubernetes clusters. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}" -"1c6e92c9-99f0-4e55-9cf2-0c234dc48f99","","BuiltIn","Kubernetes","Kubernetes clusters should not allow container privilege escalation","Do not allow containers to run with privilege escalation to root in a Kubernetes cluster. This recommendation is part of CIS 5.2.5 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2, -NIST_SP_800-53_R5_CM-6","ASB: Audit (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""NoPrivilegeEscalationInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""NoPrivilegeEscalationInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""NoPrivilegeEscalationInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}","{""NoPrivilegeEscalationInKubernetesClusterNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azure-extensions-usage-system""]}" -"d2e7ea85-6b44-4317-a0be-1b951587f626","","BuiltIn","Kubernetes","Kubernetes clusters should not grant CAP_SYS_ADMIN security capabilities","To reduce the attack surface of your containers, restrict CAP_SYS_ADMIN Linux capabilities. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","{""KubernetesClustersShouldNotGrantCAPSYSADMINSecurityCapabilitiesMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""KubernetesClustersShouldNotGrantCAPSYSADMINSecurityCapabilitiesMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""KubernetesClustersShouldNotGrantCAPSYSADMINSecurityCapabilitiesMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}","{""KubernetesClustersShouldNotGrantCAPSYSADMINSecurityCapabilitiesMonitoringNamespaceExclusion"":[""kube-system"",""gatekeeper-system"",""azure-arc"",""azuredefender"",""mdc"",""azure-extensions-usage-system""]}" -"9f061a12-e40d-4183-a00e-171812443373","","BuiltIn","Kubernetes","Kubernetes clusters should not use the default namespace","Prevent usage of the default namespace in Kubernetes clusters to protect against unauthorized access for ConfigMap, Pod, Secret, Service, and ServiceAccount resource types. For more information, see https://aka.ms/kubepolicydoc.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (PolicySet Default)","audit, -disabled, -deny","Audit","Audit","Audit","Audit","","","","" -"245fc9df-fa96-4414-9a0b-3738c2f7341c","","BuiltIn","Kubernetes","Resource logs in Azure Kubernetes Service should be enabled","Azure Kubernetes Service's resource logs can help recreate activity trails when investigating security incidents. Enable it to make sure the logs will exist when needed","","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInKubernetesRetentionDays"":""1""}","{""diagnosticsLogsInKubernetesRetentionDays"":""1""}","{""diagnosticsLogsInKubernetesRetentionDays"":""1""}","{""diagnosticsLogsInKubernetesRetentionDays"":""1""}" -"41425d9f-d1a5-499a-9932-f8ed8453932c","","BuiltIn","Kubernetes","Temp disks and cache for agent node pools in Azure Kubernetes Service clusters should be encrypted at host","To enhance data security, the data stored on the virtual machine (VM) host of your Azure Kubernetes Service nodes VMs should be encrypted at rest. This is a common requirement in many regulatory and industry compliance standards.","NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"1fafeaf6-7927-4059-a50a-8eb2a7a6f2b5","","BuiltIn","Logic Apps","Logic Apps Integration Service Environment should be encrypted with customer-managed keys","Deploy into Integration Service Environment to manage encryption at rest of Logic Apps data using customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"34f95f76-5386-4de7-b824-0d8478470c9d","","BuiltIn","Logic Apps","Resource logs in Logic Apps should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInLogicAppsRetentionDays"":""1""}","{""diagnosticsLogsInLogicAppsRetentionDays"":""1""}","{""diagnosticsLogsInLogicAppsRetentionDays"":""1""}","{""diagnosticsLogsInLogicAppsRetentionDays"":""1""}" -"f110a506-2dcb-422e-bcea-d533fc8c35e2","","BuiltIn","Machine Learning","Azure Machine Learning compute instances should be recreated to get the latest software updates","Ensure Azure Machine Learning compute instances run on the latest available operating system. Security is improved and vulnerabilities reduced by running with the latest security patches. For more information, visit http://aka.ms/azureml-ci-updates/.","Azure_Security_Benchmark_v3.0_PV-2","ASB: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" -"7804b5c7-01dc-4723-969b-ae300cc07ff1","","BuiltIn","Machine Learning","Azure Machine Learning Computes should be in a virtual network","Azure Virtual Networks provide enhanced security and isolation for your Azure Machine Learning Compute Clusters and Instances, as well as subnets, access control policies, and other features to further restrict access. When a compute is configured with a virtual network, it is not publicly addressable and can only be accessed from virtual machines and applications within the virtual network.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" -"e96a9a5f-07ca-471b-9bc5-6a0f33cbd68f","","BuiltIn","Machine Learning","Azure Machine Learning Computes should have local authentication methods disabled","Disabling local authentication methods improves security by ensuring that Machine Learning Computes require Azure Active Directory identities exclusively for authentication. Learn more at: https://aka.ms/azure-ml-aad-policy.","Azure_Security_Benchmark_v3.0_IM-1","ASB: Audit (Policy Default)","Audit, -Deny, -Disabled","Audit","Audit","Audit","Audit","","","","" -"ba769a63-b8cc-4b2d-abf6-ac33c7204be8","","BuiltIn","Machine Learning","Azure Machine Learning workspaces should be encrypted with a customer-managed key","Manage encryption at rest of Azure Machine Learning workspace data with customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/azureml-workspaces-cmk.","Azure_Security_Benchmark_v3.0_DP-5, -NIST_SP_800-53_R5_SC-12","ASB: Disabled (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Disabled","Disabled","Disabled","Disabled","","","","" -"438c38d2-3772-465a-a9cc-7a6666a275ce","","BuiltIn","Machine Learning","Azure Machine Learning Workspaces should disable public network access","Disabling public network access improves security by ensuring that the Machine Learning Workspaces aren't exposed on the public internet. You can control exposure of your workspaces by creating private endpoints instead. Learn more at: https://learn.microsoft.com/azure/machine-learning/how-to-configure-private-link?view=azureml-api-2&tabs=azure-portal.","Azure_Security_Benchmark_v3.0_NS-2","ASB: Audit (Policy Default)","Audit, -Deny, -Disabled","Audit","Audit","Audit","Audit","","","","" -"45e05259-1eb5-4f70-9574-baf73e9d219b","","BuiltIn","Machine Learning","Azure Machine Learning workspaces should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Machine Learning workspaces, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/machine-learning/how-to-configure-private-link.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"afe0c3be-ba3b-4544-ba52-0c99672a8ad6","","BuiltIn","Machine Learning","Resource logs in Azure Machine Learning Workspaces should be enabled","Resource logs enable recreating activity trails to use for investigation purposes when a security incident occurs or when your network is compromised.","Azure_Security_Benchmark_v3.0_LT-3","ASB: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"842c54e8-c2f9-4d79-ae8d-38d8b8019373","","BuiltIn","Monitoring","[Preview]: Log Analytics extension should be installed on your Linux Azure Arc machines","This policy audits Linux Azure Arc machines if the Log Analytics extension is not installed.","Azure_Security_Benchmark_v3.0_LT-5, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"d69b1763-b96d-40b8-a2d9-ca31e9fd0d3e","","BuiltIn","Monitoring","[Preview]: Log Analytics extension should be installed on your Windows Azure Arc machines","This policy audits Windows Azure Arc machines if the Log Analytics extension is not installed.","Azure_Security_Benchmark_v3.0_LT-5, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"04c4380f-3fae-46e8-96c9-30193528f602","","BuiltIn","Monitoring","[Preview]: Network traffic data collection agent should be installed on Linux virtual machines","Security Center uses the Microsoft Dependency agent to collect network traffic data from your Azure virtual machines to enable advanced network protection features such as traffic visualization on the network map, network hardening recommendations and specific network threats.","Azure_Security_Benchmark_v3.0_LT-4, -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"2f2ee1de-44aa-4762-b6bd-0893fc3f306d","","BuiltIn","Monitoring","[Preview]: Network traffic data collection agent should be installed on Windows virtual machines","Security Center uses the Microsoft Dependency agent to collect network traffic data from your Azure virtual machines to enable advanced network protection features such as traffic visualization on the network map, network hardening recommendations and specific network threats.","Azure_Security_Benchmark_v3.0_LT-4, -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"ea0dfaed-95fb-448c-934e-d6e713ce393d","","BuiltIn","Monitoring","Azure Monitor Logs clusters should be created with infrastructure-encryption enabled (double encryption)","To ensure secure data encryption is enabled at the service level and the infrastructure level with two different encryption algorithms and two different keys, use an Azure Monitor dedicated cluster. This option is enabled by default when supported at the region, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys#customer-managed-key-overview.","NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","audit","audit","audit","audit","","","","" -"1f68a601-6e6d-4e42-babf-3f643a047ea2","","BuiltIn","Monitoring","Azure Monitor Logs clusters should be encrypted with customer-managed key","Create Azure Monitor logs cluster with customer-managed keys encryption. By default, the log data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance. Customer-managed key in Azure Monitor gives you more control over the access to you data, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys.","NIST_SP_800-53_R5_SC-12","NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","audit","audit","audit","audit","","","","" -"fa298e57-9444-42ba-bf04-86e8470e32c7","","BuiltIn","Monitoring","Saved-queries in Azure Monitor should be saved in customer storage account for logs encryption","Link storage account to Log Analytics workspace to protect saved-queries with storage account encryption. Customer-managed keys are commonly required to meet regulatory compliance and for more control over the access to your saved-queries in Azure Monitor. For more details on the above, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys?tabs=portal#customer-managed-key-for-saved-queries.","NIST_SP_800-53_R5_SC-12","NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","audit","audit","audit","audit","","","","" -"fc5e4038-4584-4632-8c85-c0448d374b2c","","BuiltIn","Network","[Preview]: All Internet traffic should be routed via your deployed Azure Firewall","Azure Security Center has identified that some of your subnets aren't protected with a next generation firewall. Protect your subnets from potential threats by restricting access to them with Azure Firewall or a supported next generation firewall","Azure_Security_Benchmark_v3.0_NS-3, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3), -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"055aa869-bc98-4af8-bafc-23f1ab6ffe2c","","BuiltIn","Network","Azure Web Application Firewall should be enabled for Azure Front Door entry-points","Deploy Azure Web Application Firewall (WAF) in front of public facing web applications for additional inspection of incoming traffic. Web Application Firewall (WAF) provides centralized protection of your web applications from common exploits and vulnerabilities such as SQL injections, Cross-Site Scripting, local and remote file executions. You can also restrict access to your web applications by countries, IP address ranges, and other http(s) parameters via custom rules.","Azure_Security_Benchmark_v3.0_NS-6, -NIST_SP_800-53_R5_SC-5, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"b6e2945c-0b7b-40f5-9233-7a5323b5cdc6","","BuiltIn","Network","Network Watcher should be enabled","Network Watcher is a regional service that enables you to monitor and diagnose conditions at a network scenario level in, to, and from Azure. Scenario level monitoring enables you to diagnose problems at an end to end network level view. It is required to have a network watcher resource group to be created in every region where a virtual network is present. An alert is enabled if a network watcher resource group is not available in a particular region.","Azure_Security_Benchmark_v3.0_IR-4, -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""networkWatcherShouldBeEnabledResourceGroupName"":""NetworkWatcherRG"",""resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6"":""NetworkWatcherRG""}","{""networkWatcherShouldBeEnabledResourceGroupName"":""NetworkWatcherRG"",""resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6"":""NetworkWatcherRG""}","{""networkWatcherShouldBeEnabledResourceGroupName"":""NetworkWatcherRG"",""resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6"":""NetworkWatcherRG""}","{""networkWatcherShouldBeEnabledResourceGroupName"":""NetworkWatcherRG"",""resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6"":""NetworkWatcherRG""}" -"564feb30-bf6a-4854-b4bb-0d2d2d1e6c66","","BuiltIn","Network","Web Application Firewall (WAF) should be enabled for Application Gateway","Deploy Azure Web Application Firewall (WAF) in front of public facing web applications for additional inspection of incoming traffic. Web Application Firewall (WAF) provides centralized protection of your web applications from common exploits and vulnerabilities such as SQL injections, Cross-Site Scripting, local and remote file executions. You can also restrict access to your web applications by countries, IP address ranges, and other http(s) parameters via custom rules.","Azure_Security_Benchmark_v3.0_NS-6, -NIST_SP_800-53_R5_SC-5, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"3054c74b-9b45-2581-56cf-053a1a716c39","","BuiltIn","Regulatory Compliance","Accept assessment results","CMA_C1150 - Accept assessment results","NIST_SP_800-53_R5_CA-2(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2d2ca910-7957-23ee-2945-33f401606efc","","BuiltIn","Regulatory Compliance","Accept only FICAM-approved third-party credentials","CMA_C1348 - Accept only FICAM-approved third-party credentials","NIST_SP_800-53_R5_IA-8(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"55be3260-a7a2-3c06-7fe6-072d07525ab7","","BuiltIn","Regulatory Compliance","Accept PIV credentials","CMA_C1347 - Accept PIV credentials","NIST_SP_800-53_R5_IA-8(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"318b2bd9-9c39-9f8b-46a7-048401f33476","","BuiltIn","Regulatory Compliance","Address coding vulnerabilities","CMA_0003 - Address coding vulnerabilities","NIST_SP_800-53_R5_SA-10","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1ecb79d7-1a06-9a3b-3be8-f434d04d1ec1","","BuiltIn","Regulatory Compliance","Adhere to retention periods defined","CMA_0004 - Adhere to retention periods defined","NIST_SP_800-53_R5_AU-11","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"7d7a8356-5c34-9a95-3118-1424cfaf192a","","BuiltIn","Regulatory Compliance","Adopt biometric authentication mechanisms","CMA_0005 - Adopt biometric authentication mechanisms","NIST_SP_800-53_R5_IA-2(1), -NIST_SP_800-53_R5_IA-2(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"9622aaa9-5c49-40e2-5bf8-660b7cd23deb","","BuiltIn","Regulatory Compliance","Alert personnel of information spillage","CMA_0007 - Alert personnel of information spillage","NIST_SP_800-53_R5_IR-9, -NIST_SP_800-53_R5_SI-4(5)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ab02bb73-4ce1-89dd-3905-d93042809ba0","","BuiltIn","Regulatory Compliance","Align business objectives and IT goals","CMA_0008 - Align business objectives and IT goals","NIST_SP_800-53_R5_SA-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"90a156a6-49ed-18d1-1052-69aac27c05cd","","BuiltIn","Regulatory Compliance","Allocate resources in determining information system requirements","CMA_C1561 - Allocate resources in determining information system requirements","NIST_SP_800-53_R5_SA-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"6a379d74-903b-244a-4c44-838728bea6b0","","BuiltIn","Regulatory Compliance","Analyse data obtained from continuous monitoring","CMA_C1169 - Analyse data obtained from continuous monitoring","NIST_SP_800-53_R5_CA-7(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"37b0045b-3887-367b-8b4d-b9a6fa911bb9","","BuiltIn","Regulatory Compliance","Assess information security events","CMA_0013 - Assess information security events","NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-8","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"0d04cb93-a0f1-2f4b-4b1b-a72a1b510d08","","BuiltIn","Regulatory Compliance","Assess risk in third party relationships","CMA_0014 - Assess risk in third party relationships","NIST_SP_800-53_R5_SA-9(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c423e64d-995c-9f67-0403-b540f65ba42a","","BuiltIn","Regulatory Compliance","Assess Security Controls","CMA_C1145 - Assess Security Controls","NIST_SP_800-53_R5_CA-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"4c6df5ff-4ef2-4f17-a516-0da9189c603b","","BuiltIn","Regulatory Compliance","Assign account managers","CMA_0015 - Assign account managers","NIST_SP_800-53_R5_AC-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e29a8f1b-149b-2fa3-969d-ebee1baa9472","","BuiltIn","Regulatory Compliance","Assign an authorizing official (AO)","CMA_C1158 - Assign an authorizing official (AO)","NIST_SP_800-53_R5_CA-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"6abdf7c7-362b-3f35-099e-533ed50988f9","","BuiltIn","Regulatory Compliance","Assign information security representative to change control","CMA_C1198 - Assign information security representative to change control","NIST_SP_800-53_R5_CM-3(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b7897ddc-9716-2460-96f7-7757ad038cc4","","BuiltIn","Regulatory Compliance","Assign risk designations","CMA_0016 - Assign risk designations","NIST_SP_800-53_R5_PS-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f29b17a4-0df2-8a50-058a-8570f9979d28","","BuiltIn","Regulatory Compliance","Assign system identifiers","CMA_0018 - Assign system identifiers","NIST_SP_800-53_R5_IA-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f26af0b1-65b6-689a-a03f-352ad2d00f98","","BuiltIn","Regulatory Compliance","Audit privileged functions","CMA_0019 - Audit privileged functions","NIST_SP_800-53_R5_AC-2(7), -NIST_SP_800-53_R5_AC-6(9), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"49c23d9b-02b0-0e42-4f94-e8cef1b8381b","","BuiltIn","Regulatory Compliance","Audit user account status","CMA_0020 - Audit user account status","NIST_SP_800-53_R5_AC-2, -NIST_SP_800-53_R5_AC-2(4), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"6f1de470-79f3-1572-866e-db0771352fc8","","BuiltIn","Regulatory Compliance","Authenticate to cryptographic module","CMA_0021 - Authenticate to cryptographic module","NIST_SP_800-53_R5_IA-7","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"aeed863a-0f56-429f-945d-8bb66bd06841","","BuiltIn","Regulatory Compliance","Authorize access to security functions and information","CMA_0022 - Authorize access to security functions and information","NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_AC-6(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"50e9324a-7410-0539-0662-2c1e775538b7","","BuiltIn","Regulatory Compliance","Authorize and manage access","CMA_0023 - Authorize and manage access","NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_AC-6(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"dad8a2e9-6f27-4fc2-8933-7e99fe700c9c","","BuiltIn","Regulatory Compliance","Authorize remote access","CMA_0024 - Authorize remote access","NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(4), -NIST_SP_800-53_R5_SC-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"01c387ea-383d-4ca9-295a-977fab516b03","","BuiltIn","Regulatory Compliance","Authorize remote access to privileged commands","CMA_C1064 - Authorize remote access to privileged commands","NIST_SP_800-53_R5_AC-17(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"291f20d4-8d93-1d73-89f3-6ce28b825563","","BuiltIn","Regulatory Compliance","Authorize, monitor, and control usage of mobile code technologies","CMA_C1653 - Authorize, monitor, and control usage of mobile code technologies","NIST_SP_800-53_R5_SC-18","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e4e1f896-8a93-1151-43c7-0ad23b081ee2","","BuiltIn","Regulatory Compliance","Authorize, monitor, and control voip","CMA_0025 - Authorize, monitor, and control voip","NIST_SP_800-53_R5_SI-4(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2cc9c165-46bd-9762-5739-d2aae5ba90a1","","BuiltIn","Regulatory Compliance","Automate account management","CMA_0026 - Automate account management","NIST_SP_800-53_R5_AC-2(1), -NIST_SP_800-53_R5_AC-2(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"575ed5e8-4c29-99d0-0e4d-689fb1d29827","","BuiltIn","Regulatory Compliance","Automate approval request for proposed changes","CMA_C1192 - Automate approval request for proposed changes","NIST_SP_800-53_R5_CM-3(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"a90c4d44-7fac-8e02-6d5b-0d92046b20e6","","BuiltIn","Regulatory Compliance","Automate flaw remediation","CMA_0027 - Automate flaw remediation","NIST_SP_800-53_R5_SI-2(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c72fc0c8-2df8-7506-30be-6ba1971747e1","","BuiltIn","Regulatory Compliance","Automate implementation of approved change notifications","CMA_C1196 - Automate implementation of approved change notifications","NIST_SP_800-53_R5_CM-3(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e54901fe-42c2-7f3b-3c5f-327aa5320a69","","BuiltIn","Regulatory Compliance","Automate information sharing decisions","CMA_0028 - Automate information sharing decisions","NIST_SP_800-53_R5_AC-21","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"729c8708-2bec-093c-8427-2e87d2cd426d","","BuiltIn","Regulatory Compliance","Automate notification of employee termination","CMA_C1521 - Automate notification of employee termination","NIST_SP_800-53_R5_PS-4(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"43ac3ccb-4ef6-7d63-9a3f-6848485ba4e8","","BuiltIn","Regulatory Compliance","Automate process to document implemented changes","CMA_C1195 - Automate process to document implemented changes","NIST_SP_800-53_R5_CM-3(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"92b49e92-570f-1765-804a-378e6c592e28","","BuiltIn","Regulatory Compliance","Automate process to highlight unreviewed change proposals","CMA_C1193 - Automate process to highlight unreviewed change proposals","NIST_SP_800-53_R5_CM-3(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"7d10debd-4775-85a7-1a41-7e128e0e8c50","","BuiltIn","Regulatory Compliance","Automate process to prohibit implementation of unapproved changes","CMA_C1194 - Automate process to prohibit implementation of unapproved changes","NIST_SP_800-53_R5_CM-3(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"5c40f27b-6791-18c5-3f85-7b863bd99c11","","BuiltIn","Regulatory Compliance","Automate proposed documented changes","CMA_C1191 - Automate proposed documented changes","NIST_SP_800-53_R5_CM-3(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b8587fce-138f-86e8-33a3-c60768bf1da6","","BuiltIn","Regulatory Compliance","Automate remote maintenance activities","CMA_C1402 - Automate remote maintenance activities","NIST_SP_800-53_R5_MA-2(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"6f311b49-9b0d-8c67-3d6e-db80ae528173","","BuiltIn","Regulatory Compliance","Bind authenticators and identities dynamically","CMA_0035 - Bind authenticators and identities dynamically","NIST_SP_800-53_R5_IA-5(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3d399cf3-8fc6-0efc-6ab0-1412f1198517","","BuiltIn","Regulatory Compliance","Block untrusted and unsigned processes that run from USB","CMA_0050 - Block untrusted and unsigned processes that run from USB","NIST_SP_800-53_R5_AC-20(2), -NIST_SP_800-53_R5_MP-7, -NIST_SP_800-53_R5_SI-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"93fa357f-2e38-22a9-5138-8cc5124e1923","","BuiltIn","Regulatory Compliance","Categorize information","CMA_0052 - Categorize information","NIST_SP_800-53_R5_RA-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ee4bbbbb-2e52-9adb-4e3a-e641f7ac68ab","","BuiltIn","Regulatory Compliance","Check for privacy and security compliance before establishing internal connections","CMA_0053 - Check for privacy and security compliance before establishing internal connections","NIST_SP_800-53_R5_CA-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c42f19c9-5d88-92da-0742-371a0ea03126","","BuiltIn","Regulatory Compliance","Clear personnel with access to classified information","CMA_0054 - Clear personnel with access to classified information","NIST_SP_800-53_R5_PS-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"a1334a65-2622-28ee-5067-9d7f5b915cc5","","BuiltIn","Regulatory Compliance","Communicate contingency plan changes","CMA_C1249 - Communicate contingency plan changes","NIST_SP_800-53_R5_CP-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"214ea241-010d-8926-44cc-b90a96d52adc","","BuiltIn","Regulatory Compliance","Compile Audit records into system wide audit","CMA_C1140 - Compile Audit records into system wide audit","NIST_SP_800-53_R5_AU-12(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8eea8c14-4d93-63a3-0c82-000343ee5204","","BuiltIn","Regulatory Compliance","Conduct a full text analysis of logged privileged commands","CMA_0056 - Conduct a full text analysis of logged privileged commands","NIST_SP_800-53_R5_AC-6(9)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"203101f5-99a3-1491-1b56-acccd9b66a9e","","BuiltIn","Regulatory Compliance","Conduct a security impact analysis","CMA_0057 - Conduct a security impact analysis","NIST_SP_800-53_R5_CM-3, -NIST_SP_800-53_R5_CM-4, -NIST_SP_800-53_R5_CM-4(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b269a749-705e-8bff-055a-147744675cdf","","BuiltIn","Regulatory Compliance","Conduct backup of information system documentation","CMA_C1289 - Conduct backup of information system documentation","NIST_SP_800-53_R5_CP-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"33602e78-35e3-4f06-17fb-13dd887448e4","","BuiltIn","Regulatory Compliance","Conduct capacity planning","CMA_C1252 - Conduct capacity planning","NIST_SP_800-53_R5_CP-2(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"496b407d-9b9e-81e8-4ba4-44bc686b016a","","BuiltIn","Regulatory Compliance","Conduct exit interview upon termination","CMA_0058 - Conduct exit interview upon termination","NIST_SP_800-53_R5_PS-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3545c827-26ee-282d-4629-23952a12008b","","BuiltIn","Regulatory Compliance","Conduct incident response testing","CMA_0060 - Conduct incident response testing","NIST_SP_800-53_R5_IR-3, -NIST_SP_800-53_R5_IR-3(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"677e1da4-00c3-287a-563d-f4a1cf9b99a0","","BuiltIn","Regulatory Compliance","Conduct Risk Assessment","CMA_C1543 - Conduct Risk Assessment","NIST_SP_800-53_R5_RA-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d7c1ecc3-2980-a079-1569-91aec8ac4a77","","BuiltIn","Regulatory Compliance","Conduct risk assessment and distribute its results","CMA_C1544 - Conduct risk assessment and distribute its results","NIST_SP_800-53_R5_RA-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1dbd51c2-2bd1-5e26-75ba-ed075d8f0d68","","BuiltIn","Regulatory Compliance","Conduct risk assessment and document its results","CMA_C1542 - Conduct risk assessment and document its results","NIST_SP_800-53_R5_RA-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b53aa659-513e-032c-52e6-1ce0ba46582f","","BuiltIn","Regulatory Compliance","Configure actions for noncompliant devices","CMA_0062 - Configure actions for noncompliant devices","NIST_SP_800-53_R5_CM-2, -NIST_SP_800-53_R5_CM-2(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"a3e98638-51d4-4e28-910a-60e98c1a756f","","BuiltIn","Regulatory Compliance","Configure Azure Audit capabilities","CMA_C1108 - Configure Azure Audit capabilities","NIST_SP_800-53_R5_AU-3(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2927e340-60e4-43ad-6b5f-7a1468232cc2","","BuiltIn","Regulatory Compliance","Configure detection whitelist","CMA_0068 - Configure detection whitelist","NIST_SP_800-53_R5_CA-7","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"26daf649-22d1-97e9-2a8a-01b182194d59","","BuiltIn","Regulatory Compliance","Configure workstations to check for digital certificates","CMA_0073 - Configure workstations to check for digital certificates","NIST_SP_800-53_R5_SC-8(1), -NIST_SP_800-53_R5_SC-23","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"a8df9c78-4044-98be-2c05-31a315ac8957","","BuiltIn","Regulatory Compliance","Conform to FICAM-issued profiles","CMA_C1350 - Conform to FICAM-issued profiles","NIST_SP_800-53_R5_IA-8(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"59bedbdc-0ba9-39b9-66bb-1d1c192384e6","","BuiltIn","Regulatory Compliance","Control information flow","CMA_0079 - Control information flow","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-4(21)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b6ad009f-5c24-1dc0-a25e-74b60e4da45f","","BuiltIn","Regulatory Compliance","Control maintenance and repair activities","CMA_0080 - Control maintenance and repair activities","NIST_SP_800-53_R5_MA-2, -NIST_SP_800-53_R5_MA-3, -NIST_SP_800-53_R5_MA-3(1), -NIST_SP_800-53_R5_MA-3(2), -NIST_SP_800-53_R5_MA-3(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"55a7f9a0-6397-7589-05ef-5ed59a8149e7","","BuiltIn","Regulatory Compliance","Control physical access","CMA_0081 - Control physical access","NIST_SP_800-53_R5_PE-2, -NIST_SP_800-53_R5_PE-3, -NIST_SP_800-53_R5_PE-4, -NIST_SP_800-53_R5_PE-5, -NIST_SP_800-53_R5_PE-8, -NIST_SP_800-53_R5_SI-12","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"36b74844-4a99-4c80-1800-b18a516d1585","","BuiltIn","Regulatory Compliance","Control use of portable storage devices","CMA_0083 - Control use of portable storage devices","NIST_SP_800-53_R5_AC-20(2), -NIST_SP_800-53_R5_MP-7","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c5784049-959f-6067-420c-f4cefae93076","","BuiltIn","Regulatory Compliance","Coordinate contingency plans with related plans","CMA_0086 - Coordinate contingency plans with related plans","NIST_SP_800-53_R5_CP-2, -NIST_SP_800-53_R5_CP-2(1), -NIST_SP_800-53_R5_CP-4(1), -NIST_SP_800-53_R5_IR-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d4e6a629-28eb-79a9-000b-88030e4823ca","","BuiltIn","Regulatory Compliance","Coordinate with external organizations to achieve cross org perspective","CMA_C1368 - Coordinate with external organizations to achieve cross org perspective","NIST_SP_800-53_R5_IR-4(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"10874318-0bf7-a41f-8463-03e395482080","","BuiltIn","Regulatory Compliance","Correlate audit records","CMA_0087 - Correlate audit records","NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(1), -NIST_SP_800-53_R5_AU-6(3), -NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e3905a3c-97e7-0b4f-15fb-465c0927536f","","BuiltIn","Regulatory Compliance","Correlate Vulnerability scan information","CMA_C1558 - Correlate Vulnerability scan information","NIST_SP_800-53_R5_RA-5(10)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"043c1e56-5a16-52f8-6af8-583098ff3e60","","BuiltIn","Regulatory Compliance","Create a data inventory","CMA_0096 - Create a data inventory","NIST_SP_800-53_R5_CM-8, -NIST_SP_800-53_R5_CM-8(1), -NIST_SP_800-53_R5_CM-8(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"cc2f7339-2fac-1ea9-9ca3-cd530fbb0da2","","BuiltIn","Regulatory Compliance","Create alternative actions for identified anomalies","CMA_C1711 - Create alternative actions for identified anomalies","NIST_SP_800-53_R5_SI-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"874a6f2e-2098-53bc-3a16-20dcdc425a7e","","BuiltIn","Regulatory Compliance","Create configuration plan protection","CMA_C1233 - Create configuration plan protection","NIST_SP_800-53_R5_CM-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"81b6267b-97a7-9aa5-51ee-d2584a160424","","BuiltIn","Regulatory Compliance","Create separate alternate and primary storage sites","CMA_C1269 - Create separate alternate and primary storage sites","NIST_SP_800-53_R5_CP-6(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"51e4b233-8ee3-8bdc-8f5f-f33bd0d229b7","","BuiltIn","Regulatory Compliance","Define a physical key management process","CMA_0115 - Define a physical key management process","NIST_SP_800-53_R5_PE-3, -NIST_SP_800-53_R5_SC-12","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1afada58-8b34-7ac2-a38a-983218635201","","BuiltIn","Regulatory Compliance","Define acceptable and unacceptable mobile code technologies","CMA_C1651 - Define acceptable and unacceptable mobile code technologies","NIST_SP_800-53_R5_SC-18","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"341bc9f1-7489-07d9-4ec6-971573e1546a","","BuiltIn","Regulatory Compliance","Define access authorizations to support separation of duties","CMA_0116 - Define access authorizations to support separation of duties","NIST_SP_800-53_R5_AC-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"cbfa1bd0-714d-8d6f-0480-2ad6a53972df","","BuiltIn","Regulatory Compliance","Define and document government oversight","CMA_C1587 - Define and document government oversight","NIST_SP_800-53_R5_SA-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f7eb1d0b-6d4f-2d59-1591-7563e11a9313","","BuiltIn","Regulatory Compliance","Define and enforce conditions for shared and group accounts","CMA_0117 - Define and enforce conditions for shared and group accounts","NIST_SP_800-53_R5_AC-2, -NIST_SP_800-53_R5_AC-2(9)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2af4640d-11a6-a64b-5ceb-a468f4341c0c","","BuiltIn","Regulatory Compliance","Define and enforce inactivity log policy","CMA_C1017 - Define and enforce inactivity log policy","NIST_SP_800-53_R5_AC-2(5)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d8350d4c-9314-400b-288f-20ddfce04fbd","","BuiltIn","Regulatory Compliance","Define and enforce the limit of concurrent sessions","CMA_C1050 - Define and enforce the limit of concurrent sessions","NIST_SP_800-53_R5_AC-10","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c4ccd607-702b-8ae6-8eeb-fc3339cd4b42","","BuiltIn","Regulatory Compliance","Define cryptographic use","CMA_0120 - Define cryptographic use","NIST_SP_800-53_R5_SC-12, -NIST_SP_800-53_R5_SC-13","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ef5a7059-6651-73b1-18b3-75b1b79c1565","","BuiltIn","Regulatory Compliance","Define information security roles and responsibilities","CMA_C1565 - Define information security roles and responsibilities","NIST_SP_800-53_R5_SA-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"623b5f0a-8cbd-03a6-4892-201d27302f0c","","BuiltIn","Regulatory Compliance","Define information system account types","CMA_0121 - Define information system account types","NIST_SP_800-53_R5_AC-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"9ca3a3ea-3a1f-8ba0-31a8-6aed0fe1a7a4","","BuiltIn","Regulatory Compliance","Define mobile device requirements","CMA_0122 - Define mobile device requirements","NIST_SP_800-53_R5_AC-19, -NIST_SP_800-53_R5_AC-19(5)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d661e9eb-4e15-5ba1-6f02-cdc467db0d6c","","BuiltIn","Regulatory Compliance","Define organizational requirements for cryptographic key management","CMA_0123 - Define organizational requirements for cryptographic key management","NIST_SP_800-53_R5_SC-12","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"25a1f840-65d0-900a-43e4-bee253de04de","","BuiltIn","Regulatory Compliance","Define requirements for managing assets","CMA_0125 - Define requirements for managing assets","NIST_SP_800-53_R5_PE-16","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8e49107c-3338-40d1-02aa-d524178a2afe","","BuiltIn","Regulatory Compliance","Deliver security assessment results","CMA_C1147 - Deliver security assessment results","NIST_SP_800-53_R5_CA-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"03b6427e-6072-4226-4bd9-a410ab65317e","","BuiltIn","Regulatory Compliance","Design an access control model","CMA_0129 - Design an access control model","NIST_SP_800-53_R5_AC-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b4512986-80f5-1656-0c58-08866bd2673a","","BuiltIn","Regulatory Compliance","Designate authorized personnel to post publicly accessible information","CMA_C1083 - Designate authorized personnel to post publicly accessible information","NIST_SP_800-53_R5_AC-22","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"7a489c62-242c-5db9-74df-c073056d6fa3","","BuiltIn","Regulatory Compliance","Designate personnel to supervise unauthorized maintenance activities","CMA_C1422 - Designate personnel to supervise unauthorized maintenance activities","NIST_SP_800-53_R5_MA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"86ecd378-a3a0-5d5b-207c-05e6aaca43fc","","BuiltIn","Regulatory Compliance","Detect network services that have not been authorized or approved","CMA_C1700 - Detect network services that have not been authorized or approved","NIST_SP_800-53_R5_SI-4(22)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"7a0ecd94-3699-5273-76a5-edb8499f655a","","BuiltIn","Regulatory Compliance","Determine assertion requirements","CMA_0136 - Determine assertion requirements","NIST_SP_800-53_R5_SC-12","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2f67e567-03db-9d1f-67dc-b6ffb91312f4","","BuiltIn","Regulatory Compliance","Determine auditable events","CMA_0137 - Determine auditable events","NIST_SP_800-53_R5_AU-2, -NIST_SP_800-53_R5_AU-3, -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"67ada943-8539-083d-35d0-7af648974125","","BuiltIn","Regulatory Compliance","Determine supplier contract obligations","CMA_0140 - Determine supplier contract obligations","NIST_SP_800-53_R5_SA-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e7422f08-65b4-50e4-3779-d793156e0079","","BuiltIn","Regulatory Compliance","Develop a concept of operations (CONOPS)","CMA_0141 - Develop a concept of operations (CONOPS)","NIST_SP_800-53_R5_PL-8","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"42116f15-5665-a52a-87bb-b40e64c74b6c","","BuiltIn","Regulatory Compliance","Develop acceptable use policies and procedures","CMA_0143 - Develop acceptable use policies and procedures","NIST_SP_800-53_R5_PL-4, -NIST_SP_800-53_R5_PL-4(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"59f7feff-02aa-6539-2cf7-bea75b762140","","BuiltIn","Regulatory Compliance","Develop access control policies and procedures","CMA_0144 - Develop access control policies and procedures","NIST_SP_800-53_R5_AC-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2b4e134f-1e4c-2bff-573e-082d85479b6e","","BuiltIn","Regulatory Compliance","Develop an incident response plan","CMA_0145 - Develop an incident response plan","NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-4(1), -NIST_SP_800-53_R5_IR-7(1), -NIST_SP_800-53_R5_IR-8, -NIST_SP_800-53_R5_IR-9, -NIST_SP_800-53_R5_SI-4(5)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"bd6cbcba-4a2d-507c-53e3-296b5c238a8e","","BuiltIn","Regulatory Compliance","Develop and document a business continuity and disaster recovery plan","CMA_0146 - Develop and document a business continuity and disaster recovery plan","NIST_SP_800-53_R5_CP-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b7306e73-0494-83a2-31f5-280e934a8f70","","BuiltIn","Regulatory Compliance","Develop and document a DDoS response plan","CMA_0147 - Develop and document a DDoS response plan","NIST_SP_800-53_R5_SC-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"6de65dc4-8b4f-34b7-9290-eb137a2e2929","","BuiltIn","Regulatory Compliance","Develop and document application security requirements","CMA_0148 - Develop and document application security requirements","NIST_SP_800-53_R5_SA-10","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b2ea1058-8998-3dd1-84f1-82132ad482fd","","BuiltIn","Regulatory Compliance","Develop and establish a system security plan","CMA_0151 - Develop and establish a system security plan","NIST_SP_800-53_R5_PL-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"055da733-55c6-9e10-8194-c40731057ec4","","BuiltIn","Regulatory Compliance","Develop and maintain a vulnerability management standard","CMA_0152 - Develop and maintain a vulnerability management standard","NIST_SP_800-53_R5_CM-3, -NIST_SP_800-53_R5_CM-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2f20840e-7925-221c-725d-757442753e7c","","BuiltIn","Regulatory Compliance","Develop and maintain baseline configurations","CMA_0153 - Develop and maintain baseline configurations","NIST_SP_800-53_R5_CM-2, -NIST_SP_800-53_R5_CM-2(2), -NIST_SP_800-53_R5_CM-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"a28323fe-276d-3787-32d2-cef6395764c4","","BuiltIn","Regulatory Compliance","Develop audit and accountability policies and procedures","CMA_0154 - Develop audit and accountability policies and procedures","NIST_SP_800-53_R5_AU-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"11ba0508-58a8-44de-5f3a-9e05d80571da","","BuiltIn","Regulatory Compliance","Develop business classification schemes","CMA_0155 - Develop business classification schemes","NIST_SP_800-53_R5_RA-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"836f8406-3b8a-11bb-12cb-6c7fa0765668","","BuiltIn","Regulatory Compliance","Develop configuration item identification plan","CMA_C1231 - Develop configuration item identification plan","NIST_SP_800-53_R5_CM-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"04837a26-2601-1982-3da7-bf463e6408f4","","BuiltIn","Regulatory Compliance","Develop configuration management plan","CMA_C1232 - Develop configuration management plan","NIST_SP_800-53_R5_CM-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"aa305b4d-8c84-1754-0c74-dec004e66be0","","BuiltIn","Regulatory Compliance","Develop contingency plan","CMA_C1244 - Develop contingency plan","NIST_SP_800-53_R5_CP-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"75b42dcf-7840-1271-260b-852273d7906e","","BuiltIn","Regulatory Compliance","Develop contingency planning policies and procedures","CMA_0156 - Develop contingency planning policies and procedures","NIST_SP_800-53_R5_CP-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"af227964-5b8b-22a2-9364-06d2cb9d6d7c","","BuiltIn","Regulatory Compliance","Develop information security policies and procedures","CMA_0158 - Develop information security policies and procedures","NIST_SP_800-53_R5_AU-1, -NIST_SP_800-53_R5_PL-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d02498e0-8a6f-6b02-8332-19adf6711d1e","","BuiltIn","Regulatory Compliance","Develop organization code of conduct policy","CMA_0159 - Develop organization code of conduct policy","NIST_SP_800-53_R5_PL-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"477bd136-7dd9-55f8-48ac-bae096b86a07","","BuiltIn","Regulatory Compliance","Develop POA&M","CMA_C1156 - Develop POA&M","NIST_SP_800-53_R5_CA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1c258345-5cd4-30c8-9ef3-5ee4dd5231d6","","BuiltIn","Regulatory Compliance","Develop security assessment plan","CMA_C1144 - Develop security assessment plan","NIST_SP_800-53_R5_CA-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"423f6d9c-0c73-9cc6-64f4-b52242490368","","BuiltIn","Regulatory Compliance","Develop security safeguards","CMA_0161 - Develop security safeguards","NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-9(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"bb048641-6017-7272-7772-a008f285a520","","BuiltIn","Regulatory Compliance","Develop spillage response procedures","CMA_0162 - Develop spillage response procedures","NIST_SP_800-53_R5_IR-9(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"6b957f60-54cd-5752-44d5-ff5a64366c93","","BuiltIn","Regulatory Compliance","Develop SSP that meets criteria","CMA_C1492 - Develop SSP that meets criteria","NIST_SP_800-53_R5_PL-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d9d48ffb-0d8c-0bd5-5f31-5a5826d19f10","","BuiltIn","Regulatory Compliance","Disable authenticators upon termination","CMA_0169 - Disable authenticators upon termination","NIST_SP_800-53_R5_AC-2(3), -NIST_SP_800-53_R5_PS-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"22c16ae4-19d0-29cb-422f-cb44061180ee","","BuiltIn","Regulatory Compliance","Disable user accounts posing a significant risk","CMA_C1026 - Disable user accounts posing a significant risk","NIST_SP_800-53_R5_AC-2(13)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"07b42fb5-027e-5a3c-4915-9d9ef3020ec7","","BuiltIn","Regulatory Compliance","Discover any indicators of compromise","CMA_C1702 - Discover any indicators of compromise","NIST_SP_800-53_R5_SI-4(24)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"0471c6b7-1588-701c-2713-1fade73b75f6","","BuiltIn","Regulatory Compliance","Display an explicit logout message","CMA_C1056 - Display an explicit logout message","NIST_SP_800-53_R5_AC-12(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"9c93ef57-7000-63fb-9b74-88f2e17ca5d2","","BuiltIn","Regulatory Compliance","Disseminate security alerts to personnel","CMA_C1705 - Disseminate security alerts to personnel","NIST_SP_800-53_R5_SI-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"84a01872-5318-049e-061e-d56734183e84","","BuiltIn","Regulatory Compliance","Distribute information system documentation","CMA_C1584 - Distribute information system documentation","NIST_SP_800-53_R5_SA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"eff6e4a5-3efe-94dd-2ed1-25d56a019a82","","BuiltIn","Regulatory Compliance","Distribute policies and procedures","CMA_0185 - Distribute policies and procedures","NIST_SP_800-53_R5_CP-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"a08b18c7-9e0a-89f1-3696-d80902196719","","BuiltIn","Regulatory Compliance","Document access privileges","CMA_0186 - Document access privileges","NIST_SP_800-53_R5_AC-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"0803eaa7-671c-08a7-52fd-ac419f775e75","","BuiltIn","Regulatory Compliance","Document acquisition contract acceptance criteria","CMA_0187 - Document acquisition contract acceptance criteria","NIST_SP_800-53_R5_SA-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"04b3e7f6-4841-888d-4799-cda19a0084f6","","BuiltIn","Regulatory Compliance","Document and implement wireless access guidelines","CMA_0190 - Document and implement wireless access guidelines","NIST_SP_800-53_R5_AC-18, -NIST_SP_800-53_R5_AC-18(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8c44a0ea-9b09-4d9c-0e91-f9bee3d05bfb","","BuiltIn","Regulatory Compliance","Document customer-defined actions","CMA_C1582 - Document customer-defined actions","NIST_SP_800-53_R5_SA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"83dfb2b8-678b-20a0-4c44-5c75ada023e6","","BuiltIn","Regulatory Compliance","Document mobility training","CMA_0191 - Document mobility training","NIST_SP_800-53_R5_AC-17","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c981fa70-2e58-8141-1457-e7f62ebc2ade","","BuiltIn","Regulatory Compliance","Document organizational access agreements","CMA_0192 - Document organizational access agreements","NIST_SP_800-53_R5_PS-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"271a3e58-1b38-933d-74c9-a580006b80aa","","BuiltIn","Regulatory Compliance","Document personnel acceptance of privacy requirements","CMA_0193 - Document personnel acceptance of privacy requirements","NIST_SP_800-53_R5_PL-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f9ec3263-9562-1768-65a1-729793635a8d","","BuiltIn","Regulatory Compliance","Document protection of personal data in acquisition contracts","CMA_0194 - Document protection of personal data in acquisition contracts","NIST_SP_800-53_R5_SA-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d78f95ba-870a-a500-6104-8a5ce2534f19","","BuiltIn","Regulatory Compliance","Document protection of security information in acquisition contracts","CMA_0195 - Document protection of security information in acquisition contracts","NIST_SP_800-53_R5_SA-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3d492600-27ba-62cc-a1c3-66eb919f6a0d","","BuiltIn","Regulatory Compliance","Document remote access guidelines","CMA_0196 - Document remote access guidelines","NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"0ba211ef-0e85-2a45-17fc-401d1b3f8f85","","BuiltIn","Regulatory Compliance","Document requirements for the use of shared data in contracts","CMA_0197 - Document requirements for the use of shared data in contracts","NIST_SP_800-53_R5_SA-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"524e7136-9f6a-75ba-9089-501018151346","","BuiltIn","Regulatory Compliance","Document security and privacy training activities","CMA_0198 - Document security and privacy training activities","NIST_SP_800-53_R5_AT-1, -NIST_SP_800-53_R5_AT-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"13efd2d7-3980-a2a4-39d0-527180c009e8","","BuiltIn","Regulatory Compliance","Document security assurance requirements in acquisition contracts","CMA_0199 - Document security assurance requirements in acquisition contracts","NIST_SP_800-53_R5_SA-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"a465e8e9-0095-85cb-a05f-1dd4960d02af","","BuiltIn","Regulatory Compliance","Document security documentation requirements in acquisition contract","CMA_0200 - Document security documentation requirements in acquisition contract","NIST_SP_800-53_R5_SA-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"57927290-8000-59bf-3776-90c468ac5b4b","","BuiltIn","Regulatory Compliance","Document security functional requirements in acquisition contracts","CMA_0201 - Document security functional requirements in acquisition contracts","NIST_SP_800-53_R5_SA-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2c6bee3a-2180-2430-440d-db3c7a849870","","BuiltIn","Regulatory Compliance","Document security operations","CMA_0202 - Document security operations","NIST_SP_800-53_R5_IR-6(1), -NIST_SP_800-53_R5_IR-7, -NIST_SP_800-53_R5_SI-4(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ebb0ba89-6d8c-84a7-252b-7393881e43de","","BuiltIn","Regulatory Compliance","Document security strength requirements in acquisition contracts","CMA_0203 - Document security strength requirements in acquisition contracts","NIST_SP_800-53_R5_IA-5(1), -NIST_SP_800-53_R5_SA-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e6f7b584-877a-0d69-77d4-ab8b923a9650","","BuiltIn","Regulatory Compliance","Document separation of duties","CMA_0204 - Document separation of duties","NIST_SP_800-53_R5_AC-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c148208b-1a6f-a4ac-7abc-23b1d41121b1","","BuiltIn","Regulatory Compliance","Document the information system environment in acquisition contracts","CMA_0205 - Document the information system environment in acquisition contracts","NIST_SP_800-53_R5_SA-4, -NIST_SP_800-53_R5_SA-10","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"77acc53d-0f67-6e06-7d04-5750653d4629","","BuiltIn","Regulatory Compliance","Document the protection of cardholder data in third party contracts","CMA_0207 - Document the protection of cardholder data in third party contracts","NIST_SP_800-53_R5_SA-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b320aa42-33b4-53af-87ce-100091d48918","","BuiltIn","Regulatory Compliance","Document third-party personnel security requirements","CMA_C1531 - Document third-party personnel security requirements","NIST_SP_800-53_R5_PS-7","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8f835d6a-4d13-9a9c-37dc-176cebd37fda","","BuiltIn","Regulatory Compliance","Document wireless access security controls","CMA_C1695 - Document wireless access security controls","NIST_SP_800-53_R5_SI-4(14)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"eaaae23f-92c9-4460-51cf-913feaea4d52","","BuiltIn","Regulatory Compliance","Employ a media sanitization mechanism","CMA_0208 - Employ a media sanitization mechanism","NIST_SP_800-53_R5_MA-2, -NIST_SP_800-53_R5_MA-3(3), -NIST_SP_800-53_R5_MA-5(1), -NIST_SP_800-53_R5_MP-4, -NIST_SP_800-53_R5_MP-6, -NIST_SP_800-53_R5_MP-6(1), -NIST_SP_800-53_R5_MP-6(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c8aa992d-76b7-7ca0-07b3-31a58d773fa9","","BuiltIn","Regulatory Compliance","Employ automated training environment","CMA_C1357 - Employ automated training environment","NIST_SP_800-53_R5_IR-2(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"aa892c0d-2c40-200c-0dd8-eac8c4748ede","","BuiltIn","Regulatory Compliance","Employ automatic emergency lighting","CMA_0209 - Employ automatic emergency lighting","NIST_SP_800-53_R5_PE-12","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1b8a7ec3-11cc-a2d3-8cd0-eedf074424a4","","BuiltIn","Regulatory Compliance","Employ automatic shutdown/restart when violations are detected","CMA_C1715 - Employ automatic shutdown/restart when violations are detected","NIST_SP_800-53_R5_SI-7(5)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"311802f9-098d-0659-245a-94c5d47c0182","","BuiltIn","Regulatory Compliance","Employ boundary protection to isolate information systems","CMA_C1639 - Employ boundary protection to isolate information systems","NIST_SP_800-53_R5_SC-7(21)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8b333332-6efd-7c0d-5a9f-d1eb95105214","","BuiltIn","Regulatory Compliance","Employ FIPS 201-approved technology for PIV","CMA_C1579 - Employ FIPS 201-approved technology for PIV","NIST_SP_800-53_R5_SA-4(10)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"79365f13-8ba4-1f6c-2ac4-aa39929f56d0","","BuiltIn","Regulatory Compliance","Employ flow control mechanisms of encrypted information","CMA_0211 - Employ flow control mechanisms of encrypted information","NIST_SP_800-53_R5_AC-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3baee3fd-30f5-882c-018c-cc78703a0106","","BuiltIn","Regulatory Compliance","Employ independent assessors for continuous monitoring","CMA_C1168 - Employ independent assessors for continuous monitoring","NIST_SP_800-53_R5_CA-7(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b65c5d8e-9043-9612-2c17-65f231d763bb","","BuiltIn","Regulatory Compliance","Employ independent assessors to conduct security control assessments","CMA_C1148 - Employ independent assessors to conduct security control assessments","NIST_SP_800-53_R5_CA-2(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"611ebc63-8600-50b6-a0e3-fef272457132","","BuiltIn","Regulatory Compliance","Employ independent team for penetration testing","CMA_C1171 - Employ independent team for penetration testing","NIST_SP_800-53_R5_CA-8(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1bc7fd64-291f-028e-4ed6-6e07886e163f","","BuiltIn","Regulatory Compliance","Employ least privilege access","CMA_0212 - Employ least privilege access","NIST_SP_800-53_R5_AC-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"426c172c-9914-10d1-25dd-669641fc1af4","","BuiltIn","Regulatory Compliance","Enable detection of network devices","CMA_0220 - Enable detection of network devices","NIST_SP_800-53_R5_CM-8(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2c843d78-8f64-92b5-6a9b-e8186c0e7eb6","","BuiltIn","Regulatory Compliance","Enable dual or joint authorization","CMA_0226 - Enable dual or joint authorization","NIST_SP_800-53_R5_AU-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8c255136-994b-9616-79f5-ae87810e0dcf","","BuiltIn","Regulatory Compliance","Enable network protection","CMA_0238 - Enable network protection","NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-4(1), -NIST_SP_800-53_R5_IR-7(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b4409bff-2287-8407-05fd-c73175a68302","","BuiltIn","Regulatory Compliance","Enforce a limit of consecutive failed login attempts","CMA_C1044 - Enforce a limit of consecutive failed login attempts","NIST_SP_800-53_R5_AC-7","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8cd815bf-97e1-5144-0735-11f6ddb50a59","","BuiltIn","Regulatory Compliance","Enforce and audit access restrictions","CMA_C1203 - Enforce and audit access restrictions","NIST_SP_800-53_R5_CM-5(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"fd81a1b3-2d7a-107c-507e-29b87d040c19","","BuiltIn","Regulatory Compliance","Enforce appropriate usage of all accounts","CMA_C1023 - Enforce appropriate usage of all accounts","NIST_SP_800-53_R5_AC-2(11)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c7e8ddc1-14aa-1814-7fe1-aad1742b27da","","BuiltIn","Regulatory Compliance","Enforce expiration of cached authenticators","CMA_C1343 - Enforce expiration of cached authenticators","NIST_SP_800-53_R5_IA-5(13)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"10c4210b-3ec9-9603-050d-77e4d26c7ebb","","BuiltIn","Regulatory Compliance","Enforce logical access","CMA_0245 - Enforce logical access","NIST_SP_800-53_R5_AC-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b1666a13-8f67-9c47-155e-69e027ff6823","","BuiltIn","Regulatory Compliance","Enforce mandatory and discretionary access control policies","CMA_0246 - Enforce mandatory and discretionary access control policies","NIST_SP_800-53_R5_AC-1, -NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_AC-6(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c7d57a6a-7cc2-66c0-299f-83bf90558f5d","","BuiltIn","Regulatory Compliance","Enforce random unique session identifiers","CMA_0247 - Enforce random unique session identifiers","NIST_SP_800-53_R5_SC-23","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"509552f5-6528-3540-7959-fbeae4832533","","BuiltIn","Regulatory Compliance","Enforce rules of behavior and access agreements","CMA_0248 - Enforce rules of behavior and access agreements","NIST_SP_800-53_R5_PL-4, -NIST_SP_800-53_R5_PS-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"058e9719-1ff9-3653-4230-23f76b6492e0","","BuiltIn","Regulatory Compliance","Enforce security configuration settings","CMA_0249 - Enforce security configuration settings","NIST_SP_800-53_R5_CM-2, -NIST_SP_800-53_R5_CM-2(2), -NIST_SP_800-53_R5_CM-6, -NIST_SP_800-53_R5_CM-6(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"68d2e478-3b19-23eb-1357-31b296547457","","BuiltIn","Regulatory Compliance","Enforce software execution privileges","CMA_C1041 - Enforce software execution privileges","NIST_SP_800-53_R5_AC-6(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e336d5f4-4d8f-0059-759c-ae10f63d1747","","BuiltIn","Regulatory Compliance","Enforce user uniqueness","CMA_0250 - Enforce user uniqueness","NIST_SP_800-53_R5_IA-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e7589f4e-1e8b-72c2-3692-1e14d7f3699f","","BuiltIn","Regulatory Compliance","Ensure access agreements are signed or resigned timely","CMA_C1528 - Ensure access agreements are signed or resigned timely","NIST_SP_800-53_R5_PS-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"178c8b7e-1b6e-4289-44dd-2f1526b678a1","","BuiltIn","Regulatory Compliance","Ensure alternate storage site safeguards are equivalent to primary site","CMA_C1268 - Ensure alternate storage site safeguards are equivalent to primary site","NIST_SP_800-53_R5_CP-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"27ce30dd-3d56-8b54-6144-e26d9a37a541","","BuiltIn","Regulatory Compliance","Ensure audit records are not altered","CMA_C1125 - Ensure audit records are not altered","NIST_SP_800-53_R5_AU-7","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"37dbe3dc-0e9c-24fa-36f2-11197cbfa207","","BuiltIn","Regulatory Compliance","Ensure authorized users protect provided authenticators","CMA_C1339 - Ensure authorized users protect provided authenticators","NIST_SP_800-53_R5_IA-5(6)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b8dad106-6444-5f55-307e-1e1cc9723e39","","BuiltIn","Regulatory Compliance","Ensure cryptographic mechanisms are under configuration management","CMA_C1199 - Ensure cryptographic mechanisms are under configuration management","NIST_SP_800-53_R5_CM-3(6)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3eabed6d-1912-2d3c-858b-f438d08d0412","","BuiltIn","Regulatory Compliance","Ensure external providers consistently meet interests of the customers","CMA_C1592 - Ensure external providers consistently meet interests of the customers","NIST_SP_800-53_R5_SA-9(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"12af7c7a-92af-9e96-0d0c-5e732d1a3751","","BuiltIn","Regulatory Compliance","Ensure information system fails in known state","CMA_C1662 - Ensure information system fails in known state","NIST_SP_800-53_R5_SC-24","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"0716f0f5-4955-2ccb-8d5e-c6be14d57c0f","","BuiltIn","Regulatory Compliance","Ensure resources are authorized","CMA_C1159 - Ensure resources are authorized","NIST_SP_800-53_R5_CA-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"6c79c3e5-5f7b-a48a-5c7b-8c158bc01115","","BuiltIn","Regulatory Compliance","Ensure security categorization is approved","CMA_C1540 - Ensure security categorization is approved","NIST_SP_800-53_R5_RA-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1fdf0b24-4043-3c55-357e-036985d50b52","","BuiltIn","Regulatory Compliance","Ensure security safeguards not needed when the individuals return","CMA_C1183 - Ensure security safeguards not needed when the individuals return","NIST_SP_800-53_R5_CM-2(7)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"83eea3d3-0d2c-9ccd-1021-2111b29b2a62","","BuiltIn","Regulatory Compliance","Ensure system capable of dynamic isolation of resources","CMA_C1638 - Ensure system capable of dynamic isolation of resources","NIST_SP_800-53_R5_SC-7(20)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"eda0cbb7-6043-05bf-645b-67411f1a59b3","","BuiltIn","Regulatory Compliance","Ensure there are no unencrypted static authenticators","CMA_C1340 - Ensure there are no unencrypted static authenticators","NIST_SP_800-53_R5_IA-5(7)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"54a9c072-4a93-2a03-6a43-a060d30383d7","","BuiltIn","Regulatory Compliance","Eradicate contaminated information","CMA_0253 - Eradicate contaminated information","NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-7(1), -NIST_SP_800-53_R5_IR-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"7380631c-5bf5-0e3a-4509-0873becd8a63","","BuiltIn","Regulatory Compliance","Establish a configuration control board","CMA_0254 - Establish a configuration control board","NIST_SP_800-53_R5_CM-2, -NIST_SP_800-53_R5_CM-2(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3c9aa856-6b86-35dc-83f4-bc72cec74dea","","BuiltIn","Regulatory Compliance","Establish a data leakage management procedure","CMA_0255 - Establish a data leakage management procedure","NIST_SP_800-53_R5_SC-28","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"06af77de-02ca-0f3e-838a-a9420fe466f5","","BuiltIn","Regulatory Compliance","Establish a discrete line item in budgeting documentation","CMA_C1563 - Establish a discrete line item in budgeting documentation","NIST_SP_800-53_R5_SA-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d8bbd80e-3bb1-5983-06c2-428526ec6a63","","BuiltIn","Regulatory Compliance","Establish a password policy","CMA_0256 - Establish a password policy","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"39eb03c1-97cc-11ab-0960-6209ed2869f7","","BuiltIn","Regulatory Compliance","Establish a privacy program","CMA_0257 - Establish a privacy program","NIST_SP_800-53_R5_PL-2, -NIST_SP_800-53_R5_SA-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d36700f2-2f0d-7c2a-059c-bdadd1d79f70","","BuiltIn","Regulatory Compliance","Establish a risk management strategy","CMA_0258 - Establish a risk management strategy","NIST_SP_800-53_R5_CM-3, -NIST_SP_800-53_R5_CM-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e750ca06-1824-464a-2cf3-d0fa754d1cb4","","BuiltIn","Regulatory Compliance","Establish a secure software development program","CMA_0259 - Establish a secure software development program","NIST_SP_800-53_R5_SA-10","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b0e3035d-6366-2e37-796e-8bcab9c649e6","","BuiltIn","Regulatory Compliance","Establish a threat intelligence program","CMA_0260 - Establish a threat intelligence program","NIST_SP_800-53_R5_SI-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"245fe58b-96f8-9f1e-48c5-7f49903f66fd","","BuiltIn","Regulatory Compliance","Establish alternate storage site that facilitates recovery operations","CMA_C1270 - Establish alternate storage site that facilitates recovery operations","NIST_SP_800-53_R5_CP-6(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"0a412110-3874-9f22-187a-c7a81c8a6704","","BuiltIn","Regulatory Compliance","Establish alternate storage site to store and retrieve backup information","CMA_C1267 - Establish alternate storage site to store and retrieve backup information","NIST_SP_800-53_R5_CP-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"af5ff768-a34b-720e-1224-e6b3214f3ba6","","BuiltIn","Regulatory Compliance","Establish an alternate processing site","CMA_0262 - Establish an alternate processing site","NIST_SP_800-53_R5_CP-7, -NIST_SP_800-53_R5_CP-7(1), -NIST_SP_800-53_R5_CP-7(2), -NIST_SP_800-53_R5_CP-7(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"84245967-7882-54f6-2d34-85059f725b47","","BuiltIn","Regulatory Compliance","Establish an information security program","CMA_0263 - Establish an information security program","NIST_SP_800-53_R5_IR-3, -NIST_SP_800-53_R5_IR-3(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"526ed90e-890f-69e7-0386-ba5c0f1f784f","","BuiltIn","Regulatory Compliance","Establish and document a configuration management plan","CMA_0264 - Establish and document a configuration management plan","NIST_SP_800-53_R5_CM-2, -NIST_SP_800-53_R5_CM-2(2), -NIST_SP_800-53_R5_CM-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"bd4dc286-2f30-5b95-777c-681f3a7913d3","","BuiltIn","Regulatory Compliance","Establish and document change control processes","CMA_0265 - Establish and document change control processes","NIST_SP_800-53_R5_CM-3, -NIST_SP_800-53_R5_CM-3(2), -NIST_SP_800-53_R5_CM-4, -NIST_SP_800-53_R5_CM-4(1), -NIST_SP_800-53_R5_CM-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"27965e62-141f-8cca-426f-d09514ee5216","","BuiltIn","Regulatory Compliance","Establish and maintain an asset inventory","CMA_0266 - Establish and maintain an asset inventory","NIST_SP_800-53_R5_CM-8(4), -NIST_SP_800-53_R5_PE-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"921ae4c1-507f-5ddb-8a58-cfa9b5fd96f0","","BuiltIn","Regulatory Compliance","Establish authenticator types and processes","CMA_0267 - Establish authenticator types and processes","NIST_SP_800-53_R5_IA-5, -NIST_SP_800-53_R5_IA-5(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"4f23967c-a74b-9a09-9dc2-f566f61a87b9","","BuiltIn","Regulatory Compliance","Establish backup policies and procedures","CMA_0268 - Establish backup policies and procedures","NIST_SP_800-53_R5_AU-9(2), -NIST_SP_800-53_R5_CP-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"dd2523d5-2db3-642b-a1cf-83ac973b32c2","","BuiltIn","Regulatory Compliance","Establish benchmarks for flaw remediation","CMA_C1675 - Establish benchmarks for flaw remediation","NIST_SP_800-53_R5_SI-2(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"97cfd944-6f0c-7db2-3796-8e890ef70819","","BuiltIn","Regulatory Compliance","Establish conditions for role membership","CMA_0269 - Establish conditions for role membership","NIST_SP_800-53_R5_AC-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8747b573-8294-86a0-8914-49e9b06a5ace","","BuiltIn","Regulatory Compliance","Establish configuration management requirements for developers","CMA_0270 - Establish configuration management requirements for developers","NIST_SP_800-53_R5_CM-3, -NIST_SP_800-53_R5_CM-3(2), -NIST_SP_800-53_R5_CM-4, -NIST_SP_800-53_R5_CM-4(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"6f3866e8-6e12-69cf-788c-809d426094a1","","BuiltIn","Regulatory Compliance","Establish electronic signature and certificate requirements","CMA_0271 - Establish electronic signature and certificate requirements","NIST_SP_800-53_R5_AU-10","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"398fdbd8-56fd-274d-35c6-fa2d3b2755a1","","BuiltIn","Regulatory Compliance","Establish firewall and router configuration standards","CMA_0272 - Establish firewall and router configuration standards","NIST_SP_800-53_R5_AC-4(21)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f476f3b0-4152-526e-a209-44e5f8c968d7","","BuiltIn","Regulatory Compliance","Establish network segmentation for card holder data environment","CMA_0273 - Establish network segmentation for card holder data environment","NIST_SP_800-53_R5_AC-4(21)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"0065241c-72e9-3b2c-556f-75de66332a94","","BuiltIn","Regulatory Compliance","Establish parameters for searching secret authenticators and verifiers","CMA_0274 - Establish parameters for searching secret authenticators and verifiers","NIST_SP_800-53_R5_IA-5(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"35963d41-4263-0ef9-98d5-70eb058f9e3c","","BuiltIn","Regulatory Compliance","Establish procedures for initial authenticator distribution","CMA_0276 - Establish procedures for initial authenticator distribution","NIST_SP_800-53_R5_IA-5, -NIST_SP_800-53_R5_IA-5(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b470a37a-7a47-3792-34dd-7a793140702e","","BuiltIn","Regulatory Compliance","Establish relationship between incident response capability and external providers","CMA_C1376 - Establish relationship between incident response capability and external providers","NIST_SP_800-53_R5_IR-7(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b3c8cc83-20d3-3890-8bc8-5568777670f4","","BuiltIn","Regulatory Compliance","Establish requirements for audit review and reporting","CMA_0277 - Establish requirements for audit review and reporting","NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(1), -NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"5f2e834d-7e40-a4d5-a216-e49b16955ccf","","BuiltIn","Regulatory Compliance","Establish requirements for internet service providers","CMA_0278 - Establish requirements for internet service providers","NIST_SP_800-53_R5_CP-7(3), -NIST_SP_800-53_R5_CP-8(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"afbecd30-37ee-a27b-8e09-6ac49951a0ee","","BuiltIn","Regulatory Compliance","Establish security requirements for the manufacturing of connected devices","CMA_0279 - Establish security requirements for the manufacturing of connected devices","NIST_SP_800-53_R5_PL-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3c93dba1-84fd-57de-33c7-ef0400a08134","","BuiltIn","Regulatory Compliance","Establish terms and conditions for accessing resources","CMA_C1076 - Establish terms and conditions for accessing resources","NIST_SP_800-53_R5_AC-20","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"5715bf33-a5bd-1084-4e19-bc3c83ec1c35","","BuiltIn","Regulatory Compliance","Establish terms and conditions for processing resources","CMA_C1077 - Establish terms and conditions for processing resources","NIST_SP_800-53_R5_AC-20","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3881168c-5d38-6f04-61cc-b5d87b2c4c58","","BuiltIn","Regulatory Compliance","Establish third-party personnel security requirements","CMA_C1529 - Establish third-party personnel security requirements","NIST_SP_800-53_R5_PS-7","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ffdaa742-0d6f-726f-3eac-6e6c34e36c93","","BuiltIn","Regulatory Compliance","Establish usage restrictions for mobile code technologies","CMA_C1652 - Establish usage restrictions for mobile code technologies","NIST_SP_800-53_R5_SC-18","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"60442979-6333-85f0-84c5-b887bac67448","","BuiltIn","Regulatory Compliance","Evaluate alternate processing site capabilities","CMA_C1266 - Evaluate alternate processing site capabilities","NIST_SP_800-53_R5_CP-4(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ba78efc6-795c-64f4-7a02-91effbd34af9","","BuiltIn","Regulatory Compliance","Execute actions in response to information spills","CMA_0281 - Execute actions in response to information spills","NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-7(1), -NIST_SP_800-53_R5_IR-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"62fa14f0-4cbe-762d-5469-0899a99b98aa","","BuiltIn","Regulatory Compliance","Explicitly notify use of collaborative computing devices","CMA_C1649 - Explicitly notify use of collaborative computing devices","NIST_SP_800-53_R5_SC-15","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"a44c9fba-43f8-4b7b-7ee6-db52c96b4366","","BuiltIn","Regulatory Compliance","Facilitate information sharing","CMA_0284 - Facilitate information sharing","NIST_SP_800-53_R5_AC-21","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c2cb4658-44dc-9d11-3dad-7c6802dd5ba3","","BuiltIn","Regulatory Compliance","Generate error messages","CMA_C1724 - Generate error messages","NIST_SP_800-53_R5_SI-11","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"171e377b-5224-4a97-1eaa-62a3b5231dac","","BuiltIn","Regulatory Compliance","Generate internal security alerts","CMA_C1704 - Generate internal security alerts","NIST_SP_800-53_R5_SI-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"333b4ada-4a02-0648-3d4d-d812974f1bb2","","BuiltIn","Regulatory Compliance","Govern and monitor audit processing activities","CMA_0289 - Govern and monitor audit processing activities","NIST_SP_800-53_R5_AU-4, -NIST_SP_800-53_R5_AU-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"5c33538e-02f8-0a7f-998b-a4c1e22076d3","","BuiltIn","Regulatory Compliance","Govern compliance of cloud service providers","CMA_0290 - Govern compliance of cloud service providers","NIST_SP_800-53_R5_CM-6(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1a2a03a4-9992-5788-5953-d8f6615306de","","BuiltIn","Regulatory Compliance","Govern policies and procedures","CMA_0292 - Govern policies and procedures","NIST_SP_800-53_R5_AC-1, -NIST_SP_800-53_R5_AU-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"33d34fac-56a8-1c0f-0636-3ed94892a709","","BuiltIn","Regulatory Compliance","Govern the allocation of resources","CMA_0293 - Govern the allocation of resources","NIST_SP_800-53_R5_SA-2, -NIST_SP_800-53_R5_SC-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"92a7591f-73b3-1173-a09c-a08882d84c70","","BuiltIn","Regulatory Compliance","Identify actions allowed without authentication","CMA_0295 - Identify actions allowed without authentication","NIST_SP_800-53_R5_AC-14","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ae5345d5-8dab-086a-7290-db43a3272198","","BuiltIn","Regulatory Compliance","Identify and authenticate network devices","CMA_0296 - Identify and authenticate network devices","NIST_SP_800-53_R5_AC-18(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e1379836-3492-6395-451d-2f5062e14136","","BuiltIn","Regulatory Compliance","Identify and authenticate non-organizational users","CMA_C1346 - Identify and authenticate non-organizational users","NIST_SP_800-53_R5_IA-8","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c7fddb0e-3f44-8635-2b35-dc6b8e740b7c","","BuiltIn","Regulatory Compliance","Identify and manage downstream information exchanges","CMA_0298 - Identify and manage downstream information exchanges","NIST_SP_800-53_R5_AC-4(21)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"13939f8c-4cd5-a6db-9af4-9dfec35e3722","","BuiltIn","Regulatory Compliance","Identify and mitigate potential issues at alternate storage site","CMA_C1271 - Identify and mitigate potential issues at alternate storage site","NIST_SP_800-53_R5_CP-6(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"23d1a569-2d1e-7f43-9e22-1f94115b7dd5","","BuiltIn","Regulatory Compliance","Identify classes of Incidents and Actions taken","CMA_C1365 - Identify classes of Incidents and Actions taken","NIST_SP_800-53_R5_IR-4(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"279052a0-8238-694d-9661-bf649f951747","","BuiltIn","Regulatory Compliance","Identify contaminated systems and components","CMA_0300 - Identify contaminated systems and components","NIST_SP_800-53_R5_IR-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"46ab2c5e-6654-1f58-8c83-e97a44f39308","","BuiltIn","Regulatory Compliance","Identify external service providers","CMA_C1591 - Identify external service providers","NIST_SP_800-53_R5_SA-9(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"037c0089-6606-2dab-49ad-437005b5035f","","BuiltIn","Regulatory Compliance","Identify incident response personnel","CMA_0301 - Identify incident response personnel","NIST_SP_800-53_R5_IR-7(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"0dcbaf2f-075e-947b-8f4c-74ecc5cd302c","","BuiltIn","Regulatory Compliance","Identify individuals with security roles and responsibilities","CMA_C1566 - Identify individuals with security roles and responsibilities","NIST_SP_800-53_R5_SA-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"69d90ee6-9f9f-262a-2038-d909fb4e5723","","BuiltIn","Regulatory Compliance","Identify spilled information","CMA_0303 - Identify spilled information","NIST_SP_800-53_R5_IR-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ca748dfe-3e28-1d18-4221-89aea30aa0a5","","BuiltIn","Regulatory Compliance","Identify status of individual users","CMA_C1316 - Identify status of individual users","NIST_SP_800-53_R5_IA-4(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ced727b3-005e-3c5b-5cd5-230b79d56ee8","","BuiltIn","Regulatory Compliance","Implement a fault tolerant name/address service","CMA_0305 - Implement a fault tolerant name/address service","NIST_SP_800-53_R5_SC-20, -NIST_SP_800-53_R5_SC-21, -NIST_SP_800-53_R5_SC-22","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c2eabc28-1e5c-78a2-a712-7cc176c44c07","","BuiltIn","Regulatory Compliance","Implement a penetration testing methodology","CMA_0306 - Implement a penetration testing methodology","NIST_SP_800-53_R5_PE-13(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"33832848-42ab-63f3-1a55-c0ad309d44cd","","BuiltIn","Regulatory Compliance","Implement an automated configuration management tool","CMA_0311 - Implement an automated configuration management tool","NIST_SP_800-53_R5_CM-2, -NIST_SP_800-53_R5_CM-2(2), -NIST_SP_800-53_R5_CM-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e435f7e3-0dd9-58c9-451f-9b44b96c0232","","BuiltIn","Regulatory Compliance","Implement controls to secure all media","CMA_0314 - Implement controls to secure all media","NIST_SP_800-53_R5_AC-20(2), -NIST_SP_800-53_R5_CP-9, -NIST_SP_800-53_R5_MA-2, -NIST_SP_800-53_R5_MA-3(3), -NIST_SP_800-53_R5_MA-5(1), -NIST_SP_800-53_R5_MP-2, -NIST_SP_800-53_R5_MP-3, -NIST_SP_800-53_R5_MP-4, -NIST_SP_800-53_R5_MP-5, -NIST_SP_800-53_R5_MP-6, -NIST_SP_800-53_R5_MP-6(1), -NIST_SP_800-53_R5_MP-6(2), -NIST_SP_800-53_R5_MP-7, -NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"cd36eeec-67e7-205a-4b64-dbfe3b4e3e4e","","BuiltIn","Regulatory Compliance","Implement controls to secure alternate work sites","CMA_0315 - Implement controls to secure alternate work sites","NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(4), -NIST_SP_800-53_R5_PE-17","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"10c3a1b1-29b0-a2d5-8f4c-a284b0f07830","","BuiltIn","Regulatory Compliance","Implement cryptographic mechanisms","CMA_C1419 - Implement cryptographic mechanisms","NIST_SP_800-53_R5_MA-4(6)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"5decc032-95bd-2163-9549-a41aba83228e","","BuiltIn","Regulatory Compliance","Implement formal sanctions process","CMA_0317 - Implement formal sanctions process","NIST_SP_800-53_R5_PS-8","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"433de59e-7a53-a766-02c2-f80f8421469a","","BuiltIn","Regulatory Compliance","Implement incident handling","CMA_0318 - Implement incident handling","NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-4(1), -NIST_SP_800-53_R5_IR-4(4), -NIST_SP_800-53_R5_IR-7(1), -NIST_SP_800-53_R5_IR-8","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"98e33927-8d7f-6d5f-44f5-2469b40b7215","","BuiltIn","Regulatory Compliance","Implement Incident handling capability","CMA_C1367 - Implement Incident handling capability","NIST_SP_800-53_R5_IR-4(6)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b262e1dd-08e9-41d4-963a-258909ad794b","","BuiltIn","Regulatory Compliance","Implement managed interface for each external service","CMA_C1626 - Implement managed interface for each external service","NIST_SP_800-53_R5_SC-7(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3b30aa25-0f19-6c04-5ca4-bd3f880a763d","","BuiltIn","Regulatory Compliance","Implement parameters for memorized secret verifiers","CMA_0321 - Implement parameters for memorized secret verifiers","NIST_SP_800-53_R5_IA-5(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e0c480bf-0d68-a42d-4cbb-b60f851f8716","","BuiltIn","Regulatory Compliance","Implement personnel screening","CMA_0322 - Implement personnel screening","NIST_SP_800-53_R5_PS-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"05ec66a2-137c-14b8-8e75-3d7a2bef07f8","","BuiltIn","Regulatory Compliance","Implement physical security for offices, working areas, and secure areas","CMA_0323 - Implement physical security for offices, working areas, and secure areas","NIST_SP_800-53_R5_PE-3, -NIST_SP_800-53_R5_PE-4, -NIST_SP_800-53_R5_PE-5, -NIST_SP_800-53_R5_PE-8, -NIST_SP_800-53_R5_PE-13, -NIST_SP_800-53_R5_PE-13(1), -NIST_SP_800-53_R5_PE-13(2), -NIST_SP_800-53_R5_PE-14, -NIST_SP_800-53_R5_PE-14(2), -NIST_SP_800-53_R5_PE-15, -NIST_SP_800-53_R5_PE-18","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"5b802722-71dd-a13d-2e7e-231e09589efb","","BuiltIn","Regulatory Compliance","Implement privileged access for executing vulnerability scanning activities","CMA_C1555 - Implement privileged access for executing vulnerability scanning activities","NIST_SP_800-53_R5_RA-5(5)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"26d178a4-9261-6f04-a100-47ed85314c6e","","BuiltIn","Regulatory Compliance","Implement security directives","CMA_C1706 - Implement security directives","NIST_SP_800-53_R5_SI-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"df2e9507-169b-4114-3a52-877561ee3198","","BuiltIn","Regulatory Compliance","Implement security engineering principles of information systems","CMA_0325 - Implement security engineering principles of information systems","NIST_SP_800-53_R5_PL-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"01ae60e2-38bb-0a32-7b20-d3a091423409","","BuiltIn","Regulatory Compliance","Implement system boundary protection","CMA_0328 - Implement system boundary protection","NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(4), -NIST_SP_800-53_R5_SC-7(12), -NIST_SP_800-53_R5_SC-7(18), -NIST_SP_800-53_R5_SI-4(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e4b00788-7e1c-33ec-0418-d048508e095b","","BuiltIn","Regulatory Compliance","Implement training for protecting authenticators","CMA_0329 - Implement training for protecting authenticators","NIST_SP_800-53_R5_IA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ba02d0a0-566a-25dc-73f1-101c726a19c5","","BuiltIn","Regulatory Compliance","Implement transaction based recovery","CMA_C1296 - Implement transaction based recovery","NIST_SP_800-53_R5_CP-10(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1e0d5ba8-a433-01aa-829c-86b06c9631ec","","BuiltIn","Regulatory Compliance","Include dynamic reconfig of customer deployed resources","CMA_C1364 - Include dynamic reconfig of customer deployed resources","NIST_SP_800-53_R5_IR-4(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"34aac8b2-488a-2b96-7280-5b9b481a317a","","BuiltIn","Regulatory Compliance","Incorporate flaw remediation into configuration management","CMA_C1671 - Incorporate flaw remediation into configuration management","NIST_SP_800-53_R5_SI-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"9c954fcf-6dd8-81f1-41b5-832ae5c62caf","","BuiltIn","Regulatory Compliance","Incorporate simulated contingency training","CMA_C1260 - Incorporate simulated contingency training","NIST_SP_800-53_R5_CP-3(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1fdeb7c4-4c93-8271-a135-17ebe85f1cc7","","BuiltIn","Regulatory Compliance","Incorporate simulated events into incident response training","CMA_C1356 - Incorporate simulated events into incident response training","NIST_SP_800-53_R5_IR-2(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"13ef3484-3a51-785a-9c96-500f21f84edd","","BuiltIn","Regulatory Compliance","Information flow control using security policy filters","CMA_C1029 - Information flow control using security policy filters","NIST_SP_800-53_R5_AC-4(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8bfdbaa6-6824-3fec-9b06-7961bf7389a6","","BuiltIn","Regulatory Compliance","Initiate contingency plan testing corrective actions","CMA_C1263 - Initiate contingency plan testing corrective actions","NIST_SP_800-53_R5_CP-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b8a9bb2f-7290-3259-85ce-dca7d521302d","","BuiltIn","Regulatory Compliance","Initiate transfer or reassignment actions","CMA_0333 - Initiate transfer or reassignment actions","NIST_SP_800-53_R5_PS-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"aa0ddd99-43eb-302d-3f8f-42b499182960","","BuiltIn","Regulatory Compliance","Install an alarm system","CMA_0338 - Install an alarm system","NIST_SP_800-53_R5_PE-6(1), -NIST_SP_800-53_R5_PE-14(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"85335602-93f5-7730-830b-d43426fd51fa","","BuiltIn","Regulatory Compliance","Integrate Audit record analysis","CMA_C1120 - Integrate Audit record analysis","NIST_SP_800-53_R5_AU-6(5)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f741c4e6-41eb-15a4-25a2-61ac7ca232f0","","BuiltIn","Regulatory Compliance","Integrate audit review, analysis, and reporting","CMA_0339 - Integrate audit review, analysis, and reporting","NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(1), -NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"9fdde4a9-85fa-7850-6df4-ae9c4a2e56f9","","BuiltIn","Regulatory Compliance","Integrate cloud app security with a siem","CMA_0340 - Integrate cloud app security with a siem","NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(1), -NIST_SP_800-53_R5_AU-6(3), -NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"00f12b6f-10d7-8117-9577-0f2b76488385","","BuiltIn","Regulatory Compliance","Integrate risk management process into SDLC","CMA_C1567 - Integrate risk management process into SDLC","NIST_SP_800-53_R5_SA-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"396f465d-375e-57de-58ba-021adb008191","","BuiltIn","Regulatory Compliance","Invalidate session identifiers at logout","CMA_C1661 - Invalidate session identifiers at logout","NIST_SP_800-53_R5_SC-23(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"22457e81-3ec6-5271-a786-c3ca284601dd","","BuiltIn","Regulatory Compliance","Isolate information spills","CMA_0346 - Isolate information spills","NIST_SP_800-53_R5_IR-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"dd6d00a8-701a-5935-a22b-c7b9c0c698b2","","BuiltIn","Regulatory Compliance","Isolate SecurID systems, Security Incident Management systems","CMA_C1636 - Isolate SecurID systems, Security Incident Management systems","NIST_SP_800-53_R5_SC-7(13)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"97d91b33-7050-237b-3e23-a77d57d84e13","","BuiltIn","Regulatory Compliance","Issue public key certificates","CMA_0347 - Issue public key certificates","NIST_SP_800-53_R5_SC-12, -NIST_SP_800-53_R5_SC-17","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2af551d5-1775-326a-0589-590bfb7e9eb2","","BuiltIn","Regulatory Compliance","Limit privileges to make changes in production environment","CMA_C1206 - Limit privileges to make changes in production environment","NIST_SP_800-53_R5_CM-5(5)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3ad7f0bc-3d03-0585-4d24-529779bb02c2","","BuiltIn","Regulatory Compliance","Maintain availability of information","CMA_C1644 - Maintain availability of information","NIST_SP_800-53_R5_SC-12(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"0fd1ca29-677b-2f12-1879-639716459160","","BuiltIn","Regulatory Compliance","Maintain data breach records","CMA_0351 - Maintain data breach records","NIST_SP_800-53_R5_IR-8","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"37546841-8ea1-5be0-214d-8ac599588332","","BuiltIn","Regulatory Compliance","Maintain incident response plan","CMA_0352 - Maintain incident response plan","NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-8","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c0559109-6a27-a217-6821-5a6d44f92897","","BuiltIn","Regulatory Compliance","Maintain integrity of audit system","CMA_C1133 - Maintain integrity of audit system","NIST_SP_800-53_R5_AU-9(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"4ce91e4e-6dab-3c46-011a-aa14ae1561bf","","BuiltIn","Regulatory Compliance","Maintain list of authorized remote maintenance personnel","CMA_C1420 - Maintain list of authorized remote maintenance personnel","NIST_SP_800-53_R5_MA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"92ede480-154e-0e22-4dca-8b46a74a3a51","","BuiltIn","Regulatory Compliance","Maintain records of processing of personal data","CMA_0353 - Maintain records of processing of personal data","NIST_SP_800-53_R5_CM-8, -NIST_SP_800-53_R5_CM-8(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"bfc540fe-376c-2eef-4355-121312fa4437","","BuiltIn","Regulatory Compliance","Maintain separate execution domains for running processes","CMA_C1665 - Maintain separate execution domains for running processes","NIST_SP_800-53_R5_SC-39","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f2222056-062d-1060-6dc2-0107a68c34b2","","BuiltIn","Regulatory Compliance","Manage a secure surveillance camera system","CMA_0354 - Manage a secure surveillance camera system","NIST_SP_800-53_R5_PE-6(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"29363ae1-68cd-01ca-799d-92c9197c8404","","BuiltIn","Regulatory Compliance","Manage authenticator lifetime and reuse","CMA_0355 - Manage authenticator lifetime and reuse","NIST_SP_800-53_R5_IA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"4aacaec9-0628-272c-3e83-0d68446694e0","","BuiltIn","Regulatory Compliance","Manage Authenticators","CMA_C1321 - Manage Authenticators","NIST_SP_800-53_R5_IA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"edcc36f1-511b-81e0-7125-abee29752fe7","","BuiltIn","Regulatory Compliance","Manage availability and capacity","CMA_0356 - Manage availability and capacity","NIST_SP_800-53_R5_SC-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"63f63e71-6c3f-9add-4c43-64de23e554a7","","BuiltIn","Regulatory Compliance","Manage gateways","CMA_0363 - Manage gateways","NIST_SP_800-53_R5_SI-3, -NIST_SP_800-53_R5_SI-4(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b273f1e3-79e7-13ee-5b5d-dca6c66c3d5d","","BuiltIn","Regulatory Compliance","Manage maintenance personnel","CMA_C1421 - Manage maintenance personnel","NIST_SP_800-53_R5_MA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1fb1cb0e-1936-6f32-42fd-89970b535855","","BuiltIn","Regulatory Compliance","Manage nonlocal maintenance and diagnostic activities","CMA_0364 - Manage nonlocal maintenance and diagnostic activities","NIST_SP_800-53_R5_MA-2, -NIST_SP_800-53_R5_MA-3, -NIST_SP_800-53_R5_MA-3(1), -NIST_SP_800-53_R5_MA-3(2), -NIST_SP_800-53_R5_MA-3(3), -NIST_SP_800-53_R5_MA-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"9c276cf3-596f-581a-7fbd-f5e46edaa0f4","","BuiltIn","Regulatory Compliance","Manage symmetric cryptographic keys","CMA_0367 - Manage symmetric cryptographic keys","NIST_SP_800-53_R5_SC-12","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"34d38ea7-6754-1838-7031-d7fd07099821","","BuiltIn","Regulatory Compliance","Manage system and admin accounts","CMA_0368 - Manage system and admin accounts","NIST_SP_800-53_R5_AC-2(1), -NIST_SP_800-53_R5_AC-2(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e603da3a-8af7-4f8a-94cb-1bcc0e0333d2","","BuiltIn","Regulatory Compliance","Manage the input, output, processing, and storage of data","CMA_0369 - Manage the input, output, processing, and storage of data","NIST_SP_800-53_R5_PE-5, -NIST_SP_800-53_R5_SI-12","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"4ac81669-00e2-9790-8648-71bc11bc91eb","","BuiltIn","Regulatory Compliance","Manage the transportation of assets","CMA_0370 - Manage the transportation of assets","NIST_SP_800-53_R5_MP-5, -NIST_SP_800-53_R5_PE-16","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"df54d34f-65f3-39f1-103c-a0464b8615df","","BuiltIn","Regulatory Compliance","Manage transfers between standby and active system components","CMA_0371 - Manage transfers between standby and active system components","NIST_SP_800-53_R5_SC-7(18)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"4012c2b7-4e0e-a7ab-1688-4aab43f14420","","BuiltIn","Regulatory Compliance","Map authenticated identities to individuals","CMA_0372 - Map authenticated identities to individuals","NIST_SP_800-53_R5_IA-5(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"dad1887d-161b-7b61-2e4d-5124a7b5724e","","BuiltIn","Regulatory Compliance","Measure the time between flaw identification and flaw remediation","CMA_C1674 - Measure the time between flaw identification and flaw remediation","NIST_SP_800-53_R5_SI-2(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"979ed3b6-83f9-26bc-4b86-5b05464700bf","","BuiltIn","Regulatory Compliance","Modify access authorizations upon personnel transfer","CMA_0374 - Modify access authorizations upon personnel transfer","NIST_SP_800-53_R5_PS-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"48c816c5-2190-61fc-8806-25d6f3df162f","","BuiltIn","Regulatory Compliance","Monitor access across the organization","CMA_0376 - Monitor access across the organization","NIST_SP_800-53_R5_AC-2(1), -NIST_SP_800-53_R5_AC-2(4), -NIST_SP_800-53_R5_AC-17(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"7b28ba4f-0a87-46ac-62e1-46b7c09202a8","","BuiltIn","Regulatory Compliance","Monitor account activity","CMA_0377 - Monitor account activity","NIST_SP_800-53_R5_AC-2, -NIST_SP_800-53_R5_AC-2(7), -NIST_SP_800-53_R5_AC-2(12)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ed87d27a-9abf-7c71-714c-61d881889da4","","BuiltIn","Regulatory Compliance","Monitor privileged role assignment","CMA_0378 - Monitor privileged role assignment","NIST_SP_800-53_R5_AC-2(7), -NIST_SP_800-53_R5_AC-6(9)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"82bd024a-5c99-05d6-96ff-01f539676a1a","","BuiltIn","Regulatory Compliance","Monitor security and privacy training completion","CMA_0379 - Monitor security and privacy training completion","NIST_SP_800-53_R5_AT-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f8ded0c6-a668-9371-6bb6-661d58787198","","BuiltIn","Regulatory Compliance","Monitor third-party provider compliance","CMA_C1533 - Monitor third-party provider compliance","NIST_SP_800-53_R5_PS-7","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"41172402-8d73-64c7-0921-909083c086b0","","BuiltIn","Regulatory Compliance","Not allow for information systems to accompany with individuals","CMA_C1182 - Not allow for information systems to accompany with individuals","NIST_SP_800-53_R5_CM-2(7)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"4b8fd5da-609b-33bf-9724-1c946285a14c","","BuiltIn","Regulatory Compliance","Notify Account Managers of customer controlled accounts","CMA_C1009 - Notify Account Managers of customer controlled accounts","NIST_SP_800-53_R5_AC-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"18e9d748-73d4-0c96-55ab-b108bfbd5bc3","","BuiltIn","Regulatory Compliance","Notify personnel of any failed security verification tests","CMA_C1710 - Notify personnel of any failed security verification tests","NIST_SP_800-53_R5_SI-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"6228396e-2ace-7ca5-3247-45767dbf52f4","","BuiltIn","Regulatory Compliance","Notify personnel upon sanctions","CMA_0380 - Notify personnel upon sanctions","NIST_SP_800-53_R5_PS-8","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c79d378a-2521-822a-0407-57454f8d2c74","","BuiltIn","Regulatory Compliance","Notify upon termination or transfer","CMA_0381 - Notify upon termination or transfer","NIST_SP_800-53_R5_PS-4, -NIST_SP_800-53_R5_PS-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"fe2dff43-0a8c-95df-0432-cb1c794b17d0","","BuiltIn","Regulatory Compliance","Notify users of system logon or access","CMA_0382 - Notify users of system logon or access","NIST_SP_800-53_R5_AC-17(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8489ff90-8d29-61df-2d84-f9ab0f4c5e84","","BuiltIn","Regulatory Compliance","Notify when account is not needed","CMA_0383 - Notify when account is not needed","NIST_SP_800-53_R5_AC-2(1), -NIST_SP_800-53_R5_AC-2(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1ff03f2a-974b-3272-34f2-f6cd51420b30","","BuiltIn","Regulatory Compliance","Obscure feedback information during authentication process","CMA_C1344 - Obscure feedback information during authentication process","NIST_SP_800-53_R5_IA-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ff136354-1c92-76dc-2dab-80fb7c6a9f1a","","BuiltIn","Regulatory Compliance","Observe and report security weaknesses","CMA_0384 - Observe and report security weaknesses","NIST_SP_800-53_R5_RA-5(6)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3f1216b0-30ee-1ac9-3899-63eb744e85f5","","BuiltIn","Regulatory Compliance","Obtain Admin documentation","CMA_C1580 - Obtain Admin documentation","NIST_SP_800-53_R5_SA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"92b94485-1c49-3350-9ada-dffe94f08e87","","BuiltIn","Regulatory Compliance","Obtain approvals for acquisitions and outsourcing","CMA_C1590 - Obtain approvals for acquisitions and outsourcing","NIST_SP_800-53_R5_SA-9(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ca6d7878-3189-1833-4620-6c7254ed1607","","BuiltIn","Regulatory Compliance","Obtain continuous monitoring plan for security controls","CMA_C1577 - Obtain continuous monitoring plan for security controls","NIST_SP_800-53_R5_SA-4(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"22a02c9a-49e4-5dc9-0d14-eb35ad717154","","BuiltIn","Regulatory Compliance","Obtain design and implementation information for the security controls","CMA_C1576 - Obtain design and implementation information for the security controls","NIST_SP_800-53_R5_SA-4(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"44b71aa8-099d-8b97-1557-0e853ec38e0d","","BuiltIn","Regulatory Compliance","Obtain functional properties of security controls","CMA_C1575 - Obtain functional properties of security controls","NIST_SP_800-53_R5_SA-4(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d9af7f88-686a-5a8b-704b-eafdab278977","","BuiltIn","Regulatory Compliance","Obtain legal opinion for monitoring system activities","CMA_C1688 - Obtain legal opinion for monitoring system activities","NIST_SP_800-53_R5_SI-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"be1c34ab-295a-07a6-785c-36f63c1d223e","","BuiltIn","Regulatory Compliance","Obtain user security function documentation","CMA_C1581 - Obtain user security function documentation","NIST_SP_800-53_R5_SA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"cb8841d4-9d13-7292-1d06-ba4d68384681","","BuiltIn","Regulatory Compliance","Perform a business impact assessment and application criticality assessment","CMA_0386 - Perform a business impact assessment and application criticality assessment","NIST_SP_800-53_R5_CP-2(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d18af1ac-0086-4762-6dc8-87cdded90e39","","BuiltIn","Regulatory Compliance","Perform a privacy impact assessment","CMA_0387 - Perform a privacy impact assessment","NIST_SP_800-53_R5_CM-3, -NIST_SP_800-53_R5_CM-4, -NIST_SP_800-53_R5_CM-4(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8c5d3d8d-5cba-0def-257c-5ab9ea9644dc","","BuiltIn","Regulatory Compliance","Perform a risk assessment","CMA_0388 - Perform a risk assessment","NIST_SP_800-53_R5_CM-3, -NIST_SP_800-53_R5_CM-4, -NIST_SP_800-53_R5_RA-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"50e81644-923d-33fc-6ebb-9733bc8d1a06","","BuiltIn","Regulatory Compliance","Perform a trend analysis on threats","CMA_0389 - Perform a trend analysis on threats","NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-7(1), -NIST_SP_800-53_R5_RA-5(6), -NIST_SP_800-53_R5_SI-3, -NIST_SP_800-53_R5_SI-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"5bac5fb7-7735-357b-767d-02264bfe5c3b","","BuiltIn","Regulatory Compliance","Perform all non-local maintenance","CMA_C1417 - Perform all non-local maintenance","NIST_SP_800-53_R5_MA-4(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1282809c-9001-176b-4a81-260a085f4872","","BuiltIn","Regulatory Compliance","Perform audit for configuration change control","CMA_0390 - Perform audit for configuration change control","NIST_SP_800-53_R5_CM-3, -NIST_SP_800-53_R5_CM-3(2), -NIST_SP_800-53_R5_CM-4, -NIST_SP_800-53_R5_CM-4(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8b1f29eb-1b22-4217-5337-9207cb55231e","","BuiltIn","Regulatory Compliance","Perform information input validation","CMA_C1723 - Perform information input validation","NIST_SP_800-53_R5_SI-10","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f30edfad-4e1d-1eef-27ee-9292d6d89842","","BuiltIn","Regulatory Compliance","Perform security function verification at a defined frequency","CMA_C1709 - Perform security function verification at a defined frequency","NIST_SP_800-53_R5_SI-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"bf883b14-9c19-0f37-8825-5e39a8b66d5b","","BuiltIn","Regulatory Compliance","Perform threat modeling","CMA_0392 - Perform threat modeling","NIST_SP_800-53_R5_RA-5(6)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3c5e0e1a-216f-8f49-0a15-76ed0d8b8e1f","","BuiltIn","Regulatory Compliance","Perform vulnerability scans","CMA_0393 - Perform vulnerability scans","NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_RA-5(2), -NIST_SP_800-53_R5_RA-5(3), -NIST_SP_800-53_R5_RA-5(6), -NIST_SP_800-53_R5_SA-10, -NIST_SP_800-53_R5_SA-11, -NIST_SP_800-53_R5_SI-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d9edcea6-6cb8-0266-a48c-2061fbac4310","","BuiltIn","Regulatory Compliance","Plan for continuance of essential business functions","CMA_C1255 - Plan for continuance of essential business functions","NIST_SP_800-53_R5_CP-2(5)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"7ded6497-815d-6506-242b-e043e0273928","","BuiltIn","Regulatory Compliance","Plan for resumption of essential business functions","CMA_C1253 - Plan for resumption of essential business functions","NIST_SP_800-53_R5_CP-2(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"0f31d98d-5ce2-705b-4aa5-b4f6705110dd","","BuiltIn","Regulatory Compliance","Prepare alternate processing site for use as operational site","CMA_C1278 - Prepare alternate processing site for use as operational site","NIST_SP_800-53_R5_CP-7(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"4781e5fd-76b8-7d34-6df3-a0a7fca47665","","BuiltIn","Regulatory Compliance","Prevent identifier reuse for the defined time period","CMA_C1314 - Prevent identifier reuse for the defined time period","NIST_SP_800-53_R5_IA-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"66e5cb69-9f1c-8b8d-8fbd-b832466d5aa8","","BuiltIn","Regulatory Compliance","Prevent split tunneling for remote devices","CMA_C1632 - Prevent split tunneling for remote devices","NIST_SP_800-53_R5_SC-7(7)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"74041cfe-3f87-1d17-79ec-34ca5f895542","","BuiltIn","Regulatory Compliance","Produce complete records of remote maintenance activities","CMA_C1403 - Produce complete records of remote maintenance activities","NIST_SP_800-53_R5_MA-2(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"70a7a065-a060-85f8-7863-eb7850ed2af9","","BuiltIn","Regulatory Compliance","Produce Security Assessment report","CMA_C1146 - Produce Security Assessment report","NIST_SP_800-53_R5_CA-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"de077e7e-0cc8-65a6-6e08-9ab46c827b05","","BuiltIn","Regulatory Compliance","Produce, control and distribute asymmetric cryptographic keys","CMA_C1646 - Produce, control and distribute asymmetric cryptographic keys","NIST_SP_800-53_R5_SC-12(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"16c54e01-9e65-7524-7c33-beda48a75779","","BuiltIn","Regulatory Compliance","Produce, control and distribute symmetric cryptographic keys","CMA_C1645 - Produce, control and distribute symmetric cryptographic keys","NIST_SP_800-53_R5_SC-12(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"678ca228-042d-6d8e-a598-c58d5670437d","","BuiltIn","Regulatory Compliance","Prohibit remote activation of collaborative computing devices","CMA_C1648 - Prohibit remote activation of collaborative computing devices","NIST_SP_800-53_R5_SC-15","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"5fe84a4c-1b0c-a738-2aba-ed49c9069d3b","","BuiltIn","Regulatory Compliance","Prohibit unfair practices","CMA_0396 - Prohibit unfair practices","NIST_SP_800-53_R5_PL-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"09960521-759e-5d12-086f-4192a72a5e92","","BuiltIn","Regulatory Compliance","Protect administrator and user documentation","CMA_C1583 - Protect administrator and user documentation","NIST_SP_800-53_R5_SA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"80a97208-264e-79da-0cc7-4fca179a0c9c","","BuiltIn","Regulatory Compliance","Protect against and prevent data theft from departing employees","CMA_0398 - Protect against and prevent data theft from departing employees","NIST_SP_800-53_R5_PS-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"0e696f5a-451f-5c15-5532-044136538491","","BuiltIn","Regulatory Compliance","Protect audit information","CMA_0401 - Protect audit information","NIST_SP_800-53_R5_AU-9, -NIST_SP_800-53_R5_AU-9(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b11697e8-9515-16f1-7a35-477d5c8a1344","","BuiltIn","Regulatory Compliance","Protect data in transit using encryption","CMA_0403 - Protect data in transit using encryption","NIST_SP_800-53_R5_AC-17(2), -NIST_SP_800-53_R5_AC-19(5), -NIST_SP_800-53_R5_SC-8, -NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2401b496-7f23-79b2-9f80-89bb5abf3d4a","","BuiltIn","Regulatory Compliance","Protect incident response plan","CMA_0405 - Protect incident response plan","NIST_SP_800-53_R5_IR-8","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b2d3e5a2-97ab-5497-565a-71172a729d93","","BuiltIn","Regulatory Compliance","Protect passwords with encryption","CMA_0408 - Protect passwords with encryption","NIST_SP_800-53_R5_IA-5(1), -NIST_SP_800-53_R5_SC-8","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"a315c657-4a00-8eba-15ac-44692ad24423","","BuiltIn","Regulatory Compliance","Protect special information","CMA_0409 - Protect special information","NIST_SP_800-53_R5_PS-3(3), -NIST_SP_800-53_R5_SC-28","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d42a8f69-a193-6cbc-48b9-04a9e29961f1","","BuiltIn","Regulatory Compliance","Protect wireless access","CMA_0411 - Protect wireless access","NIST_SP_800-53_R5_AC-18, -NIST_SP_800-53_R5_AC-18(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"44f8a42d-739f-8030-89a8-4c2d5b3f6af3","","BuiltIn","Regulatory Compliance","Provide audit review, analysis, and reporting capability","CMA_C1124 - Provide audit review, analysis, and reporting capability","NIST_SP_800-53_R5_AU-7","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"4edaca8c-0912-1ac5-9eaa-6a1057740fae","","BuiltIn","Regulatory Compliance","Provide capability to disconnect or disable remote access","CMA_C1066 - Provide capability to disconnect or disable remote access","NIST_SP_800-53_R5_AC-17(9)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"21633c09-804e-7fcd-78e3-635c6bfe2be7","","BuiltIn","Regulatory Compliance","Provide capability to process customer-controlled audit records","CMA_C1126 - Provide capability to process customer-controlled audit records","NIST_SP_800-53_R5_AU-7(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"de936662-13dc-204c-75ec-1af80f994088","","BuiltIn","Regulatory Compliance","Provide contingency training","CMA_0412 - Provide contingency training","NIST_SP_800-53_R5_CP-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2d4d0e90-32d9-4deb-2166-a00d51ed57c0","","BuiltIn","Regulatory Compliance","Provide information spillage training","CMA_0413 - Provide information spillage training","NIST_SP_800-53_R5_IR-2, -NIST_SP_800-53_R5_IR-9(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"7fc1f0da-0050-19bb-3d75-81ae15940df6","","BuiltIn","Regulatory Compliance","Provide monitoring information as needed","CMA_C1689 - Provide monitoring information as needed","NIST_SP_800-53_R5_SI-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"9ac8621d-9acd-55bf-9f99-ee4212cc3d85","","BuiltIn","Regulatory Compliance","Provide periodic role-based security training","CMA_C1095 - Provide periodic role-based security training","NIST_SP_800-53_R5_AT-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"516be556-1353-080d-2c2f-f46f000d5785","","BuiltIn","Regulatory Compliance","Provide periodic security awareness training","CMA_C1091 - Provide periodic security awareness training","NIST_SP_800-53_R5_AT-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"518eafdd-08e5-37a9-795b-15a8d798056d","","BuiltIn","Regulatory Compliance","Provide privacy training","CMA_0415 - Provide privacy training","NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"0f4fa857-079d-9d3d-5c49-21f616189e03","","BuiltIn","Regulatory Compliance","Provide real-time alerts for audit event failures","CMA_C1114 - Provide real-time alerts for audit event failures","NIST_SP_800-53_R5_AU-5(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d041726f-00e0-41ca-368c-b1a122066482","","BuiltIn","Regulatory Compliance","Provide role-based practical exercises","CMA_C1096 - Provide role-based practical exercises","NIST_SP_800-53_R5_AT-3(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"4c385143-09fd-3a34-790c-a5fd9ec77ddc","","BuiltIn","Regulatory Compliance","Provide role-based security training","CMA_C1094 - Provide role-based security training","NIST_SP_800-53_R5_AT-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"bbb2e6d6-085f-5a35-a55d-e45daad38933","","BuiltIn","Regulatory Compliance","Provide secure name and address resolution services","CMA_0416 - Provide secure name and address resolution services","NIST_SP_800-53_R5_SC-20","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"9b8b05ec-3d21-215e-5d98-0f7cf0998202","","BuiltIn","Regulatory Compliance","Provide security awareness training for insider threats","CMA_0417 - Provide security awareness training for insider threats","NIST_SP_800-53_R5_AT-2(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2b05dca2-25ec-9335-495c-29155f785082","","BuiltIn","Regulatory Compliance","Provide security training before providing access","CMA_0418 - Provide security training before providing access","NIST_SP_800-53_R5_AT-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1cb7bf71-841c-4741-438a-67c65fdd7194","","BuiltIn","Regulatory Compliance","Provide security training for new users","CMA_0419 - Provide security training for new users","NIST_SP_800-53_R5_AT-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d200f199-69f4-95a6-90b0-37ff0cf1040c","","BuiltIn","Regulatory Compliance","Provide the capability to extend or limit auditing on customer-deployed resources","CMA_C1141 - Provide the capability to extend or limit auditing on customer-deployed resources","NIST_SP_800-53_R5_AU-12(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"db580551-0b3c-4ea1-8a4c-4cdb5feb340f","","BuiltIn","Regulatory Compliance","Provide the logout capability","CMA_C1055 - Provide the logout capability","NIST_SP_800-53_R5_AC-12(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"eb598832-4bcc-658d-4381-3ecbe17b9866","","BuiltIn","Regulatory Compliance","Provide timely maintenance support","CMA_C1425 - Provide timely maintenance support","NIST_SP_800-53_R5_MA-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d136ae80-54dd-321c-98b4-17acf4af2169","","BuiltIn","Regulatory Compliance","Provide updated security awareness training","CMA_C1090 - Provide updated security awareness training","NIST_SP_800-53_R5_AT-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"7805a343-275c-41be-9d62-7215b96212d8","","BuiltIn","Regulatory Compliance","Reassign or remove user privileges as needed","CMA_C1040 - Reassign or remove user privileges as needed","NIST_SP_800-53_R5_AC-6(7)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d6653f89-7cb5-24a4-9d71-51581038231b","","BuiltIn","Regulatory Compliance","Reauthenticate or terminate a user session","CMA_0421 - Reauthenticate or terminate a user session","NIST_SP_800-53_R5_SC-10","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f33c3238-11d2-508c-877c-4262ec1132e1","","BuiltIn","Regulatory Compliance","Recover and reconstitute resources after any disruption","CMA_C1295 - Recover and reconstitute resources after any disruption","NIST_SP_800-53_R5_CP-10","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e89436d8-6a93-3b62-4444-1d2a42ad56b2","","BuiltIn","Regulatory Compliance","Reevaluate access upon personnel transfer","CMA_0424 - Reevaluate access upon personnel transfer","NIST_SP_800-53_R5_PS-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3ae68d9a-5696-8c32-62d3-c6f9c52e437c","","BuiltIn","Regulatory Compliance","Refresh authenticators","CMA_0425 - Refresh authenticators","NIST_SP_800-53_R5_IA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2f204e72-1896-3bf8-75c9-9128b8683a36","","BuiltIn","Regulatory Compliance","Reissue authenticators for changed groups and accounts","CMA_0426 - Reissue authenticators for changed groups and accounts","NIST_SP_800-53_R5_AC-2, -NIST_SP_800-53_R5_IA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"be38a620-000b-21cf-3cb3-ea151b704c3b","","BuiltIn","Regulatory Compliance","Remediate information system flaws","CMA_0427 - Remediate information system flaws","NIST_SP_800-53_R5_CM-6, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_RA-5(2), -NIST_SP_800-53_R5_RA-5(3), -NIST_SP_800-53_R5_RA-5(6), -NIST_SP_800-53_R5_SA-10, -NIST_SP_800-53_R5_SA-11, -NIST_SP_800-53_R5_SI-2, -NIST_SP_800-53_R5_SI-2(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e4054c0e-1184-09e6-4c5e-701e0bc90f81","","BuiltIn","Regulatory Compliance","Report atypical behavior of user accounts","CMA_C1025 - Report atypical behavior of user accounts","NIST_SP_800-53_R5_AC-2(12)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"de770ba6-50dd-a316-2932-e0d972eaa734","","BuiltIn","Regulatory Compliance","Require approval for account creation","CMA_0431 - Require approval for account creation","NIST_SP_800-53_R5_AC-2, -NIST_SP_800-53_R5_AC-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"725164e5-3b21-1ec2-7e42-14f077862841","","BuiltIn","Regulatory Compliance","Require compliance with intellectual property rights","CMA_0432 - Require compliance with intellectual property rights","NIST_SP_800-53_R5_CM-10","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f6da5cca-5795-60ff-49e1-4972567815fe","","BuiltIn","Regulatory Compliance","Require developer to identify SDLC ports, protocols, and services","CMA_C1578 - Require developer to identify SDLC ports, protocols, and services","NIST_SP_800-53_R5_SA-4(9)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f131c8c5-a54a-4888-1efc-158928924bc1","","BuiltIn","Regulatory Compliance","Require developers to build security architecture","CMA_C1612 - Require developers to build security architecture","NIST_SP_800-53_R5_SA-17","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3e37c891-840c-3eb4-78d2-e2e0bb5063e0","","BuiltIn","Regulatory Compliance","Require developers to describe accurate security functionality","CMA_C1613 - Require developers to describe accurate security functionality","NIST_SP_800-53_R5_SA-17","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3a868d0c-538f-968b-0191-bddb44da5b75","","BuiltIn","Regulatory Compliance","Require developers to document approved changes and potential impact","CMA_C1597 - Require developers to document approved changes and potential impact","NIST_SP_800-53_R5_SA-10","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"085467a6-9679-5c65-584a-f55acefd0d43","","BuiltIn","Regulatory Compliance","Require developers to implement only approved changes","CMA_C1596 - Require developers to implement only approved changes","NIST_SP_800-53_R5_SA-10","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b33d61c1-7463-7025-0ec0-a47585b59147","","BuiltIn","Regulatory Compliance","Require developers to manage change integrity","CMA_C1595 - Require developers to manage change integrity","NIST_SP_800-53_R5_SA-10","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f8a63511-66f1-503f-196d-d6217ee0823a","","BuiltIn","Regulatory Compliance","Require developers to produce evidence of security assessment plan execution","CMA_C1602 - Require developers to produce evidence of security assessment plan execution","NIST_SP_800-53_R5_SA-11","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"676c3c35-3c36-612c-9523-36d266a65000","","BuiltIn","Regulatory Compliance","Require developers to provide training","CMA_C1611 - Require developers to provide training","NIST_SP_800-53_R5_SA-16","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"7a114735-a420-057d-a651-9a73cd0416ef","","BuiltIn","Regulatory Compliance","Require developers to provide unified security protection approach","CMA_C1614 - Require developers to provide unified security protection approach","NIST_SP_800-53_R5_SA-17","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"4e45863d-9ea9-32b4-a204-2680bc6007a6","","BuiltIn","Regulatory Compliance","Require external service providers to comply with security requirements","CMA_C1586 - Require external service providers to comply with security requirements","NIST_SP_800-53_R5_SA-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"096a7055-30cb-2db4-3fda-41b20ac72667","","BuiltIn","Regulatory Compliance","Require interconnection security agreements","CMA_C1151 - Require interconnection security agreements","NIST_SP_800-53_R5_CA-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"afd5d60a-48d2-8073-1ec2-6687e22f2ddd","","BuiltIn","Regulatory Compliance","Require notification of third-party personnel transfer or termination","CMA_C1532 - Require notification of third-party personnel transfer or termination","NIST_SP_800-53_R5_PS-7","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e8c31e15-642d-600f-78ab-bad47a5787e6","","BuiltIn","Regulatory Compliance","Require third-party providers to comply with personnel security policies and procedures","CMA_C1530 - Require third-party providers to comply with personnel security policies and procedures","NIST_SP_800-53_R5_PS-7","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"08ad71d0-52be-6503-4908-e015460a16ae","","BuiltIn","Regulatory Compliance","Require use of individual authenticators","CMA_C1305 - Require use of individual authenticators","NIST_SP_800-53_R5_IA-2(5)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3af53f59-979f-24a8-540f-d7cdbc366607","","BuiltIn","Regulatory Compliance","Require users to sign access agreement","CMA_0440 - Require users to sign access agreement","NIST_SP_800-53_R5_PS-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"c6aeb800-0b19-944d-92dc-59b893722329","","BuiltIn","Regulatory Compliance","Rescreen individuals at a defined frequency","CMA_C1512 - Rescreen individuals at a defined frequency","NIST_SP_800-53_R5_PS-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f801d58e-5659-9a4a-6e8d-02c9334732e5","","BuiltIn","Regulatory Compliance","Restore resources to operational state","CMA_C1297 - Restore resources to operational state","NIST_SP_800-53_R5_CP-10(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8d140e8b-76c7-77de-1d46-ed1b2e112444","","BuiltIn","Regulatory Compliance","Restrict access to private keys","CMA_0445 - Restrict access to private keys","NIST_SP_800-53_R5_IA-5(2), -NIST_SP_800-53_R5_SC-12","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"873895e8-0e3a-6492-42e9-22cd030e9fcd","","BuiltIn","Regulatory Compliance","Restrict access to privileged accounts","CMA_0446 - Restrict access to privileged accounts","NIST_SP_800-53_R5_AC-2, -NIST_SP_800-53_R5_AC-2(7), -NIST_SP_800-53_R5_AC-6(5), -NIST_SP_800-53_R5_AC-6(9)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"0040d2e5-2779-170d-6a2c-1f5fca353335","","BuiltIn","Regulatory Compliance","Restrict location of information processing, storage and services","CMA_C1593 - Restrict location of information processing, storage and services","NIST_SP_800-53_R5_SA-9(5)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"6122970b-8d4a-7811-0278-4c6c68f61e4f","","BuiltIn","Regulatory Compliance","Restrict media use","CMA_0450 - Restrict media use","NIST_SP_800-53_R5_MP-7","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"08c11b48-8745-034d-1c1b-a144feec73b9","","BuiltIn","Regulatory Compliance","Restrict use of open source software","CMA_C1237 - Restrict use of open source software","NIST_SP_800-53_R5_CM-10(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"5e4e9685-3818-5934-0071-2620c4fa2ca5","","BuiltIn","Regulatory Compliance","Retain previous versions of baseline configs","CMA_C1181 - Retain previous versions of baseline configs","NIST_SP_800-53_R5_CM-2(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"efef28d0-3226-966a-a1e8-70e89c1b30bc","","BuiltIn","Regulatory Compliance","Retain security policies and procedures","CMA_0454 - Retain security policies and procedures","NIST_SP_800-53_R5_AU-11","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"7c7032fe-9ce6-9092-5890-87a1a3755db1","","BuiltIn","Regulatory Compliance","Retain terminated user data","CMA_0455 - Retain terminated user data","NIST_SP_800-53_R5_AU-11, -NIST_SP_800-53_R5_PS-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3153d9c0-2584-14d3-362d-578b01358aeb","","BuiltIn","Regulatory Compliance","Retain training records","CMA_0456 - Retain training records","NIST_SP_800-53_R5_AT-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"20762f1e-85fb-31b0-a600-e833633f10fe","","BuiltIn","Regulatory Compliance","Reveal error messages","CMA_C1725 - Reveal error messages","NIST_SP_800-53_R5_SI-11","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"03d550b4-34ee-03f4-515f-f2e2faf7a413","","BuiltIn","Regulatory Compliance","Review access control policies and procedures","CMA_0457 - Review access control policies and procedures","NIST_SP_800-53_R5_AC-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"a830fe9e-08c9-a4fb-420c-6f6bf1702395","","BuiltIn","Regulatory Compliance","Review account provisioning logs","CMA_0460 - Review account provisioning logs","NIST_SP_800-53_R5_AC-2, -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(1), -NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f27a298f-9443-014a-0d40-fef12adf0259","","BuiltIn","Regulatory Compliance","Review administrator assignments weekly","CMA_0461 - Review administrator assignments weekly","NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(1), -NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"585af6e9-90c0-4575-67a7-2f9548972e32","","BuiltIn","Regulatory Compliance","Review and reevaluate privileges","CMA_C1207 - Review and reevaluate privileges","NIST_SP_800-53_R5_CM-5(5)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"6c0a312f-04c5-5c97-36a5-e56763a02b6b","","BuiltIn","Regulatory Compliance","Review and sign revised rules of behavior","CMA_0465 - Review and sign revised rules of behavior","NIST_SP_800-53_R5_PL-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"eb8a8df9-521f-3ccd-7e2c-3d1fcc812340","","BuiltIn","Regulatory Compliance","Review and update configuration management policies and procedures","CMA_C1175 - Review and update configuration management policies and procedures","NIST_SP_800-53_R5_CM-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e9c60c37-65b0-2d72-6c3c-af66036203ae","","BuiltIn","Regulatory Compliance","Review and update contingency planning policies and procedures","CMA_C1243 - Review and update contingency planning policies and procedures","NIST_SP_800-53_R5_CP-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"29acfac0-4bb4-121b-8283-8943198b1549","","BuiltIn","Regulatory Compliance","Review and update identification and authentication policies and procedures","CMA_C1299 - Review and update identification and authentication policies and procedures","NIST_SP_800-53_R5_IA-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b28c8687-4bbd-8614-0b96-cdffa1ac6d9c","","BuiltIn","Regulatory Compliance","Review and update incident response policies and procedures","CMA_C1352 - Review and update incident response policies and procedures","NIST_SP_800-53_R5_IR-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"6bededc0-2985-54d5-4158-eb8bad8070a0","","BuiltIn","Regulatory Compliance","Review and update information integrity policies and procedures","CMA_C1667 - Review and update information integrity policies and procedures","NIST_SP_800-53_R5_SI-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b4e19d22-8c0e-7cad-3219-c84c62dc250f","","BuiltIn","Regulatory Compliance","Review and update media protection policies and procedures","CMA_C1427 - Review and update media protection policies and procedures","NIST_SP_800-53_R5_MP-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e5c5fc78-4aa5-3d6b-81bc-5fcc88b318e9","","BuiltIn","Regulatory Compliance","Review and update personnel security policies and procedures","CMA_C1507 - Review and update personnel security policies and procedures","NIST_SP_800-53_R5_PS-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"91cf132e-0c9f-37a8-a523-dc6a92cd2fb2","","BuiltIn","Regulatory Compliance","Review and update physical and environmental policies and procedures","CMA_C1446 - Review and update physical and environmental policies and procedures","NIST_SP_800-53_R5_PE-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"28aa060e-25c7-6121-05d8-a846f11433df","","BuiltIn","Regulatory Compliance","Review and update planning policies and procedures","CMA_C1491 - Review and update planning policies and procedures","NIST_SP_800-53_R5_PL-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"20012034-96f0-85c2-4a86-1ae1eb457802","","BuiltIn","Regulatory Compliance","Review and update risk assessment policies and procedures","CMA_C1537 - Review and update risk assessment policies and procedures","NIST_SP_800-53_R5_RA-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"adf517f3-6dcd-3546-9928-34777d0c277e","","BuiltIn","Regulatory Compliance","Review and update system and communications protection policies and procedures","CMA_C1616 - Review and update system and communications protection policies and procedures","NIST_SP_800-53_R5_SC-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f49925aa-9b11-76ae-10e2-6e973cc60f37","","BuiltIn","Regulatory Compliance","Review and update system and services acquisition policies and procedures","CMA_C1560 - Review and update system and services acquisition policies and procedures","NIST_SP_800-53_R5_SA-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"2067b904-9552-3259-0cdd-84468e284b7c","","BuiltIn","Regulatory Compliance","Review and update system maintenance policies and procedures","CMA_C1395 - Review and update system maintenance policies and procedures","NIST_SP_800-53_R5_MA-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ced291b8-1d3d-7e27-40cf-829e9dd523c8","","BuiltIn","Regulatory Compliance","Review and update the information security architecture","CMA_C1504 - Review and update the information security architecture","NIST_SP_800-53_R5_PL-8","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"6625638f-3ba1-7404-5983-0ea33d719d34","","BuiltIn","Regulatory Compliance","Review audit data","CMA_0466 - Review audit data","NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(1), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8aec4343-9153-9641-172c-defb201f56b3","","BuiltIn","Regulatory Compliance","Review cloud identity report overview","CMA_0468 - Review cloud identity report overview","NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(1), -NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ffea18d9-13de-6505-37f3-4c1f88070ad7","","BuiltIn","Regulatory Compliance","Review cloud service provider's compliance with policies and agreements","CMA_0469 - Review cloud service provider's compliance with policies and agreements","NIST_SP_800-53_R5_SA-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"9e3c505e-7aeb-2096-3417-b132242731fc","","BuiltIn","Regulatory Compliance","Review content prior to posting publicly accessible information","CMA_C1085 - Review content prior to posting publicly accessible information","NIST_SP_800-53_R5_AC-22","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"53fc1282-0ee3-2764-1319-e20143bb0ea5","","BuiltIn","Regulatory Compliance","Review contingency plan","CMA_C1247 - Review contingency plan","NIST_SP_800-53_R5_CP-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f48b60c6-4b37-332f-7288-b6ea50d300eb","","BuiltIn","Regulatory Compliance","Review controlled folder access events","CMA_0471 - Review controlled folder access events","NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(1), -NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1e876c5c-0f2a-8eb6-69f7-5f91e7918ed6","","BuiltIn","Regulatory Compliance","Review development process, standards and tools","CMA_C1610 - Review development process, standards and tools","NIST_SP_800-53_R5_SA-15","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"a30bd8e9-7064-312a-0e1f-e1b485d59f6e","","BuiltIn","Regulatory Compliance","Review exploit protection events","CMA_0472 - Review exploit protection events","NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ef718fe4-7ceb-9ddf-3198-0ee8f6fe9cba","","BuiltIn","Regulatory Compliance","Review file and folder activity","CMA_0473 - Review file and folder activity","NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(1), -NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e23444b9-9662-40f3-289e-6d25c02b48fa","","BuiltIn","Regulatory Compliance","Review label activity and analytics","CMA_0474 - Review label activity and analytics","NIST_SP_800-53_R5_RA-2, -NIST_SP_800-53_R5_SI-12","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"4a6f5cbd-6c6b-006f-2bb1-091af1441bce","","BuiltIn","Regulatory Compliance","Review malware detections report weekly","CMA_0475 - Review malware detections report weekly","NIST_SP_800-53_R5_SI-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b5244f81-6cab-3188-2412-179162294996","","BuiltIn","Regulatory Compliance","Review publicly accessible content for nonpublic information","CMA_C1086 - Review publicly accessible content for nonpublic information","NIST_SP_800-53_R5_AC-22","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"70fe686f-1f91-7dab-11bf-bca4201e183b","","BuiltIn","Regulatory Compliance","Review role group changes weekly","CMA_0476 - Review role group changes weekly","NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(1), -NIST_SP_800-53_R5_RA-5(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"a4493012-908c-5f48-a468-1e243be884ce","","BuiltIn","Regulatory Compliance","Review security assessment and authorization policies and procedures","CMA_C1143 - Review security assessment and authorization policies and procedures","NIST_SP_800-53_R5_CA-1","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"5d3abfea-a130-1208-29c0-e57de80aa6b0","","BuiltIn","Regulatory Compliance","Review the results of contingency plan testing","CMA_C1262 - Review the results of contingency plan testing","NIST_SP_800-53_R5_CP-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"fad161f5-5261-401a-22dd-e037bae011bd","","BuiltIn","Regulatory Compliance","Review threat protection status weekly","CMA_0479 - Review threat protection status weekly","NIST_SP_800-53_R5_SI-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"79f081c7-1634-01a1-708e-376197999289","","BuiltIn","Regulatory Compliance","Review user accounts","CMA_0480 - Review user accounts","NIST_SP_800-53_R5_AC-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"eb1c944e-0e94-647b-9b7e-fdb8d2af0838","","BuiltIn","Regulatory Compliance","Review user groups and applications with access to sensitive data","CMA_0481 - Review user groups and applications with access to sensitive data","NIST_SP_800-53_R5_AC-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f96d2186-79df-262d-3f76-f371e3b71798","","BuiltIn","Regulatory Compliance","Review user privileges","CMA_C1039 - Review user privileges","NIST_SP_800-53_R5_AC-6(7)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"32f22cfa-770b-057c-965b-450898425519","","BuiltIn","Regulatory Compliance","Revoke privileged roles as appropriate","CMA_0483 - Revoke privileged roles as appropriate","NIST_SP_800-53_R5_AC-2(3), -NIST_SP_800-53_R5_AC-2(7), -NIST_SP_800-53_R5_AC-6(9)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d91558ce-5a5c-551b-8fbb-83f793255e09","","BuiltIn","Regulatory Compliance","Route traffic through authenticated proxy network","CMA_C1633 - Route traffic through authenticated proxy network","NIST_SP_800-53_R5_SC-7(8)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"bab9ef1d-a16d-421a-822d-3fa94e808156","","BuiltIn","Regulatory Compliance","Route traffic through managed network access points","CMA_0484 - Route traffic through managed network access points","NIST_SP_800-53_R5_AC-17(3), -NIST_SP_800-53_R5_SI-4(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"a8f9c283-9a66-3eb3-9e10-bdba95b85884","","BuiltIn","Regulatory Compliance","Run simulation attacks","CMA_0486 - Run simulation attacks","NIST_SP_800-53_R5_IR-3, -NIST_SP_800-53_R5_IR-3(2), -NIST_SP_800-53_R5_PE-13(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"70057208-70cc-7b31-3c3a-121af6bc1966","","BuiltIn","Regulatory Compliance","Secure commitment from leadership","CMA_0489 - Secure commitment from leadership","NIST_SP_800-53_R5_SA-2, -NIST_SP_800-53_R5_SC-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ff1efad2-6b09-54cc-01bf-d386c4d558a8","","BuiltIn","Regulatory Compliance","Secure the interface to external systems","CMA_0491 - Secure the interface to external systems","NIST_SP_800-53_R5_SC-7(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"f78fc35e-1268-0bca-a798-afcba9d2330a","","BuiltIn","Regulatory Compliance","Select additional testing for security control assessments","CMA_C1149 - Select additional testing for security control assessments","NIST_SP_800-53_R5_CA-2(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"60ee1260-97f0-61bb-8155-5d8b75743655","","BuiltIn","Regulatory Compliance","Separate duties of individuals","CMA_0492 - Separate duties of individuals","NIST_SP_800-53_R5_AC-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"8a703eb5-4e53-701b-67e4-05ba2f7930c8","","BuiltIn","Regulatory Compliance","Separate user and information system management functionality","CMA_0493 - Separate user and information system management functionality","NIST_SP_800-53_R5_SC-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"fc26e2fd-3149-74b4-5988-d64bb90f8ef7","","BuiltIn","Regulatory Compliance","Separately store backup information","CMA_C1293 - Separately store backup information","NIST_SP_800-53_R5_CP-9(3)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"af38215f-70c4-0cd6-40c2-c52d86690a45","","BuiltIn","Regulatory Compliance","Set automated notifications for new and trending cloud applications in your organization","CMA_0495 - Set automated notifications for new and trending cloud applications in your organization","NIST_SP_800-53_R5_CM-8(3), -NIST_SP_800-53_R5_SI-4(5)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"3eecf628-a1c8-1b48-1b5c-7ca781e97970","","BuiltIn","Regulatory Compliance","Specify permitted actions associated with customer audit information","CMA_C1122 - Specify permitted actions associated with customer audit information","NIST_SP_800-53_R5_AU-6(7)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1d39b5d9-0392-8954-8359-575ce1957d1a","","BuiltIn","Regulatory Compliance","Support personal verification credentials issued by legal authorities","CMA_0507 - Support personal verification credentials issued by legal authorities","NIST_SP_800-53_R5_IA-2, -NIST_SP_800-53_R5_IA-2(12)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d25cbded-121e-0ed6-1857-dc698c9095b1","","BuiltIn","Regulatory Compliance","Take action in response to customer information","CMA_C1554 - Take action in response to customer information","NIST_SP_800-53_R5_RA-5(4)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"4502e506-5f35-0df4-684f-b326e3cc7093","","BuiltIn","Regulatory Compliance","Terminate user session automatically","CMA_C1054 - Terminate user session automatically","NIST_SP_800-53_R5_AC-12","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ba99d512-3baa-1c38-8b0b-ae16bbd34274","","BuiltIn","Regulatory Compliance","Test contingency plan at an alternate processing location","CMA_C1265 - Test contingency plan at an alternate processing location","NIST_SP_800-53_R5_CP-4(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"58a51cde-008b-1a5d-61b5-d95849770677","","BuiltIn","Regulatory Compliance","Test the business continuity and disaster recovery plan","CMA_0509 - Test the business continuity and disaster recovery plan","NIST_SP_800-53_R5_CP-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"77cc89bb-774f-48d7-8a84-fb8c322c3000","","BuiltIn","Regulatory Compliance","Track software license usage","CMA_C1235 - Track software license usage","NIST_SP_800-53_R5_CM-10","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"97f0d974-1486-01e2-2088-b888f46c0589","","BuiltIn","Regulatory Compliance","Train personnel on disclosure of nonpublic information","CMA_C1084 - Train personnel on disclosure of nonpublic information","NIST_SP_800-53_R5_AC-22","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"7bdb79ea-16b8-453e-4ca4-ad5b16012414","","BuiltIn","Regulatory Compliance","Transfer backup information to an alternate storage site","CMA_C1294 - Transfer backup information to an alternate storage site","NIST_SP_800-53_R5_CP-9(5)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"5fc24b95-53f7-0ed1-2330-701b539b97fe","","BuiltIn","Regulatory Compliance","Turn on sensors for endpoint security solution","CMA_0514 - Turn on sensors for endpoint security solution","NIST_SP_800-53_R5_CA-7, -NIST_SP_800-53_R5_SI-4(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"9b55929b-0101-47c0-a16e-d6ac5c7d21f8","","BuiltIn","Regulatory Compliance","Undergo independent security review","CMA_0515 - Undergo independent security review","NIST_SP_800-53_R5_CA-7, -NIST_SP_800-53_R5_SA-9","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ea9d7c95-2f10-8a4d-61d8-7469bd2e8d65","","BuiltIn","Regulatory Compliance","Update antivirus definitions","CMA_0517 - Update antivirus definitions","NIST_SP_800-53_R5_SI-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"14a4fd0a-9100-1e12-1362-792014a28155","","BuiltIn","Regulatory Compliance","Update contingency plan","CMA_C1248 - Update contingency plan","NIST_SP_800-53_R5_CP-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"5226dee6-3420-711b-4709-8e675ebd828f","","BuiltIn","Regulatory Compliance","Update information security policies","CMA_0518 - Update information security policies","NIST_SP_800-53_R5_AT-1, -NIST_SP_800-53_R5_AU-1, -NIST_SP_800-53_R5_PL-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"d48a6f19-a284-6fc6-0623-3367a74d3f50","","BuiltIn","Regulatory Compliance","Update interconnection security agreements","CMA_0519 - Update interconnection security agreements","NIST_SP_800-53_R5_CA-3","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e21f91d1-2803-0282-5f2d-26ebc4b170ef","","BuiltIn","Regulatory Compliance","Update organizational access agreements","CMA_0520 - Update organizational access agreements","NIST_SP_800-53_R5_PS-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"cc057769-01d9-95ad-a36f-1e62a7f9540b","","BuiltIn","Regulatory Compliance","Update POA&M items","CMA_C1157 - Update POA&M items","NIST_SP_800-53_R5_CA-5","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"6610f662-37e9-2f71-65be-502bdc2f554d","","BuiltIn","Regulatory Compliance","Update rules of behavior and access agreements","CMA_0521 - Update rules of behavior and access agreements","NIST_SP_800-53_R5_PL-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"7ad83b58-2042-085d-08f0-13e946f26f89","","BuiltIn","Regulatory Compliance","Update rules of behavior and access agreements every 3 years","CMA_0522 - Update rules of behavior and access agreements every 3 years","NIST_SP_800-53_R5_PL-4","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"449ebb52-945b-36e5-3446-af6f33770f8f","","BuiltIn","Regulatory Compliance","Update the security authorization","CMA_C1160 - Update the security authorization","NIST_SP_800-53_R5_CA-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b8689b2e-4308-a58b-a0b4-6f3343a000df","","BuiltIn","Regulatory Compliance","Use automated mechanisms for security alerts","CMA_C1707 - Use automated mechanisms for security alerts","NIST_SP_800-53_R5_SI-5(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"b8972f60-8d77-1cb8-686f-9c9f4cdd8a59","","BuiltIn","Regulatory Compliance","Use dedicated machines for administrative tasks","CMA_0527 - Use dedicated machines for administrative tasks","NIST_SP_800-53_R5_SC-2","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"e714b481-8fac-64a2-14a9-6f079b2501a4","","BuiltIn","Regulatory Compliance","Use privileged identity management","CMA_0533 - Use privileged identity management","NIST_SP_800-53_R5_AC-2(7), -NIST_SP_800-53_R5_AC-6(9)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"1ee4c7eb-480a-0007-77ff-4ba370776266","","BuiltIn","Regulatory Compliance","Use system clocks for audit records","CMA_0535 - Use system clocks for audit records","NIST_SP_800-53_R5_AU-8","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"72889284-15d2-90b2-4b39-a1e9541e1152","","BuiltIn","Regulatory Compliance","Verify identity before distributing authenticators","CMA_0538 - Verify identity before distributing authenticators","NIST_SP_800-53_R5_IA-5, -NIST_SP_800-53_R5_IA-5(2)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"dc7ec756-221c-33c8-0afe-c48e10e42321","","BuiltIn","Regulatory Compliance","Verify security controls for external information systems","CMA_0541 - Verify security controls for external information systems","NIST_SP_800-53_R5_AC-20(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"ece8bb17-4080-5127-915f-dc7267ee8549","","BuiltIn","Regulatory Compliance","Verify security functions","CMA_C1708 - Verify security functions","NIST_SP_800-53_R5_SI-6","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"db28735f-518f-870e-15b4-49623cbe3aa0","","BuiltIn","Regulatory Compliance","Verify software, firmware and information integrity","CMA_0542 - Verify software, firmware and information integrity","NIST_SP_800-53_R5_SA-10(1), -NIST_SP_800-53_R5_SC-21, -NIST_SP_800-53_R5_SI-7, -NIST_SP_800-53_R5_SI-7(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"0123edae-3567-a05a-9b05-b53ebe9d3e7e","","BuiltIn","Regulatory Compliance","View and configure system diagnostic data","CMA_0544 - View and configure system diagnostic data","NIST_SP_800-53_R5_CM-6(1), -NIST_SP_800-53_R5_SI-7(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"98145a9b-428a-7e81-9d14-ebb154a24f93","","BuiltIn","Regulatory Compliance","View and investigate restricted users","CMA_0545 - View and investigate restricted users","NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-7(1)","NIST-800-53: Manual (Policy Default)","Manual, -Disabled","Manual","Manual","Manual","Manual","","","","" -"a049bf77-880b-470f-ba6d-9f21c530cf83","","BuiltIn","Search","Azure Cognitive Search service should use a SKU that supports private link","With supported SKUs of Azure Cognitive Search, Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Search service, data leakage risks are reduced. Learn more at: https://aka.ms/azure-cognitive-search/inbound-private-endpoints.","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"ee980b6d-0eca-4501-8d54-f6290fd512c3","","BuiltIn","Search","Azure Cognitive Search services should disable public network access","Disabling public network access improves security by ensuring that your Azure Cognitive Search service is not exposed on the public internet. Creating private endpoints can limit exposure of your Search service. Learn more at: https://aka.ms/azure-cognitive-search/inbound-private-endpoints.","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"0fda3595-9f2b-4592-8675-4231d6fa82fe","","BuiltIn","Search","Azure Cognitive Search services should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Cognitive Search, data leakage risks are reduced. Learn more about private links at: https://aka.ms/azure-cognitive-search/inbound-private-endpoints.","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" -"b4330a05-a843-4bc8-bf9a-cacce50c67f4","","BuiltIn","Search","Resource logs in Search services should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInSearchServiceRetentionDays"":""1""}","{""diagnosticsLogsInSearchServiceRetentionDays"":""1""}","{""diagnosticsLogsInSearchServiceRetentionDays"":""1""}","{""diagnosticsLogsInSearchServiceRetentionDays"":""1""}" -"672fe5a1-2fcd-42d7-b85d-902b6e28c6ff","","BuiltIn","Security Center","[Preview]: Guest Attestation extension should be installed on supported Linux virtual machines","Install Guest Attestation extension on supported Linux virtual machines to allow Azure Security Center to proactively attest and monitor the boot integrity. Once installed, boot integrity will be attested via Remote Attestation. This assessment applies to Trusted Launch and Confidential Linux virtual machines.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"a21f8c92-9e22-4f09-b759-50500d1d2dda","","BuiltIn","Security Center","[Preview]: Guest Attestation extension should be installed on supported Linux virtual machines scale sets","Install Guest Attestation extension on supported Linux virtual machines scale sets to allow Azure Security Center to proactively attest and monitor the boot integrity. Once installed, boot integrity will be attested via Remote Attestation. This assessment applies to Trusted Launch and Confidential Linux virtual machine scale sets.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"1cb4d9c2-f88f-4069-bee0-dba239a57b09","","BuiltIn","Security Center","[Preview]: Guest Attestation extension should be installed on supported Windows virtual machines","Install Guest Attestation extension on supported virtual machines to allow Azure Security Center to proactively attest and monitor the boot integrity. Once installed, boot integrity will be attested via Remote Attestation. This assessment applies to Trusted Launch and Confidential Windows virtual machines.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"f655e522-adff-494d-95c2-52d4f6d56a42","","BuiltIn","Security Center","[Preview]: Guest Attestation extension should be installed on supported Windows virtual machines scale sets","Install Guest Attestation extension on supported virtual machines scale sets to allow Azure Security Center to proactively attest and monitor the boot integrity. Once installed, boot integrity will be attested via Remote Attestation. This assessment applies to Trusted Launch and Confidential Windows virtual machine scale sets.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"13a6c84f-49a5-410a-b5df-5b880c3fe009","","BuiltIn","Security Center","[Preview]: Linux virtual machines should use only signed and trusted boot components","All OS boot components (boot loader, kernel, kernel drivers) must be signed by trusted publishers. Defender for Cloud has identified untrusted OS boot components on one or more of your Linux machines. To protect your machines from potentially malicious components, add them to your allow list or remove the identified components.","Azure_Security_Benchmark_v3.0_PV-4","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"7926a6d1-b268-4586-8197-e8ae90c877d7","","BuiltIn","Security Center","[Preview]: Microsoft Defender for APIs should be enabled","Microsoft Defender for APIs brings new discovery, protection, detection, & response coverage to monitor for common API based attacks & security misconfigurations.","Azure_Security_Benchmark_v3.0_DP-1, -Azure_Security_Benchmark_v3.0_DP-2, -Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5","ASB: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"97566dd7-78ae-4997-8b36-1c7bfe0d8121","","BuiltIn","Security Center","[Preview]: Secure Boot should be enabled on supported Windows virtual machines","Enable Secure Boot on supported Windows virtual machines to mitigate against malicious and unauthorized changes to the boot chain. Once enabled, only trusted bootloaders, kernel and kernel drivers will be allowed to run. This assessment applies to Trusted Launch and Confidential Windows virtual machines.","Azure_Security_Benchmark_v3.0_PV-4","ASB: Audit (PolicySet Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"f85bf3e0-d513-442e-89c3-1784ad63382b","","BuiltIn","Security Center","[Preview]: System updates should be installed on your machines (powered by Update Center)","Your machines are missing system, security, and critical updates. Software updates often include critical patches to security holes. Such holes are frequently exploited in malware attacks so it's vital to keep your software updated. To install all outstanding patches and secure your machines, follow the remediation steps.","Azure_Security_Benchmark_v3.0_PV-6","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"1c30f9cd-b84c-49cc-aa2c-9288447cc3b3","","BuiltIn","Security Center","[Preview]: vTPM should be enabled on supported virtual machines","Enable virtual TPM device on supported virtual machines to facilitate Measured Boot and other OS security features that require a TPM. Once enabled, vTPM can be used to attest boot integrity. This assessment only applies to trusted launch enabled virtual machines.","Azure_Security_Benchmark_v3.0_PV-4","ASB: Audit (PolicySet Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"4f11b553-d42e-4e3a-89be-32ca364cad4c","","BuiltIn","Security Center","A maximum of 3 owners should be designated for your subscription","It is recommended to designate up to 3 subscription owners in order to reduce the potential for breach by a compromised owner.","Azure_Security_Benchmark_v3.0_PA-1, -NIST_SP_800-53_R5_AC-2, -NIST_SP_800-53_R5_AC-6, -NIST_SP_800-53_R5_AC-6(7)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"501541f7-f7e7-4cd6-868c-4190fdad3ac9","","BuiltIn","Security Center","A vulnerability assessment solution should be enabled on your virtual machines","Audits virtual machines to detect whether they are running a supported vulnerability assessment solution. A core component of every cyber risk and security program is the identification and analysis of vulnerabilities. Azure Security Center's standard pricing tier includes vulnerability scanning for your virtual machines at no extra cost. Additionally, Security Center can automatically deploy this tool for you.","Azure_Security_Benchmark_v3.0_PV-5, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"e3e008c3-56b9-4133-8fd7-d3347377402a","","BuiltIn","Security Center","Accounts with owner permissions on Azure resources should be MFA enabled","Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with owner permissions to prevent a breach of accounts or resources.","Azure_Security_Benchmark_v3.0_IM-6, -NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_IA-2, -NIST_SP_800-53_R5_IA-2(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"81b3ccb4-e6e8-4e4a-8d05-5df25cd29fd4","","BuiltIn","Security Center","Accounts with read permissions on Azure resources should be MFA enabled","Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with read privileges to prevent a breach of accounts or resources.","Azure_Security_Benchmark_v3.0_IM-6, -NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_IA-2, -NIST_SP_800-53_R5_IA-2(2)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"931e118d-50a1-4457-a5e4-78550e086c52","","BuiltIn","Security Center","Accounts with write permissions on Azure resources should be MFA enabled","Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with write privileges to prevent a breach of accounts or resources.","Azure_Security_Benchmark_v3.0_IM-6, -NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_IA-2, -NIST_SP_800-53_R5_IA-2(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"47a6b606-51aa-4496-8bb7-64b11cf66adc","","BuiltIn","Security Center","Adaptive application controls for defining safe applications should be enabled on your machines","Enable application controls to define the list of known-safe applications running on your machines, and alert you when other applications run. This helps harden your machines against malware. To simplify the process of configuring and maintaining your rules, Security Center uses machine learning to analyze the applications running on each machine and suggest the list of known-safe applications.","Azure_Security_Benchmark_v3.0_AM-5, -NIST_SP_800-53_R5_CM-7, -NIST_SP_800-53_R5_CM-7(2), -NIST_SP_800-53_R5_CM-7(5), -NIST_SP_800-53_R5_CM-10, -NIST_SP_800-53_R5_CM-11","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"08e6af2d-db70-460a-bfe9-d5bd474ba9d6","","BuiltIn","Security Center","Adaptive network hardening recommendations should be applied on internet facing virtual machines","Azure Security Center analyzes the traffic patterns of Internet facing virtual machines and provides Network Security Group rule recommendations that reduce the potential attack surface","Azure_Security_Benchmark_v3.0_NS-1, -Azure_Security_Benchmark_v3.0_NS-7, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-4(3), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"9daedab3-fb2d-461e-b861-71790eead4f6","","BuiltIn","Security Center","All network ports should be restricted on network security groups associated to your virtual machine","Azure Security Center has identified some of your network security groups' inbound rules to be too permissive. Inbound rules should not allow access from 'Any' or 'Internet' ranges. This can potentially enable attackers to target your resources.","Azure_Security_Benchmark_v3.0_NS-1, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"123a3936-f020-408a-ba0c-47873faf1534","","BuiltIn","Security Center","Allowlist rules in your adaptive application control policy should be updated","Monitor for changes in behavior on groups of machines configured for auditing by Azure Security Center's adaptive application controls. Security Center uses machine learning to analyze the running processes on your machines and suggest a list of known-safe applications. These are presented as recommended apps to allow in adaptive application control policies.","Azure_Security_Benchmark_v3.0_AM-5, -NIST_SP_800-53_R5_CM-7, -NIST_SP_800-53_R5_CM-7(2), -NIST_SP_800-53_R5_CM-7(5), -NIST_SP_800-53_R5_CM-10, -NIST_SP_800-53_R5_CM-11","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"0e246bcf-5f6f-4f87-bc6f-775d4712c7ea","","BuiltIn","Security Center","Authorized IP ranges should be defined on Kubernetes Services","Restrict access to the Kubernetes Service Management API by granting API access only to IP addresses in specific ranges. It is recommended to limit access to authorized IP ranges to ensure that only applications from allowed networks can access the cluster.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"475aae12-b88a-4572-8b36-9b712b2b3a17","","BuiltIn","Security Center","Auto provisioning of the Log Analytics agent should be enabled on your subscription","To monitor for security vulnerabilities and threats, Azure Security Center collects data from your Azure virtual machines. Data is collected by the Log Analytics agent, formerly known as the Microsoft Monitoring Agent (MMA), which reads various security-related configurations and event logs from the machine and copies the data to your Log Analytics workspace for analysis. We recommend enabling auto provisioning to automatically deploy the agent to all supported Azure VMs and any new ones that are created.","Azure_Security_Benchmark_v3.0_LT-5, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"a7aca53f-2ed4-4466-a25e-0b45ade68efd","","BuiltIn","Security Center","Azure DDoS Protection Standard should be enabled","DDoS protection standard should be enabled for all virtual networks with a subnet that is part of an application gateway with a public IP.","Azure_Security_Benchmark_v3.0_NS-5, -NIST_SP_800-53_R5_SC-5","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"2913021d-f2fd-4f3d-b958-22354e2bdbcb","","BuiltIn","Security Center","Azure Defender for App Service should be enabled","Azure Defender for App Service leverages the scale of the cloud, and the visibility that Azure has as a cloud provider, to monitor for common web app attacks.","Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5, -NIST_SP_800-53_R5_AC-2(12), -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-5, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SI-2, -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"7fe3b40f-802b-4cdd-8bd4-fd799c948cc2","","BuiltIn","Security Center","Azure Defender for Azure SQL Database servers should be enabled","Azure Defender for SQL provides functionality for surfacing and mitigating potential database vulnerabilities, detecting anomalous activities that could indicate threats to SQL databases, and discovering and classifying sensitive data.","Azure_Security_Benchmark_v3.0_DP-2, -Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5, -NIST_SP_800-53_R5_AC-2(12), -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-5, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SI-2, -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"bdc59948-5574-49b3-bb91-76b7c986428d","","BuiltIn","Security Center","Azure Defender for DNS should be enabled","Azure Defender for DNS provides an additional layer of protection for your cloud resources by continuously monitoring all DNS queries from your Azure resources. Azure Defender alerts you about suspicious activity at the DNS layer. Learn more about the capabilities of Azure Defender for DNS at https://aka.ms/defender-for-dns . Enabling this Azure Defender plan results in charges. Learn about the pricing details per region on Security Center's pricing page: https://aka.ms/pricing-security-center .","Azure_Security_Benchmark_v3.0_NS-10, -Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5, -NIST_SP_800-53_R5_AC-2(12), -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-5, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SI-2, -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"0e6763cc-5078-4e64-889d-ff4d9a839047","","BuiltIn","Security Center","Azure Defender for Key Vault should be enabled","Azure Defender for Key Vault provides an additional layer of protection and security intelligence by detecting unusual and potentially harmful attempts to access or exploit key vault accounts.","Azure_Security_Benchmark_v3.0_DP-8, -Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5, -NIST_SP_800-53_R5_AC-2(12), -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-5, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SI-2, -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"0a9fbe0d-c5c4-4da8-87d8-f4fd77338835","","BuiltIn","Security Center","Azure Defender for open-source relational databases should be enabled","Azure Defender for open-source relational databases detects anomalous activities indicating unusual and potentially harmful attempts to access or exploit databases. Learn more about the capabilities of Azure Defender for open-source relational databases at https://aka.ms/AzDforOpenSourceDBsDocu. Important: Enabling this plan will result in charges for protecting your open-source relational databases. Learn about the pricing on Security Center's pricing page: https://aka.ms/pricing-security-center","Azure_Security_Benchmark_v3.0_DP-2, -Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"c3d20c29-b36d-48fe-808b-99a87530ad99","","BuiltIn","Security Center","Azure Defender for Resource Manager should be enabled","Azure Defender for Resource Manager automatically monitors the resource management operations in your organization. Azure Defender detects threats and alerts you about suspicious activity. Learn more about the capabilities of Azure Defender for Resource Manager at https://aka.ms/defender-for-resource-manager . Enabling this Azure Defender plan results in charges. Learn about the pricing details per region on Security Center's pricing page: https://aka.ms/pricing-security-center .","Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5, -NIST_SP_800-53_R5_AC-2(12), -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-5, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SI-2, -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"4da35fc9-c9e7-4960-aec9-797fe7d9051d","","BuiltIn","Security Center","Azure Defender for servers should be enabled","Azure Defender for servers provides real-time threat protection for server workloads and generates hardening recommendations as well as alerts about suspicious activities.","Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_ES-1, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5, -NIST_SP_800-53_R5_AC-2(12), -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_CM-7, -NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-5, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SC-3, -NIST_SP_800-53_R5_SI-2, -NIST_SP_800-53_R5_SI-3, -NIST_SP_800-53_R5_SI-4, -NIST_SP_800-53_R5_SI-16","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"6581d072-105e-4418-827f-bd446d56421b","","BuiltIn","Security Center","Azure Defender for SQL servers on machines should be enabled","Azure Defender for SQL provides functionality for surfacing and mitigating potential database vulnerabilities, detecting anomalous activities that could indicate threats to SQL databases, and discovering and classifying sensitive data.","Azure_Security_Benchmark_v3.0_DP-2, -Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5, -NIST_SP_800-53_R5_AC-2(12), -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-5, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SI-2, -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"0cfea604-3201-4e14-88fc-fae4c427a6c5","","BuiltIn","Security Center","Blocked accounts with owner permissions on Azure resources should be removed","Deprecated accounts with owner permissions should be removed from your subscription. Deprecated accounts are accounts that have been blocked from signing in.","Azure_Security_Benchmark_v3.0_PA-1, -Azure_Security_Benchmark_v3.0_PA-4, -NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"8d7e1fde-fe26-4b5f-8108-f8e432cbc2be","","BuiltIn","Security Center","Blocked accounts with read and write permissions on Azure resources should be removed","Deprecated accounts should be removed from your subscriptions. Deprecated accounts are accounts that have been blocked from signing in.","Azure_Security_Benchmark_v3.0_PA-4, -NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"5f0f936f-2f01-4bf5-b6be-d423792fa562","","BuiltIn","Security Center","Container registry images should have vulnerability findings resolved","Container image vulnerability assessment scans your registry for security vulnerabilities and exposes detailed findings for each image. Resolving the vulnerabilities can greatly improve your containers' security posture and protect them from attacks.","Azure_Security_Benchmark_v3.0_PV-6, -Azure_Security_Benchmark_v3.0_DS-6, -NIST_SP_800-53_R5_RA-5","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"090c7b07-b4ed-4561-ad20-e9075f3ccaff","","BuiltIn","Security Center","Container registry images should have vulnerability findings resolved (powered by Microsoft Defender Vulnerability Management)","Container image vulnerability assessment scans your registry for commonly known vulnerabilities (CVEs) and provides a detailed vulnerability report for each image. Resolving vulnerabilities can greatly improve your security posture, ensuring images are safe to use prior to deployment.","Azure_Security_Benchmark_v3.0_PV-6, -Azure_Security_Benchmark_v3.0_DS-6","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"6e2593d9-add6-4083-9c9b-4b7d2188c899","","BuiltIn","Security Center","Email notification for high severity alerts should be enabled","To ensure the relevant people in your organization are notified when there is a potential security breach in one of your subscriptions, enable email notifications for high severity alerts in Security Center.","Azure_Security_Benchmark_v3.0_IR-2, -NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-5, -NIST_SP_800-53_R5_IR-6(2), -NIST_SP_800-53_R5_SI-4(12)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"0b15565f-aa9e-48ba-8619-45960f2c314d","","BuiltIn","Security Center","Email notification to subscription owner for high severity alerts should be enabled","To ensure your subscription owners are notified when there is a potential security breach in their subscription, set email notifications to subscription owners for high severity alerts in Security Center.","Azure_Security_Benchmark_v3.0_IR-2, -NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-5, -NIST_SP_800-53_R5_IR-6(2), -NIST_SP_800-53_R5_SI-4(12)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"8e42c1f2-a2ab-49bc-994a-12bcd0dc4ac2","","BuiltIn","Security Center","Endpoint protection health issues should be resolved on your machines","Resolve endpoint protection health issues on your virtual machines to protect them from latest threats and vulnerabilities. Azure Security Center supported endpoint protection solutions are documented here - https://docs.microsoft.com/azure/security-center/security-center-services?tabs=features-windows#supported-endpoint-protection-solutions. Endpoint protection assessment is documented here - https://docs.microsoft.com/azure/security-center/security-center-endpoint-protection.","Azure_Security_Benchmark_v3.0_ES-2, -Azure_Security_Benchmark_v3.0_ES-3","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"1f7c564c-0a90-4d44-b7e1-9d456cffaee8","","BuiltIn","Security Center","Endpoint protection should be installed on your machines","To protect your machines from threats and vulnerabilities, install a supported endpoint protection solution.","Azure_Security_Benchmark_v3.0_ES-2","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"26a828e1-e88f-464e-bbb3-c134a282b9de","","BuiltIn","Security Center","Endpoint protection solution should be installed on virtual machine scale sets","Audit the existence and health of an endpoint protection solution on your virtual machines scale sets, to protect them from threats and vulnerabilities.","Azure_Security_Benchmark_v3.0_ES-2, -NIST_SP_800-53_R5_SC-3, -NIST_SP_800-53_R5_SI-3","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"339353f6-2387-4a45-abe4-7f529d121046","","BuiltIn","Security Center","Guest accounts with owner permissions on Azure resources should be removed","External accounts with owner permissions should be removed from your subscription in order to prevent unmonitored access.","Azure_Security_Benchmark_v3.0_PA-1, -Azure_Security_Benchmark_v3.0_PA-4, -NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"e9ac8f8e-ce22-4355-8f04-99b911d6be52","","BuiltIn","Security Center","Guest accounts with read permissions on Azure resources should be removed","External accounts with read privileges should be removed from your subscription in order to prevent unmonitored access.","Azure_Security_Benchmark_v3.0_PA-4, -NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"94e1c2ac-cbbe-4cac-a2b5-389c812dee87","","BuiltIn","Security Center","Guest accounts with write permissions on Azure resources should be removed","External accounts with write privileges should be removed from your subscription in order to prevent unmonitored access.","Azure_Security_Benchmark_v3.0_PA-4, -NIST_SP_800-53_R5_AC-2","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"ae89ebca-1c92-4898-ac2c-9f63decb045c","","BuiltIn","Security Center","Guest Configuration extension should be installed on your machines","To ensure secure configurations of in-guest settings of your machine, install the Guest Configuration extension. In-guest settings that the extension monitors include the configuration of the operating system, application configuration or presence, and environment settings. Once installed, in-guest policies will be available such as 'Windows Exploit guard should be enabled'. Learn more at https://aka.ms/gcpol.","Azure_Security_Benchmark_v3.0_PV-4, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"f6de0be7-9a8a-4b8a-b349-43cf02d22f7c","","BuiltIn","Security Center","Internet-facing virtual machines should be protected with network security groups","Protect your virtual machines from potential threats by restricting access to them with network security groups (NSG). Learn more about controlling traffic with NSGs at https://aka.ms/nsg-doc","Azure_Security_Benchmark_v3.0_NS-1, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"bd352bd5-2853-4985-bf0d-73806b4a5744","","BuiltIn","Security Center","IP Forwarding on your virtual machine should be disabled","Enabling IP forwarding on a virtual machine's NIC allows the machine to receive traffic addressed to other destinations. IP forwarding is rarely required (e.g., when using the VM as a network virtual appliance), and therefore, this should be reviewed by the network security team.","Azure_Security_Benchmark_v3.0_NS-3, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-5, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"fb893a29-21bb-418c-a157-e99480ec364c","","BuiltIn","Security Center","Kubernetes Services should be upgraded to a non-vulnerable Kubernetes version","Upgrade your Kubernetes service cluster to a later Kubernetes version to protect against known vulnerabilities in your current Kubernetes version. Vulnerability CVE-2019-9946 has been patched in Kubernetes versions 1.11.9+, 1.12.7+, 1.13.5+, and 1.14.0+","NIST_SP_800-53_R5_SI-2, -NIST_SP_800-53_R5_SI-2(6)","NIST-800-53: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" -"a4fe33eb-e377-4efb-ab31-0784311bc499","","BuiltIn","Security Center","Log Analytics agent should be installed on your virtual machine for Azure Security Center monitoring","This policy audits any Windows/Linux virtual machines (VMs) if the Log Analytics agent is not installed which Security Center uses to monitor for security vulnerabilities and threats","Azure_Security_Benchmark_v3.0_LT-5, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"a3a6ea0c-e018-4933-9ef0-5aaa1501449b","","BuiltIn","Security Center","Log Analytics agent should be installed on your virtual machine scale sets for Azure Security Center monitoring","Security Center collects data from your Azure virtual machines (VMs) to monitor for security vulnerabilities and threats.","Azure_Security_Benchmark_v3.0_LT-5, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"3ac7c827-eea2-4bde-acc7-9568cd320efa","","BuiltIn","Security Center","Machines should have secret findings resolved","Audits virtual machines to detect whether they contain secret findings from the secret scanning solutions on your virtual machines.","Azure_Security_Benchmark_v3.0_PV-5, -Azure_Security_Benchmark_v3.0_IM-8","ASB: Disabled (Policy Default)","AuditIfNotExists, -Disabled","Disabled","Disabled","Disabled","Disabled","","","","" -"b0f33259-77d7-4c9e-aac6-3aabcfae693c","","BuiltIn","Security Center","Management ports of virtual machines should be protected with just-in-time network access control","Possible network Just In Time (JIT) access will be monitored by Azure Security Center as recommendations","Azure_Security_Benchmark_v3.0_NS-3, -Azure_Security_Benchmark_v3.0_PA-2, -NIST_SP_800-53_R5_AC-2(12), -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-4(3), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"22730e10-96f6-4aac-ad84-9383d35b5917","","BuiltIn","Security Center","Management ports should be closed on your virtual machines","Open remote management ports are exposing your VM to a high level of risk from Internet-based attacks. These attacks attempt to brute force credentials to gain admin access to the machine.","Azure_Security_Benchmark_v3.0_NS-3, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"1f90fc71-a595-4066-8974-d4d0802e8ef0","","BuiltIn","Security Center","Microsoft Defender CSPM should be enabled","Defender Cloud Security Posture Management (CSPM) provides enhanced posture capabilities and a new intelligent cloud security graph to help identify, prioritize, and reduce risk. Defender CSPM is available in addition to the free foundational security posture capabilities turned on by default in Defender for Cloud.","Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5","ASB: Disabled (PolicySet Default)","Disabled, -AuditIfNotExists","Disabled","Disabled","Disabled","Disabled","","","","" -"1c988dd6-ade4-430f-a608-2a3e5b0a6d38","","BuiltIn","Security Center","Microsoft Defender for Containers should be enabled","Microsoft Defender for Containers provides hardening, vulnerability assessment and run-time protections for your Azure, hybrid, and multi-cloud Kubernetes environments.","Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5, -NIST_SP_800-53_R5_AC-2(12), -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-5, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SI-2, -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"938c4981-c2c9-4168-9cd6-972b8675f906","","BuiltIn","Security Center","Microsoft Defender for SQL status should be protected for Arc-enabled SQL Servers","Microsoft Defender for SQL provides functionality for surfacing and mitigating potential database vulnerabilities, detecting anomalous activities that could indicate threats to SQL databases, discovering and classifying sensitive data. Once enabled, the protection status indicates that the resource is actively monitored. Even when Defender is enabled, multiple configuration settings should be validated on the agent, machine, workspace and SQL server to ensure active protection.","Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5","ASB: Audit (PolicySet Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"308fbb08-4ab8-4e67-9b29-592e93fb94fa","","BuiltIn","Security Center","Microsoft Defender for Storage (Classic) should be enabled","Microsoft Defender for Storage (Classic) provides detections of unusual and potentially harmful attempts to access or exploit storage accounts.","Azure_Security_Benchmark_v3.0_DP-2, -Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5, -NIST_SP_800-53_R5_AC-2(12), -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-5, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SI-2, -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"af6cd1bd-1635-48cb-bde7-5b15693900b9","","BuiltIn","Security Center","Monitor missing Endpoint Protection in Azure Security Center","Servers without an installed Endpoint Protection agent will be monitored by Azure Security Center as recommendations","Azure_Security_Benchmark_v3.0_ES-2, -NIST_SP_800-53_R5_SC-3, -NIST_SP_800-53_R5_SI-3","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"bb91dfba-c30d-4263-9add-9c2384e659a6","","BuiltIn","Security Center","Non-internet-facing virtual machines should be protected with network security groups","Protect your non-internet-facing virtual machines from potential threats by restricting access with network security groups (NSG). Learn more about controlling traffic with NSGs at https://aka.ms/nsg-doc","Azure_Security_Benchmark_v3.0_NS-1, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"ac4a19c2-fa67-49b4-8ae5-0b2e78c49457","","BuiltIn","Security Center","Role-Based Access Control (RBAC) should be used on Kubernetes Services","To provide granular filtering on the actions that users can perform, use Role-Based Access Control (RBAC) to manage permissions in Kubernetes Service Clusters and configure relevant authorization policies.","Azure_Security_Benchmark_v3.0_PA-7, -NIST_SP_800-53_R5_AC-3(7)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"0fc39691-5a3f-4e3e-94ee-2e6447309ad9","","BuiltIn","Security Center","Running container images should have vulnerability findings resolved","Container image vulnerability assessment scans container images running on your Kubernetes clusters for security vulnerabilities and exposes detailed findings for each image. Resolving the vulnerabilities can greatly improve your containers' security posture and protect them from attacks.","Azure_Security_Benchmark_v3.0_PV-6, -Azure_Security_Benchmark_v3.0_DS-6","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"17f4b1cc-c55c-4d94-b1f9-2978f6ac2957","","BuiltIn","Security Center","Running container images should have vulnerability findings resolved (powered by Microsoft Defender Vulnerability Management)","Container image vulnerability assessment scans your registry for commonly known vulnerabilities (CVEs) and provides a detailed vulnerability report for each image. This recommendation provides visibility to vulnerable images currently running in your Kubernetes clusters. Remediating vulnerabilities in container images that are currently running is key to improving your security posture, significantly reducing the attack surface for your containerized workloads.","Azure_Security_Benchmark_v3.0_PV-6, -Azure_Security_Benchmark_v3.0_DS-6","ASB: AuditIfNotExists (PolicySet Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"feedbf84-6b99-488c-acc2-71c829aa5ffc","","BuiltIn","Security Center","SQL databases should have vulnerability findings resolved","Monitor vulnerability assessment scan results and recommendations for how to remediate database vulnerabilities.","Azure_Security_Benchmark_v3.0_PV-6, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"6ba6d016-e7c3-4842-b8f2-4992ebc0d72d","","BuiltIn","Security Center","SQL servers on machines should have vulnerability findings resolved","SQL vulnerability assessment scans your database for security vulnerabilities, and exposes any deviations from best practices such as misconfigurations, excessive permissions, and unprotected sensitive data. Resolving the vulnerabilities found can greatly improve your database security posture.","Azure_Security_Benchmark_v3.0_PV-6, -NIST_SP_800-53_R5_RA-5","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"e71308d3-144b-4262-b144-efdc3cc90517","","BuiltIn","Security Center","Subnets should be associated with a Network Security Group","Protect your subnet from potential threats by restricting access to it with a Network Security Group (NSG). NSGs contain a list of Access Control List (ACL) rules that allow or deny network traffic to your subnet.","Azure_Security_Benchmark_v3.0_NS-1, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Disabled (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","Disabled","Disabled","Disabled","Disabled","","","","" -"4f4f78b8-e367-4b10-a341-d9a4ad5cf1c7","","BuiltIn","Security Center","Subscriptions should have a contact email address for security issues","To ensure the relevant people in your organization are notified when there is a potential security breach in one of your subscriptions, set a security contact to receive email notifications from Security Center.","Azure_Security_Benchmark_v3.0_IR-2, -NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-5, -NIST_SP_800-53_R5_IR-6(2), -NIST_SP_800-53_R5_SI-4(12)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"c3f317a7-a95c-4547-b7e7-11017ebdf2fe","","BuiltIn","Security Center","System updates on virtual machine scale sets should be installed","Audit whether there are any missing system security updates and critical updates that should be installed to ensure that your Windows and Linux virtual machine scale sets are secure.","Azure_Security_Benchmark_v3.0_PV-6, -NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"86b3d65f-7626-441e-b690-81a8b71cff60","","BuiltIn","Security Center","System updates should be installed on your machines","Missing security system updates on your servers will be monitored by Azure Security Center as recommendations","Azure_Security_Benchmark_v3.0_PV-6, -NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"09024ccc-0c5f-475e-9457-b7c0d9ed487b","","BuiltIn","Security Center","There should be more than one owner assigned to your subscription","It is recommended to designate more than one subscription owner in order to have administrator access redundancy.","Azure_Security_Benchmark_v3.0_PA-1, -NIST_SP_800-53_R5_AC-5","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"0961003e-5a0a-4549-abde-af6a37f2724d","","BuiltIn","Security Center","Virtual machines should encrypt temp disks, caches, and data flows between Compute and Storage resources","By default, a virtual machine's OS and data disks are encrypted-at-rest using platform-managed keys. Temp disks, data caches and data flowing between compute and storage aren't encrypted. Disregard this recommendation if: 1. using encryption-at-host, or 2. server-side encryption on Managed Disks meets your security requirements. Learn more in: Server-side encryption of Azure Disk Storage: https://aka.ms/disksse, Different disk encryption offerings: https://aka.ms/diskencryptioncomparison","Azure_Security_Benchmark_v3.0_DP-4, -NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"d26f7642-7545-4e18-9b75-8c9bbdee3a9a","","BuiltIn","Security Center","Virtual machines' Guest Configuration extension should be deployed with system-assigned managed identity","The Guest Configuration extension requires a system assigned managed identity. Azure virtual machines in the scope of this policy will be non-compliant when they have the Guest Configuration extension installed but do not have a system assigned managed identity. Learn more at https://aka.ms/gcpol","Azure_Security_Benchmark_v3.0_IM-3, -Azure_Security_Benchmark_v3.0_PV-4, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"e8cbc669-f12d-49eb-93e7-9273119e9933","","BuiltIn","Security Center","Vulnerabilities in container security configurations should be remediated","Audit vulnerabilities in security configuration on machines with Docker installed and display as recommendations in Azure Security Center.","Azure_Security_Benchmark_v3.0_PV-6, -Azure_Security_Benchmark_v3.0_DS-6, -NIST_SP_800-53_R5_RA-5","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"e1e5fd5d-3e4c-4ce1-8661-7d1873ae6b15","","BuiltIn","Security Center","Vulnerabilities in security configuration on your machines should be remediated","Servers which do not satisfy the configured baseline will be monitored by Azure Security Center as recommendations","Azure_Security_Benchmark_v3.0_PV-6, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"3c735d8a-a4ba-4a3a-b7cf-db7754cf57f4","","BuiltIn","Security Center","Vulnerabilities in security configuration on your virtual machine scale sets should be remediated","Audit the OS vulnerabilities on your virtual machine scale sets to protect them from attacks.","Azure_Security_Benchmark_v3.0_PV-6, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SI-2","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"1c06e275-d63d-4540-b761-71f364c2111d","","BuiltIn","Service Bus","Azure Service Bus namespaces should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Service Bus namespaces, data leakage risks are reduced. Learn more at: https://docs.microsoft.com/azure/service-bus-messaging/private-link-service.","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"f8d36e2f-389b-4ee4-898d-21aeb69a0f45","","BuiltIn","Service Bus","Resource logs in Service Bus should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInServiceBusRetentionDays"":""1""}","{""diagnosticsLogsInServiceBusRetentionDays"":""1""}","{""diagnosticsLogsInServiceBusRetentionDays"":""1""}","{""diagnosticsLogsInServiceBusRetentionDays"":""1""}" -"295fc8b1-dc9f-4f53-9c61-3f313ceab40a","","BuiltIn","Service Bus","Service Bus Premium namespaces should use a customer-managed key for encryption","Azure Service Bus supports the option of encrypting data at rest with either Microsoft-managed keys (default) or customer-managed keys. Choosing to encrypt data using customer-managed keys enables you to assign, rotate, disable, and revoke access to the keys that Service Bus will use to encrypt data in your namespace. Note that Service Bus only supports encryption with customer-managed keys for premium namespaces.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" -"617c02be-7f02-4efd-8836-3180d47b6c68","","BuiltIn","Service Fabric","Service Fabric clusters should have the ClusterProtectionLevel property set to EncryptAndSign","Service Fabric provides three levels of protection (None, Sign and EncryptAndSign) for node-to-node communication using a primary cluster certificate. Set the protection level to ensure that all node-to-node messages are encrypted and digitally signed","Azure_Security_Benchmark_v3.0_DP-4, -NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"b54ed75b-3e1a-44ac-a333-05ba39b99ff0","","BuiltIn","Service Fabric","Service Fabric clusters should only use Azure Active Directory for client authentication","Audit usage of client authentication only via Azure Active Directory in Service Fabric","Azure_Security_Benchmark_v3.0_IM-1, -NIST_SP_800-53_R5_AC-2, -NIST_SP_800-53_R5_AC-2(1), -NIST_SP_800-53_R5_AC-2(7), -NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_IA-2, -NIST_SP_800-53_R5_IA-4","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"2393d2cf-a342-44cd-a2e2-fe0188fd1234","","BuiltIn","SignalR","Azure SignalR Service should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Azure SignalR Service resource instead of the entire service, you'll reduce your data leakage risks. Learn more about private links at: https://aka.ms/asrs/privatelink.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"146412e9-005c-472b-9e48-c87b72ac229e","","BuiltIn","SQL","An Azure Active Directory administrator should be provisioned for MySQL servers","Audit provisioning of an Azure Active Directory administrator for your MySQL server to enable Azure AD authentication. Azure AD authentication enables simplified permission management and centralized identity management of database users and other Microsoft services","Azure_Security_Benchmark_v3.0_DP-4","ASB: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"b4dec045-250a-48c2-b5cc-e0c4eec8b5b4","","BuiltIn","SQL","An Azure Active Directory administrator should be provisioned for PostgreSQL servers","Audit provisioning of an Azure Active Directory administrator for your PostgreSQL server to enable Azure AD authentication. Azure AD authentication enables simplified permission management and centralized identity management of database users and other Microsoft services","Azure_Security_Benchmark_v3.0_DP-4","ASB: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"1f314764-cb73-4fc9-b863-8eca98ac36e9","","BuiltIn","SQL","An Azure Active Directory administrator should be provisioned for SQL servers","Audit provisioning of an Azure Active Directory administrator for your SQL server to enable Azure AD authentication. Azure AD authentication enables simplified permission management and centralized identity management of database users and other Microsoft services","Azure_Security_Benchmark_v3.0_IM-1, -NIST_SP_800-53_R5_AC-2, -NIST_SP_800-53_R5_AC-2(1), -NIST_SP_800-53_R5_AC-2(7), -NIST_SP_800-53_R5_AC-3, -NIST_SP_800-53_R5_IA-2, -NIST_SP_800-53_R5_IA-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9","","BuiltIn","SQL","Auditing on SQL server should be enabled","Auditing on your SQL Server should be enabled to track database activities across all databases on the server and save them in an audit log.","Azure_Security_Benchmark_v3.0_LT-3, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""setting-a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9"":""enabled""}","{""setting-a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9"":""enabled""}","{""setting-a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9"":""enabled""}","{""setting-a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9"":""enabled""}" -"abfb4388-5bf4-4ad7-ba82-2cd2f41ceae9","","BuiltIn","SQL","Azure Defender for SQL should be enabled for unprotected Azure SQL servers","Audit SQL servers without Advanced Data Security","Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5, -NIST_SP_800-53_R5_AC-16, -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-5, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"abfb7388-5bf4-4ad7-ba99-2cd2f41cebb9","","BuiltIn","SQL","Azure Defender for SQL should be enabled for unprotected SQL Managed Instances","Audit each SQL Managed Instance without advanced data security.","Azure_Security_Benchmark_v3.0_DP-2, -Azure_Security_Benchmark_v3.0_LT-1, -Azure_Security_Benchmark_v3.0_LT-2, -Azure_Security_Benchmark_v3.0_IR-3, -Azure_Security_Benchmark_v3.0_IR-5, -NIST_SP_800-53_R5_AC-2(12), -NIST_SP_800-53_R5_AC-16, -NIST_SP_800-53_R5_AU-6, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1), -NIST_SP_800-53_R5_IR-4, -NIST_SP_800-53_R5_IR-5, -NIST_SP_800-53_R5_RA-5, -NIST_SP_800-53_R5_SI-4","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"40e85574-ef33-47e8-a854-7a65c7500560","","BuiltIn","SQL","Azure MySQL flexible server should have Azure Active Directory Only Authentication enabled","Disabling local authentication methods and allowing only Azure Active Directory Authentication improves security by ensuring that Azure MySQL flexible server can exclusively be accessed by Azure Active Directory identities.","Azure_Security_Benchmark_v3.0_DP-4","ASB: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"abda6d70-9778-44e7-84a8-06713e6db027","","BuiltIn","SQL","Azure SQL Database should have Azure Active Directory Only Authentication enabled","Disabling local authentication methods and allowing only Azure Active Directory Authentication improves security by ensuring that Azure SQL Databases can exclusively be accessed by Azure Active Directory identities. Learn more at: aka.ms/adonlycreate.","Azure_Security_Benchmark_v3.0_DP-4","ASB: Audit (Policy Default)","Audit, -Deny, -Disabled","Audit","Audit","Audit","Audit","","","","" -"78215662-041e-49ed-a9dd-5385911b3a1f","","BuiltIn","SQL","Azure SQL Managed Instance should have Azure Active Directory Only Authentication enabled","Disabling local authentication methods and allowing only Azure Active Directory Authentication improves security by ensuring that Azure SQL Managed Instances can exclusively be accessed by Azure Active Directory identities. Learn more at: aka.ms/adonlycreate.","Azure_Security_Benchmark_v3.0_DP-4","ASB: Audit (Policy Default)","Audit, -Deny, -Disabled","Audit","Audit","Audit","Audit","","","","" -"e802a67a-daf5-4436-9ea6-f6d821dd0c5d","","BuiltIn","SQL","Enforce SSL connection should be enabled for MySQL database servers","Azure Database for MySQL supports connecting your Azure Database for MySQL server to client applications using Secure Sockets Layer (SSL). Enforcing SSL connections between your database server and your client applications helps protect against 'man in the middle' attacks by encrypting the data stream between the server and your application. This configuration enforces that SSL is always enabled for accessing your database server.","Azure_Security_Benchmark_v3.0_DP-3, -NIST_SP_800-53_R5_SC-8, -NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"d158790f-bfb0-486c-8631-2dc6b4e8e6af","","BuiltIn","SQL","Enforce SSL connection should be enabled for PostgreSQL database servers","Azure Database for PostgreSQL supports connecting your Azure Database for PostgreSQL server to client applications using Secure Sockets Layer (SSL). Enforcing SSL connections between your database server and your client applications helps protect against 'man in the middle' attacks by encrypting the data stream between the server and your application. This configuration enforces that SSL is always enabled for accessing your database server.","Azure_Security_Benchmark_v3.0_DP-3, -NIST_SP_800-53_R5_SC-8, -NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"0ec47710-77ff-4a3d-9181-6aa50af424d0","","BuiltIn","SQL","Geo-redundant backup should be enabled for Azure Database for MariaDB","Azure Database for MariaDB allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create.","Azure_Security_Benchmark_v3.0_BR-1, -Azure_Security_Benchmark_v3.0_BR-2, -NIST_SP_800-53_R5_CP-6, -NIST_SP_800-53_R5_CP-6(1), -NIST_SP_800-53_R5_CP-9","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"82339799-d096-41ae-8538-b108becf0970","","BuiltIn","SQL","Geo-redundant backup should be enabled for Azure Database for MySQL","Azure Database for MySQL allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create.","Azure_Security_Benchmark_v3.0_BR-1, -Azure_Security_Benchmark_v3.0_BR-2, -NIST_SP_800-53_R5_CP-6, -NIST_SP_800-53_R5_CP-6(1), -NIST_SP_800-53_R5_CP-9","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"48af4db5-9b8b-401c-8e74-076be876a430","","BuiltIn","SQL","Geo-redundant backup should be enabled for Azure Database for PostgreSQL","Azure Database for PostgreSQL allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create.","Azure_Security_Benchmark_v3.0_BR-1, -Azure_Security_Benchmark_v3.0_BR-2, -NIST_SP_800-53_R5_CP-6, -NIST_SP_800-53_R5_CP-6(1), -NIST_SP_800-53_R5_CP-9","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"3a58212a-c829-4f13-9872-6371df2fd0b4","","BuiltIn","SQL","Infrastructure encryption should be enabled for Azure Database for MySQL servers","Enable infrastructure encryption for Azure Database for MySQL servers to have higher level of assurance that the data is secure. When infrastructure encryption is enabled, the data at rest is encrypted twice using FIPS 140-2 compliant Microsoft managed keys.","NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"24fba194-95d6-48c0-aea7-f65bf859c598","","BuiltIn","SQL","Infrastructure encryption should be enabled for Azure Database for PostgreSQL servers","Enable infrastructure encryption for Azure Database for PostgreSQL servers to have higher level of assurance that the data is secure. When infrastructure encryption is enabled, the data at rest is encrypted twice using FIPS 140-2 compliant Microsoft managed keys","NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"d38fc420-0735-4ef3-ac11-c806f651a570","","BuiltIn","SQL","Long-term geo-redundant backup should be enabled for Azure SQL Databases","This policy audits any Azure SQL Database with long-term geo-redundant backup not enabled.","NIST_SP_800-53_R5_CP-6, -NIST_SP_800-53_R5_CP-6(1)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"83cef61d-dbd1-4b20-a4fc-5fbc7da10833","","BuiltIn","SQL","MySQL servers should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your MySQL servers. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management.","Azure_Security_Benchmark_v3.0_DP-5, -NIST_SP_800-53_R5_SC-12","ASB: Disabled (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","Disabled","Disabled","Disabled","Disabled","","","","" -"18adea5e-f416-4d0f-8aa8-d24321e3e274","","BuiltIn","SQL","PostgreSQL servers should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your PostgreSQL servers. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management.","Azure_Security_Benchmark_v3.0_DP-5, -NIST_SP_800-53_R5_SC-12","ASB: Disabled (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","Disabled","Disabled","Disabled","Disabled","","","","" -"7698e800-9299-47a6-b3b6-5a0fee576eed","","BuiltIn","SQL","Private endpoint connections on Azure SQL Database should be enabled","Private endpoint connections enforce secure communication by enabling private connectivity to Azure SQL Database.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"0a1302fb-a631-4106-9753-f3d494733990","","BuiltIn","SQL","Private endpoint should be enabled for MariaDB servers","Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for MariaDB. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"7595c971-233d-4bcf-bd18-596129188c49","","BuiltIn","SQL","Private endpoint should be enabled for MySQL servers","Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for MySQL. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"0564d078-92f5-4f97-8398-b9f58a51f70b","","BuiltIn","SQL","Private endpoint should be enabled for PostgreSQL servers","Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for PostgreSQL. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"1b8ca024-1d5c-4dec-8995-b1a932b41780","","BuiltIn","SQL","Public network access on Azure SQL Database should be disabled","Disabling the public network access property improves security by ensuring your Azure SQL Database can only be accessed from a private endpoint. This configuration denies all logins that match IP or virtual network based firewall rules.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"fdccbe47-f3e3-4213-ad5d-ea459b2fa077","","BuiltIn","SQL","Public network access should be disabled for MariaDB servers","Disable the public network access property to improve security and ensure your Azure Database for MariaDB can only be accessed from a private endpoint. This configuration strictly disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"d9844e8a-1437-4aeb-a32c-0c992f056095","","BuiltIn","SQL","Public network access should be disabled for MySQL servers","Disable the public network access property to improve security and ensure your Azure Database for MySQL can only be accessed from a private endpoint. This configuration strictly disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"b52376f7-9612-48a1-81cd-1ffe4b61032c","","BuiltIn","SQL","Public network access should be disabled for PostgreSQL servers","Disable the public network access property to improve security and ensure your Azure Database for PostgreSQL can only be accessed from a private endpoint. This configuration disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"ac01ad65-10e5-46df-bdd9-6b0cad13e1d2","","BuiltIn","SQL","SQL managed instances should use customer-managed keys to encrypt data at rest","Implementing Transparent Data Encryption (TDE) with your own key provides you with increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. This recommendation applies to organizations with a related compliance requirement.","Azure_Security_Benchmark_v3.0_DP-5, -NIST_SP_800-53_R5_SC-12","ASB: Disabled (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Audit, -Disabled, -Deny","Disabled","Disabled","Disabled","Disabled","","","","" -"0a370ff3-6cab-4e85-8995-295fd854c5b8","","BuiltIn","SQL","SQL servers should use customer-managed keys to encrypt data at rest","Implementing Transparent Data Encryption (TDE) with your own key provides increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. This recommendation applies to organizations with a related compliance requirement.","Azure_Security_Benchmark_v3.0_DP-5, -NIST_SP_800-53_R5_SC-12","ASB: Disabled (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Audit, -Disabled, -Deny","Disabled","Disabled","Disabled","Disabled","","","","" -"89099bee-89e0-4b26-a5f4-165451757743","","BuiltIn","SQL","SQL servers with auditing to storage account destination should be configured with 90 days retention or higher","For incident investigation purposes, we recommend setting the data retention for your SQL Server' auditing to storage account destination to at least 90 days. Confirm that you are meeting the necessary retention rules for the regions in which you are operating. This is sometimes required for compliance with regulatory standards.","Azure_Security_Benchmark_v3.0_LT-6, -NIST_SP_800-53_R5_AU-11","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"17k78e20-9358-41c9-923c-fb736d382a12","","BuiltIn","SQL","Transparent Data Encryption on SQL databases should be enabled","Transparent data encryption should be enabled to protect data-at-rest and meet compliance requirements","Azure_Security_Benchmark_v3.0_DP-4, -NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"1b7aa243-30e4-4c9e-bca8-d0d3022b634a","","BuiltIn","SQL","Vulnerability assessment should be enabled on SQL Managed Instance","Audit each SQL Managed Instance which doesn't have recurring vulnerability assessment scans enabled. Vulnerability assessment can discover, track, and help you remediate potential database vulnerabilities.","Azure_Security_Benchmark_v3.0_PV-5, -NIST_SP_800-53_R5_RA-5","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"ef2a8f2a-b3d9-49cd-a8a8-9a3aaaf647d9","","BuiltIn","SQL","Vulnerability assessment should be enabled on your SQL servers","Audit Azure SQL servers which do not have vulnerability assessment properly configured. Vulnerability assessment can discover, track, and help you remediate potential database vulnerabilities.","Azure_Security_Benchmark_v3.0_PV-5, -NIST_SP_800-53_R5_RA-5","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"4fa4b6c0-31ca-4c0d-b10d-24b96f62a751","","BuiltIn","Storage","[Preview]: Storage account public access should be disallowed","Anonymous public read access to containers and blobs in Azure Storage is a convenient way to share data but might present security risks. To prevent data breaches caused by undesired anonymous access, Microsoft recommends preventing public access to a storage account unless your scenario requires it.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: audit (PolicySet Default), -NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","audit","audit","audit","audit","","","","" -"1d320205-c6a1-4ac6-873d-46224024e8e2","","BuiltIn","Storage","Azure File Sync should use private link","Creating a private endpoint for the indicated Storage Sync Service resource allows you to address your Storage Sync Service resource from within the private IP address space of your organization's network, rather than through the internet-accessible public endpoint. Creating a private endpoint by itself does not disable the public endpoint.","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"bf045164-79ba-4215-8f95-f8048dc1780b","","BuiltIn","Storage","Geo-redundant storage should be enabled for Storage Accounts","Use geo-redundancy to create highly available applications","NIST_SP_800-53_R5_CP-6, -NIST_SP_800-53_R5_CP-6(1)","NIST-800-53: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" -"970f84d8-71b6-4091-9979-ace7e3fb6dbb","","BuiltIn","Storage","HPC Cache accounts should use customer-managed key for encryption","Manage encryption at rest of Azure HPC Cache with customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"404c3081-a854-4457-ae30-26a93ef643f9","","BuiltIn","Storage","Secure transfer to storage accounts should be enabled","Audit requirement of Secure transfer in your storage account. Secure transfer is an option that forces your storage account to accept requests only from secure connections (HTTPS). Use of HTTPS ensures authentication between the server and the service and protects data in transit from network layer attacks such as man-in-the-middle, eavesdropping, and session-hijacking","Azure_Security_Benchmark_v3.0_DP-3, -NIST_SP_800-53_R5_SC-8, -NIST_SP_800-53_R5_SC-8(1)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"b5ec538c-daa0-4006-8596-35468b9148e8","","BuiltIn","Storage","Storage account encryption scopes should use customer-managed keys to encrypt data at rest","Use customer-managed keys to manage the encryption at rest of your storage account encryption scopes. Customer-managed keys enable the data to be encrypted with an Azure key-vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more about storage account encryption scopes at https://aka.ms/encryption-scopes-overview.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"37e0d2fe-28a5-43d6-a273-67d37d1f5606","","BuiltIn","Storage","Storage accounts should be migrated to new Azure Resource Manager resources","Use new Azure Resource Manager for your storage accounts to provide security enhancements such as: stronger access control (RBAC), better auditing, Azure Resource Manager based deployment and governance, access to managed identities, access to key vault for secrets, Azure AD-based authentication and support for tags and resource groups for easier security management","Azure_Security_Benchmark_v3.0_AM-2, -NIST_SP_800-53_R5_AC-3","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"4733ea7b-a883-42fe-8cac-97454c2a9e4a","","BuiltIn","Storage","Storage accounts should have infrastructure encryption","Enable infrastructure encryption for higher level of assurance that the data is secure. When infrastructure encryption is enabled, data in a storage account is encrypted twice.","NIST_SP_800-53_R5_SC-28, -NIST_SP_800-53_R5_SC-28(1)","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"34c877ad-507e-4c82-993e-3452a6e0ad3c","","BuiltIn","Storage","Storage accounts should restrict network access","Network access to storage accounts should be restricted. Configure network rules so only applications from allowed networks can access the storage account. To allow connections from specific internet or on-premises clients, access can be granted to traffic from specific Azure virtual networks or to public internet IP address ranges","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Disabled (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Disabled","Disabled","Disabled","Disabled","","","","" -"2a1a9cdf-e04d-429a-8416-3bfb72a1b26f","","BuiltIn","Storage","Storage accounts should restrict network access using virtual network rules","Protect your storage accounts from potential threats using virtual network rules as a preferred method instead of IP-based filtering. Disabling IP-based filtering prevents public IPs from accessing your storage accounts.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"6fac406b-40ca-413b-bf8e-0bf964659c25","","BuiltIn","Storage","Storage accounts should use customer-managed key for encryption","Secure your blob and file storage account with greater flexibility using customer-managed keys. When you specify a customer-managed key, that key is used to protect and control access to the key that encrypts your data. Using customer-managed keys provides additional capabilities to control rotation of the key encryption key or cryptographically erase data.","Azure_Security_Benchmark_v3.0_DP-5, -NIST_SP_800-53_R5_SC-12","ASB: Disabled (PolicySet Default), -NIST-800-53: Audit (Policy Default)","Disabled, -Audit","Disabled","Disabled","Disabled","Disabled","","","","" -"6edd7eda-6dd8-40f7-810d-67160c639cd9","","BuiltIn","Storage","Storage accounts should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your storage account, data leakage risks are reduced. Learn more about private links at - https://aka.ms/azureprivatelinkoverview","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"87ba29ef-1ab3-4d82-b763-87fcd4f531f7","","BuiltIn","Stream Analytics","Azure Stream Analytics jobs should use customer-managed keys to encrypt data","Use customer-managed keys when you want to securely store any metadata and private data assets of your Stream Analytics jobs in your storage account. This gives you total control over how your Stream Analytics data is encrypted.","NIST_SP_800-53_R5_SC-12","NIST-800-53: audit (PolicySet Default)","audit, -disabled, -deny","audit","audit","audit","audit","","","","" -"f9be5368-9bf5-4b84-9e0a-7850da98bb46","","BuiltIn","Stream Analytics","Resource logs in Azure Stream Analytics should be enabled","Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised","Azure_Security_Benchmark_v3.0_LT-3, -NIST_SP_800-53_R5_AU-6(4), -NIST_SP_800-53_R5_AU-6(5), -NIST_SP_800-53_R5_AU-12, -NIST_SP_800-53_R5_AU-12(1)","ASB: AuditIfNotExists (PolicySet Default), -NIST-800-53: AuditIfNotExists (Policy Default)","Disabled, -AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","{""diagnosticsLogsInStreamAnalyticsRetentionDays"":""1""}","{""diagnosticsLogsInStreamAnalyticsRetentionDays"":""1""}","{""diagnosticsLogsInStreamAnalyticsRetentionDays"":""1""}","{""diagnosticsLogsInStreamAnalyticsRetentionDays"":""1""}" -"f7d52b2d-e161-4dfa-a82b-55e564167385","","BuiltIn","Synapse","Azure Synapse workspaces should use customer-managed keys to encrypt data at rest","Use customer-managed keys to control the encryption at rest of the data stored in Azure Synapse workspaces. Customer-managed keys deliver double encryption by adding a second layer of encryption on top of the default encryption with service-managed keys.","NIST_SP_800-53_R5_SC-12","NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"72d11df1-dd8a-41f7-8925-b05b960ebafc","","BuiltIn","Synapse","Azure Synapse workspaces should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Synapse workspace, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/synapse-analytics/security/how-to-connect-to-workspace-with-private-links.","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" -"2158ddbe-fefa-408e-b43f-d4faef8ff3b8","","BuiltIn","Synapse","Synapse Workspaces should use only Azure Active Directory identities for authentication","Azure Active Directory (AAD) only authentication methods improves security by ensuring that Synapse Workspaces exclusively require AAD identities for authentication. Learn more at: https://aka.ms/Synapse.","Azure_Security_Benchmark_v3.0_DP-4","ASB: Audit (Policy Default)","Audit, -Deny, -Disabled","Audit","Audit","Audit","Audit","","","","" -"0049a6b3-a662-4f3e-8635-39cf44ace45a","","BuiltIn","Synapse","Vulnerability assessment should be enabled on your Synapse workspaces","Discover, track, and remediate potential vulnerabilities by configuring recurring SQL vulnerability assessment scans on your Synapse workspaces.","NIST_SP_800-53_R5_RA-5","NIST-800-53: AuditIfNotExists (Policy Default)","AuditIfNotExists, -Disabled","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","AuditIfNotExists","","","","" -"bd876905-5b84-4f73-ab2d-2e7a7c4568d9","","BuiltIn","Update Management Center","[Preview]: Machines should be configured to periodically check for missing system updates","To ensure periodic assessments for missing system updates are triggered automatically every 24 hours, the AssessmentMode property should be set to 'AutomaticByPlatform'. Learn more about AssessmentMode property for Windows: https://aka.ms/computevm-windowspatchassessmentmode, for Linux: https://aka.ms/computevm-linuxpatchassessmentmode.","Azure_Security_Benchmark_v3.0_PV-6","ASB: Audit (PolicySet Default)","Disabled, -Audit","Audit","Audit","Audit","Audit","","","","" -"2154edb9-244f-4741-9970-660785bccdaa","","BuiltIn","VM Image Builder","VM Image Builder templates should use private link","Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your VM Image Builder building resources, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/virtual-machines/linux/image-builder-networking#deploy-using-an-existing-vnet.","Azure_Security_Benchmark_v3.0_NS-2, -NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","ASB: Audit (PolicySet Default), -NIST-800-53: Audit (PolicySet Default)","Audit, -Disabled, -Deny","Audit","Audit","Audit","Audit","","","","" -"eb907f70-7514-460d-92b3-a5ae93b4f917","","BuiltIn","Web PubSub","Azure Web PubSub Service should use private link","Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Azure Web PubSub Service, you can reduce data leakage risks. Learn more about private links at: https://aka.ms/awps/privatelink.","NIST_SP_800-53_R5_AC-4, -NIST_SP_800-53_R5_AC-17, -NIST_SP_800-53_R5_AC-17(1), -NIST_SP_800-53_R5_SC-7, -NIST_SP_800-53_R5_SC-7(3)","NIST-800-53: Audit (Policy Default)","Audit, -Disabled","Audit","Audit","Audit","Audit","","","","" diff --git a/StarterKit/Pipelines/AzureDevOps/GitHub-Flow/epac-dev-pipeline.yml b/StarterKit/Pipelines/AzureDevOps/GitHub-Flow/epac-dev-pipeline.yml new file mode 100644 index 00000000..2210e8c0 --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/GitHub-Flow/epac-dev-pipeline.yml @@ -0,0 +1,81 @@ +variables: + # This pipeline is used to deploy Policies, Initiative definitions and Assignments into Azure. + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + + # Use the plain text name of each service connection as a reference + devServiceConnection: "sc-epac-dev" + +# what to build trigger +trigger: + branches: + include: + - feature/* + paths: + include: + - Definitions + - Pipelines + +pr: none + +pool: + vmImage: "ubuntu-latest" + +stages: + - stage: Plan + displayName: "Plan epac-dev" + jobs: + - job: Plan + steps: + - template: templates/plan.yml + parameters: + serviceConnection: $(devServiceConnection) + pacEnvironmentSelector: epac-dev + + - stage: Deploy + displayName: "Deploy epac-dev" + dependsOn: Plan + condition: and(not(failed()), not(canceled()), or(eq(dependencies.Plan.outputs['Plan.Plan.deployPolicyChanges'], 'yes'), eq(dependencies.Plan.outputs['Plan.Plan.deployRoleChanges'], 'yes'))) + variables: + PAC_INPUT_FOLDER: "$(Pipeline.Workspace)/plans-epac-dev" + localDeployPolicyChanges: $[stageDependencies.Plan.Plan.outputs['Plan.deployPolicyChanges']] + localDeployRoleChanges: $[stageDependencies.Plan.Plan.outputs['Plan.deployRoleChanges']] + jobs: + - deployment: DeployPolicy + displayName: "Deploy Policy Changes" + environment: PAC-DEV + condition: and(not(failed()), not(canceled()), eq(variables.localDeployPolicyChanges, 'yes')) + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-policy.yml + parameters: + serviceConnection: $(devServiceConnection) + pacEnvironmentSelector: epac-dev + - deployment: DeployRoles + displayName: "Deploy Role Changes" + dependsOn: DeployPolicy + environment: PAC-DEV + condition: and(not(failed()), not(canceled()), eq(variables.localDeployRoleChanges, 'yes')) + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-roles.yml + parameters: + serviceConnection: $(devServiceConnection) + pacEnvironmentSelector: epac-dev + + - stage: tenantPlan + displayName: "Plan tenant" + dependsOn: + - Deploy + condition: and(not(failed()), not(canceled())) + jobs: + - job: Plan + steps: + - template: templates/plan.yml + parameters: + serviceConnection: $(devServiceConnection) + pacEnvironmentSelector: tenant diff --git a/StarterKit/Pipelines/AzureDevOps/GitHub-Flow/epac-remediation-pipeline.yml b/StarterKit/Pipelines/AzureDevOps/GitHub-Flow/epac-remediation-pipeline.yml new file mode 100644 index 00000000..913e907a --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/GitHub-Flow/epac-remediation-pipeline.yml @@ -0,0 +1,50 @@ +variables: + # This pipeline is used to auto remdiate Azure policy that are non-compliant. + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + + ## Use the plain text name of each service connection as a reference + remediationServiceConnection: "sc-epac-tenant-remediation" + +# what to build trigger +trigger: none +pr: none + +pool: + vmImage: "ubuntu-latest" + +## Change the cron job schedule according to the requirement +# cron: '0 5,17 * * *' # UTC 5:00 AM daily, midnight and noon EST (might be useful for VMs that are not running 24/7) +# cron: '0 5 * * 0' # UTC 5:00 AM on Sundays only, midnight EST (0=Sunday,1=Monday,2=Tuesday,3=Wednesday,4=Thursday,5=Friday,6=Saturday) +schedules: +- cron: '0 5 * * *' # UTC 5:00 AM daily, midnight EST + displayName: Daily midnight (EST) run + branches: + include: + - main + always: true + +stages: + - stage: epacDev + dependsOn: [] + displayName: "Remediate epac-dev environment" + jobs: + - job: remediation + displayName: "Remediation Job" + steps: + - template: templates/remediate.yml + parameters: + serviceConnection: $(remediationServiceConnection) + pacEnvironmentSelector: epac-dev + + - stage: tenant + dependsOn: [] + displayName: "Remediation tenant environment" + jobs: + - job: remediation + steps: + - template: templates/remediate.yml + parameters: + serviceConnection: $(remediationServiceConnection) + pacEnvironmentSelector: tenant + diff --git a/StarterKit/Pipelines/AzureDevOps/GitHub-Flow/epac-tenant-pipeline.yml b/StarterKit/Pipelines/AzureDevOps/GitHub-Flow/epac-tenant-pipeline.yml new file mode 100644 index 00000000..fe6e45ba --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/GitHub-Flow/epac-tenant-pipeline.yml @@ -0,0 +1,63 @@ +variables: + # This pipeline is used to deploy Policies, Initiative definitions and Assignments into Azure. + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + + # Use the plain text name of each service connection as a reference + planServiceConnection: "sc-epac-tenant-plan" + deployServiceConnection: "sc-epac-tenant-deploy" + rolesServiceConnection: "sc-epac-tenant-roles" + +# what to build trigger +trigger: none +pr: none + +pool: + vmImage: "ubuntu-latest" + +stages: + - stage: Plan + displayName: "Plan tenant" + jobs: + - job: Plan + steps: + - template: templates/plan.yml + parameters: + serviceConnection: $(planServiceConnection) + pacEnvironmentSelector: tenant + + - stage: Deploy + displayName: "Deploy tenant" + dependsOn: Plan + condition: and(not(failed()), not(canceled()), or(eq(dependencies.Plan.outputs['Plan.Plan.deployPolicyChanges'], 'yes'), eq(dependencies.Plan.outputs['Plan.Plan.deployRoleChanges'], 'yes')), contains(variables['Build.SourceBranch'], 'refs/heads/main')) + variables: + PAC_INPUT_FOLDER: "$(Pipeline.Workspace)/plans-tenant" + localDeployPolicyChanges: $[stageDependencies.Plan.Plan.outputs['Plan.deployPolicyChanges']] + localDeployRoleChanges: $[stageDependencies.Plan.Plan.outputs['Plan.deployRoleChanges']] + jobs: + - deployment: DeployPolicy + displayName: "Deploy Policy Changes" + environment: PAC-POLICY + condition: and(not(failed()), not(canceled()), eq(variables.localDeployPolicyChanges, 'yes')) + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-policy.yml + parameters: + serviceConnection: $(deployPolicyServiceConnection) + pacEnvironmentSelector: tenant + - deployment: DeployRoles + displayName: "Deploy Role Changes" + dependsOn: DeployPolicy + environment: PAC-POLICY + condition: and(not(failed()), not(canceled()), eq(variables.localDeployRoleChanges, 'yes')) + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-roles.yml + parameters: + serviceConnection: $(deployRolesServiceConnection) + pacEnvironmentSelector: tenant + diff --git a/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-dev-pipeline.yml b/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-dev-pipeline.yml new file mode 100644 index 00000000..4847b783 --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-dev-pipeline.yml @@ -0,0 +1,95 @@ +variables: + # This pipeline is used to deploy Policies, Initiative definitions and Assignments into Azure. + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Test/Pipelines/Definitions + + # Use the plain text name of each service connection as a reference + devServiceConnection: "sc-epac-dev" + +# what to build trigger +trigger: + branches: + include: + - feature/* + paths: + include: + - Definitions + - Pipelines + +pr: none + +pool: + vmImage: "ubuntu-latest" + +stages: + - stage: Plan + displayName: "Plan epac-dev" + jobs: + - job: Plan + steps: + - template: templates/plan.yml + parameters: + serviceConnection: $(devServiceConnection) + pacEnvironmentSelector: epac-dev + + - stage: Deploy + displayName: "Deploy epac-dev" + dependsOn: Plan + condition: and(not(failed()), not(canceled()), or(eq(dependencies.Plan.outputs['Plan.Plan.deployPolicyChanges'], 'yes'), eq(dependencies.Plan.outputs['Plan.Plan.deployRoleChanges'], 'yes'))) + variables: + PAC_INPUT_FOLDER: "$(Pipeline.Workspace)/plans-epac-dev" + localDeployPolicyChanges: $[stageDependencies.Plan.Plan.outputs['Plan.deployPolicyChanges']] + localDeployRoleChanges: $[stageDependencies.Plan.Plan.outputs['Plan.deployRoleChanges']] + jobs: + - deployment: DeployPolicy + displayName: "Deploy Policy Changes" + environment: PAC-DEV + condition: and(not(failed()), not(canceled()), eq(variables.localDeployPolicyChanges, 'yes')) + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-policy.yml + parameters: + serviceConnection: $(devServiceConnection) + pacEnvironmentSelector: epac-dev + - deployment: DeployRoles + displayName: "Deploy Role Changes" + dependsOn: DeployPolicy + environment: PAC-DEV + condition: and(not(failed()), not(canceled()), eq(variables.localDeployRoleChanges, 'yes')) + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-roles.yml + parameters: + serviceConnection: $(devServiceConnection) + pacEnvironmentSelector: epac-dev + + + - stage: nonprodPlan + displayName: "Plan nonprod" + dependsOn: + - Deploy + condition: and(not(failed()), not(canceled())) + jobs: + - job: Plan + steps: + - template: templates/plan.yml + parameters: + serviceConnection: $(devServiceConnection) + pacEnvironmentSelector: nonprod + + - stage: prodPlan + displayName: "Plan prod" + dependsOn: + - Deploy + condition: and(not(failed()), not(canceled())) + jobs: + - job: Plan + steps: + - template: templates/plan.yml + parameters: + serviceConnection: $(devServiceConnection) + pacEnvironmentSelector: prod diff --git a/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-nonprod-pipeline.yml b/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-nonprod-pipeline.yml new file mode 100644 index 00000000..0bbb393f --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-nonprod-pipeline.yml @@ -0,0 +1,68 @@ +variables: + # This pipeline is used to deploy Policies, Initiative definitions and Assignments into Azure. + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + + # Use the plain text name of each service connection as a reference + planServiceConnection: "sc-epac-tenant-plan" + deployServiceConnection: "sc-epac-nonprod-deploy" + rolesServiceConnection: "sc-epac-nonprod-roles" + + # set the environment selector + pacEnvironmentSelector: nonprod + +# what to build trigger +trigger: +- main + +pr: none + +pool: + vmImage: "ubuntu-latest" + +stages: + - stage: Plan + displayName: "Plan nonprod" + jobs: + - job: Plan + steps: + - template: templates/plan.yml + parameters: + serviceConnection: $(planServiceConnection) + pacEnvironmentSelector: nonprod + + - stage: Deploy + displayName: "Deploy nonprod" + dependsOn: Plan + condition: and(not(failed()), not(canceled()), or(eq(dependencies.Plan.outputs['Plan.Plan.deployPolicyChanges'], 'yes'), eq(dependencies.Plan.outputs['Plan.Plan.deployRoleChanges'], 'yes')), contains(variables['Build.SourceBranch'], 'refs/heads/main')) + variables: + PAC_INPUT_FOLDER: "$(Pipeline.Workspace)/plans-nonprod" + localDeployPolicyChanges: $[stageDependencies.Plan.Plan.outputs['Plan.deployPolicyChanges']] + localDeployRoleChanges: $[stageDependencies.Plan.Plan.outputs['Plan.deployRoleChanges']] + jobs: + - deployment: DeployPolicy + displayName: "Deploy Policy Changes" + environment: PAC-POLICY + condition: and(not(failed()), not(canceled()), eq(variables.localDeployPolicyChanges, 'yes')) + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-policy.yml + parameters: + serviceConnection: $(deployPolicyServiceConnection) + pacEnvironmentSelector: nonprod + - deployment: DeployRoles + displayName: "Deploy Role Changes" + dependsOn: DeployPolicy + environment: PAC-POLICY + condition: and(not(failed()), not(canceled()), eq(variables.localDeployRoleChanges, 'yes')) + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-roles.yml + parameters: + serviceConnection: $(deployRolesServiceConnection) + pacEnvironmentSelector: nonprod + diff --git a/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-prod-exemptions-only-pipeline.yml b/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-prod-exemptions-only-pipeline.yml new file mode 100644 index 00000000..615734e6 --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-prod-exemptions-only-pipeline.yml @@ -0,0 +1,53 @@ +variables: + # This pipeline is used to deploy Policies, Initiative definitions and Assignments into Azure. + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + + # Use the plain text name of each service connection as a reference + tenantPlanServiceConnection: "epac-mg-prod" + tenantDeployServiceConnection: "epac-mg-prod" + tenantRolesServiceConnection: "epac-mg-prod" + + # System.Debug: true + +# what to build trigger +trigger: +- releases-exemptions-only/* + +pr: none + +pool: + vmImage: "ubuntu-latest" + +stages: + - stage: Plan + displayName: "Plan prod Exemptions Only" + jobs: + - job: Plan + steps: + - template: templates/plan-exemptions-only.yml + parameters: + serviceConnection: $(planServiceConnection) + pacEnvironmentSelector: prod + + - stage: Deploy + displayName: "Deploy prod Exemptions Only" + dependsOn: Plan + condition: and(not(failed()), not(canceled()), eq(dependencies.Plan.outputs['Plan.Plan.deployPolicyChanges'], 'yes'), contains(variables['Build.SourceBranch'], 'releases-exemptions-only/')) + variables: + PAC_INPUT_FOLDER: "$(Pipeline.Workspace)/plans-prod" + localDeployPolicyChanges: $[stageDependencies.Plan.Plan.outputs['Plan.deployPolicyChanges']] + localDeployRoleChanges: $[stageDependencies.Plan.Plan.outputs['Plan.deployRoleChanges']] + jobs: + - deployment: DeployPolicy + displayName: "Deploy Policy Changes" + environment: PAC-POLICY + condition: and(not(failed()), not(canceled()), eq(variables.localDeployPolicyChanges, 'yes')) + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-policy.yml + parameters: + serviceConnection: $(deployPolicyServiceConnection) + pacEnvironmentSelector: prod diff --git a/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-prod-pipeline.yml b/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-prod-pipeline.yml new file mode 100644 index 00000000..3fea46c0 --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-prod-pipeline.yml @@ -0,0 +1,68 @@ +variables: + # This pipeline is used to deploy Policies, Initiative definitions and Assignments into Azure. + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + + # Use the plain text name of each service connection as a reference + planServiceConnection: "sc-epac-tenant-plan" + deployServiceConnection: "sc-epac-prod-deploy" + rolesServiceConnection: "sc-epac-prod-roles" + + # set the environment selector + pacEnvironmentSelector: prod + +# what to build trigger +trigger: +- releases-prod/* + +pr: none + +pool: + vmImage: "ubuntu-latest" + +stages: + - stage: Plan + displayName: "Plan prod" + jobs: + - job: Plan + steps: + - template: templates/plan.yml + parameters: + serviceConnection: $(planServiceConnection) + pacEnvironmentSelector: prod + + - stage: Deploy + displayName: "Deploy prod" + dependsOn: Plan + condition: and(not(failed()), not(canceled()), or(eq(dependencies.Plan.outputs['Plan.Plan.deployPolicyChanges'], 'yes'), eq(dependencies.Plan.outputs['Plan.Plan.deployRoleChanges'], 'yes')), contains(variables['Build.SourceBranch'], 'releases-prod/') + variables: + PAC_INPUT_FOLDER: "$(Pipeline.Workspace)/plans-prod" + localDeployPolicyChanges: $[stageDependencies.Plan.Plan.outputs['Plan.deployPolicyChanges']] + localDeployRoleChanges: $[stageDependencies.Plan.Plan.outputs['Plan.deployRoleChanges']] + jobs: + - deployment: DeployPolicy + displayName: "Deploy Policy Changes" + environment: PAC-POLICY + condition: and(not(failed()), not(canceled()), eq(variables.localDeployPolicyChanges, 'yes')) + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-policy.yml + parameters: + serviceConnection: $(deployPolicyServiceConnection) + pacEnvironmentSelector: prod + - deployment: DeployRoles + displayName: "Deploy Role Changes" + dependsOn: DeployPolicy + environment: PAC-POLICY + condition: and(not(failed()), not(canceled()), eq(variables.localDeployRoleChanges, 'yes')) + strategy: + runOnce: + deploy: + steps: + - template: templates/deploy-roles.yml + parameters: + serviceConnection: $(deployRolesServiceConnection) + pacEnvironmentSelector: prod + diff --git a/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-remediation-pipeline.yml b/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-remediation-pipeline.yml new file mode 100644 index 00000000..d4c5e933 --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/Release-Flow/epac-remediation-pipeline.yml @@ -0,0 +1,60 @@ +variables: + # This pipeline is used to auto remdiate Azure policy that are non-compliant. + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + + ## Use the plain text name of each service connection as a reference + remediationServiceConnection: "sc-epac-tenant-remediation" + +# what to build trigger +trigger: none +pr: none + +pool: + vmImage: "ubuntu-latest" + +## Change the cron job schedule according to the requirement +# cron: '0 5,17 * * *' # UTC 5:00 AM daily, midnight and noon EST (might be useful for VMs that are not running 24/7) +# cron: '0 5 * * 0' # UTC 5:00 AM on Sundays only, midnight EST (0=Sunday,1=Monday,2=Tuesday,3=Wednesday,4=Thursday,5=Friday,6=Saturday) +schedules: +- cron: '0 5 * * *' # UTC 5:00 AM daily, midnight EST + displayName: Daily midnight (EST) run + branches: + include: + - main + always: true + +stages: + - stage: epacDev + dependsOn: [] + displayName: "Remediate epac-dev environment" + jobs: + - job: remediation + displayName: "Remediation Job" + steps: + - template: templates/remediate.yml + parameters: + serviceConnection: $(remediationServiceConnection) + pacEnvironmentSelector: epac-dev + + - stage: nonprod + dependsOn: [] + displayName: "Remediation nonprod environment" + jobs: + - job: remediation + steps: + - template: templates/remediate.yml + parameters: + serviceConnection: $(remediationServiceConnection) + pacEnvironmentSelector: nonprod + + - stage: prod + dependsOn: [] + displayName: "Remediation prod environment" + jobs: + - job: remediation + steps: + - template: templates/remediate.yml + parameters: + serviceConnection: $(remediationServiceConnection) + pacEnvironmentSelector: prod diff --git a/StarterKit/Pipelines/AzureDevOps/multi-tenant-pipeline.yml b/StarterKit/Pipelines/AzureDevOps/multi-tenant-pipeline.yml deleted file mode 100644 index 66e497f1..00000000 --- a/StarterKit/Pipelines/AzureDevOps/multi-tenant-pipeline.yml +++ /dev/null @@ -1,351 +0,0 @@ -variables: - # This pipeline is used to deploy Policies, Initiative definitions and Assignments into Azure. - PAC_OUTPUT_FOLDER: ./Output - PAC_DEFINITIONS_FOLDER: ./Definitions - - # Use the plain text name of each service connection as a reference - devServiceConnection: "sc-epac-dev" - tenant1PlanServiceConnection: "sc-epac-plan-tenant1" - tenant1DeployServiceConnection: "sc-epac-prod-tenant1" - tenant1RolesServiceConnection: "sc-epac-roles-tenant1" - tenant2PlanServiceConnection: "sc-epac-plan-tenant2" - tenant2DeployServiceConnection: "sc-epac-prod-tenant2" - tenant2RolesServiceConnection: "sc-epac-roles-tenant2" - tenant3PlanServiceConnection: "sc-epac-plan-tenant3" - tenant3DeployServiceConnection: "sc-epac-prod-tenant3" - tenant3RolesServiceConnection: "sc-epac-roles-tenant3" - - # System.Debug: true - -# what to build trigger -trigger: - branches: - include: - - /* - paths: - include: - - / - -pr: none - -# pool: Linux_pool -# empty = Azure pool - -stages: - - stage: devStage - displayName: "DEV Plan, Deploy Policies, Roles" - condition: and(in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), not(contains(variables['Build.SourceBranch'], 'refs/heads/main'))) - variables: - pacEnvironmentSelector: epac-dev - jobs: - - deployment: allJob - environment: PAC-DEV - strategy: - runOnce: - deploy: - steps: - - checkout: self - - task: AzurePowerShell@5 - name: planStep - displayName: Plan - inputs: - azureSubscription: $(devServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Build-DeploymentPlans.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -devOpsType "ado" ` - -InformationAction Continue - # Publish pipeline Artifact for ADO Service - - publish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - artifact: "plans-$(pacEnvironmentSelector)" - condition: and(succeeded(), or(eq(variables['planStep.deployPolicyChanges'], 'yes'), eq(variables['planStep.deployRoleChanges'], 'yes'))) - # Publish build artifact for ADO Server - # - task: PublishBuildArtifacts@1 - # inputs: - # pathToPublish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - # artifactName: "plans-$(pacEnvironmentSelector)" - # condition: and(succeeded(), or(eq(variables['planStep.deployPolicyChanges'], 'yes'), eq(variables['planStep.deployRoleChanges'], 'yes'))) - # End Publish - - task: AzurePowerShell@5 - displayName: Deploy PAC-DEV Policy - condition: and(succeeded(), eq(variables['planStep.deployPolicyChanges'], 'yes')) - inputs: - azureSubscription: $(devServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Deploy-PolicyPlan.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -InformationAction Continue - - task: AzurePowerShell@5 - displayName: Deploy PAC-DEV Role Assignments - condition: and(not(failed()), not(canceled()), eq(variables['planStep.deployRoleChanges'], 'yes')) - inputs: - azureSubscription: $(devServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Deploy-RolesPlan.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -InformationAction Continue - - stage: tenant1PlanFeatureStage - displayName: "Tenant 1 Plan - Feature Branch" - dependsOn: - - devStage - condition: and(not(failed()), not(canceled()), in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), not(contains(variables['Build.SourceBranch'], 'refs/heads/main'))) - variables: - pacEnvironmentSelector: tenant1 - jobs: - - job: planJob - steps: - - checkout: self - - task: AzurePowerShell@5 - name: planStep - displayName: Plan - inputs: - azureSubscription: $(tenant1PlanServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Build-DeploymentPlans.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -devOpsType "ado" ` - -InformationAction Continue - # Publish pipeline Artifact for ADO Service - - publish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - artifact: "plans-feature-branch-$(pacEnvironmentSelector)" - condition: and(succeeded(), or(eq(variables['planStep.deployPolicyChanges'], 'yes'), eq(variables['planStep.deployRoleChanges'], 'yes'))) - # Publish build artifact for ADO Server - # - task: PublishBuildArtifacts@1 - # inputs: - # pathToPublish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - # artifactName: "plans-feature-branch-$(pacEnvironmentSelector)" - # condition: and(succeeded(), or(eq(variables['planStep.deployPolicyChanges'], 'yes'), eq(variables['planStep.deployRoleChanges'], 'yes'))) - # End Publish - - stage: tenant2PlanFeatureStage - displayName: "Tenant 2 Plan - Feature Branch" - dependsOn: - - devStage - condition: and(not(failed()), not(canceled()), in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), not(contains(variables['Build.SourceBranch'], 'refs/heads/main'))) - variables: - pacEnvironmentSelector: tenant2 - jobs: - - job: planJob - steps: - - checkout: self - - task: AzurePowerShell@5 - name: planStep - displayName: Plan - inputs: - azureSubscription: $(tenantPlanServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Build-DeploymentPlans.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -devOpsType "ado" ` - -InformationAction Continue - # Publish pipeline Artifact for ADO Service - - publish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - artifact: "plans-feature-branch-$(pacEnvironmentSelector)" - condition: and(succeeded(), or(eq(variables['planStep.deployPolicyChanges'], 'yes'), eq(variables['planStep.deployRoleChanges'], 'yes'))) - # Publish build artifact for ADO Server - # - task: PublishBuildArtifacts@1 - # inputs: - # pathToPublish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - # artifactName: "plans-feature-branch-$(pacEnvironmentSelector)" - # condition: and(succeeded(), or(eq(variables['planStep.deployPolicyChanges'], 'yes'), eq(variables['planStep.deployRoleChanges'], 'yes'))) - # End Publish - - stage: completedFeature - displayName: "Tenant 1 and 2 Completed Plans - Feature Branch" - dependsOn: - - tenant1PlanFeatureStage - - tenant2PlanFeatureStage - condition: and(not(failed()), not(canceled()), in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), not(contains(variables['Build.SourceBranch'], 'refs/heads/main'))) - jobs: - - job: - steps: - - checkout: self - - task: PowerShell@2 - inputs: - targetType: "inline" - script: | - Write-Host "Completed Plans - Feature Branch" - - stage: tenant1PlanMainStage - displayName: "Tenant 1 Plan - Main Branch" - dependsOn: - - completedFeature - condition: and(not(failed()), not(canceled()), in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), contains(variables['Build.SourceBranch'], 'refs/heads/main')) - variables: - pacEnvironmentSelector: tenant1 - jobs: - - job: planJob - steps: - - checkout: self - - task: AzurePowerShell@5 - name: planStep - displayName: Plan - inputs: - azureSubscription: $(tenantPlanServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Build-DeploymentPlans.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -devOpsType "ado" ` - -InformationAction Continue - # Publish pipeline Artifact for ADO Service - - publish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - artifact: "plans-$(pacEnvironmentSelector)" - condition: and(succeeded(), or(eq(variables['planStep.deployPolicyChanges'], 'yes'), eq(variables['planStep.deployRoleChanges'], 'yes'))) - # Publish build artifact for ADO Server - # - task: PublishBuildArtifacts@1 - # inputs: - # pathToPublish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - # artifactName: "policy-plan-$(pacEnvironmentSelector)" - # condition: and(succeeded(), or(eq(variables['planStep.deployPolicyChanges'], 'yes'), eq(variables['planStep.deployRoleChanges'], 'yes'))) - # End Publish - - stage: tenant1DeployPolicyStage - displayName: "Tenant 1 Deploy Policy" - dependsOn: - - tenant1PlanMainStage - condition: and(not(failed()), not(canceled()), eq(dependencies.tenant1PlanMainStage.outputs['planJob.planStep.deployPolicyChanges'], 'yes'), in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), contains(variables['Build.SourceBranch'], 'refs/heads/main')) - variables: - pacEnvironmentSelector: tenant1 - PAC_INPUT_FOLDER: "$(Pipeline.Workspace)" - jobs: - - deployment: deployPolicyJob - environment: PAC-POLICY - strategy: - runOnce: - deploy: - steps: - - checkout: self - - task: AzurePowerShell@5 - name: deployStep - displayName: Deploy Tenant 1 Policy - inputs: - azureSubscription: $(tenantDeployServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Deploy-PolicyPlan.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -InformationAction Continue - - stage: tenant1RolesStage - displayName: "Tenant 1 Deploy Role Assignments" - dependsOn: - - tenant1DeployPolicyStage - condition: and(not(failed()), not(canceled()), eq(dependencies.tenant1PlanMainStage.outputs['planJob.planStep.deployRoleChanges'], 'yes'), in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), contains(variables['Build.SourceBranch'], 'refs/heads/main')) - variables: - pacEnvironmentSelector: tenant1 - PAC_INPUT_FOLDER: "$(Pipeline.Workspace)" - jobs: - - deployment: rolesJob - environment: PAC-ROLES - strategy: - runOnce: - deploy: - steps: - - checkout: self - - task: AzurePowerShell@5 - displayName: Deploy Tenant 1 Role Assignments - inputs: - azureSubscription: $(tenantRolesServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Deploy-RolesPlan.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -InformationAction Continue - condition: succeeded() - - stage: tenant2PlanMainStage - displayName: "Tenant 2 Plan - Main Branch" - dependsOn: - - completedFeature - condition: and(not(failed()), not(canceled()), in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), contains(variables['Build.SourceBranch'], 'refs/heads/main')) - variables: - pacEnvironmentSelector: tenant2 - jobs: - - job: planJob - steps: - - checkout: self - - task: AzurePowerShell@5 - name: planStep - displayName: Plan - inputs: - azureSubscription: $(tenantPlanServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Build-DeploymentPlans.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -devOpsType "ado" ` - -InformationAction Continue - # Publish pipeline Artifact for ADO Service - - publish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - artifact: "plans-$(pacEnvironmentSelector)" - condition: and(succeeded(), or(eq(variables['planStep.deployPolicyChanges'], 'yes'), eq(variables['planStep.deployRoleChanges'], 'yes'))) - # Publish build artifact for ADO Server - # - task: PublishBuildArtifacts@1 - # inputs: - # pathToPublish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - # artifactName: "policy-plan-$(pacEnvironmentSelector)" - # condition: and(succeeded(), or(eq(variables['planStep.deployPolicyChanges'], 'yes'), eq(variables['planStep.deployRoleChanges'], 'yes'))) - # End Publish - - stage: tenant2DeployPolicyStage - displayName: "Tenant 2 Deploy Policy" - dependsOn: - - tenant2PlanMainStage - condition: and(not(failed()), not(canceled()), eq(dependencies.tenant2PlanMainStage.outputs['planJob.planStep.deployPolicyChanges'], 'yes'), in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), contains(variables['Build.SourceBranch'], 'refs/heads/main')) - variables: - pacEnvironmentSelector: tenant2 - PAC_INPUT_FOLDER: "$(Pipeline.Workspace)" - jobs: - - deployment: deployPolicyJob - environment: PAC-POLICY - strategy: - runOnce: - deploy: - steps: - - checkout: self - - task: AzurePowerShell@5 - name: deployStep - displayName: Deploy Tenant 2 Policy - inputs: - azureSubscription: $(tenantDeployServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Deploy-PolicyPlan.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -InformationAction Continue - - stage: tenant2RolesStage - displayName: "Tenant 2 Deploy Role Assignments" - dependsOn: - - tenant2DeployPolicyStage - condition: and(not(failed()), not(canceled()), eq(dependencies.tenant2PlanMainStage.outputs['planJob.planStep.deployRoleChanges'], 'yes'), in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), contains(variables['Build.SourceBranch'], 'refs/heads/main')) - variables: - pacEnvironmentSelector: tenant2 - PAC_INPUT_FOLDER: "$(Pipeline.Workspace)" - jobs: - - deployment: rolesJob - environment: PAC-ROLES - strategy: - runOnce: - deploy: - steps: - - checkout: self - - task: AzurePowerShell@5 - displayName: Deploy Tenant 2 Role Assignments - inputs: - azureSubscription: $(tenantRolesServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Deploy-RolesPlan.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -InformationAction Continue - condition: succeeded() diff --git a/StarterKit/Pipelines/AzureDevOps/simplified-pipeline.yaml b/StarterKit/Pipelines/AzureDevOps/simplified-pipeline.yaml deleted file mode 100644 index 7345a186..00000000 --- a/StarterKit/Pipelines/AzureDevOps/simplified-pipeline.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# Note - Create an Azure DevOps pipeline environment for the DeployPolicy and DeployRoles stage - it can be the same environment as depicted below. It depends on how you manage approvals for stages etc. - -trigger: none - -variables: - PAC_OUTPUT_FOLDER: ./Output - environment: contoso # Specify the PAC environment here - serviceConnection: example-service-connection # This is the name of the service connection which has permission in Azure - -pool: - vmImage: "ubuntu-latest" - -stages: - - stage: Plan - displayName: Plan Deployment - jobs: - - job: Plan - steps: - - template: templates/build.yaml - parameters: - serviceConnection: $(serviceConnection) - pacEnvironment: $(environment) - - stage: DeployPolicy - displayName: Deploy Policy Changes - condition: and(succeeded(), eq(dependencies.Plan.outputs['Plan.Plan.deployPolicyChanges'], 'yes')) - jobs: - - deployment: - environment: Deploy - strategy: - runOnce: - deploy: - steps: - - template: templates/deploy.yaml - parameters: - serviceConnection: $(serviceConnection) - pacEnvironment: $(environment) - - stage: DeployRoles - displayName: Deploy Role Changes - condition: and(succeeded(), eq(dependencies.Plan.outputs['Plan.Plan.deployRoleChanges'], 'yes')) - jobs: - - deployment: - environment: Deploy - strategy: - runOnce: - deploy: - steps: - - template: templates/rbac.yaml - parameters: - serviceConnection: $(serviceConnection) - pacEnvironment: $(environment) diff --git a/StarterKit/Pipelines/AzureDevOps/single-tenant-pipeline.yml b/StarterKit/Pipelines/AzureDevOps/single-tenant-pipeline.yml deleted file mode 100644 index cf21c46d..00000000 --- a/StarterKit/Pipelines/AzureDevOps/single-tenant-pipeline.yml +++ /dev/null @@ -1,208 +0,0 @@ -variables: - # This pipeline is used to deploy Policies, Initiative definitions and Assignments into Azure. - PAC_OUTPUT_FOLDER: ./Output - PAC_DEFINITIONS_FOLDER: .//Definitions - - # Use the plain text name of each service connection as a reference - devServiceConnection: "sc-epac-dev" - tenantPlanServiceConnection: "sc-epac-plan-tenant" - tenantDeployServiceConnection: "sc-epac-prod-tenant" - tenantRolesServiceConnection: "sc-epac-roles-tenant" - - # System.Debug: true - -# what to build trigger -trigger: - branches: - include: - - /* - paths: - include: - - / - -pr: none - -# pool: Linux_pool -# empty = Azure pool - -stages: - - stage: devStage - displayName: "DEV Plan, Deploy and Roles" - condition: and(in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), not(contains(variables['Build.SourceBranch'], 'refs/heads/main'))) - variables: - pacEnvironmentSelector: epac-dev - jobs: - - deployment: allJob - environment: PAC-DEV - strategy: - runOnce: - deploy: - steps: - - checkout: self - - task: AzurePowerShell@5 - name: planStep - displayName: Plan - inputs: - azureSubscription: $(devServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Build-DeploymentPlans.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -devOpsType "ado" ` - -InformationAction Continue - # Publish pipeline Artifact for ADO Service - - publish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - artifact: "plans-$(pacEnvironmentSelector)" - condition: and(succeeded(), or(eq(variables['planStep.deployPolicyChanges'], 'yes'), eq(variables['planStep.deployRoleChanges'], 'yes'))) - # Publish build artifact for ADO Server - # - task: PublishBuildArtifacts@1 - # inputs: - # pathToPublish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - # artifactName: "plans-$(pacEnvironmentSelector)" - # condition: succeeded() - # End Publish - - task: AzurePowerShell@5 - displayName: Deploy PAC-DEV Policy - condition: and(succeeded(), eq(variables['planStep.deployPolicyChanges'], 'yes')) - inputs: - azureSubscription: $(devServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Deploy-PolicyPlan.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -InformationAction Continue - - task: AzurePowerShell@5 - displayName: Deploy PAC-DEV Role Assignments - condition: and(not(failed()), not(canceled()), eq(variables['planStep.deployRoleChanges'], 'yes')) - inputs: - azureSubscription: $(devServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Deploy-RolesPlan.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -InformationAction Continue - - stage: tenantPlanFeatureStage - displayName: "Tenant Plan - Feature Branch" - dependsOn: - - devStage - condition: and(not(failed()), not(canceled()), in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), not(contains(variables['Build.SourceBranch'], 'refs/heads/main'))) - variables: - pacEnvironmentSelector: tenant - jobs: - - job: planJob - steps: - - checkout: self - - task: AzurePowerShell@5 - name: planStep - displayName: Plan - inputs: - azureSubscription: $(tenantPlanServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Build-DeploymentPlans.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -devOpsType "ado" ` - -InformationAction Continue - # Publish pipeline Artifact for ADO Service - - publish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - artifact: "plans-feature-branch-$(pacEnvironmentSelector)" - condition: and(succeeded(), or(eq(variables['planStep.deployPolicyChanges'], 'yes'), eq(variables['planStep.deployRoleChanges'], 'yes'))) - # Publish build artifact for ADO Server - # - task: PublishBuildArtifacts@1 - # inputs: - # pathToPublish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - # artifactName: "plans-feature-branch-$(pacEnvironmentSelector)" - # condition: succeeded() - # End Publish - - stage: tenantPlanMainStage - displayName: "Tenant Plan - Main Branch" - dependsOn: - - tenantPlanFeatureStage - condition: and(not(failed()), not(canceled()), in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), contains(variables['Build.SourceBranch'], 'refs/heads/main')) - variables: - pacEnvironmentSelector: tenant - jobs: - - job: planJob - steps: - - checkout: self - - task: AzurePowerShell@5 - name: planStep - displayName: Plan - inputs: - azureSubscription: $(tenantPlanServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Build-DeploymentPlans.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -devOpsType "ado" ` - -InformationAction Continue - # Publish pipeline Artifact for ADO Service - - publish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - artifact: "plans-$(pacEnvironmentSelector)" - condition: and(succeeded(), or(eq(variables['planStep.deployPolicyChanges'], 'yes'), eq(variables['planStep.deployRoleChanges'], 'yes'))) - # Publish build artifact for ADO Server - # - task: PublishBuildArtifacts@1 - # inputs: - # pathToPublish: "$(PAC_OUTPUT_FOLDER)/plans-$(pacEnvironmentSelector)" - # artifactName: "policy-plan-$(pacEnvironmentSelector)" - # condition: succeeded() - # End Publish - - stage: tenantDeployPolicyStage - displayName: "Tenant Deploy Policy" - dependsOn: - - tenantPlanMainStage - condition: and(not(failed()), not(canceled()), eq(dependencies.tenantPlanMainStage.outputs['planJob.planStep.deployPolicyChanges'], 'yes'), in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), contains(variables['Build.SourceBranch'], 'refs/heads/main')) - variables: - pacEnvironmentSelector: tenant - PAC_INPUT_FOLDER: "$(Pipeline.Workspace)" - jobs: - - deployment: deployPolicyJob - environment: PAC-POLICY - strategy: - runOnce: - deploy: - steps: - - checkout: self - - task: AzurePowerShell@5 - name: deployStep - displayName: Deploy Tenant1 Policy - inputs: - azureSubscription: $(tenantDeployServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Deploy-PolicyPlan.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -InformationAction Continue - - stage: tenantRolesStage - displayName: "Tenant Deploy Role Assignments" - dependsOn: - - tenantDeployPolicyStage - condition: and(not(failed()), not(canceled()), eq(dependencies.tenantPlanMainStage.outputs['planJob.planStep.deployRoleChanges'], 'yes'), in(variables['Build.Reason'], 'Manual', 'IndividualCI', 'BatchedCI'), contains(variables['Build.SourceBranch'], 'refs/heads/main')) - variables: - pacEnvironmentSelector: tenant - PAC_INPUT_FOLDER: "$(Pipeline.Workspace)" - jobs: - - deployment: rolesJob - environment: PAC-ROLES - strategy: - runOnce: - deploy: - steps: - - checkout: self - - task: AzurePowerShell@5 - displayName: Deploy Tenant1 Role Assignments - inputs: - azureSubscription: $(tenantRolesServiceConnection) - pwsh: true - azurePowerShellVersion: LatestVersion - ScriptPath: "Scripts/Deploy/Deploy-RolesPlan.ps1" - ScriptArguments: - -pacEnvironmentSelector $(pacEnvironmentSelector) ` - -InformationAction Continue - condition: succeeded() diff --git a/StarterKit/Pipelines/AzureDevOps/templates/deploy.yaml b/StarterKit/Pipelines/AzureDevOps/templates-ps1-module/deploy-policy.yml similarity index 57% rename from StarterKit/Pipelines/AzureDevOps/templates/deploy.yaml rename to StarterKit/Pipelines/AzureDevOps/templates-ps1-module/deploy-policy.yml index 678fda29..d7448a70 100644 --- a/StarterKit/Pipelines/AzureDevOps/templates/deploy.yaml +++ b/StarterKit/Pipelines/AzureDevOps/templates-ps1-module/deploy-policy.yml @@ -1,26 +1,22 @@ parameters: - name: serviceConnection type: string - - name: pacEnvironment + - name: pacEnvironmentSelector type: string - - name: definitionsRootFolder - type: string - default: Definitions steps: - checkout: self - download: current - artifact: "policy-plan-${{ parameters.pacEnvironment }}" + artifact: "plans-${{ parameters.pacEnvironmentSelector }}" - pwsh: | Install-Module EnterprisePolicyAsCode -Force Install-Module Az.ResourceGraph -Force - task: AzurePowerShell@5 - name: Deploy - displayName: Deploy Policies + displayName: Deploy Policy inputs: azureSubscription: ${{ parameters.serviceConnection }} - ScriptType: InlineScript - azurePowerShellVersion: LatestVersion pwsh: true + azurePowerShellVersion: LatestVersion + ScriptType: InlineScript Inline: | - Deploy-PolicyPlan -PacEnvironmentSelector ${{ parameters.pacEnvironment }} -DefinitionsRootFolder ${{ parameters.definitionsRootFolder }} -inputFolder $env:PIPELINE_WORKSPACE/policy-plan-${{ parameters.pacEnvironment }} + Deploy-PolicyPlan -PacEnvironmentSelector ${{ parameters.pacEnvironmentSelector }} -InformationAction Continue diff --git a/StarterKit/Pipelines/AzureDevOps/templates/rbac.yaml b/StarterKit/Pipelines/AzureDevOps/templates-ps1-module/deploy-roles.yml similarity index 61% rename from StarterKit/Pipelines/AzureDevOps/templates/rbac.yaml rename to StarterKit/Pipelines/AzureDevOps/templates-ps1-module/deploy-roles.yml index 5aab8730..7b6506ea 100644 --- a/StarterKit/Pipelines/AzureDevOps/templates/rbac.yaml +++ b/StarterKit/Pipelines/AzureDevOps/templates-ps1-module/deploy-roles.yml @@ -1,26 +1,23 @@ parameters: - name: serviceConnection type: string - - name: pacEnvironment + - name: pacEnvironmentSelector type: string - - name: definitionsRootFolder - type: string - default: Definitions steps: - checkout: self - download: current - artifact: "policy-plan-${{ parameters.pacEnvironment }}" + artifact: "plans-${{ parameters.pacEnvironmentSelector }}" - pwsh: | Install-Module EnterprisePolicyAsCode -Force Install-Module Az.ResourceGraph -Force - task: AzurePowerShell@5 - name: RBAC + name: Deploy displayName: Deploy Roles inputs: azureSubscription: ${{ parameters.serviceConnection }} - ScriptType: InlineScript - azurePowerShellVersion: LatestVersion pwsh: true + azurePowerShellVersion: LatestVersion + ScriptType: InlineScript Inline: | - Deploy-RolesPlan -PacEnvironmentSelector ${{ parameters.pacEnvironment }} -DefinitionsRootFolder ${{ parameters.definitionsRootFolder }} -inputFolder $env:PIPELINE_WORKSPACE/policy-plan-${{ parameters.pacEnvironment }} + Deploy-RolesPlan -PacEnvironmentSelector ${{ parameters.pacEnvironmentSelector }} -InformationAction Continue diff --git a/StarterKit/Pipelines/AzureDevOps/templates/build.yaml b/StarterKit/Pipelines/AzureDevOps/templates-ps1-module/plan-exemptions-only.yml similarity index 67% rename from StarterKit/Pipelines/AzureDevOps/templates/build.yaml rename to StarterKit/Pipelines/AzureDevOps/templates-ps1-module/plan-exemptions-only.yml index 0f7435b7..28626f91 100644 --- a/StarterKit/Pipelines/AzureDevOps/templates/build.yaml +++ b/StarterKit/Pipelines/AzureDevOps/templates-ps1-module/plan-exemptions-only.yml @@ -1,11 +1,8 @@ parameters: - name: serviceConnection type: string - - name: pacEnvironment + - name: pacEnvironmentSelector type: string - - name: definitionsRootFolder - type: string - default: Definitions steps: - checkout: self @@ -14,14 +11,13 @@ steps: Install-Module Az.ResourceGraph -Force - task: AzurePowerShell@5 name: Plan - displayName: Run Build inputs: azureSubscription: ${{ parameters.serviceConnection }} - ScriptType: InlineScript azurePowerShellVersion: LatestVersion pwsh: true + ScriptType: InlineScript Inline: | - Build-DeploymentPlans -PacEnvironmentSelector ${{ parameters.pacEnvironment }} -DefinitionsRootFolder ${{ parameters.definitionsRootFolder }} -devOpsType ado -outputFolder $env:PAC_OUTPUT_FOLDER + Build-DeploymentPlans -PacEnvironmentSelector ${{ parameters.pacEnvironmentSelector }} -BuildExemptionsOnly -DevOpsType "ado" -InformationAction Continue - publish: "$(PAC_OUTPUT_FOLDER)" - artifact: "policy-plan-${{ parameters.pacEnvironment }}" + artifact: "plans-${{ parameters.pacEnvironmentSelector }}" condition: and(succeeded(), or(eq(variables['Plan.deployPolicyChanges'], 'yes'), eq(variables['Plan.deployRoleChanges'], 'yes'))) diff --git a/StarterKit/Pipelines/AzureDevOps/templates-ps1-module/plan.yml b/StarterKit/Pipelines/AzureDevOps/templates-ps1-module/plan.yml new file mode 100644 index 00000000..a17f21a0 --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/templates-ps1-module/plan.yml @@ -0,0 +1,23 @@ +parameters: + - name: serviceConnection + type: string + - name: pacEnvironmentSelector + type: string + +steps: + - checkout: self + - pwsh: | + Install-Module EnterprisePolicyAsCode -Force + Install-Module Az.ResourceGraph -Force + - task: AzurePowerShell@5 + name: Plan + inputs: + azureSubscription: ${{ parameters.serviceConnection }} + azurePowerShellVersion: LatestVersion + pwsh: true + ScriptType: InlineScript + Inline: | + Build-DeploymentPlans -PacEnvironmentSelector ${{ parameters.pacEnvironmentSelector }} -DevOpsType "ado" -InformationAction Continue + - publish: "$(PAC_OUTPUT_FOLDER)" + artifact: "plans-${{ parameters.pacEnvironmentSelector }}" + condition: and(succeeded(), or(eq(variables['Plan.deployPolicyChanges'], 'yes'), eq(variables['Plan.deployRoleChanges'], 'yes'))) diff --git a/StarterKit/Pipelines/AzureDevOps/templates-ps1-module/remediate.yml b/StarterKit/Pipelines/AzureDevOps/templates-ps1-module/remediate.yml new file mode 100644 index 00000000..fb2b9995 --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/templates-ps1-module/remediate.yml @@ -0,0 +1,21 @@ +parameters: + - name: serviceConnection + type: string + - name: pacEnvironmentSelector + type: string + +steps: + - checkout: self + - pwsh: | + Install-Module EnterprisePolicyAsCode -Force + Install-Module Az.ResourceGraph -Force + - task: AzurePowerShell@5 + name: PolicyRemediation + displayName: Policy Remediation + inputs: + azureSubscription: ${{ parameters.serviceConnection }} + azurePowerShellVersion: LatestVersion + pwsh: true + ScriptType: InlineScript + Inline: | + Create-AzRemediationTasks -PacEnvironmentSelector ${{ parameters.pacEnvironmentSelector }} -OnlyCheckManagedAssignments -Interactive $false -InformationAction Continue diff --git a/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/deploy-policy.yml b/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/deploy-policy.yml new file mode 100644 index 00000000..4347de90 --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/deploy-policy.yml @@ -0,0 +1,19 @@ +parameters: + - name: serviceConnection + type: string + - name: pacEnvironmentSelector + type: string + +steps: + - checkout: self + - download: current + artifact: "plans-${{ parameters.pacEnvironmentSelector }}" + - task: AzurePowerShell@5 + displayName: Deploy Policy + inputs: + azureSubscription: ${{ parameters.serviceConnection }} + pwsh: true + azurePowerShellVersion: LatestVersion + ScriptPath: "Scripts/Deploy/Deploy-PolicyPlan.ps1" + ScriptArguments: + -PacEnvironmentSelector ${{ parameters.pacEnvironmentSelector }} -InformationAction Continue diff --git a/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/deploy-roles.yml b/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/deploy-roles.yml new file mode 100644 index 00000000..d498a94a --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/deploy-roles.yml @@ -0,0 +1,20 @@ +parameters: + - name: serviceConnection + type: string + - name: pacEnvironmentSelector + type: string + +steps: + - checkout: self + - download: current + artifact: "plans-${{ parameters.pacEnvironmentSelector }}" + - task: AzurePowerShell@5 + name: Deploy + displayName: Deploy Roles + inputs: + azureSubscription: ${{ parameters.serviceConnection }} + pwsh: true + azurePowerShellVersion: LatestVersion + ScriptPath: "Scripts/Deploy/Deploy-RolesPlan.ps1" + ScriptArguments: + -PacEnvironmentSelector ${{ parameters.pacEnvironmentSelector }} -InformationAction Continue diff --git a/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/plan-exemptions-only.yml b/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/plan-exemptions-only.yml new file mode 100644 index 00000000..f868fa7b --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/plan-exemptions-only.yml @@ -0,0 +1,20 @@ +parameters: + - name: serviceConnection + type: string + - name: pacEnvironmentSelector + type: string + +steps: + - checkout: self + - task: AzurePowerShell@5 + name: Plan + inputs: + azureSubscription: ${{ parameters.serviceConnection }} + azurePowerShellVersion: LatestVersion + pwsh: true + ScriptPath: "Scripts/Deploy/Build-DeploymentPlans.ps1" + ScriptArguments: + -PacEnvironmentSelector ${{ parameters.pacEnvironmentSelector }} -BuildExemptionsOnly -DevOpsType "ado" -InformationAction Continue + - publish: "$(PAC_OUTPUT_FOLDER)" + artifact: "plans-${{ parameters.pacEnvironmentSelector }}" + condition: and(succeeded(), or(eq(variables['Plan.deployPolicyChanges'], 'yes'), eq(variables['Plan.deployRoleChanges'], 'yes'))) diff --git a/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/plan.yml b/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/plan.yml new file mode 100644 index 00000000..881b8ea1 --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/plan.yml @@ -0,0 +1,20 @@ +parameters: + - name: serviceConnection + type: string + - name: pacEnvironmentSelector + type: string + +steps: + - checkout: self + - task: AzurePowerShell@5 + name: Plan + inputs: + azureSubscription: ${{ parameters.serviceConnection }} + azurePowerShellVersion: LatestVersion + pwsh: true + ScriptPath: "Scripts/Deploy/Build-DeploymentPlans.ps1" + ScriptArguments: + -PacEnvironmentSelector ${{ parameters.pacEnvironmentSelector }} -DevOpsType "ado" -InformationAction Continue + - publish: "$(PAC_OUTPUT_FOLDER)" + artifact: "plans-${{ parameters.pacEnvironmentSelector }}" + condition: and(succeeded(), or(eq(variables['Plan.deployPolicyChanges'], 'yes'), eq(variables['Plan.deployRoleChanges'], 'yes'))) diff --git a/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/remediate.yml b/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/remediate.yml new file mode 100644 index 00000000..f8947dc0 --- /dev/null +++ b/StarterKit/Pipelines/AzureDevOps/templates-ps1-scripts/remediate.yml @@ -0,0 +1,18 @@ +parameters: + - name: serviceConnection + type: string + - name: pacEnvironmentSelector + type: string + +steps: + - checkout: self + - task: AzurePowerShell@5 + name: PolicyRemediation + displayName: Policy Remediation + inputs: + azureSubscription: ${{ parameters.serviceConnection }} + azurePowerShellVersion: LatestVersion + pwsh: true + ScriptPath: "Scripts/Operations/Create-AzRemediationTasks.ps1" + ScriptArguments: + -PacEnvironmentSelector ${{ parameters.pacEnvironmentSelector }} -OnlyCheckManagedAssignments -Interactive $false -InformationAction Continue diff --git a/StarterKit/Pipelines/GitHubActions/.github/workflows/epac-dev.yaml b/StarterKit/Pipelines/GitHubActions/.github/workflows/epac-dev.yaml deleted file mode 100644 index 5f2a7acf..00000000 --- a/StarterKit/Pipelines/GitHubActions/.github/workflows/epac-dev.yaml +++ /dev/null @@ -1,165 +0,0 @@ -name: Feature-Change - EPAC-SANDBOX Workflow - -env: - pacEnvironment: epac-dev # Change this to a PAC environment name - definitionsRootFolder: Definitions - planFolder: Output - -on: - push: - branches: - - 'feature/**' - paths: - - 'Definitions/**' - workflow_dispatch: - -jobs: - build: - name: Build Deployment Plan - runs-on: ubuntu-latest - environment: - name: EPAC-DEV - steps: - - name: Checkout - uses: actions/checkout@v3.3.0 - - - shell: pwsh - name: Install Required Modules - run: | - Install-Module Az.ResourceGraph -Force -AllowClobber - Install-Module Az.Resources -Force -AllowClobber - Install-Module EnterprisePolicyAsCode -Force - - - name: Azure Login - uses: Azure/login@v1 - with: - creds: '{"clientId":"${{ secrets.CLIENT_ID }}","clientSecret":"${{ secrets.CLIENT_SECRET }}","tenantId":"${{ secrets.TENANT_ID }}"}' - enable-AzPSSession: true - allow-no-subscriptions: true - - - name: Build Deployment Plan - uses: azure/powershell@v1 - with: - inlineScript: | - Build-DeploymentPlans -definitionsRootFolder $env:definitionsRootFolder -outputFolder $env:planFolder -pacEnvironment $env:pacEnvironment - $epacInfoStream | Set-Content body.txt - azPSVersion: "latest" - - - shell: pwsh - name: Detect Plan - run: | - if (Test-Path $env:planFolder) { - echo "Deploy=true" >> $env:GITHUB_ENV - if (!(Get-ChildItem $env:planFolder -Recurse -Include policy-plan.json)){ - echo "RolesOnly=true" >> $env:GITHUB_ENV - } - } - - - name: Display Policy Plan File - id: checkPolicy - run: | - if (Test-Path -Path "Output/plans-${{ env.pacEnvironment }}/policy-plan.json") { - Get-Content "Output/plans-${{ env.pacEnvironment }}/policy-plan.json" | ConvertFrom-Json | ConvertTo-Json -Depth 10 - } else { - Write-Output "Policy-Plan file does not exist" - } - shell: pwsh - - - name: Display Roles Plan file - id: checkRole - run: | - if (Test-Path -Path "Output/plans-${{ env.pacEnvironment }}/roles-plan.json") { - Get-Content "Output/plans-${{ env.pacEnvironment }}/roles-plan.json" | ConvertFrom-Json | ConvertTo-Json -Depth 10 - } else { - Write-Output "Roles-Plan file does not exist" - } - shell: pwsh - - - name: Upload Deployment Plan as Artifact - uses: actions/upload-artifact@v3 - with: - name: deploymentPlan - path: Output - - - deployPolicy: - needs: build - name: Deploy Policy Plan - runs-on: ubuntu-latest - environment: - name: EPAC-DEV - steps: - - name: Checkout - uses: actions/checkout@v3.3.0 - - - name: Download Artifact - uses: actions/download-artifact@v3 - with: - name: deploymentPlan - - - name: Copy Artifact directory to Output Folder - shell: pwsh - run: | - Copy-Item -Path ".\plans-${{ env.pacEnvironment }}" -Destination "$env:planFolder\plans-${{ env.pacEnvironment }}" -Recurse -Force - - - shell: pwsh - name: Install Required Modules - run: | - Install-Module Az.ResourceGraph -Force -Verbose -AllowClobber - Install-Module Az.Resources -Force -Verbose -AllowClobber - Install-Module EnterprisePolicyAsCode -Force - - - name: Azure Login - uses: Azure/login@v1 - with: - creds: '{"clientId":"${{ secrets.CLIENT_ID }}","clientSecret":"${{ secrets.CLIENT_SECRET }}","tenantId":"${{ secrets.TENANT_ID }}"}' - enable-AzPSSession: true - allow-no-subscriptions: true - - - name: Deploy Policy Plan - uses: azure/powershell@v1 - with: - inlineScript: | - Deploy-PolicyPlan -definitionsRootFolder $env:definitionsRootFolder -inputFolder $env:planFolder -pacEnvironment $env:pacEnvironment - azPSVersion: "latest" - - deployRoles: - needs: deployPolicy - name: Deploy Policy Roles - runs-on: ubuntu-latest - environment: - name: EPAC-DEV - steps: - - name: Checkout - uses: actions/checkout@v3.3.0 - - - name: Download Artifact - uses: actions/download-artifact@v3 - with: - name: deploymentPlan - - - name: Copy Artifact directory to Output Folder - shell: pwsh - run: | - Copy-Item -Path ".\plans-${{ env.pacEnvironment }}" -Destination "$env:planFolder\plans-${{ env.pacEnvironment }}" -Recurse -Force - - - shell: pwsh - name: Install Required Modules - run: | - Install-Module Az.ResourceGraph -Force -Verbose -AllowClobber - Install-Module Az.Resources -Force -Verbose -AllowClobber - Install-Module EnterprisePolicyAsCode -Force - - - name: Azure Login - uses: Azure/login@v1 - with: - creds: '{"clientId":"${{ secrets.CLIENT_ID }}","clientSecret":"${{ secrets.CLIENT_SECRET }}","tenantId":"${{ secrets.TENANT_ID }}"}' - enable-AzPSSession: true - allow-no-subscriptions: true - - - name: Deploy Role Plan - uses: azure/powershell@v1 - with: - inlineScript: | - Deploy-RolesPlan -definitionsRootFolder $env:definitionsRootFolder -inputFolder $env:planFolder -pacEnvironment $env:pacEnvironment - azPSVersion: "latest" \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/.github/workflows/tenant.yaml b/StarterKit/Pipelines/GitHubActions/.github/workflows/tenant.yaml deleted file mode 100644 index a4424415..00000000 --- a/StarterKit/Pipelines/GitHubActions/.github/workflows/tenant.yaml +++ /dev/null @@ -1,165 +0,0 @@ -name: PR-Merge - EPAC-TENANT Workflow - -env: - pacEnvironment: tenant # Change this to a PAC environment name - definitionsRootFolder: Definitions - planFolder: Output - -on: - pull_request: - types: - - closed - branches: - - 'main' - workflow_dispatch: - -jobs: - build: - name: Build Deployment Plan - runs-on: ubuntu-latest - environment: - name: TENANT-PLAN - steps: - - name: Checkout - uses: actions/checkout@v3.3.0 - - - shell: pwsh - name: Install Required Modules - run: | - Install-Module Az.ResourceGraph -Force -AllowClobber - Install-Module Az.Resources -Force -AllowClobber - Install-Module EnterprisePolicyAsCode -Force - - - name: Azure Login - uses: Azure/login@v1 - with: - creds: '{"clientId":"${{ secrets.CLIENT_ID }}","clientSecret":"${{ secrets.CLIENT_SECRET }}","tenantId":"${{ secrets.TENANT_ID }}"}' - enable-AzPSSession: true - allow-no-subscriptions: true - - - name: Build Deployment Plan - uses: azure/powershell@v1 - with: - inlineScript: | - Build-DeploymentPlans -definitionsRootFolder $env:definitionsRootFolder -outputFolder $env:planFolder -pacEnvironment $env:pacEnvironment - $epacInfoStream | Set-Content body.txt - azPSVersion: "latest" - - - shell: pwsh - name: Detect Plan - run: | - if (Test-Path $env:planFolder) { - echo "Deploy=true" >> $env:GITHUB_ENV - if (!(Get-ChildItem $env:planFolder -Recurse -Include policy-plan.json)){ - echo "RolesOnly=true" >> $env:GITHUB_ENV - } - } - - - name: Display Policy Plan File - id: checkPolicy - run: | - if (Test-Path -Path "Output/plans-${{ env.pacEnvironment }}/policy-plan.json") { - Get-Content "Output/plans-${{ env.pacEnvironment }}/policy-plan.json" | ConvertFrom-Json | ConvertTo-Json -Depth 10 - } else { - Write-Output "Policy-Plan file does not exist" - } - shell: pwsh - - - name: Display Roles Plan file - id: checkRole - run: | - if (Test-Path -Path "Output/plans-${{ env.pacEnvironment }}/roles-plan.json") { - Get-Content "Output/plans-${{ env.pacEnvironment }}/roles-plan.json" | ConvertFrom-Json | ConvertTo-Json -Depth 10 - } else { - Write-Output "Roles-Plan file does not exist" - } - shell: pwsh - - - name: Upload Deployment Plan as Artifact - uses: actions/upload-artifact@v3 - with: - name: deploymentPlan - path: Output - - - deployPolicy: - needs: build - name: Deploy Policy Plan - runs-on: ubuntu-latest - environment: - name: TENANT-DEPLOY-POLICY - steps: - - name: Checkout - uses: actions/checkout@v3.3.0 - - - name: Download Artifact - uses: actions/download-artifact@v3 - with: - name: deploymentPlan - - - name: Copy Artifact directory to Output Folder - shell: pwsh - run: | - Copy-Item -Path ".\plans-${{ env.pacEnvironment }}" -Destination "$env:planFolder\plans-${{ env.pacEnvironment }}" -Recurse -Force - - - shell: pwsh - name: Install Required Modules - run: | - Install-Module Az.ResourceGraph -Force -Verbose -AllowClobber - Install-Module Az.Resources -Force -Verbose -AllowClobber - Install-Module EnterprisePolicyAsCode -Force - - - name: Azure Login - uses: Azure/login@v1 - with: - creds: '{"clientId":"${{ secrets.CLIENT_ID }}","clientSecret":"${{ secrets.CLIENT_SECRET }}","tenantId":"${{ secrets.TENANT_ID }}"}' - enable-AzPSSession: true - allow-no-subscriptions: true - - - name: Deploy Policy Plan - uses: azure/powershell@v1 - with: - inlineScript: | - Deploy-PolicyPlan -definitionsRootFolder $env:definitionsRootFolder -inputFolder $env:planFolder -pacEnvironment $env:pacEnvironment - azPSVersion: "latest" - - deployRoles: - needs: deployPolicy - name: Deploy Policy Roles - runs-on: ubuntu-latest - environment: - name: TENANT-DEPLOY-ROLES - steps: - - name: Checkout - uses: actions/checkout@v3.3.0 - - - name: Download Artifact - uses: actions/download-artifact@v3 - with: - name: deploymentPlan - - - name: Copy Artifact directory to Output Folder - shell: pwsh - run: | - Copy-Item -Path ".\plans-${{ env.pacEnvironment }}" -Destination "$env:planFolder\plans-${{ env.pacEnvironment }}" -Recurse -Force - - - shell: pwsh - name: Install Required Modules - run: | - Install-Module Az.ResourceGraph -Force -Verbose -AllowClobber - Install-Module Az.Resources -Force -Verbose -AllowClobber - Install-Module EnterprisePolicyAsCode -Force - - - name: Azure Login - uses: Azure/login@v1 - with: - creds: '{"clientId":"${{ secrets.CLIENT_ID }}","clientSecret":"${{ secrets.CLIENT_SECRET }}","tenantId":"${{ secrets.TENANT_ID }}"}' - enable-AzPSSession: true - allow-no-subscriptions: true - - - name: Deploy Role Plan - uses: azure/powershell@v1 - with: - inlineScript: | - Deploy-RolesPlan -definitionsRootFolder $env:definitionsRootFolder -inputFolder $env:planFolder -pacEnvironment $env:pacEnvironment - azPSVersion: "latest" \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/GitHub-Flow/epac-dev-workflow.yml b/StarterKit/Pipelines/GitHubActions/GitHub-Flow/epac-dev-workflow.yml new file mode 100644 index 00000000..a6104ecc --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/GitHub-Flow/epac-dev-workflow.yml @@ -0,0 +1,65 @@ +# This pipeline is used to deploy Policies, Initiative definitions and Assignments into Azure. +name: EPAC Dev Workflow + +on: + push: + branches: + - feature/** + paths: + - 'Definitions/**' + - '.github/**' + workflow_dispatch: + +env: + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + +permissions: + contents: read + id-token: write + +jobs: + plan: + name: Plan epac-dev + uses: ./.github/workflows/plan.yml + with: + pacEnvironmentSelector: epac-dev + planGitHubEnvironment: PAC-DEV + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + deployPolicy: + name: Deploy epac-dev Policy Changes + needs: plan + if: needs.plan.outputs.deployPolicyChanges == 'yes' + uses: ./.github/workflows/deploy-policy.yml + with: + pacEnvironmentSelector: epac-dev + planGitHubEnvironment: PAC-DEV + PAC_INPUT_FOLDER: "$(GITHUB_WORKSPACE)/plans-epac-dev" + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + deployRoles: + name: Deploy epac-dev Role Changes + needs: plan + if: needs.plan.outputs.deployRoleChanges == 'yes' + uses: ./.github/workflows/deploy-roles.yml + with: + pacEnvironmentSelector: epac-dev + planGitHubEnvironment: PAC-DEV + PAC_INPUT_FOLDER: "$(GITHUB_WORKSPACE)/plans-epac-dev" + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + tenantPlan: + name: Plan tenant + needs: [deployPolicy, deployRoles] + uses: ./.github/workflows/plan.yml + with: + pacEnvironmentSelector: tenant + planGitHubEnvironment: TENANT-PLAN + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/GitHub-Flow/epac-remediation-workflow.yml b/StarterKit/Pipelines/GitHubActions/GitHub-Flow/epac-remediation-workflow.yml new file mode 100644 index 00000000..72dd2522 --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/GitHub-Flow/epac-remediation-workflow.yml @@ -0,0 +1,37 @@ +# This pipeline is used to auto remdiate Azure policy that are non-compliant. +name: EPAC Remediation + +## Change the cron job schedule according to the requirement +# cron: '0 5,17 * * *' # UTC 5:00 AM daily, midnight and noon EST (might be useful for VMs that are not running 24/7) +# cron: '0 5 * * 0' # UTC 5:00 AM on Sundays only, midnight EST (0=Sunday,1=Monday,2=Tuesday,3=Wednesday,4=Thursday,5=Friday,6=Saturday) +on: + schedule: + - cron: '0 5 * * *' # # UTC 5:00 AM daily, midnight EST + workflow_dispatch: + +env: + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + +permissions: + contents: read + id-token: write + +jobs: + epacDev: + name: 'Remediate epac-dev environment' + uses: ./.github/workflows/remediate.yml + with: + pacEnvironmentSelector: epac-dev + planGitHubEnvironment: EPAC-DEV + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + tenant: + name: 'Remediate tenant environment' + uses: ./.github/workflows/remediate.yml + with: + pacEnvironmentSelector: tenant + planGitHubEnvironment: TENANT-REMEDIATE-POLICY + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/GitHub-Flow/epac-tenant-workflow.yml b/StarterKit/Pipelines/GitHubActions/GitHub-Flow/epac-tenant-workflow.yml new file mode 100644 index 00000000..e533610a --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/GitHub-Flow/epac-tenant-workflow.yml @@ -0,0 +1,54 @@ +# This pipeline is used to deploy Policies, Initiative definitions and Assignments into Azure. +name: EPAC Tenant Workflow + +on: + pull_request: + branches: + - main + types: + - closed + paths: + - 'Definitions/**' + +env: + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + +permissions: + contents: read + id-token: write + +jobs: + plan: + name: Plan tenant + uses: ./.github/workflows/plan.yml + with: + pacEnvironmentSelector: tenant + planGitHubEnvironment: TENANT-PLAN + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + deployPolicy: + name: Deploy tenant Policy Changes + needs: plan + if: needs.plan.outputs.deployPolicyChanges == 'yes' && github.ref == 'refs/heads/main' + uses: ./.github/workflows/deploy-policy.yml + with: + pacEnvironmentSelector: tenant + planGitHubEnvironment: TENANT-DEPLOY-POLICY + PAC_INPUT_FOLDER: "$(GITHUB_WORKSPACE)/plans-tenant" + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + deployRoles: + name: Deploy tenant Role Changes + needs: plan + if: needs.plan.outputs.deployRoleChanges == 'yes' && github.ref == 'refs/heads/main' + uses: ./.github/workflows/deploy-roles.yml + with: + pacEnvironmentSelector: tenant + planGitHubEnvironment: TENANT-DEPLOY-ROLES + PAC_INPUT_FOLDER: "$(GITHUB_WORKSPACE)/plans-tenant" + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/Legacy/build.yaml b/StarterKit/Pipelines/GitHubActions/Legacy/build.yaml deleted file mode 100644 index d80896cd..00000000 --- a/StarterKit/Pipelines/GitHubActions/Legacy/build.yaml +++ /dev/null @@ -1,83 +0,0 @@ -name: Build Deployment Plan - -env: - REVIEWER: anwather # Change this to a GitHub reviewer - pacEnvironment: gh-action # Change this to a PAC environment name - definitionsRootFolder: Definitions - planFolder: Output - -on: - push: - paths: - - Definitions/** - -jobs: - build: - name: Build Deployment Plan - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3.3.0 - - name: Check for NO_ACTIONS - shell: pwsh - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - if (Get-ChildItem -Path $env:definitionsRootFolder -Filter "NO_ACTIONS" -Recurse) { - Write-Output "NO_ACTIONS file found, exiting" - gh run cancel ${{ github.run_id }} - gh run watch ${{ github.run_id }} - } - - shell: pwsh - name: Install Required Modules - run: | - Install-Module Az.ResourceGraph -Force -AllowClobber - Install-Module Az.Resources -Force -AllowClobber - Install-Module EnterprisePolicyAsCode -Force - - name: Azure Login - uses: Azure/login@v1 - with: - creds: '{"clientId":"${{ secrets.CLIENT_ID }}","clientSecret":"${{ secrets.CLIENT_SECRET }}","subscriptionId":"${{ secrets.SUBSCRIPTION_ID }}","tenantId":"${{ secrets.TENANT_ID }}"}' - enable-AzPSSession: true - - name: Build Deployment Plan - uses: azure/powershell@v1 - with: - inlineScript: | - Build-DeploymentPlans -definitionsRootFolder $env:definitionsRootFolder -outputFolder $env:planFolder -pacEnvironment $env:pacEnvironment - $epacInfoStream | Set-Content body.txt - azPSVersion: "latest" - - shell: pwsh - name: Detect Plan - run: | - if (Get-ChildItem -Path $env:definitionsRootFolder -Filter "NO_DEPLOY" -Recurse) { - Write-Output "NO_DEPLOY file found, exiting" - gh run cancel ${{ github.run_id }} - gh run watch ${{ github.run_id }} - } - if (Test-Path $env:planFolder) { - echo "Deploy=true" >> $env:GITHUB_ENV - if (!(Get-ChildItem $env:planFolder -Recurse -Include policy-plan.json)){ - echo "RolesOnly=true" >> $env:GITHUB_ENV - } - } - - shell: pwsh - name: Create PR - if: ${{ env.Deploy == 'true' }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - Remove-Item .gitignore -Verbose -Force - $branchName = "automated-pr-$(Get-Date -Format yyyy-MM-dd-HH-mm)" - git config user.name "GitHub Actions Bot" - git config user.email "<>" - git checkout -b $branchName - git add . - git commit -m "Deployment plan commit" - git push --set-upstream origin $branchName - if ($env:RolesOnly -eq "true") { - gh pr create -B main -H $branchName --title "Approval Required for Role Deployment - $branchName" -F body.txt --reviewer $env:REVIEWER --label RoleDeployment - } - else { - gh pr create -B main -H $branchName --title "Approval Required for Policy Deployment - $branchName" -F body.txt --reviewer $env:REVIEWER --label PolicyDeployment - } - diff --git a/StarterKit/Pipelines/GitHubActions/Legacy/deploy.yaml b/StarterKit/Pipelines/GitHubActions/Legacy/deploy.yaml deleted file mode 100644 index 5f3f3a2f..00000000 --- a/StarterKit/Pipelines/GitHubActions/Legacy/deploy.yaml +++ /dev/null @@ -1,69 +0,0 @@ -name: Deploy Policy Plan and Roles - -env: - REVIEWER: anwather # Change this to a GitHub reviewer - pacEnvironment: gh-action # Change this to a PAC environment name - definitionsRootFolder: Definitions - planFolder: Output - -on: - pull_request_review: - types: [submitted] - -jobs: - deploy: - name: Deploy Policy Plan and Roles - if: github.event.review.state == 'approved' - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3.3.0 - - shell: pwsh - name: Install Required Modules - run: | - Install-Module Az.ResourceGraph -Force -Verbose -AllowClobber - Install-Module Az.Resources -Force -Verbose -AllowClobber - Install-Module EnterprisePolicyAsCode -Force - - name: Azure Login - uses: Azure/login@v1 - with: - creds: '{"clientId":"${{ secrets.CLIENT_ID }}","clientSecret":"${{ secrets.CLIENT_SECRET }}","subscriptionId":"${{ secrets.SUBSCRIPTION_ID }}","tenantId":"${{ secrets.TENANT_ID }}"}' - enable-AzPSSession: true - - name: Deploy Policy Plan - if: contains(github.event.pull_request.labels.*.name, 'PolicyDeployment') - uses: azure/powershell@v1 - with: - inlineScript: | - Deploy-PolicyPlan -definitionsRootFolder $env:definitionsRootFolder -inputFolder $env:planFolder -pacEnvironment $env:pacEnvironment - azPSVersion: "latest" - - name: Deploy Role Plan - if: contains(github.event.pull_request.labels.*.name, 'RoleDeployment') - uses: azure/powershell@v1 - with: - inlineScript: | - Deploy-RolesPlan -definitionsRootFolder $env:definitionsRootFolder -inputFolder $env:planFolder -pacEnvironment $env:pacEnvironment - azPSVersion: "latest" - - shell: pwsh - if: contains(github.event.pull_request.labels.*.name, 'PolicyDeployment') - name: Confirm PR - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - run: | - if (Get-ChildItem $env:planFolder -recurse -include roles-plan.json) { - gh pr edit $env:PR_NUMBER --add-label 'RoleDeployment' --remove-label 'PolicyDeployment' - gh pr edit $env:PR_NUMBER --title 'Approval Required for Role Deployment' --remove-reviewer $env:REVIEWER - gh pr edit $env:PR_NUMBER --add-reviewer $env:REVIEWER - } - else { - gh pr close $env:PR_NUMBER --comment 'Changes deployed' --delete-branch - } - - shell: pwsh - if: contains(github.event.pull_request.labels.*.name, 'RoleDeployment') - name: Confirm PR - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - run: | - gh pr close $env:PR_NUMBER --comment 'Changes deployed' --delete-branch - diff --git a/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-dev-workflow.yml b/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-dev-workflow.yml new file mode 100644 index 00000000..6576ea36 --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-dev-workflow.yml @@ -0,0 +1,76 @@ +# This pipeline is used to deploy Policies, Initiative definitions and Assignments into Azure. +name: EPAC Dev Workflow + +on: + push: + branches: + - feature/** + paths: + - 'Definitions/**' + - '.github/**' + workflow_dispatch: + +env: + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + +permissions: + contents: read + id-token: write + +jobs: + plan: + name: Plan epac-dev + uses: ./.github/workflows/plan.yml + with: + pacEnvironmentSelector: epac-dev + planGitHubEnvironment: PAC-DEV + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + deployPolicy: + name: Deploy epac-dev Policy Changes + needs: plan + if: needs.plan.outputs.deployPolicyChanges == 'yes' + uses: ./.github/workflows/deploy-policy.yml + with: + pacEnvironmentSelector: epac-dev + planGitHubEnvironment: PAC-DEV + PAC_INPUT_FOLDER: "$(GITHUB_WORKSPACE)/plans-epac-dev" + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + deployRoles: + name: Deploy epac-dev Role Changes + needs: plan + if: needs.plan.outputs.deployRoleChanges == 'yes' + uses: ./.github/workflows/deploy-roles.yml + with: + pacEnvironmentSelector: epac-dev + planGitHubEnvironment: PAC-DEV + PAC_INPUT_FOLDER: "$(GITHUB_WORKSPACE)/plans-epac-dev" + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + nonprodPlan: + name: Plan nonprod + needs: [deployPolicy, deployRoles] + uses: ./.github/workflows/plan.yml + with: + pacEnvironmentSelector: nonnprod + planGitHubEnvironment: NONPROD-PLAN + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + prodPlan: + name: Plan prod + needs: [deployPolicy, deployRoles] + uses: ./.github/workflows/plan.yml + with: + pacEnvironmentSelector: prod + planGitHubEnvironment: PROD-PLAN + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-nonprod-workflow.yml b/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-nonprod-workflow.yml new file mode 100644 index 00000000..502d71ec --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-nonprod-workflow.yml @@ -0,0 +1,50 @@ +# This pipeline is used to deploy Policies, Initiative definitions and Assignments into Azure. +name: EPAC NONPROD Workflow + +on: + push: + branches: + - main + +env: + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + +permissions: + contents: read + id-token: write + +jobs: + plan: + name: Plan nonprod + uses: ./.github/workflows/plan.yml + with: + pacEnvironmentSelector: nonprod + planGitHubEnvironment: NONPROD-PLAN + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + deployPolicy: + name: Deploy nonprod Policy Changes + needs: plan + if: needs.plan.outputs.deployPolicyChanges == 'yes' && github.ref == 'refs/heads/main' + uses: ./.github/workflows/deploy-policy.yml + with: + pacEnvironmentSelector: nonprod + planGitHubEnvironment: NONPROD-DEPLOY-POLICY + PAC_INPUT_FOLDER: "$(GITHUB_WORKSPACE)/plans-nonprod" + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + deployRoles: + name: Deploy nonprod Role Changes + needs: plan + if: needs.plan.outputs.deployRoleChanges == 'yes' && github.ref == 'refs/heads/main' + uses: ./.github/workflows/deploy-roles.yml + with: + pacEnvironmentSelector: nonprod + planGitHubEnvironment: NONPROD-DEPLOY-ROLES + PAC_INPUT_FOLDER: "$(GITHUB_WORKSPACE)/plans-nonprod" + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-prod-exemptions-only-workflow.yml b/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-prod-exemptions-only-workflow.yml new file mode 100644 index 00000000..14bbb84d --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-prod-exemptions-only-workflow.yml @@ -0,0 +1,38 @@ +# This pipeline is used to deploy Policies, Initiative definitions and Assignments into Azure. +name: EPAC PROD Exemptions Workflow + +on: + push: + branches: + - releases-exemptions-only/* + +env: + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + +permissions: + contents: read + id-token: write + +jobs: + plan: + name: Plan prod Exemptions Only + uses: ./.github/workflows/plan-exemptions-only.yml + with: + pacEnvironmentSelector: prod + planGitHubEnvironment: PROD-PLAN + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + deployPolicy: + name: Deploy prod Exemptions Only + needs: plan + if: needs.plan.outputs.deployPolicyChanges == 'yes' && startsWith(github.ref, 'refs/heads/releases-exemptions-only/') + uses: ./.github/workflows/deploy-policy.yml + with: + pacEnvironmentSelector: prod + planGitHubEnvironment: PROD-DEPLOY-POLICY + PAC_INPUT_FOLDER: "$(GITHUB_WORKSPACE)/plans-prod" + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-prod-workflow.yml b/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-prod-workflow.yml new file mode 100644 index 00000000..073bdddb --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-prod-workflow.yml @@ -0,0 +1,50 @@ +# This pipeline is used to deploy Policies, Initiative definitions and Assignments into Azure. +name: EPAC PROD Workflow + +on: + push: + branches: + - releases-prod/** + +env: + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + +permissions: + contents: read + id-token: write + +jobs: + plan: + name: Plan prod + uses: ./.github/workflows/plan.yml + with: + pacEnvironmentSelector: prod + planGitHubEnvironment: PROD-PLAN + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + deployPolicy: + name: Deploy prod Policy Changes + needs: plan + if: needs.plan.outputs.deployPolicyChanges == 'yes' && startsWith(github.ref, 'refs/heads/releases-prod/') + uses: ./.github/workflows/deploy-policy.yml + with: + pacEnvironmentSelector: prod + planGitHubEnvironment: PROD-DEPLOY-POLICY + PAC_INPUT_FOLDER: "$(GITHUB_WORKSPACE)/plans-prod" + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + deployRoles: + name: Deploy prod Role Changes + needs: plan + if: needs.plan.outputs.deployRoleChanges == 'yes' && startsWith(github.ref, 'refs/heads/releases') + uses: ./.github/workflows/deploy-roles.yml + with: + pacEnvironmentSelector: prod + planGitHubEnvironment: PROD-DEPLOY-ROLES + PAC_INPUT_FOLDER: "$(GITHUB_WORKSPACE)/plans-prod" + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-remediation-workflow.yml b/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-remediation-workflow.yml new file mode 100644 index 00000000..30c8d49b --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/Release-Flow/epac-remediation-workflow.yml @@ -0,0 +1,45 @@ +# This pipeline is used to auto remdiate Azure policy that are non-compliant. +name: EPAC Remediation + +## Change the cron job schedule according to the requirement +# cron: '0 5,17 * * *' # UTC 5:00 AM daily, midnight and noon EST (might be useful for VMs that are not running 24/7) +# cron: '0 5 * * 0' # UTC 5:00 AM on Sundays only, midnight EST (0=Sunday,1=Monday,2=Tuesday,3=Wednesday,4=Thursday,5=Friday,6=Saturday) +on: + schedule: + - cron: '0 5 * * *' # # UTC 5:00 AM daily, midnight EST + +env: + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + +permissions: + contents: read + id-token: write + +jobs: + epacDev: + name: 'Remediate epac-dev environment' + uses: ./.github/workflows/remediate.yml + with: + pacEnvironmentSelector: epac-dev + planGitHubEnvironment: EPAC-DEV + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + nonnprod: + name: 'Remediate nonprod environment' + uses: ./.github/workflows/remediate.yml + with: + pacEnvironmentSelector: nonnprod + planGitHubEnvironment: NONPROD-REMEDIATE-POLICY + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit + + prod: + name: 'Remediate prod environment' + uses: ./.github/workflows/remediate.yml + with: + pacEnvironmentSelector: prod + planGitHubEnvironment: PROD-REMEDIATE-POLICY + PAC_DEFINITIONS_FOLDER: ./Definitions + secrets: inherit \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/.github/workflows/alz-sync.yaml b/StarterKit/Pipelines/GitHubActions/alz-sync.yaml similarity index 96% rename from StarterKit/Pipelines/GitHubActions/.github/workflows/alz-sync.yaml rename to StarterKit/Pipelines/GitHubActions/alz-sync.yaml index 72176e3d..8e2a58c1 100644 --- a/StarterKit/Pipelines/GitHubActions/.github/workflows/alz-sync.yaml +++ b/StarterKit/Pipelines/GitHubActions/alz-sync.yaml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3.3.0 + uses: actions/checkout@v4 - shell: pwsh name: Install Required Modules run: | diff --git a/StarterKit/Pipelines/GitHubActions/templates-ps1-module/deploy-policy.yml b/StarterKit/Pipelines/GitHubActions/templates-ps1-module/deploy-policy.yml new file mode 100644 index 00000000..c821d4fa --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/templates-ps1-module/deploy-policy.yml @@ -0,0 +1,58 @@ +name: 'Reusable Workflow: Deploy Policy' + +on: + workflow_call: + inputs: + pacEnvironmentSelector: + required: true + type: string + planGitHubEnvironment: + required: true + type: string + PAC_INPUT_FOLDER: + required: true + type: string + PAC_DEFINITIONS_FOLDER: + required: true + type: string + +env: + PAC_INPUT_FOLDER: ${{ inputs.PAC_INPUT_FOLDER }} + PAC_DEFINITIONS_FOLDER: ${{ inputs.PAC_DEFINITIONS_FOLDER }} + +jobs: + deployPolicy: + runs-on: ubuntu-latest + environment: ${{ inputs.planGitHubEnvironment }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download Artifact + # If you are using GHES, use v3 instead of v4. See https://github.com/actions/download-artifact#v4---whats-new for more information. + uses: actions/download-artifact@v4 + with: + name: plans-${{ inputs.pacEnvironmentSelector }} + + - name: Install Required Modules + uses: Azure/powershell@v2 + with: + inlineScript: | + Install-Module Az.ResourceGraph -Force + Install-Module EnterprisePolicyAsCode -Force + azPSVersion: "latest" + + - name: Azure Login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + enable-AzPSSession: true + allow-no-subscriptions: true + + - name: Deploy Policy + uses: azure/powershell@v2 + with: + inlineScript: | + Deploy-PolicyPlan -PacEnvironmentSelector ${{ inputs.pacEnvironmentSelector }} -InformationAction Continue + azPSVersion: "latest" \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/templates-ps1-module/deploy-roles.yml b/StarterKit/Pipelines/GitHubActions/templates-ps1-module/deploy-roles.yml new file mode 100644 index 00000000..4ad25717 --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/templates-ps1-module/deploy-roles.yml @@ -0,0 +1,58 @@ +name: 'Reusable Workflow: Deploy Roles' + +on: + workflow_call: + inputs: + pacEnvironmentSelector: + required: true + type: string + planGitHubEnvironment: + required: true + type: string + PAC_INPUT_FOLDER: + required: true + type: string + PAC_DEFINITIONS_FOLDER: + required: true + type: string + +env: + PAC_INPUT_FOLDER: ${{ inputs.PAC_INPUT_FOLDER }} + PAC_DEFINITIONS_FOLDER: ${{ inputs.PAC_DEFINITIONS_FOLDER }} + +jobs: + deployRoles: + runs-on: ubuntu-latest + environment: ${{ inputs.planGitHubEnvironment }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download Artifact + # If you are using GHES, use v3 instead of v4. See https://github.com/actions/download-artifact#v4---whats-new for more information. + uses: actions/download-artifact@v4 + with: + name: plans-${{ inputs.pacEnvironmentSelector }} + + - name: Install Required Modules + uses: Azure/powershell@v2 + with: + inlineScript: | + Install-Module Az.ResourceGraph -Force + Install-Module EnterprisePolicyAsCode -Force + azPSVersion: "latest" + + - name: Azure Login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + enable-AzPSSession: true + allow-no-subscriptions: true + + - name: Deploy Roles + uses: azure/powershell@v2 + with: + inlineScript: | + Deploy-RolesPlan -PacEnvironmentSelector ${{ inputs.pacEnvironmentSelector }} -InformationAction Continue + azPSVersion: "latest" \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/templates-ps1-module/plan-exemptions-only.yml b/StarterKit/Pipelines/GitHubActions/templates-ps1-module/plan-exemptions-only.yml new file mode 100644 index 00000000..c8ce7d6a --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/templates-ps1-module/plan-exemptions-only.yml @@ -0,0 +1,86 @@ +name: 'Reusable Workflow: Plan Exemptions Only' + +on: + workflow_call: + inputs: + pacEnvironmentSelector: + required: true + type: string + planGitHubEnvironment: + required: true + type: string + PAC_OUTPUT_FOLDER: + required: true + type: string + PAC_DEFINITIONS_FOLDER: + required: true + type: string + outputs: + deployPolicyChanges: + description: "The result of evaluating if a policy deployment is required" + value: ${{ jobs.plan.outputs.deployPolicyChanges }} + deployRoleChanges: + description: "The result of evaluating if a role deployment is required" + value: ${{ jobs.plan.outputs.deployRoleChanges }} + +env: + pacEnvironmentSelector: ${{ inputs.pacEnvironmentSelector }} + PAC_OUTPUT_FOLDER: ${{ inputs.PAC_OUTPUT_FOLDER }} + PAC_DEFINITIONS_FOLDER: ${{ inputs.PAC_DEFINITIONS_FOLDER }} + +jobs: + plan: + runs-on: ubuntu-latest + environment: ${{ inputs.planGitHubEnvironment }} + outputs: + deployPolicyChanges: ${{ steps.detectPlan.outputs.deployPolicyChanges }} + deployRoleChanges: ${{ steps.detectPlan.outputs.deployRoleChanges }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Required Modules + uses: Azure/powershell@v2 + with: + inlineScript: | + Install-Module Az.ResourceGraph -Force + Install-Module EnterprisePolicyAsCode -Force + azPSVersion: "latest" + + - name: Azure Login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + enable-AzPSSession: true + allow-no-subscriptions: true + + - name: Plan + uses: azure/powershell@v2 + with: + inlineScript: | + Build-DeploymentPlans -PacEnvironmentSelector ${{ env.pacEnvironmentSelector }} -BuildExemptionsOnly -InformationAction Continue + azPSVersion: "latest" + + - name: Detect Plan + id: detectPlan + run: | + if (Test-Path $env:PAC_OUTPUT_FOLDER) { + echo "deployPolicyChanges=yes" >> $env:GITHUB_OUTPUT + if (Get-ChildItem $env:PAC_OUTPUT_FOLDER -Recurse -Include roles-plan.json){ + echo "deployRoleChanges=yes" >> $env:GITHUB_OUTPUT + } + } + else { + echo "::notice title=Detect Plan::Plan not found. Nothing to deploy. Skipping remaining tasks and deploy jobs..." + } + shell: pwsh + + - name: Upload Deployment Plan as Artifact + if: steps.detectPlan.outputs.deployPolicyChanges == 'yes' || steps.detectPlan.outputs.deployRoleChanges == 'yes' + uses: actions/upload-artifact@v4 + with: + name: "plans-${{ inputs.pacEnvironmentSelector }}" + path: ${{ env.PAC_OUTPUT_FOLDER }} + if-no-files-found: error \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/templates-ps1-module/plan.yml b/StarterKit/Pipelines/GitHubActions/templates-ps1-module/plan.yml new file mode 100644 index 00000000..238af19e --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/templates-ps1-module/plan.yml @@ -0,0 +1,85 @@ +name: 'Reusable Workflow: Plan' + +on: + workflow_call: + inputs: + pacEnvironmentSelector: + required: true + type: string + planGitHubEnvironment: + required: true + type: string + PAC_OUTPUT_FOLDER: + required: true + type: string + PAC_DEFINITIONS_FOLDER: + required: true + type: string + outputs: + deployPolicyChanges: + description: "The result of evaluating if a policy deployment is required" + value: ${{ jobs.plan.outputs.deployPolicyChanges }} + deployRoleChanges: + description: "The result of evaluating if a role deployment is required" + value: ${{ jobs.plan.outputs.deployRoleChanges }} + +env: + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + +jobs: + plan: + runs-on: ubuntu-latest + environment: ${{ inputs.planGitHubEnvironment }} + outputs: + deployPolicyChanges: ${{ steps.detectPlan.outputs.deployPolicyChanges }} + deployRoleChanges: ${{ steps.detectPlan.outputs.deployRoleChanges }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Required Modules + uses: Azure/powershell@v2 + with: + inlineScript: | + Install-Module Az.ResourceGraph -Force + Install-Module EnterprisePolicyAsCode -Force + azPSVersion: "latest" + + - name: Azure Login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + enable-AzPSSession: true + allow-no-subscriptions: true + + - name: Plan + uses: azure/powershell@v2 + with: + inlineScript: | + Build-DeploymentPlans -PacEnvironmentSelector ${{ inputs.pacEnvironmentSelector }} -InformationAction Continue + azPSVersion: "latest" + + - name: Detect Plan File + id: detectPlan + run: | + if (Test-Path $env:PAC_OUTPUT_FOLDER) { + echo "deployPolicyChanges=yes" >> $env:GITHUB_OUTPUT + if (Get-ChildItem $env:PAC_OUTPUT_FOLDER -Recurse -Include roles-plan.json){ + echo "deployRoleChanges=yes" >> $env:GITHUB_OUTPUT + } + } + else { + echo "::notice title=Detect Plan::Plan not found. Nothing to deploy. Skipping remaining tasks and deploy jobs..." + } + shell: pwsh + + - name: Upload Deployment Plan as Artifact + if: steps.detectPlan.outputs.deployPolicyChanges == 'yes' || steps.detectPlan.outputs.deployRoleChanges == 'yes' + uses: actions/upload-artifact@v4 + with: + name: "plans-${{ inputs.pacEnvironmentSelector }}" + path: ${{ env.PAC_OUTPUT_FOLDER }} + if-no-files-found: error \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/templates-ps1-module/remediate.yml b/StarterKit/Pipelines/GitHubActions/templates-ps1-module/remediate.yml new file mode 100644 index 00000000..7098200c --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/templates-ps1-module/remediate.yml @@ -0,0 +1,50 @@ +name: 'Reusable Workflow: Remediation' + +on: + workflow_call: + inputs: + pacEnvironmentSelector: + required: true + type: string + planGitHubEnvironment: + required: true + type: string + PAC_DEFINITIONS_FOLDER: + required: true + type: string + +env: + pacEnvironmentSelector: ${{ inputs.pacEnvironmentSelector }} + PAC_DEFINITIONS_FOLDER: ${{ inputs.PAC_DEFINITIONS_FOLDER }} + +jobs: + remediation: + runs-on: ubuntu-latest + environment: ${{ inputs.planGitHubEnvironment }} + steps: + + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Required Modules + uses: Azure/powershell@v2 + with: + inlineScript: | + Install-Module Az.ResourceGraph -Force + Install-Module EnterprisePolicyAsCode -Force + azPSVersion: "latest" + + - name: Azure Login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + enable-AzPSSession: true + allow-no-subscriptions: true + + - name: PolicyRemediation + uses: azure/powershell@v2 + with: + inlineScript: | + Create-AzRemediationTasks -PacEnvironmentSelector ${{ env.pacEnvironmentSelector }} -OnlyCheckManagedAssignments -Interactive $false -InformationAction Continue + azPSVersion: "latest" \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/deploy-policy.yml b/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/deploy-policy.yml new file mode 100644 index 00000000..be7d1ee9 --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/deploy-policy.yml @@ -0,0 +1,49 @@ +name: 'Reusable Workflow: Deploy Policy' + +on: + workflow_call: + inputs: + pacEnvironmentSelector: + required: true + type: string + planGitHubEnvironment: + required: true + type: string + PAC_INPUT_FOLDER: + required: true + type: string + PAC_DEFINITIONS_FOLDER: + required: true + type: string + +env: + PAC_INPUT_FOLDER: ${{ inputs.PAC_INPUT_FOLDER }} + PAC_DEFINITIONS_FOLDER: ${{ inputs.PAC_DEFINITIONS_FOLDER }} + +jobs: + deployPolicy: + runs-on: ubuntu-latest + environment: ${{ inputs.planGitHubEnvironment }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download Artifact + # If you are using GHES, use v3 instead of v4. See https://github.com/actions/download-artifact#v4---whats-new for more information. + uses: actions/download-artifact@v4 + with: + name: plans-${{ inputs.pacEnvironmentSelector }} + + - name: Azure Login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + enable-AzPSSession: true + allow-no-subscriptions: true + + - name: Deploy Policy + uses: azure/powershell@v2 + with: + inlineScript: 'Scripts/Deploy/Deploy-PolicyPlan.ps1 -PacEnvironmentSelector ${{ inputs.pacEnvironmentSelector }} -InformationAction Continue' + azPSVersion: "latest" \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/deploy-roles.yml b/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/deploy-roles.yml new file mode 100644 index 00000000..87b771dd --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/deploy-roles.yml @@ -0,0 +1,49 @@ +name: 'Reusable Workflow: Deploy Roles' + +on: + workflow_call: + inputs: + pacEnvironmentSelector: + required: true + type: string + planGitHubEnvironment: + required: true + type: string + PAC_INPUT_FOLDER: + required: true + type: string + PAC_DEFINITIONS_FOLDER: + required: true + type: string + +env: + PAC_INPUT_FOLDER: ${{ inputs.PAC_INPUT_FOLDER }} + PAC_DEFINITIONS_FOLDER: ${{ inputs.PAC_DEFINITIONS_FOLDER }} + +jobs: + deployRoles: + runs-on: ubuntu-latest + environment: ${{ inputs.planGitHubEnvironment }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download Artifact + # If you are using GHES, use v3 instead of v4. See https://github.com/actions/download-artifact#v4---whats-new for more information. + uses: actions/download-artifact@v4 + with: + name: plans-${{ inputs.pacEnvironmentSelector }} + + - name: Azure Login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + enable-AzPSSession: true + allow-no-subscriptions: true + + - name: Deploy Roles + uses: azure/powershell@v2 + with: + inlineScript: 'Scripts/Deploy/Deploy-RolesPlan.ps1 -PacEnvironmentSelector ${{ inputs.pacEnvironmentSelector }} -InformationAction Continue' + azPSVersion: "latest" diff --git a/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/plan-exemptions-only.yml b/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/plan-exemptions-only.yml new file mode 100644 index 00000000..25046595 --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/plan-exemptions-only.yml @@ -0,0 +1,77 @@ +name: 'Reusable Workflow: Plan Exemptions Only' + +on: + workflow_call: + inputs: + pacEnvironmentSelector: + required: true + type: string + planGitHubEnvironment: + required: true + type: string + PAC_OUTPUT_FOLDER: + required: true + type: string + PAC_DEFINITIONS_FOLDER: + required: true + type: string + outputs: + deployPolicyChanges: + description: "The result of evaluating if a policy deployment is required" + value: ${{ jobs.plan.outputs.deployPolicyChanges }} + deployRoleChanges: + description: "The result of evaluating if a role deployment is required" + value: ${{ jobs.plan.outputs.deployRoleChanges }} + +env: + pacEnvironmentSelector: ${{ inputs.pacEnvironmentSelector }} + PAC_OUTPUT_FOLDER: ${{ inputs.PAC_OUTPUT_FOLDER }} + PAC_DEFINITIONS_FOLDER: ${{ inputs.PAC_DEFINITIONS_FOLDER }} + +jobs: + plan: + runs-on: ubuntu-latest + environment: ${{ inputs.planGitHubEnvironment }} + outputs: + deployPolicyChanges: ${{ steps.detectPlan.outputs.deployPolicyChanges }} + deployRoleChanges: ${{ steps.detectPlan.outputs.deployRoleChanges }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Azure Login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + enable-AzPSSession: true + allow-no-subscriptions: true + + - name: Plan + uses: azure/powershell@v2 + with: + inlineScript: 'Scripts/Deploy/Build-DeploymentPlans.ps1 -PacEnvironmentSelector ${{ env.pacEnvironmentSelector }} -BuildExemptionsOnly -InformationAction Continue' + azPSVersion: "latest" + + - name: Detect Plan + id: detectPlan + run: | + if (Test-Path $env:PAC_OUTPUT_FOLDER) { + echo "deployPolicyChanges=yes" >> $env:GITHUB_OUTPUT + if (Get-ChildItem $env:PAC_OUTPUT_FOLDER -Recurse -Include roles-plan.json){ + echo "deployRoleChanges=yes" >> $env:GITHUB_OUTPUT + } + } + else { + echo "::notice title=Detect Plan::Plan not found. Nothing to deploy. Skipping remaining tasks and deploy jobs..." + } + shell: pwsh + + - name: Upload Deployment Plan as Artifact + if: steps.detectPlan.outputs.deployPolicyChanges == 'yes' || steps.detectPlan.outputs.deployRoleChanges == 'yes' + uses: actions/upload-artifact@v4 + with: + name: "plans-${{ inputs.pacEnvironmentSelector }}" + path: ${{ env.PAC_OUTPUT_FOLDER }} + if-no-files-found: error \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/plan.yml b/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/plan.yml new file mode 100644 index 00000000..e6a59b7a --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/plan.yml @@ -0,0 +1,76 @@ +name: 'Reusable Workflow: Plan' + +on: + workflow_call: + inputs: + pacEnvironmentSelector: + required: true + type: string + planGitHubEnvironment: + required: true + type: string + PAC_OUTPUT_FOLDER: + required: true + type: string + PAC_DEFINITIONS_FOLDER: + required: true + type: string + outputs: + deployPolicyChanges: + description: "The result of evaluating if a policy deployment is required" + value: ${{ jobs.plan.outputs.deployPolicyChanges }} + deployRoleChanges: + description: "The result of evaluating if a role deployment is required" + value: ${{ jobs.plan.outputs.deployRoleChanges }} + +env: + PAC_OUTPUT_FOLDER: ./Output + PAC_DEFINITIONS_FOLDER: ./Definitions + +jobs: + plan: + runs-on: ubuntu-latest + environment: ${{ inputs.planGitHubEnvironment }} + outputs: + deployPolicyChanges: ${{ steps.detectPlan.outputs.deployPolicyChanges }} + deployRoleChanges: ${{ steps.detectPlan.outputs.deployRoleChanges }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Azure Login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + enable-AzPSSession: true + allow-no-subscriptions: true + + - name: Plan + uses: azure/powershell@v2 + with: + inlineScript: 'Scripts/Deploy/Build-DeploymentPlans.ps1 -PacEnvironmentSelector ${{ inputs.pacEnvironmentSelector }} -InformationAction Continue' + azPSVersion: "latest" + + - name: Detect Plan File + id: detectPlan + run: | + if (Test-Path $env:PAC_OUTPUT_FOLDER) { + echo "deployPolicyChanges=yes" >> $env:GITHUB_OUTPUT + if (Get-ChildItem $env:PAC_OUTPUT_FOLDER -Recurse -Include roles-plan.json){ + echo "deployRoleChanges=yes" >> $env:GITHUB_OUTPUT + } + } + else { + echo "::notice title=Detect Plan::Plan not found. Nothing to deploy. Skipping remaining tasks and deploy jobs..." + } + shell: pwsh + + - name: Upload Deployment Plan as Artifact + if: steps.detectPlan.outputs.deployPolicyChanges == 'yes' || steps.detectPlan.outputs.deployRoleChanges == 'yes' + uses: actions/upload-artifact@v4 + with: + name: "plans-${{ inputs.pacEnvironmentSelector }}" + path: ${{ env.PAC_OUTPUT_FOLDER }} + if-no-files-found: error \ No newline at end of file diff --git a/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/remediate.yml b/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/remediate.yml new file mode 100644 index 00000000..bc5c3fd7 --- /dev/null +++ b/StarterKit/Pipelines/GitHubActions/templates-ps1-use-scripts/remediate.yml @@ -0,0 +1,41 @@ +name: 'Reusable Workflow: Remediation' + +on: + workflow_call: + inputs: + pacEnvironmentSelector: + required: true + type: string + planGitHubEnvironment: + required: true + type: string + PAC_DEFINITIONS_FOLDER: + required: true + type: string + +env: + pacEnvironmentSelector: ${{ inputs.pacEnvironmentSelector }} + PAC_DEFINITIONS_FOLDER: ${{ inputs.PAC_DEFINITIONS_FOLDER }} + +jobs: + remediation: + runs-on: ubuntu-latest + environment: ${{ inputs.planGitHubEnvironment }} + steps: + + - name: Checkout + uses: actions/checkout@v4 + + - name: Azure Login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + enable-AzPSSession: true + allow-no-subscriptions: true + + - name: PolicyRemediation + uses: azure/powershell@v2 + with: + inlineScript: 'Scripts/Operations/Create-AzRemediationTasks.ps1 -PacEnvironmentSelector ${{ env.pacEnvironmentSelector }} -OnlyCheckManagedAssignments -Interactive $false -InformationAction Continue' + azPSVersion: "latest" \ No newline at end of file diff --git a/Sync-Repo.ps1 b/Sync-Repo.ps1 index 44215073..d9b00914 100644 --- a/Sync-Repo.ps1 +++ b/Sync-Repo.ps1 @@ -9,14 +9,19 @@ * Module * Schemas * Scripts + * Scripts-Deprecated * StarterKit * Files in root folder ($SourceDirectory) * CODE_OF_CONDUCT.md * LICENSE + * mkdocs.yml * README.md * SECURITY.md * SUPPORT.md * Sync-Repo.ps1 + * Sync-FromGH.ps1 + * Sync-ToGH.ps1 + * .github (workflows for publishing to PSGallery) .PARAMETER SourceDirectory Directory with the source (cloned or forked/cloned repo) @@ -84,6 +89,10 @@ if (Test-Path $SourceDirectory -PathType Container) { Write-Information "Deleting '$DestinationDirectory/Scripts'" Remove-Item "$DestinationDirectory/Scripts" -Recurse } + if (Test-Path "$DestinationDirectory/Scripts-Deprecated") { + Write-Information "Deleting '$DestinationDirectory/Scripts-Deprecated'" + Remove-Item "$DestinationDirectory/Scripts-Deprecated" -Recurse + } if (Test-Path "$DestinationDirectory/StarterKit") { Write-Information "Deleting '$DestinationDirectory/StarterKit'" Remove-Item "$DestinationDirectory/StarterKit" -Recurse @@ -98,14 +107,20 @@ if (Test-Path $SourceDirectory -PathType Container) { Copy-Item "$SourceDirectory/Schemas" "$DestinationDirectory/Schemas" -Recurse -Force Write-Information "Copying '$SourceDirectory/Scripts' to '$DestinationDirectory/Scripts'" Copy-Item "$SourceDirectory/Scripts" "$DestinationDirectory/Scripts" -Recurse -Force + Write-Information "Copying '$SourceDirectory/Scripts-Deprecated' to '$DestinationDirectory/Scripts-Deprecated'" + Copy-Item "$SourceDirectory/Scripts-Deprecated" "$DestinationDirectory/Scripts-Deprecated" -Recurse -Force Write-Information "Copying '$SourceDirectory/StarterKit' to '$DestinationDirectory/StarterKit'" Copy-Item "$SourceDirectory/StarterKit" "$DestinationDirectory/StarterKit" -Recurse -Force - Write-Information "Copying files from root directory '$SourceDirectory' to '$DestinationDirectory'" - Copy-Item "$SourceDirectory/*.md" "$DestinationDirectory" - Copy-Item "$SourceDirectory/*.ps1" "$DestinationDirectory" - Copy-Item "$SourceDirectory/*.yml" "$DestinationDirectory" + Write-Information "Copying files from root directory and workflows '$SourceDirectory' to '$DestinationDirectory'" + Copy-Item "$SourceDirectory/CODE_OF_CONDUCT.md" "$DestinationDirectory" Copy-Item "$SourceDirectory/LICENSE" "$DestinationDirectory" + Copy-Item "$SourceDirectory/README.md" "$DestinationDirectory" + Copy-Item "$SourceDirectory/SECURITY.md" "$DestinationDirectory" + Copy-Item "$SourceDirectory/SUPPORT.md" "$DestinationDirectory" + Copy-Item "$SourceDirectory/Sync-Repo.ps1" "$DestinationDirectory" + Copy-Item "$SourceDirectory/Sync-FromGH.ps1" "$DestinationDirectory" + Copy-Item "$SourceDirectory/Sync-ToGH.ps1" "$DestinationDirectory" } else { Write-Error "The source directory '$SourceDirectory' must exist" -ErrorAction Stop