Skip to content

Commit

Permalink
Merge pull request #56 from Azure/feature/definitionEntryList
Browse files Browse the repository at this point in the history
New feature definitionEntryList
  • Loading branch information
techlake authored Aug 5, 2022
2 parents 90cdd26 + e635241 commit fb1cc5a
Show file tree
Hide file tree
Showing 29 changed files with 995 additions and 3,961 deletions.
190 changes: 42 additions & 148 deletions Definitions/Assignments/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@

## Table of Contents

- [Components](#components)
- [Assignment File Overview Diagram](#assignment-file-overview-diagram)
- [Assignment Json file structure](#assignment-json-file-structure)
- [Assignment Node Components](#assignment-node-components)
- [Details for `scope` and `notScope` Values](#details-for--scope--and--notscope--values)
- [Using the `PacAssignmentSelector`](#using-the--pacassignmentselector-)
- [Resource Group patterns in `notScope`](#resource-group-patterns-in--notscope-)
- [Example Scope Definition](#example-scope-definition)
- [Reading List](#reading-list)
* [Components](#components)
* [Assignment structure](#assignment-structure)
* [Assignment nodes](#assignment-nodes)
* [Details for `scope` and `notScope`](#details-for-scope-and-notscope)
* [Using the `PacAssignmentSelector`](#using-the-pacassignmentselector)
* [Resource Group patterns in `notScope`](#resource-group-patterns-in-notscope)
* [Example Scope Definition](#example-scope-definition)
* [Examples in StarterKit](#examples-in-starterkit)
* [Single node to assign allowed locations enforcement](#single-node-to-assign-allowed-locations-enforcement)
* [Hierarchy to assign security and compliance initiatives](#hierarchy-to-assign-security-and-compliance-initiatives)
* [Hierarchy to manage Azure resource tags](#hierarchy-to-manage-azure-resource-tags)
* [Reading List](#reading-list)

## Components

This chapter describes how **Policy Assignments** are handled by PaC. To learn about how custom Policy and Initiative definitions are managed, see the [Policy Definitions](../Policies/README.md) and [Initiative Definitions](../Initiatives/README.md).
This chapter describes how **Policy Assignments** are handled by EPAC. To learn about how custom Policy and Initiative definitions are managed, see the [Policy Definitions](../Policies/README.md) and [Initiative Definitions](../Initiatives/README.md).

The components required for **creating / updating / deleting Policy assignments and Policy set (initiative) assignments** are the following:

Expand All @@ -26,158 +29,33 @@ The components required for **creating / updating / deleting Policy assignments

<br/>

## Assignment File Overview Diagram
## Assignment structure

Assignment files are hierarchical for efficient Json definitions, avoiding duplication of Json with copy/paste.
<br/>

![Assignment File Overview Diagram](../../Docs/Images/PaC-Assignment-Structure.png)
Assignment Json is hierarchical for efficient definitions, avoiding duplication of Json with copy/paste

<br/>
**Note:** the tee is not required to be balanced. The number of levels is not restricted; however, anything beyond 5 levels is unnecessary in real scenarios and would be difficult to read and manage.

## Assignment Json file structure

`scope` and `notScope` use a `PacAssignmentSelector` to specify which scope to use for different environments and tenants. The value for the `PacAssignmentSelector` is passed to the build script as a parameter. A star matches any `PacAssignmentSelector` specified.

```json
{
"nodeName": "NodeOneName",
"parameters": {
"GlobalParameterOne": [
"TestValue"
]
},
"children": [
{
"nodeName": "ChildNodeName",
"scope": {
"dev": [
"Specified scope such as: '/subscriptions/00000000-0000-0000-000000000000"
],
"test": [
"Specified scope such as: '/subscriptions/00000000-0000-0000-000000000000"
],
"prod": [
"Specified scope such as: /providers/Microsoft.Management/managementGroups/<managementGroupId>"
]
},
"children": [
{
"nodeName": "nodeName",
"assignment": {
"name": "Assignment Name",
"displayName": "Assignment Display Name",
"description": "Assignment Description"
},
"definitionEntry": {
"policyName": "Reference to Initiative or Policy being assigned",
"friendlyNameToDocumentIfGuid": "Human friendly name of policy or initiative"
},
"parameters": {
"Local Parameter such as 'Effect'": "Deny"
},
"children": [
{
"nodeName": "NodeOne",
"assignment": {
"name": "AssignmentOne",
"displayName": "Display Name",
"description": "Description"
},
"parameters": {
"Lowest Level Local Parameter": "Value"
}
},
{
"nodeName": "NodeTwo",
"assignment": {
"name": "AssignmentTwo",
"displayName": "Display Name",
"description": "Description"
},
"parameters": {
"Lowest Level Local Parameter": "Value"
}
}

]
},

]
},
{
"nodeName": "NodeTwoName",
"definitionEntry": {
"policyName": "Reference to Initiative or Policy being assigned",
"friendlyNameToDocumentIfGuid": "Human friendly name of policy or initiative"
},
"assignment": {
"name": "Assignment Name",
"displayName": "Display Name",
"description": "Description of assignment"
},
"parameters": {
"Local Parameter such as 'Effect'": "Deny"
},
"children": [
{
"nodeName": "NodeOne",
"assignment": {
"name": "Assignment Name",
"displayName": "Assignment Display Name",
"description": "Assignment Description"
},
"parameters": {
"Lowest Level Local Parameter": "Value"
},
"scope": {
"prod": [
"Desired scope such as: /providers/Microsoft.Management/managementGroups/Contoso-Prod"
]
}
},
{
"nodeName": "NodeTwo",
"assignment": {
"name": "Assignment Name",
"displayName": "Display Name",
"description": "Display Name"
},
"parameters": {
"Lowest Level Local Parameter": "Value"
},
"scope": {
"prod": [
"Desired scope such as: /providers/Microsoft.Management/managementGroups/Contoso-NonProd"
]
}
}
]
}
]
}
```
![Assignment File Overview Diagram](../../Docs/Images/PaC-Assignment-Structure.png)

<br/>

## Assignment Node Components
## Assignment nodes

| Key | Description | Rule |
|-----|-------------|------|
| `nodeName` | arbitrary name of the node for usage by the scripts to pinpoint format errors. | Must exist in each node. |
| `managedIdentityLocation` | Selects the Managed Identity location for Policies with `DeployIfnotExists` and `Modify` effects. | Any node: overrides previous setting. |
| `scope` | List of scopes for assignment. | Must exist exactly once in each branch of the tree. |
| `notScope` | List of notScopes. | Cumulative in branch. May not appear at a child node once the `scope` has been determined. |
| `assignment` | Assignment `name`, `displayName` and `description`. | String values are concatenated in each branch. Assignment `name` lengths are limited to 24. Must exist at least once in every branch. |
| `notScope` | List of notScopes. | Cumulative in branch. May not appear at a child node once the `scope` has been defined. |
| `assignment` | Assignment `name`, `displayName` and `description`. The fields `name` and `displayName` are required. | String values are concatenated in each branch. Assignment `name` lengths are limited to 24. Must exist at least once in every branch. |
| `parameters` | Parameter values for the assignment. Specified parameters not defined in the assigned Policy or Initiative are silently ignored. | Union of all the `parameters` defined in a branch. `parameters` redefined at a child (recursive) node overwrite the parent nodes value. |
| `ignoreBranch` | Ignore the rest of the tee staring at this node. Can be used to define future assignments without deploying the assignments. | Any node: overrides are ignored. |
| `enforcementMode` | Similar to `ignoreBranch`, it deploys the assignment and sets the assignment to `Default` or `DoNotEnforce`. `DoNotEnforce` allows a whatif analysis. | Any node: overrides previous setting |
| `definitionEntry` | Specifies the `policyName` or `initiativeName` for the assignment. The name should not be a fully qualified `id`. `friendlyNameToDocumentIfGuid` and is purely used as a comment to make the Json more readable if the name is a GUID. | Must exist exactly once in each branch of the tree. |
| `enforcementMode` | Similar to `ignoreBranch`, it deploys the assignment and sets the assignment to `Default` or `DoNotEnforce`. `DoNotEnforce` allows a what if analysis. | Any node: overrides previous setting |
| `additionalRoleAssignments` | `roleDefinitionIds` are calculated from the included (direct or indirect via Initiative) Policy definition(s). Fo some Policies, such as DINE `diagnosticsSettings` the monitor destination might be in a different branch of the Management Group tree from the Assignment. This field specifies any roles requiring assignments in that MG branch. The value is an array, each element containing two items: `roleDefinitionId` and `scope` | Union of all the `additionalRoleAssignments` defined in this branch |
| Option 1: `definitionEntry` | Specify the `policyName` or `initiativeName` for the assignment. The name should not be a fully qualified `id`. `friendlyNameToDocumentIfGuid` is purely used as a comment to make the Json more readable if the name is a GUID (optional). | Either option 1 or option 2 must exist exactly once in each branch of the tree. |
| Option 2: `definitionEntryList` | List of definitions to assign - creates one assignment per list entry for each tree branch. Each entry must specify a `policyName` or `initiativeName` and may specify `friendlyNameToDocumentIfGuid`. A nested `assignment` must be included to differentiate the multiple assignments being created from a `definitionEntryList`. This `assignment` structure may include an `append` boolean field to indicate that the fields should be appended instead of (default) concatenated first. | Either option 1 or option 2 must exist exactly once in each branch of the tree. |

<br/>

## Details for `scope` and `notScope` Values
## Details for `scope` and `notScope`

### Using the `PacAssignmentSelector`

Expand All @@ -190,12 +68,28 @@ The assignment selector determines the array being selected for this run of the
### Example Scope Definition

| Scope | Example |
|---|---|
|-------|---------|
| Management group | `/providers/Microsoft.Management/managementGroups/<managementGroupId>` |
| Subscription | `/subscriptions/<subscriptionId>` |
| Resource Group | `/subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName>` |

<br/>
## Examples in StarterKit folder

### Single node to assign allowed locations enforcement

Assignment file [allowed-locations-assignments.jsonc](../../StarterKit/Definitions/Assignments/allowed-locations-assignments.jsonc) contains a single node to assign a single Initiative to one scope.

### Hierarchy to assign security and compliance initiatives

Assignment file [security-baseline-assignments.jsonc](../../StarterKit/Definitions/Assignments/security-baseline-assignments.jsonc) contains 2 levels of hierarchy containing the root node and 2 child nodes. It uses a `definitionEntryList` instead of `definitionEntry`. Defining this with the `definitionEntry` approach would have increased the hierarchy from 2 levels (3 nodes) to 3 levels (7 nodes).

**Note**: With only two types of environments, 3 nodes versus 7 nodes is a small difference; however if you have a more complex environment differentiation with lots of environment types and parameters this becomes quickly untenable. As an extreme illustration with 8 environments (e.g., sandbox, dev, integration, testing, uat, perf, pre-prod and prod), you would need to specify 25 nodes. Such a file would likely be thousands of lines long and completely unreadable

### Hierarchy to manage Azure resource tags

Assignment file [tag-assignments.jsonc](../../StarterKit/Definitions/Assignments/tag-assignments.jsonc) defines:
- Required tags and inherited tags with a `definitionEntryList` using 2 levels (plus the root node)
- Environment tag values for resource groups with a `definitionEntry` using two levels (plus the shared root node)

## Reading List

Expand Down
8 changes: 4 additions & 4 deletions Definitions/Documentation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Each file must contain one or both documentation topics. This example file has b
"documentAssignments": {
"environmentCategories": [
{
"pacEnvironment": "tenant1",
"pacEnvironment": "tenant",
"environmentCategory": "PROD",
"scopes": [ // Used in Markdown output only
"Management Groups: Contoso-Prod"
Expand All @@ -50,7 +50,7 @@ Each file must contain one or both documentation topics. This example file has b
]
},
{
"pacEnvironment": "tenant1",
"pacEnvironment": "tenant",
"environmentCategory": "NONPROD",
"scopes": [ // Used in Markdown output only
"Management Groups: Contoso-NonProd"
Expand All @@ -67,7 +67,7 @@ Each file must contain one or both documentation topics. This example file has b
]
},
{
"pacEnvironment": "tenant1",
"pacEnvironment": "tenant",
"environmentCategory": "DEV",
"scopes": [ // Used in Markdown output only
"Management Groups: Contoso-Dev"
Expand Down Expand Up @@ -117,7 +117,7 @@ Each file must contain one or both documentation topics. This example file has b
},
"documentInitiatives": [
{
"pacEnvironment": "tenant1",
"pacEnvironment": "tenant",
"fileNameStem": "contoso-compliance-initiatives",
"title": "Document interesting Initiatives",
"initiatives": [
Expand Down
14 changes: 9 additions & 5 deletions Definitions/Exemptions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@

## Exemption Files

Exemptions can be defined as Json or CSV files. The names of the definition files don't matter. Additionally, through the use of a third-party PowerShell module from the PowerShell Gallery `ImportExcel` (https://www.powershellgallery.com/packages/ImportExcel, https://github.com/dfinke/ImportExcel/tree/master/Public). The contributors to this project are not responsible for any issues with that module. To mitigate the risk, the StarterKit has commented out the use of the conversion to protect your system from any vulnerabilities and executes the script without an Azure login.
Exemptions can be defined as Json or CSV files. The names of the definition files don't matter.

The pacEnvironment (see global-settings.jsonc) is represented with a folder, such as dev, test, tenant1, ... A missing folder indicates that the pacEnvironment's Exemptions are managed by this solution. To extract existing extension, the operations script Get-AzExemptions.ps1 can be used to generate Json and CSV files. The output should be used to start the Exemption definitions.
Additionally, through the use of a third-party PowerShell module from the PowerShell Gallery `ImportExcel` (https://www.powershellgallery.com/packages/ImportExcel, https://github.com/dfinke/ImportExcel/tree/master/Public). The contributors to this project are not responsible for any issues with that module. To mitigate the risk, the StarterKit has commented out the use of the conversion to protect your system from any vulnerabilities and executes the script without an Azure login.

### Format
The pacEnvironment (see global-settings.jsonc) is represented with a folder, such as dev, test, tenant, ... A missing folder indicates that the pacEnvironment's Exemptions are managed by this solution. To extract existing extension, the operations script Get-AzExemptions.ps1 can be used to generate Json and CSV files. The output should be used to start the Exemption definitions.

`name`, `exemptioncategory`, `scope` and `assignmentId` are required fields. The others are optional.
### JSON Format

`name`, `displayName`, `exemptionCategory`, `scope` and `assignmentId` are required fields. The others are optional.

```jsonc
{
Expand All @@ -37,11 +39,13 @@ The pacEnvironment (see global-settings.jsonc) is represented with a folder, suc
}
```

### CSV/XLSX Format
If you use spreadsheets (.csv or .xlsx):
- Column headers must be exactly as the Json labels above.
- `policyDefinitionReferenceIds` use comma separated list within each cell.
- `metadata` cells must conatin valid Json.
- `metadata` cells must contain valid Json.

<br/>

## Reading List

Expand Down
Loading

0 comments on commit fb1cc5a

Please sign in to comment.