Merge pull request #26969 from backstage/rugvip/harden
Update docs to be more strict around sign-in resolvers + remove insecure sign-in resolver
This commit is contained in:
@@ -49,9 +49,7 @@ auth:
|
||||
scope: ${AUTH_ATLASSIAN_SCOPES}
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
# See https://backstage.io/docs/auth/atlassian/provider#resolvers for more resolvers
|
||||
- resolver: usernameMatchingUserEntityName
|
||||
```
|
||||
|
||||
|
||||
@@ -25,9 +25,8 @@ auth:
|
||||
region: 'us-west-2'
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
# See https://backstage.io/docs/auth/aws-alb/provider#resolvers for more resolvers
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
```
|
||||
|
||||
Ensure that you have set the signer correctly. It is also recommended that you restrict your target groups' security policy to only accept connections from that ALB.
|
||||
|
||||
@@ -39,11 +39,8 @@ auth:
|
||||
clientSecret: ${AUTH_BITBUCKET_CLIENT_SECRET}
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
# See https://backstage.io/docs/auth/bitbucket/provider#resolvers for more resolvers
|
||||
- resolver: userIdMatchingUserEntityAnnotation
|
||||
- resolver: usernameMatchingUserEntityAnnotation
|
||||
```
|
||||
|
||||
The Bitbucket provider is a structure with two configuration keys:
|
||||
|
||||
@@ -41,8 +41,8 @@ auth:
|
||||
# This picks what sign in resolver(s) you want to use.
|
||||
signIn:
|
||||
resolvers:
|
||||
# See https://backstage.io/docs/auth/cloudflare/provider#resolvers for more resolvers
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
```
|
||||
|
||||
This config section must be in place for the provider to load at all.
|
||||
|
||||
@@ -51,8 +51,7 @@ auth:
|
||||
# enterpriseInstanceUrl: ${AUTH_GITHUB_ENTERPRISE_INSTANCE_URL}
|
||||
signIn:
|
||||
resolvers:
|
||||
# Matches the GitHub username with the Backstage user entity name.
|
||||
# See https://backstage.io/docs/auth/github/provider#resolvers for more resolvers.
|
||||
# See https://backstage.io/docs/auth/github/provider#resolvers for more resolvers
|
||||
- resolver: usernameMatchingUserEntityName
|
||||
```
|
||||
|
||||
|
||||
@@ -46,9 +46,7 @@ auth:
|
||||
# callbackUrl: https://${BASE_URL}/api/auth/gitlab/handler/frame
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
# See https://backstage.io/docs/auth/gitlab/provider#resolvers for more resolvers
|
||||
- resolver: usernameMatchingUserEntityName
|
||||
```
|
||||
|
||||
|
||||
@@ -29,9 +29,7 @@ auth:
|
||||
jwtHeader: x-custom-header # Optional: Only if you are using a custom header for the IAP JWT
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
# See https://backstage.io/docs/auth/google/gcp-iap-auth#resolvers for more resolvers
|
||||
- resolver: emailMatchingUserEntityAnnotation
|
||||
```
|
||||
|
||||
|
||||
@@ -44,9 +44,7 @@ auth:
|
||||
clientSecret: ${AUTH_GOOGLE_CLIENT_SECRET}
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
# See https://backstage.io/docs/auth/google/provider#resolvers for more resolvers
|
||||
- resolver: emailMatchingUserEntityAnnotation
|
||||
```
|
||||
|
||||
|
||||
@@ -70,6 +70,14 @@ always be full entity references, as opposed to shorthands like just `jane` or
|
||||
|
||||
## Sign-in Resolvers
|
||||
|
||||
:::warning
|
||||
Be careful when configuring Sign-in resolvers, as they are part of determining who
|
||||
has access to your Backstage instance, and with what identity. Always only configure
|
||||
**a single sign-in resolver for one of your auth providers**. The only reason to have
|
||||
more sign-in resolvers is if you want to allow your users to sign in to Backstage in
|
||||
multiple ways, but it increases the risk of account hijacking.
|
||||
:::
|
||||
|
||||
Signing in a user into Backstage requires a mapping of the user identity from the
|
||||
third-party auth provider to a Backstage user identity. This mapping can vary quite
|
||||
a lot between different organizations and auth providers, and because of that there's
|
||||
@@ -112,19 +120,38 @@ auth:
|
||||
signIn:
|
||||
resolvers:
|
||||
- resolver: usernameMatchingUserEntityName
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
```
|
||||
|
||||
Note that in this instance it lists several resolvers, which means that the
|
||||
framework will try them one by one until one succeeds. If none of them do, the
|
||||
sign in attempt is rejected.
|
||||
|
||||
The list of available resolvers is different for each provider, since they often
|
||||
depend on the information model returned from the upstream provider service.
|
||||
Consult the documentation of the respective provider to find the list.
|
||||
|
||||
In the example above `emailMatchingUserEntityProfileEmail` and `emailLocalPartMatchingUserEntityName` are common to all auth providers and `usernameMatchingUserEntityName` is specific to GitHub.
|
||||
In the example above, the `usernameMatchingUserEntityName` is specific to the
|
||||
GitHub provider, but you could also choose to use the
|
||||
`emailMatchingUserEntityProfileEmail` or `emailLocalPartMatchingUserEntityName`
|
||||
resolvers, which are common to all auth providers.
|
||||
|
||||
:::warning
|
||||
When using the `emailLocalPartMatchingUserEntityName` resolver it is strongly
|
||||
recommended to set the `allowedDomains` option to ensure that only authorized users
|
||||
are able to sign-in.
|
||||
:::
|
||||
|
||||
If you are using the `emailLocalPartMatchingUserEntityName` resolver, it is
|
||||
recommended to also set the `allowedDomains` option, for example:
|
||||
|
||||
```yaml title="Within the provider configuration"
|
||||
auth:
|
||||
providers:
|
||||
github:
|
||||
development:
|
||||
...
|
||||
signIn:
|
||||
resolvers:
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
allowedDomains:
|
||||
- acme.org
|
||||
```
|
||||
|
||||
### Building Custom Resolvers
|
||||
|
||||
@@ -160,8 +187,6 @@ auth:
|
||||
signIn:
|
||||
resolvers:
|
||||
- resolver: usernameMatchingUserEntityName
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
/* highlight-remove-end */
|
||||
```
|
||||
|
||||
@@ -318,6 +343,12 @@ async signInResolver({ profile: { email} }, ctx) {
|
||||
|
||||
### Sign-In without Users in the Catalog
|
||||
|
||||
:::warning
|
||||
Signing in users without verifying that they exist in the catalog can be
|
||||
dangerous. Take care to ensure that your custom resolvers only allow expected
|
||||
users to sign in, for example by checking email domains.
|
||||
:::
|
||||
|
||||
While populating the catalog with organizational data unlocks more powerful ways
|
||||
to browse your software ecosystem, it might not always be a viable or prioritized
|
||||
option. However, even if you do not have user entities populated in your catalog, you
|
||||
|
||||
@@ -66,9 +66,7 @@ auth:
|
||||
azureEasyAuth:
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
# See https://backstage.io/docs/auth/microsoft/easy-auth#resolvers for more resolvers
|
||||
- resolver: idMatchingUserEntityAnnotation
|
||||
```
|
||||
|
||||
|
||||
@@ -69,10 +69,7 @@ auth:
|
||||
domainHint: ${AZURE_TENANT_ID}
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
- resolver: emailMatchingUserEntityAnnotation
|
||||
# See https://backstage.io/docs/auth/microsoft/provider#resolvers for more resolvers
|
||||
- resolver: userIdMatchingUserEntityAnnotation
|
||||
```
|
||||
|
||||
|
||||
@@ -31,9 +31,7 @@ auth:
|
||||
oauth2Proxy:
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
# See https://backstage.io/docs/auth/oauth2-proxy/provider#resolvers for more resolvers
|
||||
- resolver: forwardedUserMatchingUserEntityName
|
||||
```
|
||||
|
||||
|
||||
@@ -156,8 +156,6 @@ auth:
|
||||
# ...
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
```
|
||||
|
||||
|
||||
@@ -49,9 +49,7 @@ auth:
|
||||
additionalScopes: ${AUTH_OKTA_ADDITIONAL_SCOPES} # Optional
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
# See https://backstage.io/docs/auth/okta/provider#resolvers for more resolvers
|
||||
- resolver: emailMatchingUserEntityAnnotation
|
||||
```
|
||||
|
||||
|
||||
@@ -40,9 +40,7 @@ auth:
|
||||
issuer: https://<company>.onelogin.com/oidc/2
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
# See https://backstage.io/docs/auth/onelogin/provider#resolvers for more resolvers
|
||||
- resolver: usernameMatchingUserEntityName
|
||||
```
|
||||
|
||||
|
||||
@@ -49,10 +49,8 @@ auth:
|
||||
organizationId: ${ORG_ID}
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
# See https://backstage.io/docs/auth/vmware-cloud/provider#resolvers for more resolvers
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
- resolver: vmwareCloudSignInResolvers
|
||||
```
|
||||
|
||||
Where `APP_ID` refers to the ID retrieved when creating the OAuth App, and
|
||||
@@ -76,7 +74,6 @@ This provider includes several resolvers out of the box that you can use:
|
||||
|
||||
- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`.
|
||||
- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`.
|
||||
- `vmwareCloudSignInResolvers`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will sign in the user without associating with a catalog user.
|
||||
|
||||
:::note Note
|
||||
|
||||
|
||||
@@ -884,8 +884,6 @@ auth:
|
||||
signIn:
|
||||
resolvers:
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
- resolver: emailMatchingUserEntityAnnotation
|
||||
```
|
||||
|
||||
:::note Note
|
||||
|
||||
@@ -53,11 +53,11 @@ Note that the `UrlReaderService` system operates with a service context and is n
|
||||
|
||||
Backstage provides authentication of users through the `auth` plugin, which primarily acts as an authorization server for different OAuth 2.0 provider integrations. These integrations can both serve the purpose of signing users into Backstage, as well as providing delegated access to external resources, and are all subject to the common concerns of implementing secure OAuth 2.0 authorization servers. All auth provider integrations are disabled by default, and need to be enabled through configuration in order to be used. For each Backstage installation it is recommended to only enable the minimal set of providers that are in use by that instance.
|
||||
|
||||
In order to use an auth provider to sign in users into Backstage, it needs to be configured with an [Identity resolver](https://backstage.io/docs/auth/identity-resolver), which is a custom callback implemented in code. The identity resolver is a sensitive part of configuring Backstage and it is important that it always resolves user identities correctly, based on information provided by the authentication provider. There are a number of built-in identity resolvers that can simplify configuration, and it is important that these all resolve users in a secure way, regardless of how they are used.
|
||||
In order to use an auth provider to sign in users into Backstage, it needs to be configured with a [sign-in resolver](https://backstage.io/docs/auth/identity-resolver). The sign-in resolver is a sensitive part of configuring Backstage and it is important that it always resolves user identities correctly, and rejects unauthorized users. There are a number of built-in sign-in resolvers that can simplify configuration, or you can implement your own custom sign-in resolver in code, either way it is very important that these resolvers map user identities correctly. You should **always use the minimum number of sign-in resolvers necessary** to avoid risk of account hijacking.
|
||||
|
||||
Backstage also supports authentication through an authenticating reverse proxy such as [AWS ALB](https://aws.amazon.com/elasticloadbalancing/application-load-balancer/), where the user identity is read from the incoming proxied decorated request. The following proxy auth providers verify the signature of incoming requests, and are therefore safe to deploy with direct access by users: `awsAlb`, `cfAccess`, and `gcpIap`. Providers like `oauth2Proxy` do not verify the incoming request and can therefore be spoofed by a malicious internal user to supply the `auth` backend with forged identity information. It’s therefore highly recommended to restrict access to the `oauth2Proxy` endpoints, or use a different provider.
|
||||
|
||||
As part of signing in with an identity resolver, a Backstage Token is issued containing the resolved user identity. The tokens are asymmetrically signed JSON Web Tokens, with the public keys available to any service that wishes to verify a token. The signing keys are rotated continuously and are unique to each installation of Backstage, meaning that Backstage Tokens are not shared across installations. The token contains claims for the user identity and ownership information, which can be used to determine what Backstage resources are owned by that user or group. It is important that this token can not be forged outside of the `auth` plugin, with the exception of other plugins deployed in the same backend service or sharing the same database. For a high-security deployment, the `auth` backend should therefore be deployed in a separate service with its own database.
|
||||
As part of signing in with a sign-in resolver, a Backstage Token is issued containing the resolved user identity. The tokens are asymmetrically signed JSON Web Tokens, with the public keys available to any service that wishes to verify a token. The signing keys are rotated continuously and are unique to each installation of Backstage, meaning that Backstage Tokens are not shared across installations. The token contains claims for the user identity and ownership information, which can be used to determine what Backstage resources are owned by that user or group. It is important that this token can not be forged outside of the `auth` plugin, with the exception of other plugins deployed in the same backend service or sharing the same database. For a high-security deployment, the `auth` backend should therefore be deployed in a separate service with its own database.
|
||||
|
||||
The token is used to prove the identity of the user within the Backstage system, and is used throughout Backstage plugins to control access. It is important that the ownership resolution logic is consistent across the entire Backstage ecosystem, with no possibility of misinterpreting the ownership information.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user