Skip to content

Commit

Permalink
Merge pull request #744 from Azure/519-clarify-spns-least-privilege-a…
Browse files Browse the repository at this point in the history
…nd-environments-for-cicd
  • Loading branch information
apybar authored Sep 12, 2024
2 parents 91b6ca2 + 85b3dc3 commit df152ae
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 42 deletions.
13 changes: 8 additions & 5 deletions Docs/ci-cd-ado-pipelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,25 @@
This page covers the specifics for the Azure DevOps (ADO) pipelines created by using the Starter Kit. Pipelines can be further customized based on requirements. Guidance provided is for the simplified GitHub Flow as documented in the [branching flows](ci-cd-branching-flows.md). Documentation on the Release Flow pipelines will be made available in a future release.

> [!Note]
> To find all examples of Azure DevOps Pipelines, please visit [StarterKit/Pipelines/AzureDevOps](https://github.com/Azure/enterprise-azure-policy-as-code/tree/main/StarterKit/Pipelines/AzureDevOps).
> [App Registration Setup](ci-cd-app-registrations.md) is a pre-requisite.
## Service connections for the Service Principals

Create ADO service connections for each of the previously created [App Registrations](ci-cd-app-registrations.md). You will need to retrieve the credential for the Service Principal that Azure Devops will use for Authentication. This can be either a Client Secret, a X509 certificate, or a Federated Credential. For more information on these options, refer to the [Application Credentials](ci-cd-app-registrations.md/#application-credentials)
Create ADO service connections for each of the previously created [App Registrations](ci-cd-app-registrations.md). You will need to retrieve the credential for the Service Principal that Azure Devops will use for Authentication. This can be either a Client Secret, a X509 certificate, or a Federated Credential. For more information on these options, refer to the [Application Credentials](ci-cd-app-registrations.md/#application-credentials).

## Pipeline Templates

The provided Azure DevOps pipelines utilize the template functionality to create re-usable components that are shared between pipeline files. More details on Azure DevOps Pipelines Templates can be found in the [Azure DevOps Documentation](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops&pivots=templates-includes)

## GitHub Flow Pipeline

If utilizing the GitHub flow branching strategy, three pipeline files are created:
- epac-dev-pipeline
- epac-tenant-pipeline
- epac-remediation-pipeline
If utilizing the GitHub flow branching strategy, three pipeline files are created

- [epac-dev-pipeline](https://github.com/Azure/enterprise-azure-policy-as-code/blob/main/StarterKit/Pipelines/AzureDevOps/GitHub-Flow/epac-dev-pipeline.yml)
- [epac-tenant-pipeline](https://github.com/Azure/enterprise-azure-policy-as-code/blob/main/StarterKit/Pipelines/AzureDevOps/GitHub-Flow/epac-tenant-pipeline.yml)
- [epac-remediation-pipeline](https://github.com/Azure/enterprise-azure-policy-as-code/blob/main/StarterKit/Pipelines/AzureDevOps/GitHub-Flow/epac-remediation-pipeline.yml)

### epac-dev-pipeline
This represents the Develop Policy Resources in a Feature Branch flow as described in [Branching Flows](ci-cd-branching-flows.md/#develop-policy-resources-in-a-feature-branch). In general, The EPAC-Dev pipeline is configured to run when any change is pushed to a `feature/*` branch. It runs across three (3) stages: Plan, Deploy & Tenant Plan.
Expand Down
2 changes: 1 addition & 1 deletion Docs/ci-cd-app-registrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ The following Service Principals & Role assignments would be created to support

Credentials will need to be created for each Service Principal to be used in the CI/CD process. Traditionally, this is accomplished by creating a Client Secret on the associated Entra ID Application, and providing the CI/CD tool with the Application's ID and Secret. Secrets present an automation challenge as they need to be managed, secured, and rotated as they eventually expire. To solve this, some tools, including Azure DevOps, now support the use of Federated Credentials as described below.

### Alternative: `Azure Federated Identity Credentials`
### Azure Federated Identity Credentials

Federated identity credentials are a new type of credential that enables workload identity federation for software workloads. Workload identity federation allows you to access Microsoft Entra protected resources without needing to manage secrets (for supported scenarios).

Expand Down
5 changes: 3 additions & 2 deletions Docs/ci-cd-github-actions.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Github Actions

The starter kit contains a sample pipeline to use GitHub Actions to deploy Enterprise Policy as Code. It features a review process and is driven by pull requests and approvals.
This page covers the specifics for the GitHub Actions pipelines created by using the Starter Kit. Pipelines can be further customized based on requirements. We have revised our approach to GitHub Actions simplifying the process and make it easier to understand. The new approach is documented below and is included in the starter kit with v8.5 and later.

We have revised our approach to GitHub Actions simplifying the process and make it easier to understand. The new approach is documented below and is included in the starter kit with v8.5 and later.
> [!Note]
> To find all examples of GitHub Actions Pipelines, please visit [StarterKit/Pipelines/GitHubActions](https://github.com/Azure/enterprise-azure-policy-as-code/tree/main/StarterKit/Pipelines/AzureDevOps).
The previous version is still available in the starter kit in folder `Legacy` and the [documentation is retained](#legacy-github-cicd-workflows) at the end of this page.

Expand Down
4 changes: 2 additions & 2 deletions Docs/operational-scripts-documenting-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ Each file must contain one or both documentation topics. This example file in th
"documentAssignments": {
"documentAllAssignments": [
{
"enabled": true,
"pacEnvironment": "EPAC-Prod",
"fileNameStemPrefix": "Production",
"skipPolicyAssignments": [],
"skipPolicyDefinitions": [
"/providers/microsoft.authorization/policysetdefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8" // Azure Security Benchmark v3
Expand Down Expand Up @@ -298,8 +298,8 @@ When enabled, this section lists all Policy Assignments across all scopes where

`documentAllAssignments` entry specifies:

* `enabled`: setting this value to "true" will enable the use of 'documentAllAssignments' and will overwrite 'environmentCategories' if the section exists within the file.
* `pacEnvironment`: references the Policy as Code environment in `global-settings.jsonc` defining the tenant and root scope where the Policies and Policy Sets are deployed.
* `fileNameStemPrefix`: add a prefix to the fileNameStem set in "documentationSpecifications". Usefull when needing to avoid overwriting of files.
* `skipPolicyAssignments`: list of Policy Assignment ID's used to define Policy Assinments that do not want to included in the output.
* `skipPolicyDefinitions`: list of Policy Definition and Policy Set ID's used to define Policy Assinments that do not want to included in the output.
* `overrideEnvironmentCategory`: list of custom defined Environment Categories that will overwrite the auto-generated values. By default, all Policy Assignment scopes are treated as an individual "Environment Category", therefore leverage this section to override these Environemnt Categories and create custom groupings. (For an example see [`Example Documentation Specification File using 'documentAllAssignments'`](#Example-Documentation-Specification-File-using-documentAllAssignments))
Expand Down
31 changes: 17 additions & 14 deletions Docs/start-implementing.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The following steps are required to implement Enterprise Policy as Code (EPAC) i
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.
7. Populate your Definitions folder with Policy resources. (For a folder structure example, please see [StarterKit/Definitions-Common](https://github.com/Azure/enterprise-azure-policy-as-code/tree/main/StarterKit/Definitions-Common))
- [Option A:] [Extract existing Policy resources](start-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.
Expand Down Expand Up @@ -113,18 +113,6 @@ The simplest `global-settings.jsonc` for the above structure is:
}
```

## Cloud Environment with Unsupported/Missing Policy Definitions

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
Expand Down Expand Up @@ -166,12 +154,27 @@ Many scripts use parameters for input and output folders. They default to the cu

### Create the Definitions folder

Create a new EPAC `Definitions` folder with a number of subfolder and a `global-settings.jsonc` file
Create a new EPAC `Definitions` folder with a number of subfolder and a `global-settings.jsonc` file.

> [!TIP]
> For a folder structure example, please see [StarterKit/Definitions-Common](https://github.com/Azure/enterprise-azure-policy-as-code/tree/main/StarterKit/Definitions-Common).
```ps1
New-HydrationDefinitionFolder -DefinitionsRootFolder Definitions
```

## Cloud Environment with Unsupported/Missing Policy Definitions

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"
]
},
```

## Debug EPAC issues

Should you encounter issues with the expected behavior of EPAC, try the following:
Expand Down
8 changes: 2 additions & 6 deletions Scripts/Helpers/Out-DocumentationForPolicyAssignments.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ function Out-DocumentationForPolicyAssignments {

# Output file
$outputFilePath = "$($OutputPath -replace '[/\\]$', '')/$($fileNameStem).md"
$allLines | Out-File $outputFilePath -Force
$allLines | Out-File "$outputFilePath" -Force

# Output file
foreach ($key in $assignmentsByCategory.keys | Sort-Object) {
Expand Down Expand Up @@ -590,11 +590,7 @@ function Out-DocumentationForPolicyAssignments {
#endregion csv

#region PushToWiki
if ($DocumentationSpecification.markdownAdoWikiConfig) {
if ($WikiClonePat -eq "") {
Write-Error "PAT Token not found! Please pass as parameter 'WikiClonePat'!"
Exit 1
}
if ($WikiClonePat) {
Write-Information "Attempting push to Azure DevOps Wiki"
# Clone down wiki
git clone "https://$($WikiClonePat):x-oauth-basic@$($DocumentationSpecification.markdownAdoWikiConfig.adoOrganization).visualstudio.com/$($DocumentationSpecification.markdownAdoWikiConfig.adoProject)/_git/$($DocumentationSpecification.markdownAdoWikiConfig.adoWiki).wiki"
Expand Down
40 changes: 28 additions & 12 deletions Scripts/Operations/Build-PolicyDocumentation.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ param (
[switch] $IncludeManualPolicies,

[Parameter(Mandatory = $false, HelpMessage = "Include if using a PAT token for pushing to ADO Wiki.")]
[string] $WikiClonePat
[string] $WikiClonePat,

[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] $pacSelector
)

# Dot Source Helper Scripts
Expand Down Expand Up @@ -258,16 +261,8 @@ foreach ($file in $files) {
}
}

# Set documentAllEnabled to false if does not exist
if ($null -eq $documentationSpec.documentAssignments.documentAllAssignments.enabled) {
$documentAllEnabled = $false
}
else {
$documentAllEnabled = $documentationSpec.documentAssignments.documentAllAssignments.enabled
}

# Process instructions to document Assignments
if ($documentationSpec.documentAssignments -and !$documentAllEnabled) {
if ($documentationSpec.documentAssignments -and !$documentationSpec.documentAssignments.documentAllAssignments) {
$documentAssignments = $documentationSpec.documentAssignments
$environmentCategories = $documentAssignments.environmentCategories

Expand Down Expand Up @@ -340,9 +335,25 @@ foreach ($file in $files) {
}
}

if ($documentationSpec.documentAssignments -and $documentAllEnabled) {
# Load pacEnvironment
if ($documentationSpec.documentAssignments -and $documentationSpec.documentAssignments.documentAllAssignments) {
# Load pacEnvironments from policy documentations folder
$pacEnvironmentSelector = $documentationSpec.documentAssignments.documentAllAssignments.pacEnvironment

# Check to see if PacSelector was passed as a parameter
if ($pacSelector) {
$pacEnvironmentSelector = $pacSelector
$pacSelectorDocumentAllAssignments = $documentationSpec.documentAssignments.documentAllAssignments | Where-Object { $_.pacEnvironment -eq "$pacSelector" }
$documentationSpec.documentAssignments.documentAllAssignments = $pacSelectorDocumentAllAssignments

if ($null -eq $documentationSpec.documentAssignments.documentAllAssignments) {
Write-Error "Provided PacSelector '$pacSelector' not found in $($file.Name)!" -ErrorAction Stop
}
}

# Check to see if PacSelector was not passed as a parameter but there are multiple pacEnvironments configured within documentAllAssignments
if ($pacEnvironmentSelector.count -gt 1 -and $pacSelector -eq "") {
Write-Error "Multiple 'pacEnvironments' found in $($file.Name) - Please provide parameter -PacSelector to specify the documentation needed to be created" -ErrorAction Stop
}
$pacEnvironment = Switch-PacEnvironment `
-PacEnvironmentSelector $pacEnvironmentSelector `
-PacEnvironments $pacEnvironments `
Expand Down Expand Up @@ -493,6 +504,11 @@ foreach ($file in $files) {
# Build documents
$documentationSpecifications = $documentAssignments.documentationSpecifications
foreach ($documentationSpecification in $documentationSpecifications) {
# Check to see if naming contains prefix for file name
if ($documentationSpec.documentAssignments.documentAllAssignments.fileNameStemPrefix) {
$documentationSpecification.fileNameStem = $documentationSpec.documentAssignments.documentAllAssignments.fileNameStemPrefix + "-" + $documentationSpecification.fileNameStem
}

$documentationType = $documentationSpecification.type
if ($null -ne $documentationType) {
Write-Information "Field documentationType ($($documentationType)) is deprecated"
Expand Down
32 changes: 32 additions & 0 deletions StarterKit/Definitions-Common/global-settings.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"$schema": "https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/main/Schemas/global-settings-schema.json",
"pacOwnerId": "bd715eb8-36d2-4d33-8db0-505e04c0e4aa",
"pacEnvironments": [
{
"pacSelector": "EPAC-DEV",
"cloud": "AzureCloud",
"tenantId": "4df7a0a2-1b2f-4a43-b48f-bed4b04a4f91",
"deploymentRootScope": "/providers/Microsoft.Management/managementGroups/4df7a0a2-1b2f-4a43-b48f-bed4b04a4f91",
"desiredState": { // [optional]
"strategy": "ownedOnly", // default full
"keepDfcSecurityAssignments": true, // default false
"doNotDisableDeprecatedPolicies": false
},
"globalNotScopes": [],
"managedIdentityLocation": "eastus2"
},
{
"pacSelector": "EPAC-PROD",
"cloud": "AzureCloud",
"tenantId": "3385800d-0197-4981-92e4-12a04898f862",
"deploymentRootScope": "/providers/Microsoft.Management/managementGroups/3385800d-0197-4981-92e4-12a04898f862",
"desiredState": { // [optional]
"strategy": "full", // default full
"keepDfcSecurityAssignments": true, // default false // default full
"doNotDisableDeprecatedPolicies": false
},
"globalNotScopes": [],
"managedIdentityLocation": "eastus2"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"$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"
],
"tenant": [
"/providers/Microsoft.Management/managementGroups/mg-enterprise"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"documentAssignments": {
"documentAllAssignments": [
{
"enabled": true,
"pacEnvironment": "EPAC-PROD",
"fileNameStemPrefix": "Production",
"skipPolicyAssignments": [],
"skipPolicyDefinitions": [
"/providers/microsoft.authorization/policysetdefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8" // Azure Security Benchmark v3
],
"overrideEnvironmentCategory": {}
}
],
"documentationSpecifications": [
{
"fileNameStem": "Azure-Policy-Assignments",
"environmentCategories": [],
"title": "Current list of Azure Policies deployed",
"markdownAdoWiki": true,
"markdownAdoWikiConfig": [
{
"adoOrganization": "EPAC",
"adoProject": "EPAC",
"adoWiki": "EPAC"
}
]
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"exemptions": [
{
"name": "short-name",
"displayName": "Descriptive name displayed on portal",
"description": "More details",
"exemptionCategory": "Waiver",
"scopes": [
"/subscriptions/11111111-2222-3333-4444-555555555555",
"/subscriptions/11111111-2222-3333-4444-555555555556/resourceGroups/resourceGroupName1",
],
"policyDefinitionId": "/providers/microsoft.authorization/policyDefinitions/00000000-0000-0000-0000-000000000000",
}
]
}

0 comments on commit df152ae

Please sign in to comment.