From a53d06afe5b9cee29037538d342c187f144d0c9b Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Mon, 30 Jan 2023 09:11:36 -0500 Subject: [PATCH 1/3] Document the proxy endpoint Signed-off-by: Jamie Klassen --- .changeset/tidy-kings-cough.md | 5 ++ docs/features/kubernetes/proxy.md | 90 +++++++++++++++++++ microsite/sidebars.json | 3 +- plugins/kubernetes-backend/api-report.md | 2 +- .../src/service/KubernetesProxy.ts | 2 +- 5 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 .changeset/tidy-kings-cough.md create mode 100644 docs/features/kubernetes/proxy.md diff --git a/.changeset/tidy-kings-cough.md b/.changeset/tidy-kings-cough.md new file mode 100644 index 0000000000..e908572c8b --- /dev/null +++ b/.changeset/tidy-kings-cough.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +--- + +The name of the header used to specify a cluster to the proxy endpoint is now visible in the API reference. diff --git a/docs/features/kubernetes/proxy.md b/docs/features/kubernetes/proxy.md new file mode 100644 index 0000000000..a98cdfd16b --- /dev/null +++ b/docs/features/kubernetes/proxy.md @@ -0,0 +1,90 @@ +--- +id: proxy +title: Kubernetes Backend Proxy Endpoint +sidebar_label: Proxy +description: Interacting with the Kubernetes API in Backstage plugins +--- + +[Contributors](../../overview/glossary#backstage-user-profiles) wanting to +create developer portal experiences based on data from Kubernetes (e.g. for +interacting with [Custom +Resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) +beyond the default behaviors of the existing Kubernetes plugin) can leverage the +Kubernetes backend plugin's proxy endpoint to allow them to make arbitrary +requests to the [REST +API](https://kubernetes.io/docs/reference/using-api/api-concepts/). + +Here is a snippet fetching namespaces from a cluster configured with the +`google` [auth provider](./configuration#clustersauthprovider): + +```typescript +import { + discoveryApiRef, + googleAuthApiRef, + useApi, +} from '@backstage/core-plugin-api'; + +const CLUSTER_NAME = ''; // use a known cluster name + +// get a bearer token from Google +const googleAuthApi = useApi(googleAuthApiRef); +const token = await googleAuthApi.getAccessToken( + 'https://www.googleapis.com/auth/cloud-platform', +); + +const discoveryApi = useApi(discoveryApiRef); +const kubernetesBaseUrl = await discoveryApi.getBaseUrl('kubernetes'); +const kubernetesProxyEndpoint = `${kubernetesBaseUrl}/proxy`; + +// fetch namespaces +await fetch(`${kubernetesProxyEndpoint}/api/v1/namespaces`, { + method: 'GET', + headers: { + 'X-Kubernetes-Cluster': CLUSTER_NAME, + Authorization: `Bearer ${token}`, + }, +}); +``` + +## How it works + +The proxy will interpret the +[`X-Kubernetes-Cluster` +header](../../reference/plugin-kubernetes-backend.header_kubernetes_cluster) +as the name of the cluster to target. This name will be compared to each cluster +returned by all the configured [cluster +locators](./kubernetes/configuration#clusterlocatormethods) +-- the first cluster whose [`name` field](./configuration#clustersname) matches +the value in the header will be targeted. + +Then the request will be forwarded verbatim (but with the endpoint's base URL +prefix stripped) to the cluster. + +## Authentication + +Until some security and permission decisions are made (see [this +conversation](https://github.com/backstage/backstage/pull/13026/files#r1029376939) +for context), contributors consuming the proxy endpoint in their plugin code are +responsible for negotiating their own bearer token out-of-band. This requires +knowing some auth details about the cluster being contacted -- in practice, only +clusters with [client side auth +providers](./authentication#client-side-providers) can reasonably be reached. + +The proxy has no provisions for mTLS, so it cannot be used to connect to +clusters using the [x509 Client +Certs](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) +authentication strategy. [Bearer +tokens](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#putting-a-bearer-token-in-a-request) +will be forwarded as-is. + +## Other known limitations + +The proxy as it was released in [Backstage +1.9](https://github.com/backstage/backstage/blob/master/docs/releases/v1.9.0-changelog.md#patch-changes-15) +has a few known bugs: + +- [#15901](https://github.com/backstage/backstage/issues/15901) - it cannot + reliably target clusters who share the same name with another located cluster. +- [#16018](https://github.com/backstage/backstage/issues/16018) - it does not + forward request bodies, making it incapable of supporting `POST`, `PUT` or + `PATCH` verbs in practice. diff --git a/microsite/sidebars.json b/microsite/sidebars.json index f051d3c70b..6baeb20e8b 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -87,7 +87,8 @@ "features/kubernetes/installation", "features/kubernetes/configuration", "features/kubernetes/authentication", - "features/kubernetes/troubleshooting" + "features/kubernetes/troubleshooting", + "features/kubernetes/proxy" ] }, { diff --git a/plugins/kubernetes-backend/api-report.md b/plugins/kubernetes-backend/api-report.md index 4ec043a8f9..006f980c56 100644 --- a/plugins/kubernetes-backend/api-report.md +++ b/plugins/kubernetes-backend/api-report.md @@ -141,7 +141,7 @@ export class GoogleServiceAccountAuthTranslator ): Promise; } -// @alpha +// @public export const HEADER_KUBERNETES_CLUSTER: string; // @alpha (undocumented) diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts index 9d88d2ab84..cb36c647ac 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts @@ -32,7 +32,7 @@ export const APPLICATION_JSON: string = 'application/json'; /** * The header that is used to specify the cluster name. * - * @alpha + * @public */ export const HEADER_KUBERNETES_CLUSTER: string = 'X-Kubernetes-Cluster'; From 05c26fd47567978174633a145d645ac24eac2ac6 Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Mon, 30 Jan 2023 10:19:50 -0500 Subject: [PATCH 2/3] remove relative links Otherwise, `scripts/verify-links.js` will fail. Signed-off-by: Jamie Klassen --- docs/features/kubernetes/proxy.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/features/kubernetes/proxy.md b/docs/features/kubernetes/proxy.md index a98cdfd16b..859bcb0b3c 100644 --- a/docs/features/kubernetes/proxy.md +++ b/docs/features/kubernetes/proxy.md @@ -5,7 +5,7 @@ sidebar_label: Proxy description: Interacting with the Kubernetes API in Backstage plugins --- -[Contributors](../../overview/glossary#backstage-user-profiles) wanting to +[Contributors](https://backstage.io/docs/overview/glossary#backstage-user-profiles) wanting to create developer portal experiences based on data from Kubernetes (e.g. for interacting with [Custom Resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) @@ -15,7 +15,7 @@ requests to the [REST API](https://kubernetes.io/docs/reference/using-api/api-concepts/). Here is a snippet fetching namespaces from a cluster configured with the -`google` [auth provider](./configuration#clustersauthprovider): +`google` [auth provider](https://backstage.io/docs/features/kubernetes/configuration#clustersauthprovider): ```typescript import { @@ -50,11 +50,11 @@ await fetch(`${kubernetesProxyEndpoint}/api/v1/namespaces`, { The proxy will interpret the [`X-Kubernetes-Cluster` -header](../../reference/plugin-kubernetes-backend.header_kubernetes_cluster) +header](https://backstage.io/docs/reference/plugin-kubernetes-backend.header_kubernetes_cluster) as the name of the cluster to target. This name will be compared to each cluster returned by all the configured [cluster -locators](./kubernetes/configuration#clusterlocatormethods) --- the first cluster whose [`name` field](./configuration#clustersname) matches +locators](https://backstage.io/docs/features/kubernetes/configuration#clusterlocatormethods) +-- the first cluster whose [`name` field](https://backstage.io/docs/features/kubernetes/configuration#clustersname) matches the value in the header will be targeted. Then the request will be forwarded verbatim (but with the endpoint's base URL @@ -68,7 +68,7 @@ for context), contributors consuming the proxy endpoint in their plugin code are responsible for negotiating their own bearer token out-of-band. This requires knowing some auth details about the cluster being contacted -- in practice, only clusters with [client side auth -providers](./authentication#client-side-providers) can reasonably be reached. +providers](https://backstage.io/docs/features/kubernetes/authentication#client-side-providers) can reasonably be reached. The proxy has no provisions for mTLS, so it cannot be used to connect to clusters using the [x509 Client From 7126b48d6a1e2022ea225a59ae1cc126f1868925 Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Wed, 8 Feb 2023 13:31:49 -0500 Subject: [PATCH 3/3] update known issues since #16018 was fixed Signed-off-by: Jamie Klassen --- docs/features/kubernetes/proxy.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/features/kubernetes/proxy.md b/docs/features/kubernetes/proxy.md index 859bcb0b3c..5848d62e3e 100644 --- a/docs/features/kubernetes/proxy.md +++ b/docs/features/kubernetes/proxy.md @@ -81,10 +81,7 @@ will be forwarded as-is. The proxy as it was released in [Backstage 1.9](https://github.com/backstage/backstage/blob/master/docs/releases/v1.9.0-changelog.md#patch-changes-15) -has a few known bugs: +has a known bug: - [#15901](https://github.com/backstage/backstage/issues/15901) - it cannot reliably target clusters who share the same name with another located cluster. -- [#16018](https://github.com/backstage/backstage/issues/16018) - it does not - forward request bodies, making it incapable of supporting `POST`, `PUT` or - `PATCH` verbs in practice.