Add allowedInstallationIds list to each github app

This allows a single instance of backstage to optionally limit the set of
github app installations that may be used by backstage.

Previously, if you had github app installations for tenant1 and tenant2
there was nothing stopping the first from accessing resources of the
second.

The default behaviour of the GithubCredentialsProvider remains the same.

Signed-off-by: Brian Fletcher <brian@roadie.io>
This commit is contained in:
Brian Fletcher
2021-06-14 13:50:36 +01:00
parent 1bcb8693bf
commit 68af4d556b
4 changed files with 45 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/integration': patch
---
adds an allow list of github installations
+20
View File
@@ -84,3 +84,23 @@ integrations:
apps:
- $include: example-backstage-app-credentials.yaml
```
### Limiting the Github App installations
If you want to limit the Github app installations visible to backstage you
may optionally include the `allowedInstallationIds` option.
```yaml
appId: 1
allowedInstallationIds: [1234]
clientId: client id
clientSecret: client secret
webhookSecret: webhook secret
privateKey: |
-----BEGIN RSA PRIVATE KEY-----
...Key content...
-----END RSA PRIVATE KEY-----
```
This will result in backstage preventing the use of any installation that is not within the
allow list.
@@ -68,8 +68,10 @@ class GithubAppManager {
private readonly baseAuthConfig: { appId: number; privateKey: string };
private installations?: RestEndpointMethodTypes['apps']['listInstallations']['response'];
private readonly cache = new Cache();
private readonly allowedInstallations: number[] | undefined; // undefined allows all installations
constructor(config: GithubAppConfig, baseUrl?: string) {
this.allowedInstallations = config.allowedInstallations;
this.baseAuthConfig = {
appId: config.appId,
privateKey: config.privateKey,
@@ -91,6 +93,17 @@ class GithubAppManager {
suspended,
repositorySelection,
} = await this.getInstallationData(owner);
if (this.allowedInstallations) {
if (!this.allowedInstallations?.includes(installationId)) {
throw new Error(
`The GitHub application for ${[owner, repo]
.filter(Boolean)
.join(
'/',
)} is not included in the allowed installation list (${installationId}).`,
);
}
}
if (suspended) {
throw new Error(
`The GitHub application for ${[owner, repo]
@@ -93,6 +93,10 @@ export type GithubAppConfig = {
* Client secrets can be generated at https://github.com/organizations/$org/settings/apps/$AppName
*/
clientSecret: string;
/**
* List of installations allowed to be used by this backstage https://github.com/app/installations/$InstallationId
*/
allowedInstallations?: number[];
};
/**
@@ -113,6 +117,9 @@ export function readGitHubIntegrationConfig(
clientSecret: c.getString('clientSecret'),
webhookSecret: c.getString('webhookSecret'),
privateKey: c.getString('privateKey'),
allowedInstallations: c
.getOptionalStringArray('allowedInstallations')
?.map(allowedInstallation => Number(allowedInstallation)),
}));
if (!isValidHost(host)) {