@backstage/plugin-kubernetes-backend 0.21.7-next.0 → 0.21.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @backstage/plugin-kubernetes-backend
2
2
 
3
+ ## 0.21.7
4
+
5
+ ### Patch Changes
6
+
7
+ - 684c9b9: Fixed `AwsIamStrategy` to resolve account-specific AWS credentials when an assume role ARN is configured, enabling support for `webIdentityTokenFile` and `accountDefaults` in environments without default AWS credentials.
8
+ - c6af8ac: Added audit logging for kubernetes-backend routes. The plugin now emits auditor events for cluster list, cluster proxy, entity workload queries, custom resource queries, and the deprecated services endpoint. Administrators can filter audit logs by `eventId` values `cluster-fetch` and `resource-fetch`, and by `queryType` in event metadata.
9
+
10
+ `KubernetesProxyOptions` accepts an optional `auditor` for adopters that construct the proxy directly. When omitted, proxy requests are handled as before without audit events.
11
+
12
+ - bac00a5: The Kubernetes API proxy now refreshes cached middleware when cluster details change, after a configurable TTL, or when the cache reaches its size limit. At startup, the backend logs a warning for each cluster configured with `skipTLSVerify: true`. Invalid cache configuration values fall back to defaults. Optional configuration is available under `kubernetes.proxy.middlewareCache`.
13
+ - f0834bd: Added a `kubernetes.clusterLocatorContinueOnError` configuration option. When set to `true`, a failing cluster locator no longer causes the entire cluster list request to fail — errors are logged and clusters from the remaining successful locators are still returned. The default is `false`, preserving the existing behavior.
14
+ - Updated dependencies
15
+ - @backstage/catalog-model@1.10.0
16
+ - @backstage/backend-plugin-api@1.10.0
17
+ - @backstage/integration-aws-node@0.2.1
18
+ - @backstage/plugin-permission-common@0.9.10
19
+ - @backstage/plugin-permission-node@0.11.3
20
+ - @backstage/plugin-catalog-node@2.2.4
21
+ - @backstage/plugin-kubernetes-node@0.4.7
22
+
23
+ ## 0.22.0-next.1
24
+
25
+ ### Minor Changes
26
+
27
+ - c6af8ac: Added audit logging for kubernetes-backend routes. The plugin now emits auditor events for cluster list, cluster proxy, entity workload queries, custom resource queries, and the deprecated services endpoint. Administrators can filter audit logs by `eventId` values `cluster-fetch` and `resource-fetch`, and by `queryType` in event metadata.
28
+
29
+ **BREAKING**: `KubernetesProxyOptions` now requires `AuditorService`.
30
+
3
31
  ## 0.21.7-next.0
4
32
 
5
33
  ### Patch Changes
@@ -289,6 +289,30 @@
289
289
  }
290
290
  },
291
291
  "description": "(Optional) API Version Overrides If set, the specified api version will be used to make requests for the corresponding object. If running a legacy Kubernetes version, you may use this to override the default api versions that are not supported in your cluster."
292
+ },
293
+ "proxy": {
294
+ "type": "object",
295
+ "properties": {
296
+ "middlewareCache": {
297
+ "type": "object",
298
+ "properties": {
299
+ "maxSize": {
300
+ "type": "number",
301
+ "description": "Maximum number of cached middleware instances. Defaults to 100."
302
+ },
303
+ "ttl": {
304
+ "type": "object",
305
+ "properties": {
306
+ "milliseconds": {
307
+ "type": "number",
308
+ "description": "Time-to-live for cached middleware in milliseconds. Defaults to 60000."
309
+ }
310
+ }
311
+ }
312
+ }
313
+ }
314
+ },
315
+ "description": "Options for the Kubernetes API proxy middleware cache."
292
316
  }
293
317
  },
