Merge pull request #28437 from sanderaernouts/users/saernouts/client-assertion-credential
Added support for federated credentials using a managed identity (to generate the client assertion)
This commit is contained in:
@@ -13,7 +13,17 @@ or registered with the
|
||||
[catalog-import](https://github.com/backstage/backstage/tree/master/plugins/catalog-import)
|
||||
plugin.
|
||||
|
||||
Using a service principal:
|
||||
## Authentication
|
||||
|
||||
The Azure integration supports several methods to authenticate against Azure DevOps. The following sections describe how to configure the integration for each authentication method.
|
||||
|
||||
It is also possible to configure separate authentication methods for different Azure DevOps organizations. This is useful if you have multiple organizations and want to use (or have to) different credentials for each organization.
|
||||
|
||||
### Using a service principal with a client secret
|
||||
|
||||
A service principal is an Entra ID identity that can be used to authenticate against Azure DevOps. The service principal is created in Entra ID and has a client ID and client secret (akin to a username and password).
|
||||
|
||||
The following configuration shows how to use a service principal to authenticate against Azure DevOps:
|
||||
|
||||
```yaml
|
||||
integrations:
|
||||
@@ -25,7 +35,29 @@ integrations:
|
||||
tenantId: ${AZURE_TENANT_ID}
|
||||
```
|
||||
|
||||
Using a managed identity:
|
||||
See the Azure DevOps documentation on how to grant access to the [service principal](https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity).
|
||||
|
||||
#### Using a system-assigned managed identity
|
||||
|
||||
A system-assigned [managed identity](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) is an Entra ID identity that is tied to a specific Azure resource and managed by Azure. In contrast to a user-assigned managed identity, a system-assigned managed identity shares the lifecycle of the resource to which it is assigned and Azure guarantees that the identity can only be used by the specific resource.
|
||||
|
||||
The following configuration shows how to use a system-assigned managed identity to authenticate against Azure DevOps:
|
||||
|
||||
```yaml
|
||||
integrations:
|
||||
azure:
|
||||
- host: dev.azure.com
|
||||
credentials:
|
||||
- clientId: system-assigned
|
||||
```
|
||||
|
||||
See the Azure DevOps documentation on how to grant access to the [managed identity](https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity).
|
||||
|
||||
#### Using a user-assigned managed identity
|
||||
|
||||
A user-assigned [managed identity](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) is an Entra ID identity that is created as a standalone resource by the user and assigned to one or more Azure resources. This allows you to use the same managed identity across multiple resources.
|
||||
|
||||
The following configuration shows how to use a user-assigned managed identity to authenticate against Azure DevOps:
|
||||
|
||||
```yaml
|
||||
integrations:
|
||||
@@ -35,7 +67,13 @@ integrations:
|
||||
- clientId: ${AZURE_CLIENT_ID}
|
||||
```
|
||||
|
||||
Using a personal access token (PAT):
|
||||
See the Azure DevOps documentation on how to grant access to the [managed identity](https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity).
|
||||
|
||||
### Using a personal access token (PAT)
|
||||
|
||||
A personal access token (PAT) is a token you generate with a specific scope and expiration date. It allows Backstage to authenticate against Azure DevOps on your behalf.
|
||||
|
||||
The following configuration shows how to use a personal access token to authenticate against Azure DevOps:
|
||||
|
||||
```yaml
|
||||
integrations:
|
||||
@@ -45,6 +83,55 @@ integrations:
|
||||
- personalAccessToken: ${PERSONAL_ACCESS_TOKEN}
|
||||
```
|
||||
|
||||
See the Azure DevOps documentation on how to create a [personal access token](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate)
|
||||
|
||||
### Using a service principal with a managed identity to generate the client assertion
|
||||
|
||||
Using a managed identity to generate a client assertion is an advanced scenario. It requires you to setup a federated credential for the app registration in Azure Entra ID.
|
||||
|
||||
It is most useful when you want to [authenticate against an Azure DevOps organization in a different tenant](#authenticate-against-an-azure-devops-organization-in-a-different-tenant) than the managed identity itself. Otherwise [a regular managed identity](#using-a-system-assigned-managed-identity) is probably a more suitable choice.
|
||||
|
||||
#### Add a federated credential
|
||||
|
||||
To be able to use a managed identity to generate a client assertion, you need to create a federated credential in Azure Entra ID. Follow these steps:
|
||||
|
||||
1. Create an app registration in Entra ID (or use an existing one).
|
||||
2. Navigate to the "Certificates & secrets" tab for your app registration.
|
||||
3. Add a new federated credential using the "Customer managed keys" scenario.
|
||||
4. Select the managed identity you want to use to generate the client assertion.
|
||||
5. Enter the name and description.
|
||||
6. Click "Add".
|
||||
|
||||
You can now add the required configuration to the Azure DevOps integration in Backstage. The `${APP_REGISTRATION_CLIENT_ID}` is the client ID of the app registration in Entra ID where you added the federated credential.
|
||||
|
||||
#### Using a system-assigned managed identity to generate the client assertion
|
||||
|
||||
This is the most secure option because Azure guarantees that the identity can only be used by the specific resource, whereas a user-assigned managed identity can be assigned to any resource in the same tenant.
|
||||
|
||||
```yaml
|
||||
integrations:
|
||||
azure:
|
||||
- host: dev.azure.com
|
||||
credentials:
|
||||
- clientId: ${APP_REGISTRATION_CLIENT_ID}
|
||||
managedIdentityClientId: system-assigned
|
||||
tenantId: ${AZURE_TENANT_ID}
|
||||
```
|
||||
|
||||
#### Using a user-assigned managed identity to generate the client assertion
|
||||
|
||||
```yaml
|
||||
integrations:
|
||||
azure:
|
||||
- host: dev.azure.com
|
||||
credentials:
|
||||
- clientId: ${APP_REGISTRATION_CLIENT_ID}
|
||||
managedIdentityClientId: ${MANAGED_IDENTITY_CLIENT_ID}
|
||||
tenantId: ${AZURE_TENANT_ID}
|
||||
```
|
||||
|
||||
### Authenticating against multiple Azure DevOps organizations
|
||||
|
||||
You can use specific credentials for different Azure DevOps organizations by specifying the `organizations` field on the credential:
|
||||
|
||||
```yaml
|
||||
@@ -68,27 +155,76 @@ integrations:
|
||||
|
||||
If you do not specify the `organizations` field the credential will be used for all organizations for which no other credential is configured.
|
||||
|
||||
### Authenticate against an Azure DevOps organization in a different tenant
|
||||
|
||||
If you need to authenticate against an Azure DevOps organization in a different tenant than the service principal, you have to either:
|
||||
|
||||
- [Create a multi-tenant application in Entra ID](https://learn.microsoft.com/en-us/entra/identity-platform/single-and-multi-tenant-apps).
|
||||
- [Convert the existing application to a multi-tenant application](https://learn.microsoft.com/en-gb/entra/identity-platform/howto-convert-app-to-be-multi-tenant#update-registration-to-be-multitenant).
|
||||
|
||||
:::note Note
|
||||
|
||||
An Azure DevOps provider is added automatically at startup for
|
||||
convenience, so you only need to list it if you want to supply a
|
||||
[personalAccessToken](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate),
|
||||
a [service principal](https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity),
|
||||
or a [managed identity](https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity)
|
||||
Make sure that your application requests at least one Graph API permission. This is required to be able to install the application in another tenant. The least privileged permission you can request is the [`email` permission](https://learn.microsoft.com/en-us/graph/permissions-reference#email) with type `Delegated`. This allows the application to read the e-mail address of the signed-in user, but without the [`openid` permission](https://learn.microsoft.com/en-us/graph/permissions-reference#openid) users cannot actually sign in.
|
||||
|
||||
:::
|
||||
|
||||
After you have done that, an admin from the other tenant has to install your application by providing admin consent for the requested permissions. This can be done by visiting the following URL:
|
||||
|
||||
```plaintext
|
||||
https://login.microsoftonline.com/<other-tenant-id>/oauth2/authorize?client_id=<client-id>&response_type=code&redirect_uri=<redirect-uri>
|
||||
```
|
||||
|
||||
The `<other-tenant-id>` is the tenant ID of the other tenant, `<client-id>` is the client ID of the application (in your tenant), and `<redirect-uri>` is the redirect URI configured for the application. The redirect URI must be a valid URI in the application registration, but you can use any valid URI for this purpose, for example `https://backstage.io`.
|
||||
|
||||
After the admin has consented to the application, an Enterprise Application, also called a Service Principal, will be created in the other tenant with the same client ID as the app registration in the original tenant. You can now grant the service principal access to the Azure DevOps organization in the other tenant. To authenticate against the Azure DevOps organization in the other tenant, you can use the same service principal as before, but with the tenant ID of the other tenant:
|
||||
|
||||
```yaml
|
||||
integrations:
|
||||
azure:
|
||||
- host: dev.azure.com
|
||||
credentials:
|
||||
- clientId: ${APP_REGISTRATION_CLIENT_ID}
|
||||
managedIdentityClientId: system-assigned
|
||||
tenantId: ${OTHER_TENANT_ID}
|
||||
```
|
||||
|
||||
Where `${APP_REGISTRATION_CLIENT_ID}` is the client ID of the multi-tenant app registration in you created in your own tenant, and `${OTHER_TENANT_ID}` is the tenant ID of the other tenant where you .
|
||||
|
||||
:::note Note
|
||||
|
||||
The example above uses a [system-assigned managed identity to generate the client assertion](#using-a-system-assigned-managed-identity-to-generate-the-client-assertion). You can also use a [user-assigned managed identity to generate the client assertion](#using-a-user-assigned-managed-identity-to-generate-the-client-assertion) or a client secret to authenticate for the application.
|
||||
|
||||
However a system-assigned managed identity is the most secure option because:
|
||||
|
||||
- Azure guarantees that the identity can only be used by the specific resource, whereas a user-assigned managed identity can be used by any resource.
|
||||
- There is no need to manage the underlying secrets, Azure takes care of that for you.
|
||||
|
||||
:::
|
||||
|
||||
## Configuration schema
|
||||
|
||||
The configuration is a structure with these elements:
|
||||
|
||||
- `credentials`: (optional): A service principal, managed identity, or personal access token
|
||||
- `credentials`: (optional): must be one of the following:
|
||||
- A service principal using a client secret
|
||||
- A service principal using a managed identity client assertion
|
||||
- A managed identity
|
||||
- A personal access token
|
||||
|
||||
The `credentials` element is a structure with these elements:
|
||||
The `credentials` element is an array where each entry is a structure with exactly these of elements:
|
||||
|
||||
- `organizations`: (optional): A list of organizations for which this credential should be used. If not specified the credential will be used for all organizations for which no other credential is configured.
|
||||
- `clientId`: The client ID of the service principal or managed identity (required for service principal and managed identities)
|
||||
- `clientSecret`: The client secret of the service principal (required for service principal)
|
||||
- `tenantId`: The tenant ID of the service principal (required for service principal)
|
||||
- `personalAccessToken`: The personal access token (required for personal access token)
|
||||
- For a service principal with client secret:
|
||||
- `clientId`: The client ID of the service principal
|
||||
- `clientSecret`: The client secret of the service principal
|
||||
- `tenantId`: The tenant ID of the service principal
|
||||
- For a service principal with managed identity client assertion:
|
||||
- `clientId`: The client ID of the service principal
|
||||
- `managedIdentityClientId`: the client ID of the managed identity used to generate the client assertion token. Use `system-assigned` for system-assigned managed identities or the client ID of a user-assigned managed identity.
|
||||
- `tenantId`: The tenant ID of the service principal
|
||||
- For managed identity:
|
||||
- `clientId`: the client ID of the managed identity used to generate the client assertion token.
|
||||
- For personal access token:
|
||||
- `personalAccessToken`: The personal access token
|
||||
|
||||
:::note Note
|
||||
|
||||
@@ -96,5 +232,6 @@ The `credentials` element is a structure with these elements:
|
||||
- You can only use a service principal or managed identity for Microsoft Entra ID (formerly Azure Active Directory) backed Azure DevOps organizations
|
||||
- You can only specify one credential per host without any organizations specified
|
||||
- The personal access token should just be provided as the raw token generated by Azure DevOps using the format `raw_token` with no base64 encoding. Formatting and base64'ing is handled by dependent libraries handling the Azure DevOps API
|
||||
- The managed identity used to generate the client assertion must be in the same Entra ID tenant as the app registration.
|
||||
|
||||
:::
|
||||
|
||||
Reference in New Issue
Block a user