For many organizations, centralized identity management has been a “must have” feature to even begin considering the move to the cloud. The idea is simple – have a central location to manage identities from and leverage it to provision access and enable SSO across all your apps. Over the past decade, we’ve seen a steady move from on-premises AD towards Azure AD as the control plane. And as cloud adoption matured, organizations in turn faced the challenges of multi-tenant scenarios.
This is of course a new retelling of the same old story. Even back in the on-premises days, the need to consolidate to or split into multiple directories was nothing uncommon, as was establishing a prolonged co-existence between separate directories. When it comes to its cloud offerings, Microsoft largely ignored that part of the market for years, allowing third-party tools to fill in the gaps. Only in the past two years or so we’ve seen substantial effort on Microsoft’s side, both in the migration space as well as cross-tenant collaboration. In this article, we will cover Microsoft’s latest feature – cross-tenant synchronization.
What is cross-tenant synchronization
As the name suggests, cross-tenant sync is a feature that allows you to synchronize identities (user objects) between multiple Azure AD/Microsoft 365 tenants. Synchronization is one-way only, from a “source” to a “target” tenant, but you can have multiple sync configurations, including a “mesh” structure (a limit of single source:target mapping is enforced though). Moreover, synchronization is not a one-time operation but runs continuously (at a 40min interval), providing a substantial improvement over the existing B2B collaboration feature. In effect, you can think of cross-tenant sync as the analog of AAD Connect or AAD Cloud sync, but using your Azure AD tenant instead of on-premises AD as the source.
The feature is intended to be used as a way to boost the collaboration experience between users in the same (multi-tenant) organization, where organization is a loose term. Technically, there are no restrictions to synchronizing say Amazon users into the Microsoft tenant, but because we’re provisioning user objects along with their relevant attributes, all in an automatic manner, there are obvious privacy implications. Thus, Microsoft currently positions this feature to use in scenarios where “high level of trust” exists between the individual tenants.
Prerequisites and initial configuration steps
To configure cross-tenant sync, some preparatory work is needed, most importantly deciding on the topology to use. The only other requirement is licensing – an Azure AD Premium P1 SKU or equivalent is needed. Once the plan is fleshed out, you can proceed with setting up the configuration. Start by creating a cross-tenant settings object for each of the tenants involved. While none of the B2B collaboration or B2B Direct connect settings are required for cross-tenant sync, the feature uses the cross-tenant settings object for parts of the setup process. Specifically, the Allow users sync into this tenant setting can be found under the newly introduced Cross-tenant sync tab.
An important note is due here. As the name of the aforementioned setting suggests, cross-tenant sync is PUSH operation from a SOURCE tenant to a TARGET one. Thus, in order to allow provisioning of users from another tenant, you need to first configure a cross-tenant settings object, then toggle the Allow users sync into this tenant setting under the Inbound access settings configuration corresponding to the source-target relationship in the target tenant (in fact, you will only find it under Inbound, and not Outbound settings). If this sounds confusing, perhaps the official documentation would help – you can find detailed step-by-step instructions therein, with lots and lots of screenshots we prefer not to duplicate here.
Apart from toggling the Allow users sync into this tenant setting, one additional bit of config needs to be completed. This time, both the source and the target tenant need to toggle the Suppress consent prompts … setting under Trust settings for the Outbound (in the source tenant) and Inbound (target tenant) settings, respectively. The full name of the setting will actually differ depending on where you’re toggling it from, so pay attention to it! This is the bit where the Azure AD Premium licensing requirement is enforced – without it, said option will be grayed out and cannot be toggled, and in turn the cross-tenant sync cannot be configured. While the documentation and the setting description itself leave you with the impression that this is an optional setting, in fact it’s a mandatory one and failing to toggle it will result in an impasse later on.
After configuring the cross-tenant access settings, we can proceed with the creation of the actual cross-tenant sync object. This step is configured on the source tenant’s side, as only the source tenant can control the sync settings. First, navigate to the newly introduced Cross-tenant synchronization tab under the Azure AD blade. Therein, click the Configurations tab, then the New configuration button. The only required bit of input here is the Name of the configuration. This is basically a container for the configuration settings. However, you might notice that at this step of the process, a new application registration is configured bearing, the name of the cross-tenant sync object:
Said application will be used to govern the sync process, as we will see later on. Interestingly, no Owner is stamped on it and no API permissions either. But I digress.
Finishing up the config and initial sync
Once the configuration object has been created, the actual setup can be performed. The first step is verifying the tenant configuration, which we performed back under the Cross-tenant access settings page on both tenants. With the target tenant’s ID value at hand, click the newly created configuration object and under Provisioning > Provisioning mode, select the Automatic value. Therein, enter the Tenant ID value and press the Test connection button. This is the only place where the target tenant will be referenced, and you might find it surprising that no credentials or secrets are requested. We will explain why later on. Press the Save button to complete this step. At this point, the cross-tenant access settings of both tenants will be checked.
With this, we have configured an outbound cross-tenant sync/provisioning from our source tenant to the designated target one. As mentioned above, the source tenant is in full control of the sync settings, which include scoping/filtering the set of users to synchronize, the set of attribute mappings and corresponding sync rules, generic sync settings and more advanced options such as fine-tuning the schema or controlling the out of scope deletions (more on this later). Due to the plethora of settings available, we will only cover the default configuration here, with few minor exceptions, and refer you to the official documentation instead.
It’s worth mentioning that by default, only users that have been assigned (either directly or via group) to the service principal object corresponding to the given configuration will be synced. If you want to change this behavior, toggle the value of the Scope setting value under Configurations > Name > Provisioning > Settings. Here’s also a good place to mention the other method to access the provisioning settings, namely by opening the service principal properties > Provisioning > Edit provisioning page. As each source:target sync config will have a separate application/service principal, you can granularly control the sync settings per mapping.
Bit I digress, again. To start the actual sync process, open the corresponding configuration object’s page and under Overview, hit the Start provisioning button. Alternatively, you can use the Provision on demand option to test with a user or two. Executing either of these tasks will trigger a sync job, and after a short moment will display this sync cycle summary/results. Alternatively, you can monitor the result of the operation via the Provisioning logs tab. Examining the events therein, you will notice that most operations on the source side are driven by the same application object we noted above.
Some additional information can also be found under the Audit logs tab. For anyone familiar with the AAD Cloud sync/AAD Provisioning process, the steps and details revealed by the logs will surely look quite familiar. After all, the cross-tenant sync feature is powered by the same stack on the backend.
Of course, the most interesting bit is what happens on the receiving side, in the target tenant. After a minute or two, depending on the number of users to sync, you can see the newly provisioned objects popping up in the target tenant, either as Member users (default configuration) or as Guests (if you change the userType attribute mapping to Guest). Unfortunately, neither the Azure AD blade nor the Graph API allow you to easily filter on just such users, as the corresponding Identities property is not supported for filtering. Instead, you can filter by Creation type or External user state, though in the set of results will likely be larger than just the users provisioned from the source tenant.
Some of the properties shown on the above screenshot might need further explanation. The users are provisioned as external members (userType value of Member), and still depend on the source tenant for authentication. The Creation type value of Invitation and External user state value of Accepted both signal that the familiar B2B framework was leveraged, yet none of the users will actually see an invitation email or a consent prompt – the whole process is transparent to them thanks to the automatic redemption settings we configured as part of the cross-tenant access policy. The process will also handle conflicts – if an existing B2B user is found, it will be matched against the source object and its properties updated.
And in case you were wondering, changes on the target tenant are executed by a set of two built-in service principals. First, we have the Microsoft B2B Admin Worker, with ClientID 1e2ca66a-c176-45ea-a877-e87f7231e0ee. Its job is complemented by the Microsoft.Azure.SyncFabric service principal, corresponding to ClientID 00000014-0000-0000-c000-000000000000. By leveraging these two “system” objects, already provisioned in every Azure AD tenant, Microsoft is effectively bypassing the need for the source and target organization to exchange admin credentials or any other type of secret.
Some additional details
One of the biggest benefits of the cross-tenant sync feature is that synchronization occurs continuously. This in turn means that changes of user objects and their properties will be synchronized from the source tenant to the target one periodically, on a 40-min (non-configurable) cadence. This is in stark contrast with the standard B2B invitation process, which is one-time only operation. The screenshot below illustrates how the cross-tenant sync process picks up changes in the properties of a previously synced user:
An important thing to understand here is that unlike AAD Connect/AAD Cloud, the cross-tenant sync process does not force a change in the source of authority (SOA) for the user. In other words, the objects provisioned within the target tenant are fully editable. As changes only ever flow from the source to the target tenant, and never in the opposite direction, any modifications of the user properties in the target tenant will result in some drift. The incremental sync process will not overwrite changes made on the target side, unless something changed with the user on the source side too. On a related note, if needed you can disable the Update action in the Attribute mappings, so that changes in user’s properties on the source side never flow to the target tenant.
Lastly, we are given some control over how deletions are processed. Few items come into play here. First, the Delete action can be disabled on the source side, as part of the Attribute mappings. Also on the source side, you can control the processing of accounts that fall out of scope of the sync process. By toggling the SkipOutOfScopeDeletions flag on the service principal object, you can decide whether such accounts will be disabled in the target tenant or remain active therein. Lastly, you can control the Accidental deletion prevention feature, as detailed here. On the target side, you can control the self-service ability for users to remove themselves from your organization, as detailed in this article.
Summary and final remarks
There is a lot more that we can cover about the cross-cloud sync process, but this should be sufficient for the purposes of this article. In summary, Microsoft has taken a proven solution and extended it to cover multi-tenant scenarios. While the initial setup process can be streamlined a bit (or a lot), organizations will certainly appreciate the tight integration with the Azure AD platform, which allows the configuration to be performed without ever exchanging admin credentials. Others will likely enjoy the set of Graph API endpoints that can be used to govern each step of the process.
Since cross-cloud sync is based on existing technology, it offers an extensive array of customizations for a preview feature. Several different ways of scoping the set of users to include, robust set of attributes and rule mappings, and a method to provision users on demand, to name a few. The feature is of course not without limitations. Cross-cloud synchronization isn’t currently supported, although it’s top of mind for Microsoft and will likely make its way to the tool in time for the GA release. Synchronizing objects other than users is also not currently supported, and neither are some properties for user objects, such as the photo or managerial relationships. Guest user objects are also not supported, although you can decide whether to provision a regular “member” object as either Member or a Guest. User’s credentials are also not synchronized, and the authentication process is still completely governed by the source tenant. An extensive list of known issues and limitations can be found here.