Conditional Access as a Code with DevOps and PowerShell – Part 1

I’m often getting asked – “Why do we need to manage stuff as a Code anyways” and my reply is usually “Well, try implementing conditional access manually with the Azure GUI and see how many mistakes you make.”

Managing CA as a Code not only reduces the human errors, but ensures that we have traceability over who does what in CA and more importantly who did what in the past. It also ensures faster deployments – like, much faster ๐Ÿ™‚

Once the initial setup is done, it is also very easy to onboard new customers on it.

Many thanks to my colleagues, who inspired me for the solution:

  • Roger Zander’s work https://rzander.azurewebsites.net/ . Roger is the Author of the Get-AuthToken function.
  • Martin Wรผtrich’s work https://blog.hosebei.ch/ . Martin created a brilliant similar solution. I am sure his code is much more optimized ๐Ÿ™‚
  • Alex Filipin’s work : https://github.com/AlexFilipin/ – he has posted the Policy Repository

So, without further ado, here is what I’m using with success in many productive environments, so this setup is super battle-tested

First a little bit over the setup. You’d need the following components:

  • Azure DevOps Org
  • A project in DevOps
  • A minimum of Entra ID P1 License
  • Disabled Security Defaults in Entra ID (So that we can create CA policies)
  • Repo in DevOps
  • App Registration per client tenant (Also possible with service connection – not in scope of the blog)

This is a diagram of how the whole setup looks like:

Let’s explain:

  • Each Conditional Access policy creates 2 groups – One for Temporary Exclusions and One for Permanent Exclusions. The groups are then excluded from the policy
  • Each Policy has an Exclusion for the Emergency Access Accounts EXCEPT the policy 110 – Admin protection – All apps Require Strong Auth For BreakGlassAccounts, which ONLY has the Breaking Glass accounts inside

Let’s start with the App Registration in DevOps. You’d need the following Application permissions:

  • Application.Read.All
  • Directory.ReadWrite.All
  • Group.Create
  • Group.ReadWrite.All
  • GroupMember.Read.All
  • Policy.Read.All
  • Policy.ReadWrite.ConditionalAccess

Once this is ready, create a Client Secret (Or use a certificate or service connection)

Once this is done, go to DevOps and create a new Variable Group:

You’d need 3 values here:

  • Tenant ID (You can find it in the app Registration Overview)
  • Application ID (Again in the app registration overview)
  • Client Secret – make sure to copy it when you create it as afterwards it is hidden

The next step is to create the Repo.

Here are all files you need: https://github.com/Nikolay-Marinov/Conditional-Access-as-a-Code

Create a new Repo and Upload the files inside:

Now create a simple YAML file:

trigger:
- main

pool:
  vmImage: windows-latest

steps:
- task: PublishBuildArtifacts@1
  inputs:
    PathtoPublish: '$(Pipeline.Workspace)/s/'
    ArtifactName: 'ConditionalAccessPolicies'
    publishLocation: 'Container'

Now Upload the other files from the GitHub Repo to the DevOps Repo:

https://github.com/Nikolay-Marinov/Conditional-Access-as-a-Code

Let’s also explain the config file. If you take a look at the release script, you’d notice than it needs 4 parameters:

[CmdletBinding()]
param(
    [Parameter(Mandatory = $false)]
    $tenantid, #This one we have from the target tenant

    [Parameter(Mandatory = $false)]
    $applicationid,#This one we have from the target tenant app ID

    [Parameter(Mandatory = $false)]
    $clientsecret,#This one we have from the target tenant app cl secret
    
    [Parameter(Mandatory = $false)]
    $configname #This one we need to create

)

Here is how – it’s super easy

{
    "Policies": [
        { "Name": "801","Status": "Disabled"},
        { "Name": "802","Status": "Disabled"}
    ],
    "Prefix" : "configroar-demo",
    "Administrator Group" : "configroar-Demo-CA-Administrators",
    "DeployToPilotFirst" : "true"
}

The config is in JSON format and you need one per target tenant

Policies you need to choose how the policies are to be created – in my example they are disabled and I’d recommend to start with disabled ones

The Prefix means how the groups , which are created, will be called – they all start with “ConfigRoar-Demo” in this case

The “Administrator Group” is relevant for the 100-199 policies for Admin protection. They are usually role-targeted but you may want to add more accounts in the scope and this group is for that

and finally “DeployToPilotFirst” is a Boolean Switch , which defines if the policies are to be deployed to a Pilot Group first instead of all Users. The Group will be automatically created and I advise to start with this option

Once you are ready with the “Cocktail” of policies, you can make the release pipeline:

Use the published Artefact from the Build Pipeline and just add one PowerShell Job, where you call the script with the necessary parameters (As you defined them in the Variables Group – DO NOT FORGET TO ADD THE VARIABLES GROUP to the Release Pipeline ๐Ÿ™‚

That’s it – let’s explore what happens in Azure on the target Tenant in Part 2 of the series

Leave a Reply

Your email address will not be published. Required fields are marked *