Microsoft Entra Tenant Data
This documentation is written for the new backend system which is the default since Backstage version 1.24. If you are still on the old backend system, you may want to read its own article instead, and consider migrating!
The Backstage catalog can be set up to ingest organizational data - users and teams - directly from a tenant in Microsoft Entra ID via the Microsoft Graph API.
Installation
The package is not installed by default, therefore you have to add @backstage/plugin-catalog-backend-module-msgraph
to your backend package.
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-msgraph
Next add the basic configuration to app-config.yaml
catalog:
providers:
microsoftGraphOrg:
default:
tenantId: ${AZURE_TENANT_ID}
user:
filter: accountEnabled eq true and userType eq 'member'
group:
filter: >
securityEnabled eq false
and mailEnabled eq true
and groupTypes/any(c:c+eq+'Unified')
schedule:
frequency: PT1H
timeout: PT50M
For large organizations, this plugin can take a long time, so be careful setting low frequency / timeouts and importing a large amount of users / groups for the first try.
Finally, updated your backend by adding the following line:
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(import('@backstage/plugin-catalog-backend-module-msgraph/alpha'));
Authenticating with Microsoft Graph
Local Development
For a local dev environment, it's recommended you have the Azure CLI or Azure PowerShell installed, and are logged in to those.
Alternatively you can use VSCode with the Azure extension if you install @azure/identity-vscode
.
When these are set up, the plugin will authenticate with the Microsoft Graph API without you needing to configure any credentials, or granting any special permissions.
If you can't do this, you'll have to create an App Registration.
App Registration
If none of the other authentication methods work, you can create an app registration in the azure portal. By default the graph plugin requires the following Application permissions (not Delegated) for Microsoft Graph:
GroupMember.Read.All
User.Read.All
If your organization required Admin Consent for these permissions, that will need to be granted.
When authenticating with a ClientId/ClientSecret, you can either set the AZURE_TENANT_ID
, AZURE_CLIENT_ID
and AZURE_CLIENT_SECRET
environment variables, or specify the values in configuration
microsoftGraphOrg:
default:
##...
clientId: 9ef1aac6-b454-4e69-9cf5-7199df049281
clientSecret: REDACTED
To authenticate with a certificate rather than a client secret, you can set the AZURE_TENANT_ID
, AZURE_CLIENT_ID
and AZURE_CLIENT_CERTIFICATE_PATH
environments
Managed Identity
If deploying to resources that supports Managed Identity, and has identities configured (e.g. Azure App Services, Azure Container Apps), Managed Identity should be picked up without any additional configuration.
If your app has multiple managed identities, you may need to set the AZURE_CLIENT_ID
environment variable to tell Azure Identity which identity to use.
To grant the managed identity the same permissions as mentioned in App Registration above, please follow this guide
Filtering imported Users and Groups
By default, the plugin will import all users and groups from your directory. This can be customized through filters and search queries. Keep in mind that if you omit filters and search queries for the user or group properties, the plugin will automatically import all available users or groups.
Groups
A smaller set of groups can be obtained by configuring a search query or a filter.
If both filter
and search
are provided, then groups must match both to be ingested.
microsoftGraphOrg:
providerId:
group:
filter: securityEnabled eq false and mailEnabled eq true and groupTypes/any(c:c+eq+'Unified')
search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
If you don't want to only ingest groups matching the search
and/or filter
query, but also the groups which are members of the matched groups, you can use the includeSubGroups
configuration:
microsoftGraphOrg:
providerId:
group:
filter: securityEnabled eq false and mailEnabled eq true and groupTypes/any(c:c+eq+'Unified')
search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
includeSubGroups: true
In addition to these groups, one additional group will be created for your organization. All imported groups will be a child of this group.
Users
There are two modes for importing users - You can import all user objects matching a filter
.
microsoftGraphOrg:
providerId:
user:
filter: accountEnabled eq true and userType eq 'member'
Alternatively you can import users that are members of specific groups.
For each group matching the search
and filter
query, each group member will be imported.
Only direct group members will be imported, not transient users.
microsoftGraphOrg:
providerId:
userGroupMember:
filter: "displayName eq 'Backstage Users'"
search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
User photos
By default, the photos of users will be fetched and added to each user entity. For huge organizations this may be unfeasible, as it will take a very long time, and can be disabled by setting loadPhotos
to false
:
microsoftGraphOrg:
providerId:
user:
filter: ...
loadPhotos: false
If you are using userGroupMember
, the configuration for loadPhotos
should still be managed under users:
while omitting search
and filters
.
microsoftGraphOrg:
providerId:
user:
loadPhotos: false
userGroupMember:
filter: "displayName eq 'Backstage Users'"
search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
Customizing Transformation
Ingested entities can be customized by providing custom transformers.
These can be used to completely replace the built in logic, or used to tweak it by using the default transformers (defaultGroupTransformer
, defaultUserTransformer
and defaultOrganizationTransformer
Entities can also be excluded from backstage by returning undefined
.
When using custom transformers, you may want to customize the data returned. Several configuration options can be provided to tweak the Microsoft Graph query to get the data you need
microsoftGraphOrg:
providerId:
user:
expand: manager
group:
expand: member
select: ['id', 'displayName', 'description']
Using Provider Config Transformer
Dynamic configuration scaling allows the msgraph
catalog plugin to adjust its settings at runtime without requiring a redeploy. This feature is useful for scenarios where configuration needs to be updated based on real-time events or changing conditions. For example, you can dynamically adjust synchronization schedules, filters, and search parameters to optimize performance and responsiveness.
Adjusting fields that are not used on each scheduled ingestion (e.g., id
, schedule
) will have no effect.
Dynamically changing configuration on the fly can introduce unintended consequences, such as system instability and configuration errors. Please review your transformer carefully to ensure that it is working as anticipated!
Example Use Cases:
- Filter Scaling: Adjust filters like
userGroupMember
andgroupFilter
dynamically. - Search Parameter Adjustment: Change search parameters such as
groupSearch
anduserSelect
on-the-fly.
Using Custom Transformers
Transformers can be configured by extending microsoftGraphOrgEntityProviderTransformExtensionPoint
. Here is an example:
import { createBackendModule } from '@backstage/backend-plugin-api';
import { microsoftGraphOrgEntityProviderTransformExtensionPoint } from '@backstage/plugin-catalog-backend-module-msgraph/alpha';
import {
myUserTransformer,
myGroupTransformer,
myOrganizationTransformer,
myProviderConfigTransformer,
} from './transformers';
backend.add(
createBackendModule({
pluginId: 'catalog',
moduleId: 'microsoft-graph-extensions',
register(env) {
env.registerInit({
deps: {
microsoftGraphTransformers:
microsoftGraphOrgEntityProviderTransformExtensionPoint,
},
async init({ microsoftGraphTransformers }) {
microsoftGraphTransformers.setUserTransformer(myUserTransformer);
microsoftGraphTransformers.setGroupTransformer(myGroupTransformer);
microsoftGraphTransformers.setOrganizationTransformer(
myOrganizationTransformer,
);
microsoftGraphTransformers.setProviderConfigTransformer(
myProviderConfigTransformer,
);
},
});
},
}),
);
The myUserTransformer
, myGroupTransformer
, myOrganizationTransformer
, and myProviderConfigTransformer
transformer functions are from the examples in the section below.