Azure Conditional Access Policies as Code with Graph API, Part 2: Plan
In the second part of our Azure Conditional Access Policies as Code with Graph API series, we'll be covering the Plan phase of our policies.
You can check out the other parts from the links below:
Part 2: Plan
Now that we have our current conditional access policies written, we can start making changes to the configuration through code rather than the portal.
We need to have a way to compare the local configuration with that of the remote, such as in Terraform Plan. The below PowerShell script will help with that.
PowerShell script
The script to compare the local configuration with the remote is [here]
The script imports the graph token module (created in the previous post)
Declares two functions. The first,
Get-Policies
, gets all local and remote policy configurations and stores them in variablesThe second function,
Get-JsonPaths
, is a recursive function to get all paths for our JSON properties to allow for comparisonsGet-Policies
is called andGet-JsonPaths
then loops over the policies to get all paths for properties which are then storedConducts a soft check to see if the remote JSON schema has changed from the local configuration
Compares the values for each local and remote JSON property and stores the results
Outputs a Plan of changes to let you preview the changes the script plans to make to the live policies
Creates directories and copies the policy files to create, update and delete to them
Pipeline
Now that we have the script to Plan our changes, let's add a stage to our pipeline to run it
- stage: Plan
dependsOn: [Validate]
condition: succeeded('Validate')
jobs:
- job: compare_local_remote
steps:
- task: PowerShell@2
displayName: 'plan policies'
inputs:
filePath: '$(Build.SourcesDirectory)/scripts/compare-conditional-access-policies.ps1'
arguments: '-clientID $(clientID) -clientSecret $(clientSecret) -tenantID $(tenantID)'
- task: PublishPipelineArtifact@1
inputs:
targetPath: '$(Build.SourcesDirectory)\update'
artifact: 'update'
publishLocation: 'pipeline'
- task: PublishPipelineArtifact@1
inputs:
targetPath: '$(Build.SourcesDirectory)\new'
artifact: 'new'
publishLocation: 'pipeline'
- task: PublishPipelineArtifact@1
inputs:
targetPath: '$(Build.SourcesDirectory)\remove'
artifact: 'remove'
publishLocation: 'pipeline'
I've set variables for the service principal's credentials in the pipeline settings UI and these are then passed in as arguments to the PowerShell script.
There are 3 tasks that publish the folders, with the policy files to create, update and delete, as pipeline artifacts. These will then be downloaded and used later in the Apply stage.
Running the pipeline now has the below output:
Within the Plan, I have made use of log formatting commands to better the output for readability. For instance, in the PowerShell script I've used ##[group]
and ##[endgroup]
so that I can output the live and local policy configurations in collapsible sections to prevent the plan from becoming too noisy.
Be sure to check out the last part 3 of this series where we'll discuss the Apply phase of Conditional Access Policies as Code with Graph API.