From 094b12b59ea6c2341c25fc535ae8cc9d8ce7b5bf Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Tue, 5 Sep 2023 15:42:34 -0400 Subject: [PATCH] refactor: migrate token field to authMetadata and remove the special ServiceAccountClusterDetails accordingly. Signed-off-by: Jamie Klassen --- plugins/kubernetes-backend/api-report.md | 17 ++++------- .../ConfigClusterLocator.test.ts | 15 +++------- .../cluster-locator/ConfigClusterLocator.ts | 3 +- .../src/cluster-locator/index.test.ts | 3 +- .../AksKubernetesAuthTranslator.test.ts | 2 +- .../AksKubernetesAuthTranslator.ts | 10 ++++++- .../AwsIamKubernetesAuthTranslator.test.ts | 6 ++-- .../AwsIamKubernetesAuthTranslator.ts | 13 +++++---- ...reIdentityKubernetesAuthTranslator.test.ts | 22 +++++++-------- .../AzureIdentityKubernetesAuthTranslator.ts | 5 +++- ...ispatchingKubernetesAuthTranslator.test.ts | 2 +- .../GoogleKubernetesAuthTranslator.ts | 5 +++- .../GoogleServiceAccountAuthProvider.ts | 5 +++- .../NoopKubernetesAuthTranslator.ts | 6 ++-- .../OidcKubernetesAuthTranslator.test.ts | 2 +- .../OidcKubernetesAuthTranslator.ts | 5 +++- .../src/service/KubernetesBuilder.test.ts | 2 -- .../service/KubernetesFanOutHandler.test.ts | 4 +-- .../src/service/KubernetesFetcher.test.ts | 28 +++++++++---------- .../src/service/KubernetesFetcher.ts | 4 +-- .../src/service/KubernetesProxy.test.ts | 19 ++++--------- .../src/service/KubernetesProxy.ts | 10 +++---- plugins/kubernetes-backend/src/types/types.ts | 15 ++-------- 23 files changed, 97 insertions(+), 106 deletions(-) diff --git a/plugins/kubernetes-backend/api-report.md b/plugins/kubernetes-backend/api-report.md index ad8ff32891..95aff769e9 100644 --- a/plugins/kubernetes-backend/api-report.md +++ b/plugins/kubernetes-backend/api-report.md @@ -65,6 +65,8 @@ export class AzureIdentityKubernetesAuthTranslator // @public (undocumented) export interface ClusterDetails { + // (undocumented) + authMetadata?: Record; // (undocumented) authProvider: string; // (undocumented) @@ -77,8 +79,6 @@ export interface ClusterDetails { dashboardUrl?: string; name: string; oidcTokenProvider?: string | undefined; - // (undocumented) - serviceAccountToken?: string | undefined; skipMetricsLookup?: boolean; // (undocumented) skipTLSVerify?: boolean; @@ -399,18 +399,14 @@ export interface KubernetesServiceLocator { export class NoopKubernetesAuthTranslator implements KubernetesAuthTranslator { // (undocumented) decorateClusterDetailsWithAuth( - clusterDetails: ServiceAccountClusterDetails, - ): Promise; + clusterDetails: ClusterDetails, + ): Promise; } // @public (undocumented) export interface ObjectFetchParams { // (undocumented) - clusterDetails: - | AWSClusterDetails - | GKEClusterDetails - | ServiceAccountClusterDetails - | ClusterDetails; + clusterDetails: AWSClusterDetails | GKEClusterDetails | ClusterDetails; // (undocumented) customResources: CustomResource[]; // (undocumented) @@ -463,9 +459,6 @@ export interface RouterOptions { permissions: PermissionEvaluator; } -// @public (undocumented) -export interface ServiceAccountClusterDetails extends ClusterDetails {} - // @public (undocumented) export type ServiceLocatorMethod = 'multiTenant' | 'http'; diff --git a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts index b85dfac38e..f5d056f355 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts @@ -17,7 +17,7 @@ import '@backstage/backend-common'; import { ConfigReader, Config } from '@backstage/config'; import { ConfigClusterLocator } from './ConfigClusterLocator'; -import { ClusterDetails } from '../types/types'; +import { AWSClusterDetails, ClusterDetails } from '../types/types'; describe('ConfigClusterLocator', () => { it('empty clusters returns empty cluster details', async () => { @@ -50,7 +50,6 @@ describe('ConfigClusterLocator', () => { expect(result).toStrictEqual([ { name: 'cluster1', - serviceAccountToken: undefined, url: 'http://localhost:8080', authProvider: 'serviceAccount', skipMetricsLookup: false, @@ -91,17 +90,16 @@ describe('ConfigClusterLocator', () => { { name: 'cluster1', dashboardUrl: 'https://k8s.foo.com', - serviceAccountToken: 'token', url: 'http://localhost:8080', authProvider: 'serviceAccount', skipTLSVerify: false, skipMetricsLookup: true, caData: undefined, caFile: undefined, + authMetadata: { serviceAccountToken: 'token' }, }, { name: 'cluster2', - serviceAccountToken: undefined, url: 'http://localhost:8081', authProvider: 'google', skipTLSVerify: true, @@ -144,14 +142,14 @@ describe('ConfigClusterLocator', () => { const result = await sut.getClusters(); - expect(result).toStrictEqual([ + expect(result).toStrictEqual([ { assumeRole: undefined, name: 'cluster1', - serviceAccountToken: 'token', externalId: undefined, url: 'http://localhost:8080', authProvider: 'aws', + authMetadata: { serviceAccountToken: 'token' }, skipTLSVerify: false, skipMetricsLookup: false, caData: undefined, @@ -161,7 +159,6 @@ describe('ConfigClusterLocator', () => { assumeRole: 'SomeRole', name: 'cluster2', externalId: undefined, - serviceAccountToken: undefined, url: 'http://localhost:8081', authProvider: 'aws', skipTLSVerify: true, @@ -174,7 +171,6 @@ describe('ConfigClusterLocator', () => { name: 'cluster2', externalId: 'SomeExternalId', url: 'http://localhost:8081', - serviceAccountToken: undefined, authProvider: 'aws', skipTLSVerify: true, skipMetricsLookup: false, @@ -208,7 +204,6 @@ describe('ConfigClusterLocator', () => { expect(result).toStrictEqual([ { name: 'cluster1', - serviceAccountToken: undefined, url: 'http://localhost:8080', authProvider: 'serviceAccount', skipMetricsLookup: false, @@ -245,7 +240,6 @@ describe('ConfigClusterLocator', () => { expect(result).toStrictEqual([ { name: 'cluster1', - serviceAccountToken: undefined, url: 'http://localhost:8080', authProvider: 'serviceAccount', skipMetricsLookup: false, @@ -298,7 +292,6 @@ describe('ConfigClusterLocator', () => { expect(result).toStrictEqual([ { name: 'cluster1', - serviceAccountToken: undefined, url: 'http://localhost:8080', authProvider: 'serviceAccount', skipMetricsLookup: false, diff --git a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts index 4d49e2d128..e83bd763c4 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts @@ -30,15 +30,16 @@ export class ConfigClusterLocator implements KubernetesClustersSupplier { return new ConfigClusterLocator( config.getConfigArray('clusters').map(c => { const authProvider = c.getString('authProvider'); + const serviceAccountToken = c.getOptionalString('serviceAccountToken'); const clusterDetails: ClusterDetails = { name: c.getString('name'), url: c.getString('url'), - serviceAccountToken: c.getOptionalString('serviceAccountToken'), skipTLSVerify: c.getOptionalBoolean('skipTLSVerify') ?? false, skipMetricsLookup: c.getOptionalBoolean('skipMetricsLookup') ?? false, caData: c.getOptionalString('caData'), caFile: c.getOptionalString('caFile'), authProvider: authProvider, + ...(serviceAccountToken && { authMetadata: { serviceAccountToken } }), }; const customResources = c.getOptionalConfigArray('customResources'); diff --git a/plugins/kubernetes-backend/src/cluster-locator/index.test.ts b/plugins/kubernetes-backend/src/cluster-locator/index.test.ts index 1797d3a1b2..e1bca888b5 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/index.test.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/index.test.ts @@ -55,9 +55,9 @@ describe('getCombinedClusterSupplier', () => { expect(result).toStrictEqual([ { name: 'cluster1', - serviceAccountToken: 'token', url: 'http://localhost:8080', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, skipMetricsLookup: false, skipTLSVerify: false, caData: undefined, @@ -65,7 +65,6 @@ describe('getCombinedClusterSupplier', () => { }, { name: 'cluster2', - serviceAccountToken: undefined, url: 'http://localhost:8081', authProvider: 'google', skipMetricsLookup: false, diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AksKubernetesAuthTranslator.test.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AksKubernetesAuthTranslator.test.ts index d0d3cf87bb..b39377f5a3 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AksKubernetesAuthTranslator.test.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AksKubernetesAuthTranslator.test.ts @@ -24,6 +24,6 @@ describe('AksKubernetesAuthTranslator', () => { { aks: 'aksToken' }, ); - expect(details.serviceAccountToken).toBe('aksToken'); + expect(details.authMetadata!.serviceAccountToken).toBe('aksToken'); }); }); diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AksKubernetesAuthTranslator.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AksKubernetesAuthTranslator.ts index 13d784293e..bdaafc507b 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AksKubernetesAuthTranslator.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AksKubernetesAuthTranslator.ts @@ -25,6 +25,14 @@ export class AksKubernetesAuthTranslator { clusterDetails: ClusterDetails, auth: KubernetesRequestAuth, ): Promise { - return { ...clusterDetails, serviceAccountToken: auth.aks }; + return { + ...clusterDetails, + ...(auth.aks && { + authMetadata: { + serviceAccountToken: auth.aks, + ...clusterDetails.authMetadata, + }, + }), + }; } } diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.test.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.test.ts index b080aa332b..30bb240a9f 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.test.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.test.ts @@ -61,7 +61,7 @@ describe('AwsIamKubernetesAuthTranslator tests', () => { url: '', authProvider: 'aws', }); - expect((await authPromise).serviceAccountToken).toEqual( + expect((await authPromise).authMetadata!.serviceAccountToken).toEqual( 'k8s-aws-v1.aHR0cHM6Ly9odHRwczovL2V4YW1wbGUuY29tL2FzZGY_', ); }); @@ -75,7 +75,7 @@ describe('AwsIamKubernetesAuthTranslator tests', () => { url: '', authProvider: 'aws', }); - expect((await authPromise).serviceAccountToken).toEqual( + expect((await authPromise).authMetadata!.serviceAccountToken).toEqual( 'k8s-aws-v1.aHR0cHM6Ly9odHRwczovL2V4YW1wbGUuY29tL2FzZGY_', ); expect(fromTemporaryCredentials).toHaveBeenCalledWith({ @@ -102,7 +102,7 @@ describe('AwsIamKubernetesAuthTranslator tests', () => { url: '', authProvider: 'aws', }); - expect((await authPromise).serviceAccountToken).toEqual( + expect((await authPromise).authMetadata!.serviceAccountToken).toEqual( 'k8s-aws-v1.aHR0cHM6Ly9odHRwczovL2V4YW1wbGUuY29tL2FzZGY_', ); expect(fromTemporaryCredentials).toHaveBeenCalledWith({ diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.ts index cc46fd567a..c30cfd5bfd 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.ts @@ -117,11 +117,14 @@ export class AwsIamKubernetesAuthTranslator clusterDetails, ); - clusterDetailsWithAuthToken.serviceAccountToken = await this.getBearerToken( - clusterDetails.name, - clusterDetails.assumeRole, - clusterDetails.externalId, - ); + clusterDetailsWithAuthToken.authMetadata = { + serviceAccountToken: await this.getBearerToken( + clusterDetails.name, + clusterDetails.assumeRole, + clusterDetails.externalId, + ), + ...clusterDetailsWithAuthToken.authMetadata, + }; return clusterDetailsWithAuthToken; } } diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AzureIdentityKubernetesAuthTranslator.test.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AzureIdentityKubernetesAuthTranslator.test.ts index 704551eb9f..dbc48857f4 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AzureIdentityKubernetesAuthTranslator.test.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AzureIdentityKubernetesAuthTranslator.test.ts @@ -57,7 +57,7 @@ describe('AzureIdentityKubernetesAuthTranslator tests', () => { ); const response = await authTranslator.decorateClusterDetailsWithAuth(cd); - expect(response.serviceAccountToken).toEqual('MY_TOKEN_1'); + expect(response.authMetadata!.serviceAccountToken).toEqual('MY_TOKEN_1'); }); it('should re-use token before expiry', async () => { @@ -67,10 +67,10 @@ describe('AzureIdentityKubernetesAuthTranslator tests', () => { ); const response = await authTranslator.decorateClusterDetailsWithAuth(cd); - expect(response.serviceAccountToken).toEqual('MY_TOKEN_1'); + expect(response.authMetadata!.serviceAccountToken).toEqual('MY_TOKEN_1'); const response2 = await authTranslator.decorateClusterDetailsWithAuth(cd); - expect(response2.serviceAccountToken).toEqual('MY_TOKEN_1'); + expect(response2.authMetadata!.serviceAccountToken).toEqual('MY_TOKEN_1'); }); it('should issue new token 15 minutes befory expiry', async () => { @@ -82,12 +82,12 @@ describe('AzureIdentityKubernetesAuthTranslator tests', () => { ); const response = await authTranslator.decorateClusterDetailsWithAuth(cd); - expect(response.serviceAccountToken).toEqual('MY_TOKEN_1'); + expect(response.authMetadata!.serviceAccountToken).toEqual('MY_TOKEN_1'); jest.setSystemTime(Date.now() + 2 * 60 * 1000); // advance time by 2mins const response2 = await authTranslator.decorateClusterDetailsWithAuth(cd); - expect(response2.serviceAccountToken).toEqual('MY_TOKEN_2'); + expect(response2.authMetadata!.serviceAccountToken).toEqual('MY_TOKEN_2'); }); it('should re-use existing token if there is afailure', async () => { @@ -99,20 +99,20 @@ describe('AzureIdentityKubernetesAuthTranslator tests', () => { ); const response = await authTranslator.decorateClusterDetailsWithAuth(cd); - expect(response.serviceAccountToken).toEqual('MY_TOKEN_1'); + expect(response.authMetadata!.serviceAccountToken).toEqual('MY_TOKEN_1'); jest.setSystemTime(Date.now() + 2 * 60 * 1000); // advance time by 2min const response2 = await authTranslator.decorateClusterDetailsWithAuth(cd); - expect(response2.serviceAccountToken).toEqual('MY_TOKEN_2'); + expect(response2.authMetadata!.serviceAccountToken).toEqual('MY_TOKEN_2'); jest.setSystemTime(Date.now() + 2 * 60 * 1000); // advance time by 2min const response3 = await authTranslator.decorateClusterDetailsWithAuth(cd); - expect(response3.serviceAccountToken).toEqual('MY_TOKEN_2'); + expect(response3.authMetadata!.serviceAccountToken).toEqual('MY_TOKEN_2'); const response4 = await authTranslator.decorateClusterDetailsWithAuth(cd); - expect(response4.serviceAccountToken).toEqual('MY_TOKEN_4'); + expect(response4.authMetadata!.serviceAccountToken).toEqual('MY_TOKEN_4'); }); it('should throw if existing token expired and failed to fetch a new one', async () => { @@ -124,12 +124,12 @@ describe('AzureIdentityKubernetesAuthTranslator tests', () => { ); const response = await authTranslator.decorateClusterDetailsWithAuth(cd); - expect(response.serviceAccountToken).toEqual('MY_TOKEN_1'); + expect(response.authMetadata!.serviceAccountToken).toEqual('MY_TOKEN_1'); jest.setSystemTime(Date.now() + 2 * 60 * 1000); // advance time by 2min const response2 = await authTranslator.decorateClusterDetailsWithAuth(cd); - expect(response2.serviceAccountToken).toEqual('MY_TOKEN_2'); + expect(response2.authMetadata!.serviceAccountToken).toEqual('MY_TOKEN_2'); jest.setSystemTime(Date.now() + 17 * 60 * 1000); // advance time by 17min diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AzureIdentityKubernetesAuthTranslator.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AzureIdentityKubernetesAuthTranslator.ts index 2633598d6c..784e3c7311 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AzureIdentityKubernetesAuthTranslator.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AzureIdentityKubernetesAuthTranslator.ts @@ -48,7 +48,10 @@ export class AzureIdentityKubernetesAuthTranslator clusterDetails, ); - clusterDetailsWithAuthToken.serviceAccountToken = await this.getToken(); + clusterDetailsWithAuthToken.authMetadata = { + serviceAccountToken: await this.getToken(), + ...clusterDetailsWithAuthToken.authMetadata, + }; return clusterDetailsWithAuthToken; } diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/DispatchingKubernetesAuthTranslator.test.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/DispatchingKubernetesAuthTranslator.test.ts index 3132bdef76..be41c593f2 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/DispatchingKubernetesAuthTranslator.test.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/DispatchingKubernetesAuthTranslator.test.ts @@ -36,7 +36,7 @@ describe('decorateClusterDetailsWithAuth', () => { url: 'notanything.com', name: 'randomName', authProvider: 'google', - serviceAccountToken: 'added by mock translator', + authMetadata: { serviceAccountToken: 'added by mock translator' }, }; mockTranslator.decorateClusterDetailsWithAuth.mockResolvedValue( diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/GoogleKubernetesAuthTranslator.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/GoogleKubernetesAuthTranslator.ts index e8dae56997..96b2daebad 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/GoogleKubernetesAuthTranslator.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/GoogleKubernetesAuthTranslator.ts @@ -36,7 +36,10 @@ export class GoogleKubernetesAuthTranslator const authToken: string | undefined = authConfig.google; if (authToken) { - clusterDetailsWithAuthToken.serviceAccountToken = authToken; + clusterDetailsWithAuthToken.authMetadata = { + serviceAccountToken: authToken, + ...clusterDetailsWithAuthToken.authMetadata, + }; } else { throw new Error( 'Google token not found under auth.google in request body', diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/GoogleServiceAccountAuthProvider.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/GoogleServiceAccountAuthProvider.ts index cca510ad6c..81b50c478b 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/GoogleServiceAccountAuthProvider.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/GoogleServiceAccountAuthProvider.ts @@ -35,7 +35,10 @@ export class GoogleServiceAccountAuthTranslator const accessToken = await client.auth.getAccessToken(); if (accessToken) { - clusterDetailsWithAuthToken.serviceAccountToken = accessToken; + clusterDetailsWithAuthToken.authMetadata = { + serviceAccountToken: accessToken, + ...clusterDetailsWithAuthToken.authMetadata, + }; } else { throw new Error( 'Unable to obtain access token for the current Google Application Default Credentials', diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/NoopKubernetesAuthTranslator.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/NoopKubernetesAuthTranslator.ts index 32aa141e50..a44710f58b 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/NoopKubernetesAuthTranslator.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/NoopKubernetesAuthTranslator.ts @@ -15,7 +15,7 @@ */ import { KubernetesAuthTranslator } from './types'; -import { ServiceAccountClusterDetails } from '../types/types'; +import { ClusterDetails } from '../types/types'; /** * @@ -23,8 +23,8 @@ import { ServiceAccountClusterDetails } from '../types/types'; */ export class NoopKubernetesAuthTranslator implements KubernetesAuthTranslator { async decorateClusterDetailsWithAuth( - clusterDetails: ServiceAccountClusterDetails, - ): Promise { + clusterDetails: ClusterDetails, + ): Promise { return clusterDetails; } } diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.test.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.test.ts index 68f24bd020..fe604008f1 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.test.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.test.ts @@ -36,7 +36,7 @@ describe('OidcKubernetesAuthTranslator tests', () => { }, ); - expect(details.serviceAccountToken).toBe('fakeToken'); + expect(details.authMetadata!.serviceAccountToken).toBe('fakeToken'); }); it('returns error when oidcTokenProvider is not configured', async () => { diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.ts index cee1ec1e0c..5c0c0de181 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/OidcKubernetesAuthTranslator.ts @@ -43,7 +43,10 @@ export class OidcKubernetesAuthTranslator implements KubernetesAuthTranslator { const authToken: string | undefined = authConfig.oidc?.[oidcTokenProvider]; if (authToken) { - clusterDetailsWithAuthToken.serviceAccountToken = authToken; + clusterDetailsWithAuthToken.authMetadata = { + serviceAccountToken: authToken, + ...clusterDetailsWithAuthToken.authMetadata, + }; } else { throw new Error( `Auth token not found under oidc.${oidcTokenProvider} in request body`, diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index 8eb7a066df..9d663a4185 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -64,7 +64,6 @@ describe('KubernetesBuilder', () => { name: 'some-cluster', authProvider: 'serviceAccount', url: 'https://localhost:1234', - serviceAccountToken: 'someToken', }, { name: 'some-other-cluster', @@ -192,7 +191,6 @@ describe('KubernetesBuilder', () => { name: 'some-cluster', authProvider: 'serviceAccount', url: 'https://localhost:1234', - serviceAccountToken: 'someToken', }; const clusters: ClusterDetails[] = [ someCluster, diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts index a76406be07..e092ac082c 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts @@ -1068,14 +1068,14 @@ describe('KubernetesFanOutHandler', () => { url: 'https://works', authProvider: 'serviceAccount', skipMetricsLookup: true, - serviceAccountToken: 'token', + authMetadata: { serviceAccountToken: 'token' }, }, { name: 'fails', url: 'https://fails', authProvider: 'serviceAccount', skipMetricsLookup: true, - serviceAccountToken: 'token', + authMetadata: { serviceAccountToken: 'token' }, }, ], }), diff --git a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts index 1a603a7a98..37f134be46 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts @@ -138,8 +138,8 @@ describe('KubernetesFetcher', () => { clusterDetails: { name: 'cluster1', url: 'http://localhost:9999', - serviceAccountToken: 'token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, }, objectTypesToFetch: OBJECTS_TO_FETCH, labelSelector: '', @@ -199,8 +199,8 @@ describe('KubernetesFetcher', () => { clusterDetails: { name: 'cluster1', url: 'http://localhost:9999/k8s/clusters/1234', - serviceAccountToken: 'token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, }, objectTypesToFetch: OBJECTS_TO_FETCH, labelSelector: '', @@ -309,8 +309,8 @@ describe('KubernetesFetcher', () => { clusterDetails: { name: 'cluster1', url: 'http://localhost:9999', - serviceAccountToken: 'token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, }, objectTypesToFetch: OBJECTS_TO_FETCH, labelSelector: '', @@ -383,8 +383,8 @@ describe('KubernetesFetcher', () => { clusterDetails: { name: 'cluster1', url: 'http://localhost:9999', - serviceAccountToken: 'token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, }, objectTypesToFetch: OBJECTS_TO_FETCH, labelSelector: '', @@ -475,8 +475,8 @@ describe('KubernetesFetcher', () => { clusterDetails: { name: 'cluster1', url: 'http://localhost:9999', - serviceAccountToken: 'token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, }, objectTypesToFetch: OBJECTS_TO_FETCH, labelSelector: '', @@ -563,8 +563,8 @@ describe('KubernetesFetcher', () => { clusterDetails: { name: 'cluster1', url: 'http://badurl.does.not.exist', - serviceAccountToken: 'token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, }, objectTypesToFetch: OBJECTS_TO_FETCH, labelSelector: '', @@ -600,8 +600,8 @@ describe('KubernetesFetcher', () => { clusterDetails: { name: 'cluster1', url: 'http://localhost:9999', - serviceAccountToken: 'token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, }, objectTypesToFetch: OBJECTS_TO_FETCH, labelSelector: 'service-label=value', @@ -667,8 +667,8 @@ describe('KubernetesFetcher', () => { clusterDetails: { name: 'cluster1', url: 'https://localhost:9999', - serviceAccountToken: 'token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, caData: 'MOCKCA', }, objectTypesToFetch: new Set([ @@ -704,8 +704,8 @@ describe('KubernetesFetcher', () => { clusterDetails: { name: 'cluster1', url: 'https://localhost:9999', - serviceAccountToken: 'token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, }, objectTypesToFetch: new Set([ { @@ -747,8 +747,8 @@ describe('KubernetesFetcher', () => { clusterDetails: { name: 'cluster1', url: 'https://localhost:9999', - serviceAccountToken: 'token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, caFile: '/path/to/ca.crt', }, objectTypesToFetch: new Set([ @@ -785,8 +785,8 @@ describe('KubernetesFetcher', () => { clusterDetails: { name: 'cluster1', url: 'https://localhost:9999', - serviceAccountToken: 'token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, skipTLSVerify: true, }, objectTypesToFetch: new Set([ @@ -836,8 +836,8 @@ describe('KubernetesFetcher', () => { clusterDetails: { name: 'cluster1', url: 'http://localhost:9999', - serviceAccountToken: 'token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, }, objectTypesToFetch: OBJECTS_TO_FETCH, labelSelector: '', @@ -1019,8 +1019,8 @@ describe('KubernetesFetcher', () => { { name: 'cluster1', url: 'http://localhost:9999', - serviceAccountToken: 'token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, }, new Set(['ns-a']), ); @@ -1106,8 +1106,8 @@ describe('KubernetesFetcher', () => { { name: 'cluster1', url: 'http://localhost:9999', - serviceAccountToken: 'token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'token' }, }, new Set(['ns-a', 'ns-b']), ); diff --git a/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts b/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts index 25bade3e97..f3499f039e 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts @@ -201,7 +201,7 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher { let url: URL; let requestInit: RequestInit; if ( - clusterDetails.serviceAccountToken || + clusterDetails?.authMetadata?.serviceAccountToken || clusterDetails.authProvider === 'localKubectlProxy' ) { [url, requestInit] = this.fetchArgsFromClusterDetails(clusterDetails); @@ -236,7 +236,7 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher { headers: { Accept: 'application/json', 'Content-Type': 'application/json', - Authorization: `Bearer ${clusterDetails.serviceAccountToken}`, + Authorization: `Bearer ${clusterDetails.authMetadata?.serviceAccountToken}`, }, }; diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts index 6c8953d0a3..8f25b217ab 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts @@ -154,8 +154,8 @@ describe('KubernetesProxy', () => { { name: 'cluster1', url: 'https://localhost:9999', - serviceAccountToken: 'tokenA', authProvider: 'googleServiceAccount', + authMetadata: { serviceAccountToken: 'tokenA' }, } as ClusterDetails, ]); @@ -172,8 +172,8 @@ describe('KubernetesProxy', () => { { name: 'cluster1', url: 'https://localhost:9999', - serviceAccountToken: 'tokenA', authProvider: 'googleServiceAccount', + authMetadata: { serviceAccountToken: 'tokenA' }, } as ClusterDetails, ]); @@ -201,7 +201,6 @@ describe('KubernetesProxy', () => { { name: 'cluster1', url: 'https://localhost:9999', - serviceAccountToken: '', authProvider: 'serviceAccount', }, ] as ClusterDetails[]); @@ -209,7 +208,6 @@ describe('KubernetesProxy', () => { authTranslator.decorateClusterDetailsWithAuth.mockResolvedValue({ name: 'cluster1', url: 'https://localhost:9999', - serviceAccountToken: '', authProvider: 'serviceAccount', } as ClusterDetails); @@ -247,7 +245,6 @@ describe('KubernetesProxy', () => { { name: 'cluster1', url: 'https://localhost:9999', - serviceAccountToken: '', authProvider: 'serviceAccount', }, ] as ClusterDetails[]); @@ -255,7 +252,6 @@ describe('KubernetesProxy', () => { authTranslator.decorateClusterDetailsWithAuth.mockResolvedValue({ name: 'cluster1', url: 'https://localhost:9999', - serviceAccountToken: '', authProvider: 'serviceAccount', } as ClusterDetails); @@ -344,7 +340,6 @@ describe('KubernetesProxy', () => { { name: 'cluster1', url: 'https://localhost:9999', - serviceAccountToken: '', authProvider: 'serviceAccount', }, ] as ClusterDetails[]); @@ -352,8 +347,8 @@ describe('KubernetesProxy', () => { authTranslator.decorateClusterDetailsWithAuth.mockResolvedValue({ name: 'cluster1', url: 'https://localhost:9999', - serviceAccountToken: 'translator-provided-token', authProvider: 'serviceAccount', + authMetadata: { serviceAccountToken: 'translator-provided-token' }, } as ClusterDetails); const requestPromise = setupProxyPromise({ @@ -401,8 +396,8 @@ describe('KubernetesProxy', () => { authTranslator.decorateClusterDetailsWithAuth.mockResolvedValue({ name: 'cluster1', url: 'https://localhost:9999', - serviceAccountToken: 'my-token', authProvider: 'googleServiceAccount', + authMetadata: { serviceAccountToken: 'my-token' }, } as ClusterDetails); const requestPromise = setupProxyPromise({ @@ -455,8 +450,8 @@ describe('KubernetesProxy', () => { authTranslator.decorateClusterDetailsWithAuth.mockResolvedValue({ name: 'cluster1', url: 'https://localhost:9999', - serviceAccountToken: 'tokenA', authProvider: 'googleServiceAccount', + authMetadata: { serviceAccountToken: 'tokenA' }, } as ClusterDetails); const requestPromise = setupProxyPromise({ @@ -600,7 +595,7 @@ describe('KubernetesProxy', () => { name: 'cluster1', url: 'https://localhost:9999', authProvider: 'google', - serviceAccountToken: 'client-side-token', + authMetadata: { serviceAccountToken: 'client-side-token' }, }, ] as ClusterDetails[]); @@ -788,7 +783,6 @@ describe('KubernetesProxy', () => { { name: 'local', url: `http://localhost:${wsPort}`, - serviceAccountToken: '', authProvider: 'serviceAccount', }, ] as ClusterDetails[]); @@ -796,7 +790,6 @@ describe('KubernetesProxy', () => { authTranslator.decorateClusterDetailsWithAuth.mockResolvedValue({ name: 'local', url: `http://localhost:${wsPort}`, - serviceAccountToken: '', authProvider: 'serviceAccount', } as ClusterDetails); diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts index 8ae1fb9fcc..e3fc293436 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts @@ -112,11 +112,11 @@ export class KubernetesProxy { if (authHeader) { req.headers.authorization = authHeader; } else { - const { serviceAccountToken } = await this.getClusterForRequest( - req, - ).then(cd => - this.authTranslator.decorateClusterDetailsWithAuth(cd, {}), - ); + const serviceAccountToken = await this.getClusterForRequest(req) + .then(cd => + this.authTranslator.decorateClusterDetailsWithAuth(cd, {}), + ) + .then(cd => cd?.authMetadata?.serviceAccountToken); if (serviceAccountToken) { req.headers.authorization = `Bearer ${serviceAccountToken}`; } diff --git a/plugins/kubernetes-backend/src/types/types.ts b/plugins/kubernetes-backend/src/types/types.ts index 15ed1662de..6711462916 100644 --- a/plugins/kubernetes-backend/src/types/types.ts +++ b/plugins/kubernetes-backend/src/types/types.ts @@ -33,11 +33,7 @@ import { Config } from '@backstage/config'; */ export interface ObjectFetchParams { serviceId: string; - clusterDetails: - | AWSClusterDetails - | GKEClusterDetails - | ServiceAccountClusterDetails - | ClusterDetails; + clusterDetails: AWSClusterDetails | GKEClusterDetails | ClusterDetails; objectTypesToFetch: Set; labelSelector: string; customResources: CustomResource[]; @@ -159,7 +155,6 @@ export interface ClusterDetails { name: string; url: string; authProvider: string; - serviceAccountToken?: string | undefined; /** * oidc provider used to get id tokens to authenticate against kubernetes */ @@ -209,6 +204,8 @@ export interface ClusterDetails { * Kubernetes resources. */ customResources?: CustomResourceMatcher[]; + + authMetadata?: Record; } /** @@ -223,12 +220,6 @@ export interface GKEClusterDetails extends ClusterDetails {} */ export interface AzureClusterDetails extends ClusterDetails {} -/** - * - * @public - */ -export interface ServiceAccountClusterDetails extends ClusterDetails {} - /** * * @public