Skip to content

Commit

Permalink
Merge pull request #47 from Azure/feature/h
Browse files Browse the repository at this point in the history
Major improvements to pipeline
  • Loading branch information
techlake authored May 4, 2022
1 parent 9ed5583 commit 6fae684
Show file tree
Hide file tree
Showing 36 changed files with 1,129 additions and 2,220 deletions.
12 changes: 5 additions & 7 deletions Definitions/Assignments/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,7 @@ Assignment files are hierarchical for efficient JSON definitions, avoiding dupli
"nodeName": "NodeTwoName",
"definitionEntry": {
"policyName": "Reference to Initiative or Policy being assigned",
"friendlyNameToDocumentIfGuid": "Human friendly name of policy or initiative",
"roleDefinitionIds": [
"Role definitions needed. For example: b24988ac-6180-42a0-ab88-20f7382dd24c"
]
"friendlyNameToDocumentIfGuid": "Human friendly name of policy or initiative"
},
"assignment": {
"name": "Assignment Name",
Expand Down Expand Up @@ -170,12 +167,13 @@ Assignment files are hierarchical for efficient JSON definitions, avoiding dupli
| `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. |
| `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. |
| `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. |
| `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` 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. |
| `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. |
| `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 |

<br/>[Back to top](#policy-assignments)<br/>

Expand Down
Binary file added Docs/Azure Security Controls Process.vsdx
Binary file not shown.
16 changes: 10 additions & 6 deletions Pipeline/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Create service connections for each of your environments and require minimum rol
|Parameter | Required | Explanation |
|----------|----------|-------------|
| `PacEnvironmentSelector` | Optional | Selects the tenant, rootScope, defaultSubscription, assignment scopes/notScope and file names. If omitted, interactively prompts for the value. |
| `DefinitionsRootFolder` | Optional | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_ROOT_FOLDER` or `./Definitions`. It contains `global-settings.jsonc`.
| `DefinitionsRootFolder` | Optional | Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER` or `./Definitions`. It contains `global-settings.jsonc`.

<br/>[Back to top](#pipeline)<br/>

Expand All @@ -114,8 +114,9 @@ In addition to the [common parameters](#common-parmeters-for-flexible-and-unifie
|----------|----------|-------------|
| `IncludeResource GroupsForAssignments` | Optional | Resource Group level assignments are not recommended; therefore, the script excludes Resource Groups from processing to save substantial execution time (tens of minutes to hours). This switch parameter overrides that default behavior. |
| `SuppressDeletes` | Optional | When using this switch, the script will NOT delete extraneous Policy definitions, Initiative definitions and Assignments. This can be useful for brown field deployments. |
| `PlanFile` | Optional | Plan filename. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER/Plans/$PacEnvironmentSelector-plan.json` or `./Outputs/Plans/$PacEnvironmentSelector-plan.json`. |
| `RolesPlanFile` | Optional | Role Assignment plan output filename. Defaults to environment
| `OutputFolder` | Optional | Output folder path for plan files. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER` or `./Output`. |
| `PlanFile` | Optional | Plan output filename. Defaults to `$OutputFolder/policy-plan-$PacEnvironmentSelector/policy-plan.json`. |

<br/>[Back to top](#pipeline)<br/>

### Deploy-AzPoliciesInitiativesAssignmentsFromPlan.ps1
Expand All @@ -124,8 +125,10 @@ Deploys Policies, Initiatives, and Policy Assignments at their desired scope bas

|Parameter | Required | Explanation |
|----------|----------|-------------|
| `PlanFile` | Optional | Plan filename. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER/Plans/$PacEnvironmentSelector-plan.json` or `./Outputs/Plans/$PacEnvironmentSelector-plan.json`. |
| `RolesPlanFile` | Optional | Role Assignment plan filename. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER/Plans/$PacEnvironmentSelector-roles.json` or `./Outputs/Plans/$PacEnvironmentSelector-roles.json`. |
| `InputFolder` | Optional | Input folder path for plan files. Defaults to environment variable `$env:PAC_INPUT_FOLDER`, `$env:PAC_OUTPUT_FOLDER` or `./Output`. |
| `OutputFolder` | Optional | Output folder path for plan files. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER` or `./Output`. |
| `PlanFile` | Optional | Plan input filename. Defaults to `$InputFolder/policy-plan-$PacEnvironmentSelector/policy-plan.json`. |
| `RolesPlanFile` | Optional | Role Assignment plan output filename. Defaults to environment variable `$OutputFolder/roles-plan-$PacEnvironmentSelector/roles-plan.json`. |

<br/>[Back to top](#pipeline)<br/>

Expand All @@ -135,7 +138,8 @@ Creates the role assignments for the Managed Identities required for `DeployIfNo

|Parameter | Required | Explanation |
|----------|----------|-------------|
| `RolesPlanFile` | Optional | Role Assignment plan filename. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER/Plans/$PacEnvironmentSelector-roles.json` or `./Outputs/Plans/$PacEnvironmentSelector-roles.json`. |
| `InputFolder` | Optional | Input folder path for plan files. Defaults to environment variable `$env:PAC_INPUT_FOLDER`, `$env:PAC_OUTPUT_FOLDER` or `./Output`. |
| `RolesPlanFile` | Optional | Role Assignment plan input filename. Defaults to `$InputFolder/roles-plan-$PacEnvironmentSelector/roles-plan.json`. |

<br/>[Back to top](#pipeline)<br/>

Expand Down
24 changes: 18 additions & 6 deletions Scripts/Deploy/Build-AzPoliciesInitiativesAssignmentsPlan.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ param (
[Parameter(Mandatory = $false, HelpMessage = "When using this switch, the script will NOT delete extraneous Policy definitions, Initiative definitions and Assignments.")]
[switch]$SuppressDeletes,

[Parameter(Mandatory = $false, HelpMessage = "Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_ROOT_FOLDER or './Definitions'.")]
[Parameter(Mandatory = $false, HelpMessage = "Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER or './Definitions'.")]
[string]$DefinitionsRootFolder,

[Parameter(Mandatory = $false, HelpMessage = "Plan output filename. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER/Plans/`$PacEnvironmentSelector-plan.json or './Outputs/Plans/`$PacEnvironmentSelector-plan.json'.")]
[Parameter(Mandatory = $false, HelpMessage = "Output folder path for plan files. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER or './Output'.")]
[string]$OutpuFolder,

[Parameter(Mandatory = $false, HelpMessage = "Plan output filename. Defaults to `$OutputFolder/policy-plan-`$PacEnvironmentSelector/policy-plan.json.")]
[string]$PlanFile

)
Expand Down Expand Up @@ -70,11 +73,11 @@ function Write-AssignmentDetails {
# Initialize
$InformationPreference = "Continue"
Invoke-AzCli config set extension.use_dynamic_install=yes_without_prompt -SuppressOutput
$environment = Initialize-Environment $PacEnvironmentSelector -DefinitionsRootFolder $DefinitionsRootFolder
$environment = Initialize-Environment $PacEnvironmentSelector -definitionsRootFolder $DefinitionsRootFolder -outputFolder $OutputFolder
$rootScope = $environment.rootScope
$rootScopeId = $environment.rootScopeId
if ($PlanFile -eq "") {
$PlanFile = $environment.planFile
$PlanFile = $environment.policyPlanOutputFile
}

# Getting existing Policy Assignmentscls
Expand All @@ -92,6 +95,10 @@ $existingAssignments, $null = Get-AzAssignmentsAtScopeRecursive `
# Getting existing Policy/Initiative definitions and Policy Assignments in the chosen scope of Azure
$collections = Get-AllAzPolicyInitiativeDefinitions -rootScopeId $rootScopeId

# Collections for roleDefinitionIds
[hashtable] $policyNeededRoleDefinitionIds = @{}
[hashtable] $initiativeNeededRoleDefinitionIds = @{}

# Process Policy definitions
$newPolicyDefinitions = @{}
$updatedPolicyDefinitions = @{}
Expand All @@ -112,7 +119,8 @@ Build-AzPolicyDefinitionsPlan `
-replacedPolicyDefinitions $replacedPolicyDefinitions `
-deletedPolicyDefinitions $deletedPolicyDefinitions `
-unchangedPolicyDefinitions $unchangedPolicyDefinitions `
-customPolicyDefinitions $customPolicyDefinitions
-customPolicyDefinitions $customPolicyDefinitions `
-policyNeededRoleDefinitionIds $policyNeededRoleDefinitionIds

# Process Initiative definitions
$newInitiativeDefinitions = @{}
Expand All @@ -136,7 +144,9 @@ Build-AzInitiativeDefinitionsPlan `
-replacedInitiativeDefinitions $replacedInitiativeDefinitions `
-deletedInitiativeDefinitions $deletedInitiativeDefinitions `
-unchangedInitiativeDefinitions $unchangedInitiativeDefinitions `
-customInitiativeDefinitions $customInitiativeDefinitions
-customInitiativeDefinitions $customInitiativeDefinitions `
-policyNeededRoleDefinitionIds $policyNeededRoleDefinitionIds `
-initiativeNeededRoleDefinitionIds $initiativeNeededRoleDefinitionIds

# Process Assignment JSON files
$newAssignments = @{}
Expand All @@ -162,6 +172,8 @@ if (!$TestInitiativeMerge.IsPresent) {
-allInitiativeDefinitions $allInitiativeDefinitions `
-customInitiativeDefinitions $customInitiativeDefinitions `
-replacedInitiativeDefinitions $replacedInitiativeDefinitions `
-policyNeededRoleDefinitionIds $policyNeededRoleDefinitionIds `
-initiativeNeededRoleDefinitionIds $initiativeNeededRoleDefinitionIds `
-existingAssignments $existingAssignments `
-newAssignments $newAssignments `
-updatedAssignments $updatedAssignments `
Expand Down
24 changes: 16 additions & 8 deletions Scripts/Deploy/Deploy-AzPoliciesInitiativesAssignmentsFromPlan.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@ param (
[parameter(Mandatory = $false, HelpMessage = "Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a vlaue. The values are read from `$DefinitionsRootFolder/global-settings.jsonc.", Position = 0)]
[string] $PacEnvironmentSelector,

[Parameter(Mandatory = $false, HelpMessage = "Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_ROOT_FOLDER or './Definitions'.")]
[Parameter(Mandatory = $false, HelpMessage = "Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER or './Definitions'.")]
[string]$DefinitionsRootFolder,

[Parameter(Mandatory = $false, HelpMessage = "Plan input filename. Defaults to environment variable `"`$env:PAC_OUTPUT_FOLDER/Plans/`$PacEnvironmentSelector-plan.json`" or './Outputs/Plans/`$PacEnvironmentSelector-plan.json`"'.")]
[Parameter(Mandatory = $false, HelpMessage = "Input folder path for plan files. Defaults to environment variable `$env:PAC_INPUT_FOLDER, `$env:PAC_OUTPUT_FOLDER or './Output'.")]
[string]$InputFolder,

[Parameter(Mandatory = $false, HelpMessage = "Output folder path for plan files. Defaults to environment variable `$env:PAC_OUTPUT_FOLDER or './Output'.")]
[string]$OutputFolder,

[Parameter(Mandatory = $false, HelpMessage = "Plan input filename. Defaults to `$InputFolder/policy-plan-`$PacEnvironmentSelector/policy-plan.json`"'.")]
[string] $PlanFile,

[Parameter(Mandatory = $false, HelpMessage = "Role Assignment plan output filename. Defaults to environment variable `"`$env:PAC_OUTPUT_FOLDER/Plans/`$PacEnvironmentSelector-roles.json`" or './Outputs/Plans/`$PacEnvironmentSelector-roles.json`"'.")]
[Parameter(Mandatory = $false, HelpMessage = "Role Assignment plan output filename. Defaults to environment variable `$OutputFolder/roles-plan-`$PacEnvironmentSelector/roles-plan.json.")]
[string] $RolesPlanFile
)

Expand Down Expand Up @@ -67,6 +73,8 @@ function New-AzPolicyAssignmentHelper {
}
$splat.Add("WarningAction", "SilentlyContinue")

Write-Information "`$assignmentDefinition: Name=$($assignmentDefinition.Name), identityRequired=$($assignmentDefinition.identityRequired)"
Write-Information "`$assignmentDefinition: $($assignmentDefinition | ConvertTo-Json -Depth 100)"
if ($assignmentDefinition.identityRequired) {
$splat.Add("Location", $assignmentDefinition.managedIdentityLocation)
$assignmentCreated = New-AzPolicyAssignment @splat -AssignIdentity
Expand Down Expand Up @@ -116,12 +124,12 @@ function Set-AzPolicyAssignmentHelper {
#region Deploy Plan

$InformationPreference = "Continue"
$environment = Initialize-Environment $PacEnvironmentSelector -DefinitionsRootFolder $DefinitionsRootFolder
$environment = Initialize-Environment $PacEnvironmentSelector -DefinitionsRootFolder $DefinitionsRootFolder -outputFolder $OutputFolder -inputFolder $InputFolder
if ($PlanFile -eq "") {
$PlanFile = $environment.planFile
$PlanFile = $environment.policyPlanInputFile
}
if ($RolesPlanFile -eq "") {
$RolesPlanFile = $environment.rolesFile
$RolesPlanFile = $environment.rolesPlanOutputFile
}
$plan = Get-DeploymentPlan -PlanFile $PlanFile

Expand Down Expand Up @@ -310,7 +318,7 @@ if (!$noChanges) {
Write-Information " PrincipaId: $($identity.principalId)"

foreach ($roleAssignment in $roleAssignments) {
Write-Information " '$($roleAssignment.roleDefinitionName)' - '$($roleAssignment.roleDefinitionId)', Scope='$($roleAssignment.scope)'"
Write-Information " '$($roleAssignment.roleDisplayName)' - '$($roleAssignment.roleDefinitionId)', Scope='$($roleAssignment.scope)'"
}

}
Expand All @@ -328,7 +336,7 @@ if (!$noChanges) {
Write-Information " PrincipaId: $($identity.principalId)"

foreach ($role in $roles) {
Write-Information " $($role.roleDefinitionName) - $($role.roleDefinitionId), Scope=`'$($role.scope)`'"
Write-Information " $($role.roleDisplayName) - $($role.roleDefinitionId), Scope=`'$($role.scope)`'"
}

}
Expand Down
21 changes: 13 additions & 8 deletions Scripts/Deploy/Set-AzPolicyRolesFromPlan.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ param (
[parameter(Mandatory = $false, HelpMessage = "Defines which Policy as Code (PAC) environment we are using, if omitted, the script prompts for a vlaue. The values are read from `$DefinitionsRootFolder/global-settings.jsonc.", Position = 0)]
[string] $PacEnvironmentSelector,

[Parameter(Mandatory = $false, HelpMessage = "Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_ROOT_FOLDER or './Definitions'.")]
[Parameter(Mandatory = $false, HelpMessage = "Definitions folder path. Defaults to environment variable `$env:PAC_DEFINITIONS_FOLDER or './Definitions'.")]
[string]$DefinitionsRootFolder,

[Parameter(Mandatory = $false, HelpMessage = "Role Assignment plan input filename. Defaults to environment variable `"`$env:PAC_OUTPUT_FOLDER/Plans/`$PacEnvironmentSelector-roles.json`" or './Outputs/Plans/`$PacEnvironmentSelector-roles.json`"'.")]
[Parameter(Mandatory = $false, HelpMessage = "Input folder path for plan files. Defaults to environment variable `$env:PAC_INPUT_FOLDER, `$env:PAC_OUTPUT_FOLDER or './Output'.")]
[string]$InputFolder,

[Parameter(Mandatory = $false, HelpMessage = "Role Assignment plan input filename. Defaults to `$InputFolder/roles-plan-`$PacEnvironmentSelector/roles-plan.json.")]
[string] $RolesPlanFile
)

Expand All @@ -31,12 +34,13 @@ Write-Information ""
. "$PSScriptRoot/../Helpers/Split-AzPolicyAssignmentIdForAzCli.ps1"
. "$PSScriptRoot/../Helpers/Invoke-AzCli.ps1"
. "$PSScriptRoot/../Helpers/ConvertTo-HashTable.ps1"
. "$PSScriptRoot/../Helpers/Initialize-Environment.ps1"

$InformationPreference = "Continue"
Invoke-AzCli config set extension.use_dynamic_install=yes_without_prompt -SuppressOutput
$environment = Initialize-Environment $PacEnvironmentSelector -DefinitionsRootFolder $DefinitionsRootFolder
$environment = Initialize-Environment $PacEnvironmentSelector -DefinitionsRootFolder $DefinitionsRootFolder -inputFolder $InputFolder
if ($RolesPlanFile -eq "") {
$RolesPlanFile = $environment.rolesPlanFile
$RolesPlanFile = $environment.rolesPlanInputFile
}
$plan = Get-DeploymentPlan -PlanFile $RolesPlanFile

Expand All @@ -59,8 +63,8 @@ if ($changesNeeded) {
foreach ($roleAssignment in $roleAssignments) {
$scope = $roleAssignment.scope
$roleDefinitionId = $roleAssignment.roleDefinitionId
$roleDefinitionName = $roleAssignment.roleDefinitionName
Write-Information " $($roleDefinitionName) - $($roleDefinitionId), Scope=$($scope), Role Assignment Id=$($roleAssignment.id)"
$roleDisplayName = $roleAssignment.roleDisplayName
Write-Information " $($roleDisplayName) - $($roleDefinitionId), Scope=$($scope), Role Assignment Id=$($roleAssignment.id)"
Invoke-AzCli role assignment delete --ids $roleAssignment.id -SuppressOutput
}
}
Expand All @@ -81,8 +85,9 @@ if ($changesNeeded) {
foreach ($role in $roles) {
$scope = $role.scope
$roleDefinitionId = $role.roleDefinitionId
$roleDefinitionName = $role.roleDefinitionName
Write-Information " $($roleDefinitionName) - $($roleDefinitionId), Scope=$($scope)"
$roleDefinitionName = $roleDefinitionId.Split('/')[-1]
$roleDisplayName = $role.roleDisplayName
Write-Information " $($roleDisplayName) - $($roleDefinitionName), Scope=$($scope)"

$retries = 0
while ($retries -le $retriesLimit) {
Expand Down
Loading

0 comments on commit 6fae684

Please sign in to comment.