thinformatics

View Original

Cloning Entra Cloud Sync Jobs

Today I want to share my experience that I’ve gained while setting up Entra Cloud Sync in a Topology where more than one Active Directory should receive synced Group-Objects from one centralized Entra ID Environment. The destination AD’s were organized slightly differently and some minor mappings differed, but in general the syncs should be very similar.

Because I was expecting to do this more than once and I like the “Configuration as Code”-Concept, I’ve looked for a way to clone an existing Entra Cloud Sync Config.

In this article, I will share how I got the job done.

The Challenge

Cause we are aiming for a cloud-first approach for Identity, we implemented Cloud Sync for Group provisioning as soon as it was announced as the successor of the Entra Connect Group Writeback feature. We use Entra Cloud Sync to provision selected Groups in an OnPrem Active Directory. We have specific scoping filters and attribute mappings in place to identify the groups we provision and to modify the destination attributes like the OrganizationalUnit, or the displayName. These mappings differ from the Microsoft standard.

Now we had the challenge to integrate another OnPrem AD Environment into the tenant. We had similar requirements for the group provisioning to this new destination AD. Cause the way to add these mappings and filters into a new sync is complex and needs a lot of clicks (which means that you can click false often!), I’ve looked for a way to create a configuration by code.

I also can imagine similar requirements where this approach could be useful:

  • You want to define a new group provisioning in your existing AD, e.g. when you target another default OU.

  • You need to modify your sync rules but need a test-setup that is similar to production.

  • You have “Desired State Configuration“ requirements and you want to be able to go back to a validated configuration.

  • You want to migrate a sync setup to another tenant.

The Tools

As you might remember from blog posts I published in the past I’m a friend of using PowerShell with as less as possible modules. All you need to use this approach is PowerShell and an Entra App Registration for authentication. With PowerShell and Graph API, you can manage most parts Entra ID.

The Preparation

To be able to provision Groups to a new Active Directory, you need to setup and configure the provisioning Agent first. You can use this link as instruction: Install the Microsoft Entra provisioning agent - Microsoft Entra ID | Microsoft Learn. Afterward, you should see the new Agent in the Entra Portal. Entra will choose the agent automatically by checking the managed domain it was configured for. In my setup, I have one agent that is responsible for the existing AD (jsflab.com) and one for the new AD (dev.jsflab.com).

Now we’re prepared to clone our existing setup and target the new AD. To be able to clone it using PowerShell, we need to authenticate first. For this, I’ve created an App Registration and assigned permissions to it. For simplicity, I’ve used application permissions with an app secret. In productive environments, you should use delegated permissions or at least certificate based authentication.

So, navigate to Entra ID > Applications > App Registrations and create a new App Registration. You need to assign the application permissions Application.ReadWrite.All & Synchronization.ReadWrite.All. Please note the Application ID, the Tenant ID, and a secret value to use it in the Script.

The “Cloning“

I will share and describe single script parts here. I will share the whole script later. You can also recycle the method to create the access token which I will not explain here.

My goal was not to create a 1:1 clone, but I wanted to clone most of the settings. As I recognized the API Endpoint “synchronizationSchema“ which is the main sync config object only allows to update the schema at all. So I can’t just modify single values easily. Every time you update it, all the config must be contained in the PUT Request. Because the config contains a lot of settings and is deeply nested, I’ve tried to download an existing schema from my clone source and use it at the creation of the new job. Luckily that works!

I downloaded the configuration of an existing job and stored it as a JSON file. To do so you need to navigate to your existing Job in the Entra Portal and note the Sync App objectID ($ServicePrincipalID) and the Sync Job ID ($SyncJobID):

With these ID’s your able to download the configured schema. You can do so and store the JSON with the following cmdlets. (Script can be downloaded here: thinBlog/DownloadCloudSyncJson.ps1 at main · thinformatics/thinBlog (github.com))

Now you have a local copy of your JSON. I aimed to change the destination OU (mapping) and the group filter (scope). I used search and replace within the JSON to create a new JSON which defines the Schema for my cloned Job.

Now, where we have defined the schema we have everything we need to create a new sync. To clone the sync based on the JSON, the attached script contains requests for the following steps.

Create a Service Principal

The provisioning job is defined in a ServicePrincipal (Enterprise Application). Important is that you choose the right template for the creation of the EA which is "fb81332f-3eca-4ecf-a939-4278e501d330" (I looked this up in the existing EA, which also displays the information from which template it was generated)

Create and configure the Sync-Job

Now we have the base for the provisioning app. The displayName of the App was provided within the body. Next, we need to create the sync job which initiates the group provisioning every 20 minutes. The Body contains the Template ID “AAD2ADGroupProvisioning” which defines that the sync is for group provisioning in the direction Entra ID -> Active Directory, not for user cloud sync etc.

The next step is to configure the managed Domain for which the sync will be responsible. At least one provisioning agent must be registered for the named domain. The job will choose one of the existing domains for the managed domain automatically.

We’re already on the home straight. We have prepared the synchronization and defined the sync target by setting a managed domain. Now we will import the JSON we might have modified before for our requirements. We import the JSON File content and use it as body for our sync job schema definition.

You might want to check the job in the Entra Admin Portal and validate if the job was configured as expected. You can do so and start the sync job manually in the portal, or you can use the sync API Endpoint to start the Sync.

All cmdlet’s together

I’ve created a simple script which uses the shown cmdlets to create a clone/modified config. Feel free to use it. All you need to do is provide your auth information by inserting the App-Registration values you’ve noted in the preparation. Insert the values into the function “Get-AppAuthCredentials“. I’m using the SecretManagement Module to store these values, but you can also provide them in clear text for testing. Afterward you can run the script like this:

The script can be found here: thinBlog/Clone-EntraCloudSyncConfig.ps1 at main · thinformatics/thinBlog (github.com)

Summary

I’ve shared cmdlets and a script that can be used to create a 1:1 or a modified copy of a group provisioning job in Entra Cloud Sync. The script makes it easy for you to create duplicates of a tested and acknowledged configuration. I can imagine various use cases for this method. If you find this useful, maybe you can share the use-cases for which you used it.

It’s a bit spooky to clone a configuration (the JSON has 8000+ lines) like this. Unfortunately, the synchronizationSchema Graph Endpoint only accepts full replacement of the whole schema. So I can’t easily start with the default configuration and only update single values afterward without enormous effort.

But in general, I’m happy with this handling and the sync jobs I’ve created using this method do what they are designed for. Until now I have not tested if this method also works for other sync jobs like user synchronization. But from my first understanding, it should work very similarly. Maybe I will share my experience it at a later point in time.