Merge branch 'master' into feature/EKSCatalog

Signed-off-by: Jonah Back <jonah@jonahback.com>
This commit is contained in:
Jonah Back
2022-06-26 13:37:24 -07:00
453 changed files with 6414 additions and 3751 deletions
+1 -2
View File
@@ -223,8 +223,7 @@ For more information, see our
No, this is not a service offering. We build the piece of software, and someone
in your infrastructure team is responsible for
[deploying](https://backstage.io/docs/getting-started/deployment-k8s) and
maintaining it.
[deploying](https://backstage.io/docs/deployment) and maintaining it.
### How secure is Backstage?
+5 -7
View File
@@ -57,7 +57,7 @@ In order to use the Bitbucket provider for sign-in, you must configure it with a
`signIn.resolver`. See the
[Sign-In Resolver documentation](../identity-resolver.md) for more details on
how this is done. Note that for the Bitbucket provider, you'll want to use
`bitbucket` as the provider ID, and `createBitbucketProvider` for the provider
`bitbucket` as the provider ID, and `providers.bitbucket.create` for the provider
factory.
The `@backstage/plugin-auth-backend` plugin also comes with two built-in
@@ -74,16 +74,14 @@ same way, but uses the Bitbucket user ID instead, and matches on the
The following is an example of how to use one of the built-in resolvers:
```ts
import {
createBitbucketProvider,
bitbucketUsernameSignInResolver,
} from '@backstage/plugin-auth-backend';
import { providers } from '@backstage/plugin-auth-backend';
// ...
providerFactories: {
bitbucket: createBitbucketProvider({
bitbucket: providers.bitbucket.create({
signIn: {
resolver: bitbucketUsernameSignInResolver,
resolver:
providers.bitbucket.resolvers.usernameMatchingUserEntityAnnotation(),
},
}),
},
+91 -62
View File
@@ -110,6 +110,7 @@ Now let's look at the example, with the rest of the commentary being made with i
the code comments:
```ts
// File: packages/backend/src/plugins/auth.ts
import {
createRouter,
providers,
@@ -170,11 +171,21 @@ property of each of the auth provider integrations. For example, the Google prov
a built in resolver that works just like the one we defined above:
```ts
providers.google.create({
signIn: {
resolver: providers.google.resolvers.emailLocalPartMatchingUserEntityName(),
},
});
// File: packages/backend/src/plugins/auth.ts
export default async function createPlugin(
// ...
return await createRouter({
// ...
providerFactories: {
// ...
google: providers.google.create({
signIn: {
resolver: providers.google.resolvers.emailLocalPartMatchingUserEntityName(),
},
});
}
})
)
```
There are also other options, like the this one that looks up a user
@@ -195,40 +206,49 @@ that happens during sign-in you can replace `ctx.signInWithCatalogUser` with a s
of lower-level calls:
```ts
// File: packages/backend/src/plugins/auth.ts
import { getDefaultOwnershipRefs } from '@backstage/plugin-auth-backend';
// This example only shows the resolver function itself.
async ({ profile: { email } }, ctx) => {
if (!email) {
throw new Error('User profile contained no email');
}
export default async function createPlugin(
// ...
return await createRouter({
// ...
providerFactories: {
// ...
google: async ({ profile: { email } }, ctx) => {
if (!email) {
throw new Error('User profile contained no email');
}
// This step calls the catalog to look up a user entity. You could for example
// replace it with a call to a different external system.
const { entity } = await ctx.findCatalogUser({
annotations: {
'acme.org/email': email,
},
});
// This step calls the catalog to look up a user entity. You could for example
// replace it with a call to a different external system.
const { entity } = await ctx.findCatalogUser({
annotations: {
'acme.org/email': email,
},
});
// In this step we extract the ownership references from the user entity using
// the standard logic. It uses a reference to the entity itself, as well as the
// target of each `memberOf` relation where the target is of the kind `Group`.
//
// If you replace the catalog lookup with something does not return
// an entity you will need to replace this step as well.
//
// You might also replace it if you for example want to filter out certain groups.
const ownershipRefs = getDefaultOwnershipRefs(entity);
// In this step we extract the ownership references from the user entity using
// the standard logic. It uses a reference to the entity itself, as well as the
// target of each `memberOf` relation where the target is of the kind `Group`.
//
// If you replace the catalog lookup with something that does not return
// an entity you will need to replace this step as well.
//
// You might also replace it if you for example want to filter out certain groups.
const ownershipRefs = getDefaultOwnershipRefs(entity);
// The last step is to issue the token, where we might provide more options in the future.
return ctx.issueToken({
claims: {
sub: stringifyEntityRef(entity),
ent: ownershipRefs,
},
});
};
// The last step is to issue the token, where we might provide more options in the future.
return ctx.issueToken({
claims: {
sub: stringifyEntityRef(entity),
ent: ownershipRefs,
},
});
};
}
})
)
```
## Sign-In without Users in the Catalog
@@ -252,38 +272,47 @@ check like in the example below, or you might for example look up the GitHub org
that the user belongs to using the user access token in the provided result object.
```ts
// File: packages/backend/src/plugins/auth.ts
import { DEFAULT_NAMESPACE, stringifyEntityRef, } from '@backstage/catalog-model';
// This example only shows the resolver function itself.
async ({ profile }, ctx) => {
if (!profile.email) {
throw new Error(
'Login failed, user profile does not contain an email',
);
}
// Split the email into the local part and the domain.
const [localPart, domain] = profile.email.split('@');
export default async function createPlugin(
// ...
return await createRouter({
// ...
providerFactories: {
// ...
google: async ({ profile }, ctx) => {
if (!profile.email) {
throw new Error(
'Login failed, user profile does not contain an email',
);
}
// Split the email into the local part and the domain.
const [localPart, domain] = profile.email.split('@');
// Next we verify the email domain. It is recommended to include this
// kind of check if you don't look up the user in an external service.
if (domain !== 'acme.org') {
throw new Error('Login failed, user email domain check failed');
}
// Next we verify the email domain. It is recommended to include this
// kind of check if you don't look up the user in an external service.
if (domain !== 'acme.org') {
throw new Error('Login failed, user email domain check failed');
}
// By using `stringifyEntityRef` we ensure that the reference is formatted correctly
const userEntityRef = stringifyEntityRef({
kind: 'User',
name: localPart,
namespace: DEFAULT_NAMESPACE,
});
// By using `stringifyEntityRef` we ensure that the reference is formatted correctly
const userEntityRef = stringifyEntityRef({
kind: 'User',
name: localPart,
namespace: DEFAULT_NAMESPACE,
});
return ctx.issueToken({
claims: {
sub: userEntityRef,
ent: [userEntityRef],
},
});
},
return ctx.issueToken({
claims: {
sub: userEntityRef,
ent: [userEntityRef],
},
});
},
}
})
)
```
## AuthHandler
@@ -304,7 +333,7 @@ export default async function createPlugin(
return await createRouter({
...
providerFactories: {
google: createGoogleProvider({
google: providers.google.create({
authHandler: async ({
fullProfile // Type: passport.Profile,
idToken // Type: (Optional) string,
+6
View File
@@ -74,6 +74,12 @@ techdocs:
type: 'local'
# Optional when techdocs.publisher.type is set to 'local'.
local:
# (Optional). Set this to specify where the generated documentation is stored.
publishDirectory: '/path/to/local/directory'
# Required when techdocs.publisher.type is set to 'googleGcs'. Skip otherwise.
googleGcs:
+6 -3
View File
@@ -155,6 +155,8 @@ auth:
clientSecret: YOUR CLIENT SECRET
```
### Add sign-in option to the frontend
Backstage will re-read the configuration. If there's no errors, that's great! We
can continue with the last part of the configuration. The next step is needed to
change the sign-in page, this you actually need to add in the source code.
@@ -185,10 +187,11 @@ components: {
},
```
> Since [v1.1.0](https://github.com/backstage/backstage/releases/tag/v1.1.0-next.3), you must provide an [explicit sign-in resolver](../auth/identity-resolver.md).
> Note: The default Backstage app comes with a guest Sign In Resolver. This resolver makes all users share a single "guest" identity and is only intended as a minimum requirement to quickly get up and running. You can read more about how [Sign In Resolvers](../auth/identity-resolver.md#sign-in-resolvers) play a role in creating a [Backstage User Identity](../auth/identity-resolver.md#backstage-user-identity) for logged in users.
That should be it. You can stop your Backstage App. When you start it again and
go to your Backstage portal in your browser, you should have your login prompt!
Restart Backstage from the terminal, by stopping it with `Control-C`, and starting it with `yarn dev` . You should be welcomed by a login prompt!
> Note: Sometimes the frontend starts before the backend resulting in errors on the sign in page. Wait for the backend to start and then reload Backstage to proceed.
To learn more about Authentication in Backstage, here are some docs you
could read:
+1 -1
View File
@@ -157,7 +157,7 @@ export const HomePage = () => {
return (
<Grid container spacing={3}>
<Grid item xs={12} md={4}>
<HomePageCompanyLogo className={container} />
<HomePageCompanyLogo />
</Grid>
</Grid>
);
+1 -1
View File
@@ -28,7 +28,7 @@ the code.
sub-folder which is used for a markdown spellchecker.
- [`.yarn/`](https://github.com/backstage/backstage/tree/master/.yarn) -
Backstage ships with it's own `yarn` implementation. This allows us to have
Backstage ships with its own `yarn` implementation. This allows us to have
better control over our `yarn.lock` file and hopefully avoid problems due to
yarn versioning differences.
+1 -1
View File
@@ -45,7 +45,7 @@ catalog:
anotherProviderId: # another identifier
organization: myorg
project: myproject
repository: '*' # this will match all repos starting with service-*
repository: '*' # this will match all repos
path: /src/*/catalog-info.yaml # this will search for files deep inside the /src folder
yetAotherProviderId: # guess, what? Another one :)
host: selfhostedazure.yourcompany.com
+1 -1
View File
@@ -22,7 +22,7 @@ catalog:
yourProviderId:
host: gitlab-host # Identifies one of the hosts set up in the integrations
branch: main # Optional. Uses `master` as default
group: example-group # Group and subgroup (if needed) to look for repositories
group: example-group # Optional. Group and subgroup (if needed) to look for repositories. If not present the whole project will be scanned
entityFilename: catalog-info.yaml # Optional. Defaults to `catalog-info.yaml`
```
+18
View File
@@ -135,3 +135,21 @@ package export.
accessed via `<package-name>/beta` or `<package-name>/alpha` imports.
- `@alpha` - here be dragons. Not visible in the main package entry point, alpha
exports must be accessed via `<package-name>/alpha` imports.
## Node.js Releases
The Backstage project uses [Node.js](https://nodejs.org/) for both its development
tooling and backend runtime. In order for expectations to be clear we use the
following schedule for determining the [Node.js releases](https://nodejs.org/en/about/releases/) that we support:
- At any given point in time we support exactly two adjacent even-numbered
releases of Node.js, for example v12 and v14.
- Three months before a Node.js release becomes _Active LTS_ we switch support
to that release and the previous one. This is halfway through the _Current LTS_
cycle for that release and occurs at the end of July every year.
When we say _Supporting_ a Node.js release, that means the following:
- The CI pipeline in the main Backstage repo tests towards the supported releases, and we encourage any other Backstage related projects to do the same.
- New Backstage projects created with `@backstage/create-app` will have their `engines.node` version set accordingly.
- Dropping compatibility with unsupported releases is not considered a breaking change. This includes using new syntax or APIs, as well as bumping dependencies that drop support for these versions.
File diff suppressed because it is too large Load Diff