Skip to content

Commit

Permalink
feat: align msgraph provider config
Browse files Browse the repository at this point in the history
Align msgraph entity provider config with the config of other entity providers.

Closes: backstage#12065
Signed-off-by: Patrick Jungermann <Patrick.Jungermann@gmail.com>
  • Loading branch information
pjungermann committed Jul 5, 2022
1 parent 06b6920 commit a145672
Show file tree
Hide file tree
Showing 12 changed files with 710 additions and 125 deletions.
91 changes: 91 additions & 0 deletions .changeset/long-bananas-rescue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
'@backstage/plugin-catalog-backend-module-msgraph': minor
---

Align `msgraph` plugin's entity provider config with other providers. **Deprecated** entity processor as well as previous config.

You will see warning at the log output until you migrate to the new setup.
All deprecated parts will be removed eventually after giving some time to migrate.

Please find information on how to migrate your current setup to the new one below.

**Migration Guide:**

There were two different way on how to use the msgraph plugin: processor or provider.

Previous registration for the processor:

```typescript
// packages/backend/src/plugins/catalog.ts
builder.addProcessor(
MicrosoftGraphOrgReaderProcessor.fromConfig(env.config, {
logger: env.logger,
// [...]
}),
);
```

Previous registration when using the provider:

```typescript
// packages/backend/src/plugins/catalog.ts
builder.addEntityProvider(
MicrosoftGraphOrgEntityProvider.fromConfig(env.config, {
id: 'https://graph.microsoft.com/v1.0',
target: 'https://graph.microsoft.com/v1.0',
logger: env.logger,
schedule: env.scheduler.createScheduledTaskRunner({
frequency: { minutes: 30 },
timeout: { minutes: 3 },
}),
// [...]
}),
);
```

Previous configuration as used for both:

```yaml
# app-config.yaml
catalog:
processors:
microsoftGraphOrg:
providers:
- target: https://graph.microsoft.com/v1.0
# [...]
```

**Replacement:**

Please check https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-msgraph/README.md for the complete documentation of all configuration options (config as well as registration of the provider).

```yaml
# app-config.yaml
catalog:
providers:
microsoftGraphOrg:
# In case you used the deprecated configuration with the entity provider
# using the value of `target` will keep the same location key for all
providerId: # some stable ID which will be used as part of the location key for all ingested data
target: https://graph.microsoft.com/v1.0
# [...]
```

```typescript
// packages/backend/src/plugins/catalog.ts
builder.addEntityProvider(
MicrosoftGraphOrgEntityProvider.fromConfig(env.config, {
logger: env.logger,
schedule: env.scheduler.createScheduledTaskRunner({
frequency: { minutes: 30 },
timeout: { minutes: 3 },
}),
// [...]
}),
);
```

In case you've used multiple entity providers before
**and** you had different transformers for each of them
you can provide these directly at the one `fromConfig` call
by passing a Record with the provider ID as key.
10 changes: 0 additions & 10 deletions app-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -234,16 +234,6 @@ catalog:
# dn: ou=access,ou=groups,ou=example,dc=example,dc=net
# options:
# filter: (&(objectClass=some-group-class)(!(groupType=email)))
microsoftGraphOrg:
### Example for how to add your Microsoft Graph tenant
#providers:
# - target: https://graph.microsoft.com/v1.0
# authority: https://login.microsoftonline.com
# tenantId: ${MICROSOFT_GRAPH_TENANT_ID}
# clientId: ${MICROSOFT_GRAPH_CLIENT_ID}
# clientSecret: ${MICROSOFT_GRAPH_CLIENT_SECRET_TOKEN}
# userFilter: accountEnabled eq true and userType eq 'member'
# groupFilter: securityEnabled eq false and mailEnabled eq true and groupTypes/any(c:c+eq+'Unified')

locations:
# Add a location here to ingest it, for example from a URL:
Expand Down
144 changes: 57 additions & 87 deletions plugins/catalog-backend-module-msgraph/README.md
Original file line number Diff line number Diff line change
@@ -1,85 +1,86 @@
# Catalog Backend Module for Microsoft Graph