294
318
  "required": [
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
2
- import { LoggerService, DiscoveryService, HttpAuthService, PermissionsService } from '@backstage/backend-plugin-api';
2
+ import { LoggerService, DiscoveryService, HttpAuthService, AuditorService, PermissionsService } from '@backstage/backend-plugin-api';
3
3
  import * as k8sTypes from '@backstage/plugin-kubernetes-node';
4
4
  import { AuthenticationStrategy, ClusterDetails, KubernetesCredential, AuthMetadata, ObjectToFetch, KubernetesClustersSupplier } from '@backstage/plugin-kubernetes-node';
5
5
  import { KubernetesRequestAuth, KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';
@@ -222,6 +222,11 @@ type KubernetesProxyOptions = {
222
222
  authStrategy: AuthenticationStrategy;
223
223
  discovery: DiscoveryService;
224
224
  httpAuth: HttpAuthService;
225
+ auditor?: AuditorService;
226
+ middlewareCache?: {
227
+ ttlMs?: number;
228
+ maxSize?: number;
229
+ };
225
230
  };
226
231
  /**
227
232
  * A proxy that routes requests to the Kubernetes API.
@@ -229,14 +234,35 @@ type KubernetesProxyOptions = {
229
234
  * @public
230
235
  */
231
236
  declare class KubernetesProxy {
232
- private readonly middlewareForClusterName;
237
+ private readonly middlewareCache;
233
238
  private readonly logger;
234
239
  private readonly clusterSupplier;
235
240
  private readonly authStrategy;
236
241
  private readonly httpAuth;
242
+ private readonly auditor?;
237
243
  constructor(options: KubernetesProxyOptions);
238
244
  createRequestHandler(options: KubernetesProxyCreateRequestHandlerOptions): RequestHandler;
239
- private getMiddleware;
245
+ /**
246
+ * Authorizes the request, resolves the target cluster, and dispatches
247
+ * to either the HTTP or WebSocket proxy path. Returns `true` when
248
+ * HTTP finish listeners have been attached.
249
+ */
250
+ private authorizeAndDispatch;
251
+ /**
252
+ * Resolves the cluster, credentials, and target URL for a proxy request
253
+ * before dispatching to the middleware. This ensures all async preparation
254
+ * completes under the caller's try/catch, avoiding unhandled rejections
255
+ * from http-proxy-middleware's fire-and-forget upgrade() path.
256
+ */
257
+ private prepareProxyTarget;
258
+ private getOrCreateMiddleware;
259
+ /**
260
+ * Branches to WebSocket upgrade or HTTP middleware dispatch and wires
261
+ * up the appropriate audit listeners. Returns `true` when HTTP finish
262
+ * listeners have been attached (used by the caller's catch block to
263
+ * avoid double-finalizing).
264
+ */
265
+ private static dispatchToProxy;
240
266
  private getClusterForRequest;
241
267
  private static authHeadersToKubernetesRequestAuth;
242
268
  private static headerToDictionary;
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var version = "0.21.7-next.0";
5
+ var version = "0.21.7";
6
6
  var packageinfo = {
7
7
  version: version};
8
8
 
@@ -146,7 +146,8 @@ const kubernetesPlugin = backendPluginApi.createBackendPlugin({
146
146
  catalog: pluginCatalogNode.catalogServiceRef,
147
147
  permissions: backendPluginApi.coreServices.permissions,
148
148
  auth: backendPluginApi.coreServices.auth,
149
- httpAuth: backendPluginApi.coreServices.httpAuth
149
+ httpAuth: backendPluginApi.coreServices.httpAuth,
150
+ auditor: backendPluginApi.coreServices.auditor
150
151
  },
151
152
  async init({
152
153
  http,
@@ -156,7 +157,8 @@ const kubernetesPlugin = backendPluginApi.createBackendPlugin({
156
157
  catalog,
157
158
  permissions,
158
159
  auth,
159
- httpAuth
160
+ httpAuth,
161
+ auditor
160
162
  }) {
161
163
  if (config.has("kubernetes")) {
162
164
  const initializer = KubernetesInitializer.KubernetesInitializer.create({
@@ -185,6 +187,7 @@ const kubernetesPlugin = backendPluginApi.createBackendPlugin({
185
187
  discovery,
186
188
  auth,
187
189
  httpAuth,
190
+ auditor,
188
191
  authStrategyMap: Object.fromEntries(authStrategyMap.entries()),
189
192
  fetcher,
190
193
  clusterSupplier,
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node';\n\nimport {\n type AuthenticationStrategy,\n kubernetesAuthStrategyExtensionPoint,\n type KubernetesAuthStrategyExtensionPoint,\n type KubernetesClustersSupplier,\n kubernetesClusterSupplierExtensionPoint,\n type KubernetesClusterSupplierExtensionPoint,\n KubernetesClusterSupplierFactory,\n type KubernetesFetcher,\n kubernetesFetcherExtensionPoint,\n type KubernetesFetcherExtensionPoint,\n KubernetesFetcherFactory,\n type KubernetesObjectsProvider,\n kubernetesObjectsProviderExtensionPoint,\n type KubernetesObjectsProviderExtensionPoint,\n KubernetesObjectsProviderFactory,\n KubernetesRouterExtensionPoint,\n kubernetesRouterExtensionPoint,\n KubernetesRouterFactory,\n type KubernetesServiceLocator,\n kubernetesServiceLocatorExtensionPoint,\n type KubernetesServiceLocatorExtensionPoint,\n KubernetesServiceLocatorFactory,\n} from '@backstage/plugin-kubernetes-node';\nimport { KubernetesRouter } from './service/KubernetesRouter';\nimport { KubernetesInitializer } from './service/KubernetesInitializer';\n\nclass ObjectsProvider implements KubernetesObjectsProviderExtensionPoint {\n private objectsProvider: KubernetesObjectsProviderFactory | undefined;\n\n getObjectsProvider() {\n return this.objectsProvider;\n }\n\n addObjectsProvider(\n provider: KubernetesObjectsProvider | KubernetesObjectsProviderFactory,\n ) {\n if (this.objectsProvider) {\n throw new Error(\n 'Multiple Kubernetes objects provider is not supported at this time',\n );\n }\n if (typeof provider !== 'function') {\n this.objectsProvider = async () => provider;\n } else {\n this.objectsProvider = provider;\n }\n }\n}\n\nclass ClusterSuplier implements KubernetesClusterSupplierExtensionPoint {\n private clusterSupplier: KubernetesClusterSupplierFactory | undefined;\n\n getClusterSupplier() {\n return this.clusterSupplier;\n }\n\n addClusterSupplier(\n clusterSupplier:\n | KubernetesClustersSupplier\n | KubernetesClusterSupplierFactory,\n ) {\n if (this.clusterSupplier) {\n throw new Error(\n 'Multiple Kubernetes Cluster Suppliers is not supported at this time',\n );\n }\n if (typeof clusterSupplier !== 'function') {\n this.clusterSupplier = async () => clusterSupplier;\n } else {\n this.clusterSupplier = clusterSupplier;\n }\n }\n}\n\nclass Fetcher implements KubernetesFetcherExtensionPoint {\n private fetcher: KubernetesFetcherFactory | undefined;\n\n getFetcher() {\n return this.fetcher;\n }\n\n addFetcher(fetcher: KubernetesFetcher | KubernetesFetcherFactory) {\n if (this.fetcher) {\n throw new Error(\n 'Multiple Kubernetes Fetchers is not supported at this time',\n );\n }\n if (typeof fetcher !== 'function') {\n this.fetcher = async () => fetcher;\n } else {\n this.fetcher = fetcher;\n }\n }\n}\n\nclass ServiceLocator implements KubernetesServiceLocatorExtensionPoint {\n private serviceLocator: KubernetesServiceLocatorFactory | undefined;\n\n getServiceLocator() {\n return this.serviceLocator;\n }\n\n addServiceLocator(\n serviceLocator: KubernetesServiceLocator | KubernetesServiceLocatorFactory,\n ) {\n if (this.serviceLocator) {\n throw new Error(\n 'Multiple Kubernetes Service Locators is not supported at this time',\n );\n }\n\n if (typeof serviceLocator !== 'function') {\n this.serviceLocator = async () => serviceLocator;\n } else {\n this.serviceLocator = serviceLocator;\n }\n }\n}\n\nclass AuthStrategy implements KubernetesAuthStrategyExtensionPoint {\n private authStrategies: Map<string, AuthenticationStrategy> | undefined;\n\n getAuthenticationStrategies() {\n return this.authStrategies;\n }\n\n addAuthStrategy(key: string, authStrategy: AuthenticationStrategy) {\n if (!this.authStrategies) {\n this.authStrategies = new Map<string, AuthenticationStrategy>();\n }\n\n if (key.includes('-')) {\n throw new Error('Strategy name can not include dashes');\n }\n\n this.authStrategies.set(key, authStrategy);\n }\n}\n\nclass CustomRouter implements KubernetesRouterExtensionPoint {\n private router: KubernetesRouterFactory | undefined;\n\n getRouter() {\n return this.router;\n }\n\n addRouter(router: KubernetesRouterFactory) {\n if (this.router) {\n throw new Error(\n 'Multiple Kubernetes routers is not supported at this time',\n );\n }\n\n this.router = router;\n }\n}\n\n/**\n * This is the backend plugin that provides the Kubernetes integration.\n * @public\n */\nexport const kubernetesPlugin = createBackendPlugin({\n pluginId: 'kubernetes',\n register(env) {\n const extPointObjectsProvider = new ObjectsProvider();\n const extPointClusterSuplier = new ClusterSuplier();\n const extPointAuthStrategy = new AuthStrategy();\n const extPointFetcher = new Fetcher();\n const extPointServiceLocator = new ServiceLocator();\n const extPointRouter = new CustomRouter();\n\n env.registerExtensionPoint(\n kubernetesObjectsProviderExtensionPoint,\n extPointObjectsProvider,\n );\n env.registerExtensionPoint(\n kubernetesClusterSupplierExtensionPoint,\n extPointClusterSuplier,\n );\n env.registerExtensionPoint(\n kubernetesAuthStrategyExtensionPoint,\n extPointAuthStrategy,\n );\n env.registerExtensionPoint(\n kubernetesFetcherExtensionPoint,\n extPointFetcher,\n );\n env.registerExtensionPoint(\n kubernetesServiceLocatorExtensionPoint,\n extPointServiceLocator,\n );\n env.registerExtensionPoint(kubernetesRouterExtensionPoint, extPointRouter);\n\n env.registerInit({\n deps: {\n http: coreServices.httpRouter,\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n discovery: coreServices.discovery,\n catalog: catalogServiceRef,\n permissions: coreServices.permissions,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n },\n async init({\n http,\n logger,\n config,\n discovery,\n catalog,\n permissions,\n auth,\n httpAuth,\n }) {\n // TODO: this could do with a cleanup and push some of this initialization somewhere else\n if (config.has('kubernetes')) {\n const initializer = KubernetesInitializer.create({\n logger,\n config,\n catalog,\n auth,\n fetcher: extPointFetcher.getFetcher(),\n clusterSupplier: extPointClusterSuplier.getClusterSupplier(),\n serviceLocator: extPointServiceLocator.getServiceLocator(),\n objectsProvider: extPointObjectsProvider.getObjectsProvider(),\n authStrategyMap: extPointAuthStrategy.getAuthenticationStrategies(),\n });\n\n const {\n fetcher,\n authStrategyMap,\n clusterSupplier,\n serviceLocator,\n objectsProvider,\n } = await initializer.init();\n\n const router = KubernetesRouter.create({\n logger,\n config,\n catalog,\n permissions,\n discovery,\n auth,\n httpAuth,\n authStrategyMap: Object.fromEntries(authStrategyMap.entries()),\n fetcher,\n clusterSupplier,\n serviceLocator,\n objectsProvider,\n customRouter: extPointRouter.getRouter(),\n });\n\n http.use(await router.getRouter());\n } else {\n logger.warn(\n 'Failed to initialize kubernetes backend: valid kubernetes config is missing',\n );\n }\n },\n });\n },\n});\n"],"names":["createBackendPlugin","kubernetesObjectsProviderExtensionPoint","kubernetesClusterSupplierExtensionPoint","kubernetesAuthStrategyExtensionPoint","kubernetesFetcherExtensionPoint","kubernetesServiceLocatorExtensionPoint","kubernetesRouterExtensionPoint","coreServices","catalogServiceRef","KubernetesInitializer","KubernetesRouter"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node';\n\nimport {\n type AuthenticationStrategy,\n kubernetesAuthStrategyExtensionPoint,\n type KubernetesAuthStrategyExtensionPoint,\n type KubernetesClustersSupplier,\n kubernetesClusterSupplierExtensionPoint,\n type KubernetesClusterSupplierExtensionPoint,\n KubernetesClusterSupplierFactory,\n type KubernetesFetcher,\n kubernetesFetcherExtensionPoint,\n type KubernetesFetcherExtensionPoint,\n KubernetesFetcherFactory,\n type KubernetesObjectsProvider,\n kubernetesObjectsProviderExtensionPoint,\n type KubernetesObjectsProviderExtensionPoint,\n KubernetesObjectsProviderFactory,\n KubernetesRouterExtensionPoint,\n kubernetesRouterExtensionPoint,\n KubernetesRouterFactory,\n type KubernetesServiceLocator,\n kubernetesServiceLocatorExtensionPoint,\n type KubernetesServiceLocatorExtensionPoint,\n KubernetesServiceLocatorFactory,\n} from '@backstage/plugin-kubernetes-node';\nimport { KubernetesRouter } from './service/KubernetesRouter';\nimport { KubernetesInitializer } from './service/KubernetesInitializer';\n\nclass ObjectsProvider implements KubernetesObjectsProviderExtensionPoint {\n private objectsProvider: KubernetesObjectsProviderFactory | undefined;\n\n getObjectsProvider() {\n return this.objectsProvider;\n }\n\n addObjectsProvider(\n provider: KubernetesObjectsProvider | KubernetesObjectsProviderFactory,\n ) {\n if (this.objectsProvider) {\n throw new Error(\n 'Multiple Kubernetes objects provider is not supported at this time',\n );\n }\n if (typeof provider !== 'function') {\n this.objectsProvider = async () => provider;\n } else {\n this.objectsProvider = provider;\n }\n }\n}\n\nclass ClusterSuplier implements KubernetesClusterSupplierExtensionPoint {\n private clusterSupplier: KubernetesClusterSupplierFactory | undefined;\n\n getClusterSupplier() {\n return this.clusterSupplier;\n }\n\n addClusterSupplier(\n clusterSupplier:\n | KubernetesClustersSupplier\n | KubernetesClusterSupplierFactory,\n ) {\n if (this.clusterSupplier) {\n throw new Error(\n 'Multiple Kubernetes Cluster Suppliers is not supported at this time',\n );\n }\n if (typeof clusterSupplier !== 'function') {\n this.clusterSupplier = async () => clusterSupplier;\n } else {\n this.clusterSupplier = clusterSupplier;\n }\n }\n}\n\nclass Fetcher implements KubernetesFetcherExtensionPoint {\n private fetcher: KubernetesFetcherFactory | undefined;\n\n getFetcher() {\n return this.fetcher;\n }\n\n addFetcher(fetcher: KubernetesFetcher | KubernetesFetcherFactory) {\n if (this.fetcher) {\n throw new Error(\n 'Multiple Kubernetes Fetchers is not supported at this time',\n );\n }\n if (typeof fetcher !== 'function') {\n this.fetcher = async () => fetcher;\n } else {\n this.fetcher = fetcher;\n }\n }\n}\n\nclass ServiceLocator implements KubernetesServiceLocatorExtensionPoint {\n private serviceLocator: KubernetesServiceLocatorFactory | undefined;\n\n getServiceLocator() {\n return this.serviceLocator;\n }\n\n addServiceLocator(\n serviceLocator: KubernetesServiceLocator | KubernetesServiceLocatorFactory,\n ) {\n if (this.serviceLocator) {\n throw new Error(\n 'Multiple Kubernetes Service Locators is not supported at this time',\n );\n }\n\n if (typeof serviceLocator !== 'function') {\n this.serviceLocator = async () => serviceLocator;\n } else {\n this.serviceLocator = serviceLocator;\n }\n }\n}\n\nclass AuthStrategy implements KubernetesAuthStrategyExtensionPoint {\n private authStrategies: Map<string, AuthenticationStrategy> | undefined;\n\n getAuthenticationStrategies() {\n return this.authStrategies;\n }\n\n addAuthStrategy(key: string, authStrategy: AuthenticationStrategy) {\n if (!this.authStrategies) {\n this.authStrategies = new Map<string, AuthenticationStrategy>();\n }\n\n if (key.includes('-')) {\n throw new Error('Strategy name can not include dashes');\n }\n\n this.authStrategies.set(key, authStrategy);\n }\n}\n\nclass CustomRouter implements KubernetesRouterExtensionPoint {\n private router: KubernetesRouterFactory | undefined;\n\n getRouter() {\n return this.router;\n }\n\n addRouter(router: KubernetesRouterFactory) {\n if (this.router) {\n throw new Error(\n 'Multiple Kubernetes routers is not supported at this time',\n );\n }\n\n this.router = router;\n }\n}\n\n/**\n * This is the backend plugin that provides the Kubernetes integration.\n * @public\n */\nexport const kubernetesPlugin = createBackendPlugin({\n pluginId: 'kubernetes',\n register(env) {\n const extPointObjectsProvider = new ObjectsProvider();\n const extPointClusterSuplier = new ClusterSuplier();\n const extPointAuthStrategy = new AuthStrategy();\n const extPointFetcher = new Fetcher();\n const extPointServiceLocator = new ServiceLocator();\n const extPointRouter = new CustomRouter();\n\n env.registerExtensionPoint(\n kubernetesObjectsProviderExtensionPoint,\n extPointObjectsProvider,\n );\n env.registerExtensionPoint(\n kubernetesClusterSupplierExtensionPoint,\n extPointClusterSuplier,\n );\n env.registerExtensionPoint(\n kubernetesAuthStrategyExtensionPoint,\n extPointAuthStrategy,\n );\n env.registerExtensionPoint(\n kubernetesFetcherExtensionPoint,\n extPointFetcher,\n );\n env.registerExtensionPoint(\n kubernetesServiceLocatorExtensionPoint,\n extPointServiceLocator,\n );\n env.registerExtensionPoint(kubernetesRouterExtensionPoint, extPointRouter);\n\n env.registerInit({\n deps: {\n http: coreServices.httpRouter,\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n discovery: coreServices.discovery,\n catalog: catalogServiceRef,\n permissions: coreServices.permissions,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n auditor: coreServices.auditor,\n },\n async init({\n http,\n logger,\n config,\n discovery,\n catalog,\n permissions,\n auth,\n httpAuth,\n auditor,\n }) {\n // TODO: this could do with a cleanup and push some of this initialization somewhere else\n if (config.has('kubernetes')) {\n const initializer = KubernetesInitializer.create({\n logger,\n config,\n catalog,\n auth,\n fetcher: extPointFetcher.getFetcher(),\n clusterSupplier: extPointClusterSuplier.getClusterSupplier(),\n serviceLocator: extPointServiceLocator.getServiceLocator(),\n objectsProvider: extPointObjectsProvider.getObjectsProvider(),\n authStrategyMap: extPointAuthStrategy.getAuthenticationStrategies(),\n });\n\n const {\n fetcher,\n authStrategyMap,\n clusterSupplier,\n serviceLocator,\n objectsProvider,\n } = await initializer.init();\n\n const router = KubernetesRouter.create({\n logger,\n config,\n catalog,\n permissions,\n discovery,\n auth,\n httpAuth,\n auditor,\n authStrategyMap: Object.fromEntries(authStrategyMap.entries()),\n fetcher,\n clusterSupplier,\n serviceLocator,\n objectsProvider,\n customRouter: extPointRouter.getRouter(),\n });\n\n http.use(await router.getRouter());\n } else {\n logger.warn(\n 'Failed to initialize kubernetes backend: valid kubernetes config is missing',\n );\n }\n },\n });\n },\n});\n"],"names":["createBackendPlugin","kubernetesObjectsProviderExtensionPoint","kubernetesClusterSupplierExtensionPoint","kubernetesAuthStrategyExtensionPoint","kubernetesFetcherExtensionPoint","kubernetesServiceLocatorExtensionPoint","kubernetesRouterExtensionPoint","coreServices","catalogServiceRef","KubernetesInitializer","KubernetesRouter"],"mappings":"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"}
@@ -5,9 +5,9 @@ var errors = require('@backstage/errors');
5
5
  var requirePermission = require('../auth/requirePermission.cjs.js');
6
6
  var pluginKubernetesCommon = require('@backstage/plugin-kubernetes-common');
7
7
 
8
- const addResourceRoutesToRouter = (router, catalog, objectsProvider, httpAuth, permissionApi) => {
8
+ const addResourceRoutesToRouter = (router, catalog, objectsProvider, httpAuth, permissionApi, auditor, logger) => {
9
9
  const getEntityByReq = async (req) => {
10
- const rawEntityRef = req.body.entityRef;
10
+ const rawEntityRef = req.body?.entityRef;
11
11
  if (rawEntityRef && typeof rawEntityRef !== "string") {
12
12
  throw new errors.InputError(`entity query must be a string`);
13
13
  } else if (!rawEntityRef) {
@@ -30,46 +30,82 @@ const addResourceRoutesToRouter = (router, catalog, objectsProvider, httpAuth, p
30
30
  return entity;
31
31
  };
32
32
  router.post("/resources/workloads/query", async (req, res) => {
33
- await requirePermission.requirePermission(
34
- permissionApi,
35
- pluginKubernetesCommon.kubernetesResourcesReadPermission,
36
- httpAuth,
37
- req
38
- );
39
- const entity = await getEntityByReq(req);
40
- const response = await objectsProvider.getKubernetesObjectsByEntity(
41
- {
42
- entity,
43
- auth: req.body.auth
44
- },
45
- { credentials: await httpAuth.credentials(req) }
46
- );
47
- res.json(response);
33
+ const entityRef = typeof req.body?.entityRef === "string" ? req.body.entityRef : void 0;
34
+ const auditorEvent = await auditor.createEvent({
35
+ eventId: "resource-fetch",
36
+ request: req,
37
+ meta: { queryType: "workloads", entityRef }
38
+ });
39
+ try {
40
+ await requirePermission.requirePermission(
41
+ permissionApi,
42
+ pluginKubernetesCommon.kubernetesResourcesReadPermission,
43
+ httpAuth,
44
+ req
45
+ );
46
+ const entity = await getEntityByReq(req);
47
+ const response = await objectsProvider.getKubernetesObjectsByEntity(
48
+ {
49
+ entity,
50
+ auth: req.body.auth
51
+ },
52
+ { credentials: await httpAuth.credentials(req) }
53
+ );
54
+ res.json(response);
55
+ auditorEvent.success().catch(
56
+ (error) => logger.error(
57
+ "Failed to emit audit event resource-fetch (workloads)",
58
+ error
59
+ )
60
+ );
61
+ } catch (error) {
62
+ const err = error instanceof Error ? error : new Error(String(error));
63
+ await auditorEvent.fail({ error: err });
64
+ throw error;
65
+ }
48
66
  });
49
67
  router.post("/resources/custom/query", async (req, res) => {
50
- await requirePermission.requirePermission(
51
- permissionApi,
52
- pluginKubernetesCommon.kubernetesResourcesReadPermission,
53
- httpAuth,
54
- req
55
- );
56
- const entity = await getEntityByReq(req);
57
- if (!req.body.customResources) {
58
- throw new errors.InputError("customResources is a required field");
59
- } else if (!Array.isArray(req.body.customResources)) {
60
- throw new errors.InputError("customResources must be an array");
61
- } else if (req.body.customResources.length === 0) {
62
- throw new errors.InputError("at least 1 customResource is required");
68
+ const entityRef = typeof req.body?.entityRef === "string" ? req.body.entityRef : void 0;
69
+ const auditorEvent = await auditor.createEvent({
70
+ eventId: "resource-fetch",
71
+ request: req,
72
+ meta: { queryType: "custom", entityRef }
73
+ });
74
+ try {
75
+ await requirePermission.requirePermission(
76
+ permissionApi,
77
+ pluginKubernetesCommon.kubernetesResourcesReadPermission,
78
+ httpAuth,
79
+ req
80
+ );
81
+ const entity = await getEntityByReq(req);
82
+ if (!req.body.customResources) {
83
+ throw new errors.InputError("customResources is a required field");
84
+ } else if (!Array.isArray(req.body.customResources)) {
85
+ throw new errors.InputError("customResources must be an array");
86
+ } else if (req.body.customResources.length === 0) {
87
+ throw new errors.InputError("at least 1 customResource is required");
88
+ }
89
+ const response = await objectsProvider.getCustomResourcesByEntity(
90
+ {
91
+ entity,
92
+ customResources: req.body.customResources,
93
+ auth: req.body.auth
94
+ },
95
+ { credentials: await httpAuth.credentials(req) }
96
+ );
97
+ res.json(response);
98
+ auditorEvent.success().catch(
99
+ (error) => logger.error(
100
+ "Failed to emit audit event resource-fetch (custom)",
101
+ error
102
+ )
103
+ );
104
+ } catch (error) {
105
+ const err = error instanceof Error ? error : new Error(String(error));
106
+ await auditorEvent.fail({ error: err });
107
+ throw error;
63
108
  }
64
- const response = await objectsProvider.getCustomResourcesByEntity(
65
- {
66
- entity,
67
- customResources: req.body.customResources,
68
- auth: req.body.auth
69
- },
70
- { credentials: await httpAuth.credentials(req) }
71
- );
72
- res.json(response);
73
109
  });
74
110
  };
75
111
 
@@ -1 +1 @@
1
- {"version":3,"file":"resourcesRoutes.cjs.js","sources":["../../src/routes/resourcesRoutes.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n CompoundEntityRef,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { InputError } from '@backstage/errors';\nimport express, { Request } from 'express';\nimport { KubernetesObjectsProvider } from '@backstage/plugin-kubernetes-node';\nimport { HttpAuthService } from '@backstage/backend-plugin-api';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport { requirePermission } from '../auth/requirePermission';\nimport { kubernetesResourcesReadPermission } from '@backstage/plugin-kubernetes-common';\nimport { CatalogService } from '@backstage/plugin-catalog-node';\n\nexport const addResourceRoutesToRouter = (\n router: express.Router,\n catalog: CatalogService,\n objectsProvider: KubernetesObjectsProvider,\n httpAuth: HttpAuthService,\n permissionApi: PermissionEvaluator,\n) => {\n const getEntityByReq = async (req: Request<any>) => {\n const rawEntityRef = req.body.entityRef;\n if (rawEntityRef && typeof rawEntityRef !== 'string') {\n throw new InputError(`entity query must be a string`);\n } else if (!rawEntityRef) {\n throw new InputError('entity is a required field');\n }\n let entityRef: CompoundEntityRef | undefined = undefined;\n\n try {\n entityRef = parseEntityRef(rawEntityRef);\n } catch (error) {\n throw new InputError(`Invalid entity ref, ${error}`);\n }\n\n const entity = await catalog.getEntityByRef(entityRef, {\n credentials: await httpAuth.credentials(req),\n });\n if (!entity) {\n throw new InputError(\n `Entity ref missing, ${stringifyEntityRef(entityRef)}`,\n );\n }\n\n return entity;\n };\n\n router.post('/resources/workloads/query', async (req, res) => {\n await requirePermission(\n permissionApi,\n kubernetesResourcesReadPermission,\n httpAuth,\n req,\n );\n const entity = await getEntityByReq(req);\n const response = await objectsProvider.getKubernetesObjectsByEntity(\n {\n entity,\n auth: req.body.auth,\n },\n { credentials: await httpAuth.credentials(req) },\n );\n res.json(response);\n });\n\n router.post('/resources/custom/query', async (req, res) => {\n await requirePermission(\n permissionApi,\n kubernetesResourcesReadPermission,\n httpAuth,\n req,\n );\n const entity = await getEntityByReq(req);\n\n if (!req.body.customResources) {\n throw new InputError('customResources is a required field');\n } else if (!Array.isArray(req.body.customResources)) {\n throw new InputError('customResources must be an array');\n } else if (req.body.customResources.length === 0) {\n throw new InputError('at least 1 customResource is required');\n }\n\n const response = await objectsProvider.getCustomResourcesByEntity(\n {\n entity,\n customResources: req.body.customResources,\n auth: req.body.auth,\n },\n { credentials: await httpAuth.credentials(req) },\n );\n res.json(response);\n });\n};\n"],"names":["InputError","parseEntityRef","stringifyEntityRef","requirePermission","kubernetesResourcesReadPermission"],"mappings":"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"}
1
+ {"version":3,"file":"resourcesRoutes.cjs.js","sources":["../../src/routes/resourcesRoutes.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n CompoundEntityRef,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { InputError } from '@backstage/errors';\nimport express, { Request } from 'express';\nimport { KubernetesObjectsProvider } from '@backstage/plugin-kubernetes-node';\nimport {\n AuditorService,\n HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport { requirePermission } from '../auth/requirePermission';\nimport { kubernetesResourcesReadPermission } from '@backstage/plugin-kubernetes-common';\nimport { CatalogService } from '@backstage/plugin-catalog-node';\n\nexport const addResourceRoutesToRouter = (\n router: express.Router,\n catalog: CatalogService,\n objectsProvider: KubernetesObjectsProvider,\n httpAuth: HttpAuthService,\n permissionApi: PermissionEvaluator,\n auditor: AuditorService,\n logger: LoggerService,\n) => {\n const getEntityByReq = async (req: Request<any>) => {\n const rawEntityRef = req.body?.entityRef;\n if (rawEntityRef && typeof rawEntityRef !== 'string') {\n throw new InputError(`entity query must be a string`);\n } else if (!rawEntityRef) {\n throw new InputError('entity is a required field');\n }\n let entityRef: CompoundEntityRef | undefined = undefined;\n\n try {\n entityRef = parseEntityRef(rawEntityRef);\n } catch (error) {\n throw new InputError(`Invalid entity ref, ${error}`);\n }\n\n const entity = await catalog.getEntityByRef(entityRef, {\n credentials: await httpAuth.credentials(req),\n });\n if (!entity) {\n throw new InputError(\n `Entity ref missing, ${stringifyEntityRef(entityRef)}`,\n );\n }\n\n return entity;\n };\n\n router.post('/resources/workloads/query', async (req, res) => {\n const entityRef =\n typeof req.body?.entityRef === 'string' ? req.body.entityRef : undefined;\n\n const auditorEvent = await auditor.createEvent({\n eventId: 'resource-fetch',\n request: req,\n meta: { queryType: 'workloads', entityRef },\n });\n\n try {\n await requirePermission(\n permissionApi,\n kubernetesResourcesReadPermission,\n httpAuth,\n req,\n );\n const entity = await getEntityByReq(req);\n const response = await objectsProvider.getKubernetesObjectsByEntity(\n {\n entity,\n auth: req.body.auth,\n },\n { credentials: await httpAuth.credentials(req) },\n );\n res.json(response);\n auditorEvent\n .success()\n .catch(error =>\n logger.error(\n 'Failed to emit audit event resource-fetch (workloads)',\n error,\n ),\n );\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n await auditorEvent.fail({ error: err });\n throw error;\n }\n });\n\n router.post('/resources/custom/query', async (req, res) => {\n const entityRef =\n typeof req.body?.entityRef === 'string' ? req.body.entityRef : undefined;\n\n const auditorEvent = await auditor.createEvent({\n eventId: 'resource-fetch',\n request: req,\n meta: { queryType: 'custom', entityRef },\n });\n\n try {\n await requirePermission(\n permissionApi,\n kubernetesResourcesReadPermission,\n httpAuth,\n req,\n );\n const entity = await getEntityByReq(req);\n\n if (!req.body.customResources) {\n throw new InputError('customResources is a required field');\n } else if (!Array.isArray(req.body.customResources)) {\n throw new InputError('customResources must be an array');\n } else if (req.body.customResources.length === 0) {\n throw new InputError('at least 1 customResource is required');\n }\n\n const response = await objectsProvider.getCustomResourcesByEntity(\n {\n entity,\n customResources: req.body.customResources,\n auth: req.body.auth,\n },\n { credentials: await httpAuth.credentials(req) },\n );\n res.json(response);\n auditorEvent\n .success()\n .catch(error =>\n logger.error(\n 'Failed to emit audit event resource-fetch (custom)',\n error,\n ),\n );\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n await auditorEvent.fail({ error: err });\n throw error;\n }\n });\n};\n"],"names":["InputError","parseEntityRef","stringifyEntityRef","requirePermission","kubernetesResourcesReadPermission"],"mappings":"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"}