diff --git a/plugins/kubernetes-backend/src/routes/resourcesRoutes.ts b/plugins/kubernetes-backend/src/routes/resourcesRoutes.ts index 6e05f69d04..838e039d27 100644 --- a/plugins/kubernetes-backend/src/routes/resourcesRoutes.ts +++ b/plugins/kubernetes-backend/src/routes/resourcesRoutes.ts @@ -63,10 +63,13 @@ export const addResourceRoutesToRouter = ( router.post('/resources/workloads/query', async (req, res) => { const entity = await getEntityByReq(req); - const response = await objectsProvider.getKubernetesObjectsByEntity({ - entity, - auth: req.body.auth, - }); + const response = await objectsProvider.getKubernetesObjectsByEntity( + { + entity, + auth: req.body.auth, + }, + { credentials: await httpAuth.credentials(req) }, + ); res.json(response); }); @@ -81,11 +84,14 @@ export const addResourceRoutesToRouter = ( throw new InputError('at least 1 customResource is required'); } - const response = await objectsProvider.getCustomResourcesByEntity({ - entity, - customResources: req.body.customResources, - auth: req.body.auth, - }); + const response = await objectsProvider.getCustomResourcesByEntity( + { + entity, + customResources: req.body.customResources, + auth: req.body.auth, + }, + { credentials: await httpAuth.credentials(req) }, + ); res.json(response); }); }; diff --git a/plugins/kubernetes-backend/src/service-locator/CatalogRelationServiceLocator.ts b/plugins/kubernetes-backend/src/service-locator/CatalogRelationServiceLocator.ts index 9ac945bd84..1a9ad33641 100644 --- a/plugins/kubernetes-backend/src/service-locator/CatalogRelationServiceLocator.ts +++ b/plugins/kubernetes-backend/src/service-locator/CatalogRelationServiceLocator.ts @@ -33,7 +33,7 @@ export class CatalogRelationServiceLocator implements KubernetesServiceLocator { // As this implementation always returns all clusters serviceId is ignored here getClustersByEntity( entity: Entity, - _requestContext: ServiceLocatorRequestContext, + requestContext: ServiceLocatorRequestContext, ): Promise<{ clusters: ClusterDetails[] }> { if ( entity.relations && @@ -41,13 +41,15 @@ export class CatalogRelationServiceLocator implements KubernetesServiceLocator { r => r.type === 'dependsOn' && r.targetRef.includes('resource:'), ) ) { - return this.clusterSupplier.getClusters().then(clusters => { - return { - clusters: clusters.filter(c => - this.doesEntityDependOnCluster(entity, c), - ), - }; - }); + return this.clusterSupplier + .getClusters({ credentials: requestContext.credentials }) + .then(clusters => { + return { + clusters: clusters.filter(c => + this.doesEntityDependOnCluster(entity, c), + ), + }; + }); } return Promise.resolve({ clusters: [] }); } diff --git a/plugins/kubernetes-backend/src/service-locator/MultiTenantServiceLocator.ts b/plugins/kubernetes-backend/src/service-locator/MultiTenantServiceLocator.ts index ed902b194a..12946d27b9 100644 --- a/plugins/kubernetes-backend/src/service-locator/MultiTenantServiceLocator.ts +++ b/plugins/kubernetes-backend/src/service-locator/MultiTenantServiceLocator.ts @@ -34,8 +34,10 @@ export class MultiTenantServiceLocator implements KubernetesServiceLocator { // As this implementation always returns all clusters serviceId is ignored here getClustersByEntity( _entity: Entity, - _requestContext: ServiceLocatorRequestContext, + requestContext: ServiceLocatorRequestContext, ): Promise<{ clusters: ClusterDetails[] }> { - return this.clusterSupplier.getClusters().then(clusters => ({ clusters })); + return this.clusterSupplier + .getClusters({ credentials: requestContext.credentials }) + .then(clusters => ({ clusters })); } } diff --git a/plugins/kubernetes-backend/src/service-locator/SingleTenantServiceLocator.ts b/plugins/kubernetes-backend/src/service-locator/SingleTenantServiceLocator.ts index e94d95776c..f3ea2d49f1 100644 --- a/plugins/kubernetes-backend/src/service-locator/SingleTenantServiceLocator.ts +++ b/plugins/kubernetes-backend/src/service-locator/SingleTenantServiceLocator.ts @@ -34,21 +34,25 @@ export class SingleTenantServiceLocator implements KubernetesServiceLocator { // As this implementation always returns all clusters serviceId is ignored here getClustersByEntity( _entity: Entity, - _requestContext: ServiceLocatorRequestContext, + requestContext: ServiceLocatorRequestContext, ): Promise<{ clusters: ClusterDetails[] }> { - return this.clusterSupplier.getClusters().then(clusters => { - if (_entity.metadata?.annotations?.['backstage.io/kubernetes-cluster']) { - return { - clusters: clusters.filter( - c => - c.name === - _entity.metadata?.annotations?.[ - 'backstage.io/kubernetes-cluster' - ], - ), - }; - } - return { clusters }; - }); + return this.clusterSupplier + .getClusters({ credentials: requestContext.credentials }) + .then(clusters => { + if ( + _entity.metadata?.annotations?.['backstage.io/kubernetes-cluster'] + ) { + return { + clusters: clusters.filter( + c => + c.name === + _entity.metadata?.annotations?.[ + 'backstage.io/kubernetes-cluster' + ], + ), + }; + } + return { clusters }; + }); } } diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts index fd59741e76..63ed66d4d6 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts @@ -157,7 +157,7 @@ export class KubernetesBuilder { const authStrategyMap = this.getAuthStrategyMap(); - const proxy = this.getProxy(logger, clusterSupplier); + const proxy = this.getProxy(logger, clusterSupplier, httpAuth); const serviceLocator = this.getServiceLocator(); @@ -350,6 +350,7 @@ export class KubernetesBuilder { protected buildProxy( logger: Logger, clusterSupplier: KubernetesClustersSupplier, + httpAuth: HttpAuthService, ): KubernetesProxy { const authStrategyMap = this.getAuthStrategyMap(); const authStrategy = new DispatchStrategy({ @@ -359,6 +360,7 @@ export class KubernetesBuilder { logger, clusterSupplier, authStrategy, + httpAuth, }); return this.proxy; } @@ -386,10 +388,13 @@ export class KubernetesBuilder { const serviceId = req.params.serviceId; const requestBody: ObjectsByEntityRequest = req.body; try { - const response = await objectsProvider.getKubernetesObjectsByEntity({ - entity: requestBody.entity, - auth: requestBody.auth || {}, - }); + const response = await objectsProvider.getKubernetesObjectsByEntity( + { + entity: requestBody.entity, + auth: requestBody.auth || {}, + }, + { credentials: await httpAuth.credentials(req) }, + ); res.json(response); } catch (e) { logger.error( @@ -530,8 +535,9 @@ export class KubernetesBuilder { protected getProxy( logger: Logger, clusterSupplier: KubernetesClustersSupplier, + httpAuth: HttpAuthService, ) { - return this.proxy ?? this.buildProxy(logger, clusterSupplier); + return this.proxy ?? this.buildProxy(logger, clusterSupplier, httpAuth); } protected getAuthStrategyMap() { diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts index 5c4534d61b..bf735cdb28 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts @@ -35,6 +35,7 @@ import { } from '@backstage/plugin-kubernetes-common'; import { Config, ConfigReader } from '@backstage/config'; import { Entity } from '@backstage/catalog-model'; +import { BackstageCredentials } from '@backstage/backend-plugin-api'; describe('KubernetesFanOutHandler', () => { const fetchObjectsForService = jest.fn(); @@ -62,6 +63,14 @@ describe('KubernetesFanOutHandler', () => { pod: {}, }; + const mockCredentials: BackstageCredentials = { + $$type: '@backstage/BackstageCredentials', + principal: { + userEntityRef: 'user:default/guest', + type: 'user', + }, + }; + const entity = { apiVersion: 'backstage.io/v1beta1', kind: 'Component', @@ -372,10 +381,13 @@ describe('KubernetesFanOutHandler', () => { sut = getKubernetesFanOutHandler([]); - const result = await sut.getKubernetesObjectsByEntity({ - entity, - auth: {}, - }); + const result = await sut.getKubernetesObjectsByEntity( + { + entity, + auth: {}, + }, + { credentials: mockCredentials }, + ); expect(getClustersByEntity).toHaveBeenCalledTimes(1); expect(fetchObjectsForService).toHaveBeenCalledTimes(1); @@ -410,10 +422,13 @@ describe('KubernetesFanOutHandler', () => { sut = getKubernetesFanOutHandler([]); - await sut.getKubernetesObjectsByEntity({ - entity, - auth: {}, - }); + await sut.getKubernetesObjectsByEntity( + { + entity, + auth: {}, + }, + { credentials: mockCredentials }, + ); expect(fetchObjectsForService).toHaveBeenCalledTimes(1); expect( @@ -442,10 +457,13 @@ describe('KubernetesFanOutHandler', () => { sut = getKubernetesFanOutHandler([]); - await sut.getKubernetesObjectsByEntity({ - entity, - auth: {}, - }); + await sut.getKubernetesObjectsByEntity( + { + entity, + auth: {}, + }, + { credentials: mockCredentials }, + ); expect(fetchObjectsForService).toHaveBeenCalledTimes(2); expect(fetchObjectsForService).toHaveBeenCalledWith( @@ -497,10 +515,13 @@ describe('KubernetesFanOutHandler', () => { }, ]); - await sut.getKubernetesObjectsByEntity({ - entity, - auth: {}, - }); + await sut.getKubernetesObjectsByEntity( + { + entity, + auth: {}, + }, + { credentials: mockCredentials }, + ); expect(fetchObjectsForService).toHaveBeenCalledTimes(2); expect(fetchObjectsForService).toHaveBeenCalledWith( @@ -559,10 +580,13 @@ describe('KubernetesFanOutHandler', () => { }, ]); - await sut.getKubernetesObjectsByEntity({ - entity, - auth: {}, - }); + await sut.getKubernetesObjectsByEntity( + { + entity, + auth: {}, + }, + { credentials: mockCredentials }, + ); expect(fetchObjectsForService).toHaveBeenCalledWith( expect.objectContaining({ @@ -600,10 +624,13 @@ describe('KubernetesFanOutHandler', () => { }, ]); - await sut.getKubernetesObjectsByEntity({ - entity, - auth: {}, - }); + await sut.getKubernetesObjectsByEntity( + { + entity, + auth: {}, + }, + { credentials: mockCredentials }, + ); expect(fetchObjectsForService).toHaveBeenCalledWith( expect.objectContaining({ @@ -665,10 +692,13 @@ describe('KubernetesFanOutHandler', () => { sut = getKubernetesFanOutHandler([]); - const result = await sut.getKubernetesObjectsByEntity({ - entity, - auth: {}, - }); + const result = await sut.getKubernetesObjectsByEntity( + { + entity, + auth: {}, + }, + { credentials: mockCredentials }, + ); expect(getClustersByEntity).toHaveBeenCalledTimes(1); expect(fetchObjectsForService).toHaveBeenCalledTimes(1); @@ -744,10 +774,13 @@ describe('KubernetesFanOutHandler', () => { sut = getKubernetesFanOutHandler([]); - const result = await sut.getKubernetesObjectsByEntity({ - entity, - auth: {}, - }); + const result = await sut.getKubernetesObjectsByEntity( + { + entity, + auth: {}, + }, + { credentials: mockCredentials }, + ); expect(getClustersByEntity).toHaveBeenCalledTimes(1); expect(fetchObjectsForService).toHaveBeenCalledTimes(1); @@ -779,12 +812,15 @@ describe('KubernetesFanOutHandler', () => { sut = getKubernetesFanOutHandler([]); - const result = await sut.getKubernetesObjectsByEntity({ - entity, - auth: { - google: 'google_token_123', + const result = await sut.getKubernetesObjectsByEntity( + { + entity, + auth: { + google: 'google_token_123', + }, }, - }); + { credentials: mockCredentials }, + ); expect(getClustersByEntity).toHaveBeenCalledTimes(1); expect(fetchObjectsForService).toHaveBeenCalledTimes(2); @@ -836,12 +872,15 @@ describe('KubernetesFanOutHandler', () => { sut = getKubernetesFanOutHandler([]); - const result = await sut.getKubernetesObjectsByEntity({ - entity, - auth: { - google: 'google_token_123', + const result = await sut.getKubernetesObjectsByEntity( + { + entity, + auth: { + google: 'google_token_123', + }, }, - }); + { credentials: mockCredentials }, + ); expect(getClustersByEntity).toHaveBeenCalledTimes(1); expect(fetchObjectsForService).toHaveBeenCalledTimes(3); @@ -897,12 +936,15 @@ describe('KubernetesFanOutHandler', () => { sut = getKubernetesFanOutHandler([]); - const result = await sut.getKubernetesObjectsByEntity({ - entity, - auth: { - google: 'google_token_123', + const result = await sut.getKubernetesObjectsByEntity( + { + entity, + auth: { + google: 'google_token_123', + }, }, - }); + { credentials: mockCredentials }, + ); expect(getClustersByEntity).toHaveBeenCalledTimes(1); expect(fetchObjectsForService).toHaveBeenCalledTimes(4); @@ -1015,12 +1057,15 @@ describe('KubernetesFanOutHandler', () => { sut = getKubernetesFanOutHandler([]); - const result = await sut.getKubernetesObjectsByEntity({ - entity, - auth: { - google: 'google_token_123', + const result = await sut.getKubernetesObjectsByEntity( + { + entity, + auth: { + google: 'google_token_123', + }, }, - }); + { credentials: mockCredentials }, + ); expect(getClustersByEntity).toHaveBeenCalledTimes(1); expect(fetchObjectsForService).toHaveBeenCalledTimes(2); @@ -1069,10 +1114,13 @@ describe('KubernetesFanOutHandler', () => { sut = getKubernetesFanOutHandler([]); - const result = sut.getKubernetesObjectsByEntity({ - entity, - auth: {}, - }); + const result = sut.getKubernetesObjectsByEntity( + { + entity, + auth: {}, + }, + { credentials: mockCredentials }, + ); await expect(result).rejects.toThrow(nonFetchError); }); @@ -1155,10 +1203,13 @@ describe('KubernetesFanOutHandler', () => { }); const result = - await kubernetesFanOutHandler.getKubernetesObjectsByEntity({ - entity, - auth: {}, - }); + await kubernetesFanOutHandler.getKubernetesObjectsByEntity( + { + entity, + auth: {}, + }, + { credentials: mockCredentials }, + ); const expected: ObjectsByEntityResponse = { items: [ @@ -1200,17 +1251,20 @@ describe('KubernetesFanOutHandler', () => { sut = getKubernetesFanOutHandler([]); - await sut.getCustomResourcesByEntity({ - entity, - auth: {}, - customResources: [ - { - group: 'parameter-crd.example.com', - apiVersion: 'v1alpha1', - plural: 'parameter-crd', - }, - ], - }); + await sut.getCustomResourcesByEntity( + { + entity, + auth: {}, + customResources: [ + { + group: 'parameter-crd.example.com', + apiVersion: 'v1alpha1', + plural: 'parameter-crd', + }, + ], + }, + { credentials: mockCredentials }, + ); expect(fetchObjectsForService).toHaveBeenCalledTimes(1); expect(fetchObjectsForService).toHaveBeenCalledWith( @@ -1262,17 +1316,20 @@ describe('KubernetesFanOutHandler', () => { }, ]); - await sut.getCustomResourcesByEntity({ - entity, - auth: {}, - customResources: [ - { - group: 'parameter-crd.example.com', - apiVersion: 'v1alpha1', - plural: 'parameter-crd', - }, - ], - }); + await sut.getCustomResourcesByEntity( + { + entity, + auth: {}, + customResources: [ + { + group: 'parameter-crd.example.com', + apiVersion: 'v1alpha1', + plural: 'parameter-crd', + }, + ], + }, + { credentials: mockCredentials }, + ); expect(fetchObjectsForService).toHaveBeenCalledTimes(2); expect(fetchObjectsForService).toHaveBeenCalledWith( @@ -1329,17 +1386,20 @@ describe('KubernetesFanOutHandler', () => { sut = getKubernetesFanOutHandler([]); - await sut.getCustomResourcesByEntity({ - entity, - auth: {}, - customResources: [ - { - group: 'parameter-crd.example.com', - apiVersion: 'v1alpha1', - plural: 'parameter-crd', - }, - ], - }); + await sut.getCustomResourcesByEntity( + { + entity, + auth: {}, + customResources: [ + { + group: 'parameter-crd.example.com', + apiVersion: 'v1alpha1', + plural: 'parameter-crd', + }, + ], + }, + { credentials: mockCredentials }, + ); expect(fetchObjectsForService).toHaveBeenCalledWith( expect.objectContaining({ diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts index 4df60bc8da..b48abc8816 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts @@ -48,7 +48,9 @@ import { CustomResourcesByEntity, KubernetesCredential, KubernetesObjectsByEntity, + KubernetesObjectsProvider, } from '@backstage/plugin-kubernetes-node'; +import { BackstageCredentials } from '@backstage/backend-plugin-api'; /** * @@ -190,7 +192,7 @@ const toClientSafePodMetrics = ( type responseWithMetrics = [FetchResponseWrapper, PodStatusFetchResponse[]]; -export class KubernetesFanOutHandler { +export class KubernetesFanOutHandler implements KubernetesObjectsProvider { private readonly logger: Logger; private readonly fetcher: KubernetesFetcher; private readonly serviceLocator: KubernetesServiceLocator; @@ -214,30 +216,38 @@ export class KubernetesFanOutHandler { this.authStrategy = authStrategy; } - async getCustomResourcesByEntity({ - entity, - auth, - customResources, - }: CustomResourcesByEntity): Promise { + async getCustomResourcesByEntity( + { entity, auth, customResources }: CustomResourcesByEntity, + options: { credentials: BackstageCredentials }, + ): Promise { // Don't fetch the default object types only the provided custom resources return this.fanOutRequests( entity, auth, + { credentials: options.credentials }, new Set(), customResources, ); } - async getKubernetesObjectsByEntity({ - entity, - auth, - }: KubernetesObjectsByEntity): Promise { - return this.fanOutRequests(entity, auth, this.objectTypesToFetch); + async getKubernetesObjectsByEntity( + { entity, auth }: KubernetesObjectsByEntity, + options: { credentials: BackstageCredentials }, + ): Promise { + return this.fanOutRequests( + entity, + auth, + { + credentials: options?.credentials, + }, + this.objectTypesToFetch, + ); } private async fanOutRequests( entity: Entity, auth: KubernetesRequestAuth, + options: { credentials: BackstageCredentials }, objectTypesToFetch: Set, customResources?: CustomResourceMatcher[], ) { @@ -248,6 +258,7 @@ export class KubernetesFanOutHandler { const { clusters } = await this.serviceLocator.getClustersByEntity(entity, { objectTypesToFetch: objectTypesToFetch, customResources: customResources ?? [], + credentials: options.credentials, }); this.logger.info( diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts index 241df1c6f0..81ae2e74bd 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts @@ -55,6 +55,10 @@ import { } from './KubernetesProxy'; import type { Request } from 'express'; +import { + BackstageCredentials, + HttpAuthService, +} from '@backstage/backend-plugin-api'; const mockCertDir = createMockDirectory({ content: { @@ -69,7 +73,10 @@ describe('KubernetesProxy', () => { const logger = getVoidLogger(); const clusterSupplier: jest.Mocked = { - getClusters: jest.fn, []>(), + getClusters: jest.fn< + Promise, + [{ credentials: BackstageCredentials }] + >(), }; const permissionApi: jest.Mocked = { @@ -77,6 +84,11 @@ describe('KubernetesProxy', () => { authorizeConditional: jest.fn(), }; + const mockHttpAuth: jest.Mocked = { + credentials: jest.fn(), + issueUserCookie: jest.fn(), + }; + setupRequestMockHandlers(worker); const buildMockRequest = (clusterName: any, path: string): Request => { @@ -146,7 +158,12 @@ describe('KubernetesProxy', () => { validateCluster: jest.fn(), presentAuthMetadata: jest.fn(), }; - proxy = new KubernetesProxy({ logger, clusterSupplier, authStrategy }); + proxy = new KubernetesProxy({ + logger, + clusterSupplier, + authStrategy, + httpAuth: mockHttpAuth, + }); permissionApi.authorize.mockResolvedValue([ { result: AuthorizeResult.ALLOW }, ]); @@ -535,6 +552,7 @@ describe('KubernetesProxy', () => { logger: getVoidLogger(), clusterSupplier: clusterSupplier, authStrategy: strategy, + httpAuth: mockHttpAuth, }); worker.use( @@ -656,6 +674,7 @@ describe('KubernetesProxy', () => { logger: getVoidLogger(), clusterSupplier: new LocalKubectlProxyClusterLocator(), authStrategy: new AnonymousStrategy(), + httpAuth: mockHttpAuth, }); worker.use( diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts index b4536c5880..4380bc922e 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts @@ -45,6 +45,7 @@ import { ClusterDetails, KubernetesClustersSupplier } from '../types/types'; import type { Request } from 'express'; import { IncomingHttpHeaders } from 'http'; +import { HttpAuthService } from '@backstage/backend-plugin-api'; export const APPLICATION_JSON: string = 'application/json'; @@ -81,6 +82,7 @@ export type KubernetesProxyOptions = { logger: Logger; clusterSupplier: KubernetesClustersSupplier; authStrategy: AuthenticationStrategy; + httpAuth: HttpAuthService; }; /** @@ -93,11 +95,13 @@ export class KubernetesProxy { private readonly logger: Logger; private readonly clusterSupplier: KubernetesClustersSupplier; private readonly authStrategy: AuthenticationStrategy; + private readonly httpAuth: HttpAuthService; constructor(options: KubernetesProxyOptions) { this.logger = options.logger; this.clusterSupplier = options.clusterSupplier; this.authStrategy = options.authStrategy; + this.httpAuth = options.httpAuth; } public createRequestHandler( @@ -108,6 +112,7 @@ export class KubernetesProxy { const authorizeResponse = await permissionApi.authorize( [{ permission: kubernetesProxyPermission }], { + // todo: this should be updated too. token: getBearerTokenFromAuthorizationHeader( req.header('authorization'), ), @@ -220,7 +225,9 @@ export class KubernetesProxy { private async getClusterForRequest(req: Request): Promise { const clusterName = req.headers[HEADER_KUBERNETES_CLUSTER.toLowerCase()]; - const clusters = await this.clusterSupplier.getClusters(); + const clusters = await this.clusterSupplier.getClusters({ + credentials: await this.httpAuth.credentials(req), + }); if (!clusters || clusters.length <= 0) { throw new NotFoundError(`No Clusters configured`); diff --git a/plugins/kubernetes-node/src/types/types.ts b/plugins/kubernetes-node/src/types/types.ts index b89811ae99..dd23907e25 100644 --- a/plugins/kubernetes-node/src/types/types.ts +++ b/plugins/kubernetes-node/src/types/types.ts @@ -32,9 +32,15 @@ import { JsonObject } from '@backstage/types'; export interface KubernetesObjectsProvider { getKubernetesObjectsByEntity( kubernetesObjectsByEntity: KubernetesObjectsByEntity, + options: { + credentials: BackstageCredentials; + }, ): Promise; getCustomResourcesByEntity( customResourcesByEntity: CustomResourcesByEntity, + options: { + credentials: BackstageCredentials; + }, ): Promise; } @@ -135,7 +141,7 @@ export interface KubernetesClustersSupplier { * Implementations _should_ cache the clusters and refresh them periodically, * as getClusters is called whenever the list of clusters is needed. */ - getClusters(options?: { + getClusters(options: { credentials: BackstageCredentials; }): Promise; } @@ -248,6 +254,7 @@ export interface KubernetesFetcher { export interface ServiceLocatorRequestContext { objectTypesToFetch: Set; customResources: CustomResourceMatcher[]; + credentials: BackstageCredentials; } /**