This is an extension module to the `plugin-catalog-backend` plugin, providing a
`MicrosoftGraphOrgReaderProcessor` and a `MicrosoftGraphOrgEntityProvider` that
can be used to ingest organization data from the Microsoft Graph API. This
processor is useful if you want to import users and groups from Azure Active
Directory or Office 365.
This is an extension module to the `plugin-catalog-backend` plugin, providing a `MicrosoftGraphOrgEntityProvider`
that can be used to ingest organization data from the Microsoft Graph API.
This provider is useful if you want to import users and groups from Azure Active Directory or Office 365.

## Getting Started

First you need to decide whether you want to use an [entity provider or a processor](https://backstage.io/docs/features/software-catalog/life-of-an-entity#stitching) to ingest the organization data.
If you want groups and users deleted from the source to be automatically deleted
from Backstage, choose the entity provider.

1. Create or use an existing App registration in the [Microsoft Azure Portal](https://portal.azure.com/).
The App registration requires at least the API permissions `Group.Read.All`,
`GroupMember.Read.All`, `User.Read` and `User.Read.All` for Microsoft Graph
(if you still run into errors about insufficient privileges, add
`Team.ReadBasic.All` and `TeamMember.Read.All` too).

2. Configure the processor or entity provider:
2. Configure the entity provider:

```yaml
# app-config.yaml
catalog:
processors:
providers:
microsoftGraphOrg:
providers:
- target: https://graph.microsoft.com/v1.0
authority: https://login.microsoftonline.com
# If you don't know you tenantId, you can use Microsoft Graph Explorer
# to query it
tenantId: ${MICROSOFT_GRAPH_TENANT_ID}
# Client Id and Secret can be created under Certificates & secrets in
# the App registration in the Microsoft Azure Portal.
clientId: ${MICROSOFT_GRAPH_CLIENT_ID}
clientSecret: ${MICROSOFT_GRAPH_CLIENT_SECRET_TOKEN}
# Optional mode for querying which defaults to "basic".
# By default, the Microsoft Graph API only provides the basic feature set
# for querying. Certain features are limited to advanced querying capabilities.
# (See https://docs.microsoft.com/en-us/graph/aad-advanced-queries)
queryMode: basic # basic | advanced
providerId:
target: https://graph.microsoft.com/v1.0
authority: https://login.microsoftonline.com
# If you don't know you tenantId, you can use Microsoft Graph Explorer
# to query it
tenantId: ${MICROSOFT_GRAPH_TENANT_ID}
# Client Id and Secret can be created under Certificates & secrets in
# the App registration in the Microsoft Azure Portal.
clientId: ${MICROSOFT_GRAPH_CLIENT_ID}
clientSecret: ${MICROSOFT_GRAPH_CLIENT_SECRET_TOKEN}
# Optional mode for querying which defaults to "basic".
# By default, the Microsoft Graph API only provides the basic feature set
# for querying. Certain features are limited to advanced querying capabilities.
# (See https://docs.microsoft.com/en-us/graph/aad-advanced-queries)
queryMode: basic # basic | advanced
# Optional configuration block
user:
# Optional parameter to include the expanded resource or collection referenced
# by a single relationship (navigation property) in your results.
# Only one relationship can be expanded in a single request.
# See https://docs.microsoft.com/en-us/graph/query-parameters#expand-parameter
# Can be combined with userGroupMember[...] instead of userFilter.
userExpand: manager
expand: manager
# Optional filter for user, see Microsoft Graph API for the syntax
# See https://docs.microsoft.com/en-us/graph/api/resources/user?view=graph-rest-1.0#properties
# and for the syntax https://docs.microsoft.com/en-us/graph/query-parameters#filter-parameter
# This and userGroupMemberFilter are mutually exclusive, only one can be specified
userFilter: accountEnabled eq true and userType eq 'member'
filter: accountEnabled eq true and userType eq 'member'
# Optional configuration block
userGroupMember:
# Optional filter for users, use group membership to get users.
# (Filtered groups and fetch their members.)
# This and userFilter are mutually exclusive, only one can be specified
# See https://docs.microsoft.com/en-us/graph/search-query-parameter
userGroupMemberFilter: "displayName eq 'Backstage Users'"
filter: "displayName eq 'Backstage Users'"
# Optional search for users, use group membership to get users.
# (Search for groups and fetch their members.)
# This and userFilter are mutually exclusive, only one can be specified
search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
# Optional configuration block
group:
# Optional parameter to include the expanded resource or collection referenced
# by a single relationship (navigation property) in your results.
# Only one relationship can be expanded in a single request.
# See https://docs.microsoft.com/en-us/graph/query-parameters#expand-parameter
# Can be combined with userGroupMember[...] instead of userFilter.
groupExpand: member
# Optional search for users, use group membership to get users.
# (Search for groups and fetch their members.)
# This and userFilter are mutually exclusive, only one can be specified
userGroupMemberSearch: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
expand: member
# Optional filter for group, see Microsoft Graph API for the syntax
# See https://docs.microsoft.com/en-us/graph/api/resources/group?view=graph-rest-1.0#properties
groupFilter: securityEnabled eq false and mailEnabled eq true and groupTypes/any(c:c+eq+'Unified')
filter: securityEnabled eq false and mailEnabled eq true and groupTypes/any(c:c+eq+'Unified')
# Optional search for groups, see Microsoft Graph API for the syntax
# See https://docs.microsoft.com/en-us/graph/search-query-parameter
groupSearch: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
# Optional select for groups, this will allow you work with schemaExtensions in order to add extra information to your groups that can be used on you custom groupTransformers
search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
# Optional select for groups, this will allow you work with schemaExtensions
# in order to add extra information to your groups that can be used on you custom groupTransformers
# See https://docs.microsoft.com/en-us/graph/api/resources/schemaextension?view=graph-rest-1.0
groupSelect: ['id', 'displayName', 'description']
select: ['id', 'displayName', 'description']
```
`userFilter` and `userGroupMemberFilter` are mutually exclusive, only one can be provided. If both are provided, an error will be thrown.
`user.filter` and `userGroupMember.filter` are mutually exclusive, only one can be provided. If both are provided, an error will be thrown.

By default, all users are loaded. If you want to filter users based on their attributes, use `userFilter`. `userGroupMemberFilter` can be used if you want to load users based on their group membership.
By default, all users are loaded. If you want to filter users based on their attributes, use `user.filter`. `userGroupMember.filter` can be used if you want to load users based on their group membership.

3. The package is not installed by default, therefore you have to add a
dependency to `@backstage/plugin-catalog-backend-module-msgraph` to your
Expand All @@ -90,69 +91,34 @@ By default, all users are loaded. If you want to filter users based on their att
yarn add --cwd packages/backend @backstage/plugin-catalog-backend-module-msgraph
```

### Using the Entity Provider

4. The `MicrosoftGraphOrgEntityProvider` is not registered by default, so you
have to register it in the catalog plugin. Pass the target to reference a
provider from the configuration.

```diff
// packages/backend/src/plugins/catalog.ts
+import { Duration } from 'luxon';
+import { MicrosoftGraphOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-msgraph';
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
const builder = await CatalogBuilder.create(env);
+ // The target parameter below needs to match one of the providers' target
+ // value specified in your app-config (see above).
+ builder.addEntityProvider(
+ MicrosoftGraphOrgEntityProvider.fromConfig(env.config, {
+ id: 'production',
+ target: 'https://graph.microsoft.com/v1.0',
+ logger: env.logger,
+ schedule: env.scheduler.createScheduledTaskRunner({
+ frequency: Duration.fromObject({ minutes: 5 }),
+ timeout: Duration.fromObject({ minutes: 3 }),
+ frequency: { minutes: 5 },
+ timeout: { minutes: 3 },
+ }),
+ }),
+ );
```

### Using the Processor

4. The `MicrosoftGraphOrgReaderProcessor` is not registered by default, so you
have to register it in the catalog plugin:

```typescript
// packages/backend/src/plugins/catalog.ts
builder.addProcessor(
MicrosoftGraphOrgReaderProcessor.fromConfig(env.config, {
logger: env.logger,
}),
);
```

5. Add a location that ingests from Microsoft Graph:

```yaml
# app-config.yaml
catalog:
locations:
- type: microsoft-graph-org
target: https://graph.microsoft.com/v1.0
rules:
- allow: [Group, User]
```

## Customize the Processor or Entity Provider

In case you want to customize the ingested entities, both the `MicrosoftGraphOrgReaderProcessor`
and the `MicrosoftGraphOrgEntityProvider` allows to pass transformers for users,
groups and the organization.
In case you want to customize the ingested entities, the `MicrosoftGraphOrgEntityProvider`
allows to pass transformers for users, groups and the organization.

1. Create a transformer:

Expand All @@ -179,13 +145,17 @@ export async function myGroupTransformer(
}
```

2. Configure the processor with the transformer:
2. Add the transformer:

```ts
builder.addProcessor(
MicrosoftGraphOrgReaderProcessor.fromConfig(env.config, {
logger: env.logger,
groupTransformer: myGroupTransformer,
}),
);
```diff
builder.addEntityProvider(
MicrosoftGraphOrgEntityProvider.fromConfig(env.config, {
logger: env.logger,
schedule: env.scheduler.createScheduledTaskRunner({
frequency: { minutes: 5 },
timeout: { minutes: 3 },
}),
+ groupTransformer: myGroupTransformer,
}),
);
```
22 changes: 18 additions & 4 deletions plugins/catalog-backend-module-msgraph/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,14 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider {
static fromConfig(
configRoot: Config,
options: MicrosoftGraphOrgEntityProviderOptions,
): MicrosoftGraphOrgEntityProvider;
): MicrosoftGraphOrgEntityProvider[];
// (undocumented)
getProviderName(): string;
read(options?: { logger?: Logger }): Promise<void>;
}

// @public
export interface MicrosoftGraphOrgEntityProviderOptions {
// @public @deprecated
export interface MicrosoftGraphOrgEntityProviderLegacyOptions {
groupTransformer?: GroupTransformer;
id: string;
logger: Logger;
Expand All @@ -143,6 +143,19 @@ export interface MicrosoftGraphOrgEntityProviderOptions {
}

// @public
export type MicrosoftGraphOrgEntityProviderOptions =
| MicrosoftGraphOrgEntityProviderLegacyOptions
| {
logger: Logger;
schedule: 'manual' | TaskRunner;
userTransformer?: UserTransformer | Record<string, UserTransformer>;
groupTransformer?: GroupTransformer | Record<string, GroupTransformer>;
organizationTransformer?:
| OrganizationTransformer
| Record<string, OrganizationTransformer>;
};

// @public @deprecated
export class MicrosoftGraphOrgReaderProcessor implements CatalogProcessor {
constructor(options: {
providers: MicrosoftGraphProviderConfig[];
Expand Down Expand Up @@ -173,6 +186,7 @@ export class MicrosoftGraphOrgReaderProcessor implements CatalogProcessor {

// @public
export type MicrosoftGraphProviderConfig = {
id: string;
target: string;
authority?: string;
tenantId: string;
Expand Down Expand Up @@ -206,7 +220,7 @@ export type OrganizationTransformer = (
organization: MicrosoftGraph.Organization,
) => Promise<GroupEntity | undefined>;

// @public
// @public @deprecated
export function readMicrosoftGraphConfig(
config: Config,
): MicrosoftGraphProviderConfig[];
Expand Down
Loading

0 comments on commit a145672

Please sign in to comment.