diff --git a/.changeset/many-pugs-change.md b/.changeset/many-pugs-change.md new file mode 100644 index 0000000000..318c571891 --- /dev/null +++ b/.changeset/many-pugs-change.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +--- + +The purpose of this patch is to add a new login method which is `googleServiceAccount` configuring the kubernetes properties in the app-config.yaml file with authProvider key diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index 0d66341c40..331883be35 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -393,6 +393,7 @@ For example: - type: 'gke' projectId: 'gke-clusters' region: 'europe-west1' # optional + authProvider: 'google' # optional skipTLSVerify: false # optional skipMetricsLookup: false # optional exposeDashboard: false # optional @@ -417,6 +418,18 @@ The Google Cloud project to look for Kubernetes clusters in. The Google Cloud region to look for Kubernetes clusters in. Defaults to all regions. +##### `authProvider` (optional) + +Set the authentication method for discovering clusters and gathering information +about resources. + +Defaults to `google` which leverages the logged in user's Google OAuth credentials. + +Set to `googleServiceAccount` to leverage +Application Default Credentials (https://cloud.google.com/docs/authentication/application-default-credentials). +To use a service account JSON key (not recommended), set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable +on the Backstage backend to the path of the service account key file. + ##### `skipTLSVerify` (optional) This determines whether the Kubernetes client verifies the TLS certificate diff --git a/plugins/kubernetes-backend/config.d.ts b/plugins/kubernetes-backend/config.d.ts index 9c5417a00e..de7f79b66c 100644 --- a/plugins/kubernetes-backend/config.d.ts +++ b/plugins/kubernetes-backend/config.d.ts @@ -84,6 +84,8 @@ export interface Config { /** @visibility frontend */ region?: string; /** @visibility frontend */ + authProvider?: string; + /** @visibility frontend */ skipTLSVerify?: boolean; /** @visibility frontend */ skipMetricsLookup?: boolean; diff --git a/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.test.ts b/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.test.ts index f919561490..849a7839e2 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.test.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.test.ts @@ -382,5 +382,108 @@ describe('GkeClusterLocator', () => { parent: 'projects/some-project/locations/some-region', }); }); + it('return google login when no authProvider is specified', async () => { + mockedListClusters.mockReturnValueOnce([ + { + clusters: [ + { + name: 'some-cluster', + endpoint: '1.2.3.4', + }, + ], + }, + ]); + + const config: Config = new ConfigReader({ + type: 'gke', + projectId: 'some-project', + }); + + const sut = GkeClusterLocator.fromConfigWithClient(config, { + listClusters: mockedListClusters, + } as any); + + const result = await sut.getClusters(); + + expect(result).toStrictEqual([ + { + name: 'some-cluster', + url: 'https://1.2.3.4', + authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google' }, + skipTLSVerify: false, + skipMetricsLookup: false, + }, + ]); + }); + it('return googleServiceAccount login when authProvider is specified', async () => { + mockedListClusters.mockReturnValueOnce([ + { + clusters: [ + { + name: 'some-cluster', + endpoint: '1.2.3.4', + }, + ], + }, + ]); + + const config: Config = new ConfigReader({ + type: 'gke', + projectId: 'some-project', + authProvider: 'googleServiceAccount', + }); + + const sut = GkeClusterLocator.fromConfigWithClient(config, { + listClusters: mockedListClusters, + } as any); + + const result = await sut.getClusters(); + + expect(result).toStrictEqual([ + { + name: 'some-cluster', + url: 'https://1.2.3.4', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'googleServiceAccount', + }, + skipTLSVerify: false, + skipMetricsLookup: false, + }, + ]); + }); + it('return google login when authProvider property has invalid value', async () => { + mockedListClusters.mockReturnValueOnce([ + { + clusters: [ + { + name: 'some-cluster', + endpoint: '1.2.3.4', + }, + ], + }, + ]); + + const config: Config = new ConfigReader({ + type: 'gke', + projectId: 'some-project', + authProvider: 'differentValue', + }); + + const sut = GkeClusterLocator.fromConfigWithClient(config, { + listClusters: mockedListClusters, + } as any); + + const result = await sut.getClusters(); + + expect(result).toStrictEqual([ + { + name: 'some-cluster', + url: 'https://1.2.3.4', + authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google' }, + skipTLSVerify: false, + skipMetricsLookup: false, + }, + ]); + }); }); }); diff --git a/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.ts b/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.ts index 74e7ebc9af..03f5bda103 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.ts @@ -29,6 +29,7 @@ interface MatchResourceLabelEntry { type GkeClusterLocatorOptions = { projectId: string; + authProvider: string; region?: string; skipTLSVerify?: boolean; skipMetricsLookup?: boolean; @@ -54,8 +55,14 @@ export class GkeClusterLocator implements KubernetesClustersSupplier { return { key: mrl.getString('key'), value: mrl.getString('value') }; }) ?? []; + const storeAuthProviderString = + config.getOptionalString('authProvider') === 'googleServiceAccount' + ? 'googleServiceAccount' + : 'google'; + const options = { projectId: config.getString('projectId'), + authProvider: storeAuthProviderString, region: config.getOptionalString('region') ?? '-', skipTLSVerify: config.getOptionalBoolean('skipTLSVerify') ?? false, skipMetricsLookup: @@ -97,6 +104,7 @@ export class GkeClusterLocator implements KubernetesClustersSupplier { const { projectId, region, + authProvider, skipTLSVerify, skipMetricsLookup, exposeDashboard, @@ -121,7 +129,7 @@ export class GkeClusterLocator implements KubernetesClustersSupplier { // TODO filter out clusters which don't have name or endpoint name: r.name ?? 'unknown', url: `https://${r.endpoint ?? ''}`, - authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google' }, + authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: authProvider }, skipTLSVerify, skipMetricsLookup, ...(exposeDashboard