Merge pull request #11328 from dbravovmw/kubernetes-oidc-auth
Add generic OIDC as a Kubernetes auth provider
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
'@backstage/plugin-kubernetes-backend': patch
|
||||
'@backstage/plugin-kubernetes-common': patch
|
||||
---
|
||||
|
||||
Add support for 'oidc' as authProvider for kubernetes authentication
|
||||
and adds optional 'oidcTokenProvider' config value. This will allow
|
||||
users to authenticate to kubernetes cluster using id tokens obtained
|
||||
from the configured auth provider in their backstage instance.
|
||||
@@ -85,13 +85,14 @@ array. Users will see this value in the Software Catalog Kubernetes plugin.
|
||||
This determines how the Kubernetes client authenticates with the Kubernetes
|
||||
cluster. Valid values are:
|
||||
|
||||
| Value | Description |
|
||||
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `serviceAccount` | This will use a Kubernetes [service account](https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/) to access the Kubernetes API. When this is used the `serviceAccountToken` field should also be set. |
|
||||
| `google` | This will use a user's Google auth token from the [Google auth plugin](https://backstage.io/docs/auth/) to access the Kubernetes API. |
|
||||
| `aws` | This will use AWS credentials to access resources in EKS clusters |
|
||||
| `googleServiceAccount` | This will use the Google Cloud service account credentials to access resources in clusters |
|
||||
| `azure` | This will use [Azure Identity](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) to access resources in clusters |
|
||||
| Value | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `serviceAccount` | This will use a Kubernetes [service account](https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/) to access the Kubernetes API. When this is used the `serviceAccountToken` field should also be set. |
|
||||
| `google` | This will use a user's Google auth token from the [Google auth plugin](https://backstage.io/docs/auth/) to access the Kubernetes API. |
|
||||
| `aws` | This will use AWS credentials to access resources in EKS clusters |
|
||||
| `googleServiceAccount` | This will use the Google Cloud service account credentials to access resources in clusters |
|
||||
| `azure` | This will use [Azure Identity](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) to access resources in clusters |
|
||||
| `oidc` | This will use [Oidc Tokens](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens) to authenticate to the Kubernetes API. When this is used the `oidcTokenProvider` field should also be set. |
|
||||
|
||||
##### `clusters.\*.skipTLSVerify`
|
||||
|
||||
@@ -115,6 +116,33 @@ kubectl -n <NAMESPACE> get secret $(kubectl -n <NAMESPACE> get sa <SERVICE_ACCOU
|
||||
| base64 --decode
|
||||
```
|
||||
|
||||
##### `clusters.\*.oidcTokenProvider` (optional)
|
||||
|
||||
This field is to be used when using the `oidc` auth provider. It will use the id tokens
|
||||
from a configured [backstage auth provider](https://backstage.io/docs/auth/) to
|
||||
authenticate to the cluster. The selected `oidcTokenProvider` needs to be properly
|
||||
configured under `auth` for this to work.
|
||||
|
||||
```yaml
|
||||
kubernetes:
|
||||
clusterLocatorMethods:
|
||||
- type: 'config'
|
||||
clusters:
|
||||
- name: test-cluster
|
||||
url: http://localhost:8080
|
||||
authProvider: oidc
|
||||
oidcTokenProvider: okta # This value needs to match a config under auth.providers
|
||||
auth:
|
||||
providers:
|
||||
okta:
|
||||
development:
|
||||
clientId: ${AUTH_OKTA_CLIENT_ID}
|
||||
clientSecret: ${AUTH_OKTA_CLIENT_SECRET}
|
||||
audience: ${AUTH_OKTA_AUDIENCE}
|
||||
```
|
||||
|
||||
The following values are supported out-of-the-box by the frontend: `google`, `microsoft`, `okta`, `onelogin`.
|
||||
|
||||
##### `clusters.\*.dashboardUrl` (optional)
|
||||
|
||||
Specifies the link to the Kubernetes dashboard managing this cluster.
|
||||
|
||||
@@ -41,6 +41,7 @@ export interface ClusterDetails {
|
||||
dashboardParameters?: JsonObject;
|
||||
dashboardUrl?: string;
|
||||
name: string;
|
||||
oidcTokenProvider?: string | undefined;
|
||||
// (undocumented)
|
||||
serviceAccountToken?: string | undefined;
|
||||
skipMetricsLookup?: boolean;
|
||||
|
||||
+8
-1
@@ -52,7 +52,14 @@ export interface Config {
|
||||
/** @visibility secret */
|
||||
serviceAccountToken?: string;
|
||||
/** @visibility frontend */
|
||||
authProvider: 'aws' | 'google' | 'serviceAccount' | 'azure';
|
||||
authProvider:
|
||||
| 'aws'
|
||||
| 'google'
|
||||
| 'serviceAccount'
|
||||
| 'azure'
|
||||
| 'oidc';
|
||||
/** @visibility frontend */
|
||||
oidcTokenProvider?: string;
|
||||
/** @visibility frontend */
|
||||
skipTLSVerify?: boolean;
|
||||
}>;
|
||||
|
||||
@@ -64,6 +64,11 @@ export class ConfigClusterLocator implements KubernetesClustersSupplier {
|
||||
case 'azure': {
|
||||
return clusterDetails;
|
||||
}
|
||||
case 'oidc': {
|
||||
const oidcTokenProvider = c.getString('oidcTokenProvider');
|
||||
|
||||
return { oidcTokenProvider, ...clusterDetails };
|
||||
}
|
||||
case 'serviceAccount': {
|
||||
return clusterDetails;
|
||||
}
|
||||
|
||||
+7
@@ -19,6 +19,7 @@ import { GoogleKubernetesAuthTranslator } from './GoogleKubernetesAuthTranslator
|
||||
import { KubernetesAuthTranslatorGenerator } from './KubernetesAuthTranslatorGenerator';
|
||||
import { ServiceAccountKubernetesAuthTranslator } from './ServiceAccountKubernetesAuthTranslator';
|
||||
import { AwsIamKubernetesAuthTranslator } from './AwsIamKubernetesAuthTranslator';
|
||||
import { OidcKubernetesAuthTranslator } from './OidcKubernetesAuthTranslator';
|
||||
|
||||
describe('getKubernetesAuthTranslatorInstance', () => {
|
||||
const sut = KubernetesAuthTranslatorGenerator;
|
||||
@@ -43,6 +44,12 @@ describe('getKubernetesAuthTranslatorInstance', () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('can return an auth translator for oidc auth', () => {
|
||||
const authTranslator: KubernetesAuthTranslator =
|
||||
sut.getKubernetesAuthTranslatorInstance('oidc');
|
||||
expect(authTranslator instanceof OidcKubernetesAuthTranslator).toBe(true);
|
||||
});
|
||||
|
||||
it('throws an error when asked for an auth translator for an unsupported auth type', () => {
|
||||
expect(() => sut.getKubernetesAuthTranslatorInstance('linode')).toThrow(
|
||||
'authProvider "linode" has no KubernetesAuthTranslator associated with it',
|
||||
|
||||
+4
@@ -20,6 +20,7 @@ import { ServiceAccountKubernetesAuthTranslator } from './ServiceAccountKubernet
|
||||
import { AwsIamKubernetesAuthTranslator } from './AwsIamKubernetesAuthTranslator';
|
||||
import { GoogleServiceAccountAuthTranslator } from './GoogleServiceAccountAuthProvider';
|
||||
import { AzureIdentityKubernetesAuthTranslator } from './AzureIdentityKubernetesAuthTranslator';
|
||||
import { OidcKubernetesAuthTranslator } from './OidcKubernetesAuthTranslator';
|
||||
|
||||
export class KubernetesAuthTranslatorGenerator {
|
||||
static getKubernetesAuthTranslatorInstance(
|
||||
@@ -41,6 +42,9 @@ export class KubernetesAuthTranslatorGenerator {
|
||||
case 'googleServiceAccount': {
|
||||
return new GoogleServiceAccountAuthTranslator();
|
||||
}
|
||||
case 'oidc': {
|
||||
return new OidcKubernetesAuthTranslator();
|
||||
}
|
||||
default: {
|
||||
throw new Error(
|
||||
`authProvider "${authProvider}" has no KubernetesAuthTranslator associated with it`,
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { OidcKubernetesAuthTranslator } from './OidcKubernetesAuthTranslator';
|
||||
import { ClusterDetails } from '../types/types';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
describe('OidcKubernetesAuthTranslator tests', () => {
|
||||
const at = new OidcKubernetesAuthTranslator();
|
||||
const entity: Entity = {
|
||||
apiVersion: 'v1',
|
||||
kind: 'service',
|
||||
metadata: { name: 'test' },
|
||||
};
|
||||
const baseClusterDetails: ClusterDetails = {
|
||||
name: 'test',
|
||||
authProvider: 'oidc',
|
||||
url: '',
|
||||
};
|
||||
|
||||
it('returns cluster details with auth token', async () => {
|
||||
const details = await at.decorateClusterDetailsWithAuth(
|
||||
{
|
||||
oidcTokenProvider: 'okta',
|
||||
...baseClusterDetails,
|
||||
},
|
||||
{
|
||||
auth: {
|
||||
oidc: { okta: 'fakeToken' },
|
||||
},
|
||||
entity,
|
||||
},
|
||||
);
|
||||
|
||||
expect(details.serviceAccountToken).toBe('fakeToken');
|
||||
});
|
||||
|
||||
it('returns error when oidcTokenProvider is not configured', async () => {
|
||||
await expect(
|
||||
at.decorateClusterDetailsWithAuth(baseClusterDetails, { entity }),
|
||||
).rejects.toThrow(
|
||||
'oidc authProvider requires a configured oidcTokenProvider',
|
||||
);
|
||||
});
|
||||
|
||||
it('returns error when token is not included in request body', async () => {
|
||||
await expect(
|
||||
at.decorateClusterDetailsWithAuth(
|
||||
{ oidcTokenProvider: 'okta', ...baseClusterDetails },
|
||||
{ entity },
|
||||
),
|
||||
).rejects.toThrow('Auth token not found under oidc.okta in request body');
|
||||
});
|
||||
});
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { KubernetesAuthTranslator } from './types';
|
||||
import { ClusterDetails } from '../types/types';
|
||||
import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';
|
||||
|
||||
export class OidcKubernetesAuthTranslator implements KubernetesAuthTranslator {
|
||||
async decorateClusterDetailsWithAuth(
|
||||
clusterDetails: ClusterDetails,
|
||||
requestBody: KubernetesRequestBody,
|
||||
): Promise<ClusterDetails> {
|
||||
const clusterDetailsWithAuthToken: ClusterDetails = Object.assign(
|
||||
{},
|
||||
clusterDetails,
|
||||
);
|
||||
|
||||
const { oidcTokenProvider } = clusterDetails;
|
||||
|
||||
if (!oidcTokenProvider || oidcTokenProvider === '') {
|
||||
throw new Error(
|
||||
`oidc authProvider requires a configured oidcTokenProvider`,
|
||||
);
|
||||
}
|
||||
|
||||
const authToken: string | undefined =
|
||||
requestBody.auth?.oidc?.[oidcTokenProvider];
|
||||
|
||||
if (authToken) {
|
||||
clusterDetailsWithAuthToken.serviceAccountToken = authToken;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Auth token not found under oidc.${oidcTokenProvider} in request body`,
|
||||
);
|
||||
}
|
||||
return clusterDetailsWithAuthToken;
|
||||
}
|
||||
}
|
||||
@@ -246,6 +246,7 @@ export class KubernetesBuilder {
|
||||
name: cd.name,
|
||||
dashboardUrl: cd.dashboardUrl,
|
||||
authProvider: cd.authProvider,
|
||||
oidcTokenProvider: cd.oidcTokenProvider,
|
||||
})),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -105,6 +105,10 @@ export interface ClusterDetails {
|
||||
url: string;
|
||||
authProvider: string;
|
||||
serviceAccountToken?: string | undefined;
|
||||
/**
|
||||
* oidc provider used to get id tokens to authenticate against kubernetes
|
||||
*/
|
||||
oidcTokenProvider?: string | undefined;
|
||||
skipTLSVerify?: boolean;
|
||||
/**
|
||||
* Whether to skip the lookup to the metrics server to retrieve pod resource usage.
|
||||
|
||||
@@ -195,6 +195,9 @@ export interface KubernetesRequestBody {
|
||||
// (undocumented)
|
||||
auth?: {
|
||||
google?: string;
|
||||
oidc?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
};
|
||||
// (undocumented)
|
||||
entity: Entity;
|
||||
|
||||
@@ -31,6 +31,9 @@ import { Entity } from '@backstage/catalog-model';
|
||||
export interface KubernetesRequestBody {
|
||||
auth?: {
|
||||
google?: string;
|
||||
oidc?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
};
|
||||
entity: Entity;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import type { JsonObject } from '@backstage/types';
|
||||
import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';
|
||||
import { OAuthApi } from '@backstage/core-plugin-api';
|
||||
import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common';
|
||||
import { OpenIdConnectApi } from '@backstage/core-plugin-api';
|
||||
import { default as React_2 } from 'react';
|
||||
import { RouteRef } from '@backstage/core-plugin-api';
|
||||
import { V1ConfigMap } from '@kubernetes/client-node';
|
||||
@@ -225,6 +226,7 @@ export interface KubernetesApi {
|
||||
{
|
||||
name: string;
|
||||
authProvider: string;
|
||||
oidcTokenProvider?: string | undefined;
|
||||
}[]
|
||||
>;
|
||||
// (undocumented)
|
||||
@@ -242,7 +244,12 @@ export const kubernetesApiRef: ApiRef<KubernetesApi>;
|
||||
//
|
||||
// @public (undocumented)
|
||||
export class KubernetesAuthProviders implements KubernetesAuthProvidersApi {
|
||||
constructor(options: { googleAuthApi: OAuthApi });
|
||||
constructor(options: {
|
||||
googleAuthApi: OAuthApi;
|
||||
oidcProviders?: {
|
||||
[key: string]: OpenIdConnectApi;
|
||||
};
|
||||
});
|
||||
// (undocumented)
|
||||
decorateRequestBodyForAuth(
|
||||
authProvider: string,
|
||||
|
||||
@@ -28,5 +28,11 @@ export interface KubernetesApi {
|
||||
getObjectsByEntity(
|
||||
requestBody: KubernetesRequestBody,
|
||||
): Promise<ObjectsByEntityResponse>;
|
||||
getClusters(): Promise<{ name: string; authProvider: string }[]>;
|
||||
getClusters(): Promise<
|
||||
{
|
||||
name: string;
|
||||
authProvider: string;
|
||||
oidcTokenProvider?: string | undefined;
|
||||
}[]
|
||||
>;
|
||||
}
|
||||
|
||||
@@ -53,8 +53,16 @@ export const useKubernetesObjects = (
|
||||
}
|
||||
|
||||
const authProviders: string[] = [
|
||||
...new Set(clusters.map(c => c.authProvider)),
|
||||
...new Set(
|
||||
clusters.map(
|
||||
c =>
|
||||
`${c.authProvider}${
|
||||
c.oidcTokenProvider ? `.${c.oidcTokenProvider}` : ''
|
||||
}`,
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
// For each auth type, invoke decorateRequestBodyForAuth on corresponding KubernetesAuthProvider
|
||||
let requestBody: KubernetesRequestBody = {
|
||||
entity,
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { OAuthApi, OpenIdConnectApi } from '@backstage/core-plugin-api';
|
||||
import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';
|
||||
import { KubernetesAuthProviders } from './KubernetesAuthProviders';
|
||||
|
||||
class MockAuthApi implements OAuthApi, OpenIdConnectApi {
|
||||
constructor(private readonly token: string) {}
|
||||
|
||||
getAccessToken = jest.fn(async () => {
|
||||
return this.token;
|
||||
});
|
||||
|
||||
getIdToken = jest.fn(async () => {
|
||||
return this.token;
|
||||
});
|
||||
}
|
||||
|
||||
const requestBody: KubernetesRequestBody = {
|
||||
entity: {
|
||||
apiVersion: 'v1',
|
||||
kind: 'service',
|
||||
metadata: { name: 'test' },
|
||||
},
|
||||
};
|
||||
|
||||
describe('KubernetesAuthProviders tests', () => {
|
||||
const kap = new KubernetesAuthProviders({
|
||||
googleAuthApi: new MockAuthApi('googleToken'),
|
||||
oidcProviders: {
|
||||
okta: new MockAuthApi('oktaToken'),
|
||||
},
|
||||
});
|
||||
|
||||
it('adds token to request body for google authProvider', async () => {
|
||||
const details = await kap.decorateRequestBodyForAuth('google', requestBody);
|
||||
|
||||
expect(details.auth?.google).toBe('googleToken');
|
||||
});
|
||||
|
||||
it('adds token to request body for oidc authProvider', async () => {
|
||||
const details = await kap.decorateRequestBodyForAuth(
|
||||
'oidc.okta',
|
||||
requestBody,
|
||||
);
|
||||
|
||||
expect(details.auth?.oidc?.okta).toBe('oktaToken');
|
||||
});
|
||||
|
||||
it('returns error for unknown authProvider', async () => {
|
||||
await expect(
|
||||
kap.decorateRequestBodyForAuth('unknown', requestBody),
|
||||
).rejects.toThrow(
|
||||
'authProvider "unknown" has no KubernetesAuthProvider defined for it',
|
||||
);
|
||||
});
|
||||
|
||||
it('returns error for missconfigured oidc authProvider', async () => {
|
||||
await expect(
|
||||
kap.decorateRequestBodyForAuth('oidc.random', requestBody),
|
||||
).rejects.toThrow(
|
||||
'KubernetesAuthProviders has no oidcProvider configured for oidc.random',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -19,9 +19,10 @@ import { KubernetesAuthProvider, KubernetesAuthProvidersApi } from './types';
|
||||
import { GoogleKubernetesAuthProvider } from './GoogleKubernetesAuthProvider';
|
||||
import { ServiceAccountKubernetesAuthProvider } from './ServiceAccountKubernetesAuthProvider';
|
||||
import { AwsKubernetesAuthProvider } from './AwsKubernetesAuthProvider';
|
||||
import { OAuthApi } from '@backstage/core-plugin-api';
|
||||
import { OAuthApi, OpenIdConnectApi } from '@backstage/core-plugin-api';
|
||||
import { GoogleServiceAccountAuthProvider } from './GoogleServiceAccountAuthProvider';
|
||||
import { AzureKubernetesAuthProvider } from './AzureKubernetesAuthProvider';
|
||||
import { OidcKubernetesAuthProvider } from './OidcKubernetesAuthProvider';
|
||||
|
||||
export class KubernetesAuthProviders implements KubernetesAuthProvidersApi {
|
||||
private readonly kubernetesAuthProviderMap: Map<
|
||||
@@ -29,7 +30,10 @@ export class KubernetesAuthProviders implements KubernetesAuthProvidersApi {
|
||||
KubernetesAuthProvider
|
||||
>;
|
||||
|
||||
constructor(options: { googleAuthApi: OAuthApi }) {
|
||||
constructor(options: {
|
||||
googleAuthApi: OAuthApi;
|
||||
oidcProviders?: { [key: string]: OpenIdConnectApi };
|
||||
}) {
|
||||
this.kubernetesAuthProviderMap = new Map<string, KubernetesAuthProvider>();
|
||||
this.kubernetesAuthProviderMap.set(
|
||||
'google',
|
||||
@@ -48,6 +52,18 @@ export class KubernetesAuthProviders implements KubernetesAuthProvidersApi {
|
||||
'azure',
|
||||
new AzureKubernetesAuthProvider(),
|
||||
);
|
||||
|
||||
if (options.oidcProviders) {
|
||||
Object.keys(options.oidcProviders).forEach(provider => {
|
||||
this.kubernetesAuthProviderMap.set(
|
||||
`oidc.${provider}`,
|
||||
new OidcKubernetesAuthProvider(
|
||||
provider,
|
||||
options.oidcProviders![provider],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async decorateRequestBodyForAuth(
|
||||
@@ -61,6 +77,12 @@ export class KubernetesAuthProviders implements KubernetesAuthProvidersApi {
|
||||
requestBody,
|
||||
);
|
||||
}
|
||||
|
||||
if (authProvider.startsWith('oidc.')) {
|
||||
throw new Error(
|
||||
`KubernetesAuthProviders has no oidcProvider configured for ${authProvider}`,
|
||||
);
|
||||
}
|
||||
throw new Error(
|
||||
`authProvider "${authProvider}" has no KubernetesAuthProvider defined for it`,
|
||||
);
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { KubernetesAuthProvider } from './types';
|
||||
import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common';
|
||||
import { OpenIdConnectApi } from '@backstage/core-plugin-api';
|
||||
|
||||
export class OidcKubernetesAuthProvider implements KubernetesAuthProvider {
|
||||
providerName: string;
|
||||
authProvider: OpenIdConnectApi;
|
||||
|
||||
constructor(providerName: string, authProvider: OpenIdConnectApi) {
|
||||
this.providerName = providerName;
|
||||
this.authProvider = authProvider;
|
||||
}
|
||||
|
||||
async decorateRequestBodyForAuth(
|
||||
requestBody: KubernetesRequestBody,
|
||||
): Promise<KubernetesRequestBody> {
|
||||
const authToken: string = await this.authProvider.getIdToken();
|
||||
const auth = { ...requestBody.auth };
|
||||
if (auth.oidc) {
|
||||
auth.oidc[this.providerName] = authToken;
|
||||
} else {
|
||||
auth.oidc = { [this.providerName]: authToken };
|
||||
}
|
||||
requestBody.auth = auth;
|
||||
return requestBody;
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,9 @@ import {
|
||||
discoveryApiRef,
|
||||
identityApiRef,
|
||||
googleAuthApiRef,
|
||||
microsoftAuthApiRef,
|
||||
oktaAuthApiRef,
|
||||
oneloginAuthApiRef,
|
||||
createRoutableExtension,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
@@ -45,9 +48,26 @@ export const kubernetesPlugin = createPlugin({
|
||||
}),
|
||||
createApiFactory({
|
||||
api: kubernetesAuthProvidersApiRef,
|
||||
deps: { googleAuthApi: googleAuthApiRef },
|
||||
factory: ({ googleAuthApi }) => {
|
||||
return new KubernetesAuthProviders({ googleAuthApi });
|
||||
deps: {
|
||||
googleAuthApi: googleAuthApiRef,
|
||||
microsoftAuthApi: microsoftAuthApiRef,
|
||||
oktaAuthApi: oktaAuthApiRef,
|
||||
oneloginAuthApi: oneloginAuthApiRef,
|
||||
},
|
||||
factory: ({
|
||||
googleAuthApi,
|
||||
microsoftAuthApi,
|
||||
oktaAuthApi,
|
||||
oneloginAuthApi,
|
||||
}) => {
|
||||
const oidcProviders = {
|
||||
google: googleAuthApi,
|
||||
microsoft: microsoftAuthApi,
|
||||
okta: oktaAuthApi,
|
||||
onelogin: oneloginAuthApi,
|
||||
};
|
||||
|
||||
return new KubernetesAuthProviders({ googleAuthApi, oidcProviders });
|
||||
},
|
||||
}),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user