use annotation key authProvider in metadata

This allows the nice simplification of the catalog clusterLocator -- just read
the entire annotations block as auth metadata.

Signed-off-by: Jamie Klassen <jklassen@vmware.com>
This commit is contained in:
Jamie Klassen
2023-09-07 10:39:08 -04:00
parent efc0d893cd
commit 279adfc6fd
9 changed files with 71 additions and 49 deletions
@@ -14,9 +14,12 @@
* limitations under the License.
*/
import {
ANNOTATION_KUBERNETES_AUTH_PROVIDER,
KubernetesRequestAuth,
} from '@backstage/plugin-kubernetes-common';
import { DispatchStrategy } from './DispatchStrategy';
import { ClusterDetails } from '../types';
import { KubernetesRequestAuth } from '@backstage/plugin-kubernetes-common';
import { AuthenticationStrategy } from './types';
describe('decorateClusterDetailsWithAuth', () => {
@@ -39,7 +42,7 @@ describe('decorateClusterDetailsWithAuth', () => {
url: 'notanything.com',
name: 'randomName',
authMetadata: {
authProvider: 'google',
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google',
serviceAccountToken: 'added by mock strategy',
},
};
@@ -52,7 +55,7 @@ describe('decorateClusterDetailsWithAuth', () => {
{
name: 'googleCluster',
url: 'anything.com',
authMetadata: { authProvider: 'google' },
authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google' },
},
authObject,
);
@@ -61,7 +64,7 @@ describe('decorateClusterDetailsWithAuth', () => {
{
name: 'googleCluster',
url: 'anything.com',
authMetadata: { authProvider: 'google' },
authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google' },
},
authObject,
);
@@ -74,7 +77,7 @@ describe('decorateClusterDetailsWithAuth', () => {
{
name: 'test-cluster',
url: 'anything.com',
authMetadata: { authProvider: 'linode' },
authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'linode' },
},
authObject,
),
@@ -16,7 +16,10 @@
import { AuthenticationStrategy } from './types';
import { AuthMetadata, ClusterDetails } from '../types';
import { KubernetesRequestAuth } from '@backstage/plugin-kubernetes-common';
import {
ANNOTATION_KUBERNETES_AUTH_PROVIDER,
KubernetesRequestAuth,
} from '@backstage/plugin-kubernetes-common';
/**
*
@@ -42,7 +45,8 @@ export class DispatchStrategy implements AuthenticationStrategy {
clusterDetails: ClusterDetails,
auth: KubernetesRequestAuth,
) {
const authProvider = clusterDetails.authMetadata.authProvider;
const authProvider =
clusterDetails.authMetadata[ANNOTATION_KUBERNETES_AUTH_PROVIDER];
if (this.strategyMap[authProvider]) {
return this.strategyMap[authProvider].decorateClusterDetailsWithAuth(
clusterDetails,
@@ -55,10 +59,11 @@ export class DispatchStrategy implements AuthenticationStrategy {
}
public validate(authMetadata: AuthMetadata) {
const strategy = this.strategyMap[authMetadata.authProvider];
const authProvider = authMetadata[ANNOTATION_KUBERNETES_AUTH_PROVIDER];
const strategy = this.strategyMap[authProvider];
if (!strategy) {
throw new Error(
`authProvider "${authMetadata.authProvider}" has no config associated with it`,
`authProvider "${authProvider}" has no config associated with it`,
);
}
strategy.validate(authMetadata);
@@ -16,6 +16,7 @@
import '@backstage/backend-common';
import {
ANNOTATION_KUBERNETES_AUTH_PROVIDER,
ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE,
ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID,
ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER,
@@ -35,7 +36,7 @@ const mockCatalogApi = {
annotations: {
'kubernetes.io/api-server': 'https://apiserver.com',
'kubernetes.io/api-server-certificate-authority': 'caData',
'kubernetes.io/auth-provider': 'oidc',
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'oidc',
[ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER]: 'google',
'kubernetes.io/skip-metrics-lookup': 'true',
'kubernetes.io/skip-tls-verify': 'true',
@@ -53,7 +54,7 @@ const mockCatalogApi = {
annotations: {
'kubernetes.io/api-server': 'https://apiserver.com',
'kubernetes.io/api-server-certificate-authority': 'caData',
'kubernetes.io/auth-provider': 'aws',
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'aws',
[ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE]: 'my-role',
[ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID]: 'my-id',
[ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER]: 'google',
@@ -97,10 +98,9 @@ describe('CatalogClusterLocator', () => {
url: 'https://apiserver.com',
caData: 'caData',
authMetadata: {
authProvider: 'oidc',
'kubernetes.io/api-server': 'https://apiserver.com',
'kubernetes.io/api-server-certificate-authority': 'caData',
'kubernetes.io/auth-provider': 'oidc',
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'oidc',
[ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER]: 'google',
'kubernetes.io/skip-metrics-lookup': 'true',
'kubernetes.io/skip-tls-verify': 'true',
@@ -125,10 +125,9 @@ describe('CatalogClusterLocator', () => {
url: 'https://apiserver.com',
caData: 'caData',
authMetadata: {
authProvider: 'aws',
'kubernetes.io/api-server': 'https://apiserver.com',
'kubernetes.io/api-server-certificate-authority': 'caData',
'kubernetes.io/auth-provider': 'aws',
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'aws',
[ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE]: 'my-role',
[ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID]: 'my-id',
[ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER]: 'google',
@@ -57,17 +57,9 @@ export class CatalogClusterLocator implements KubernetesClustersSupplier {
const clusterDetails: ClusterDetails = {
name: entity.metadata.name,
url: entity.metadata.annotations![ANNOTATION_KUBERNETES_API_SERVER]!,
authMetadata: entity.metadata.annotations!,
caData:
entity.metadata.annotations![ANNOTATION_KUBERNETES_API_SERVER_CA]!,
...{
authMetadata: {
authProvider:
entity.metadata.annotations![
ANNOTATION_KUBERNETES_AUTH_PROVIDER
]!,
...entity.metadata.annotations,
},
},
skipMetricsLookup:
entity.metadata.annotations![
ANNOTATION_KUBERNETES_SKIP_METRICS_LOOKUP
@@ -17,6 +17,7 @@
import '@backstage/backend-common';
import { ConfigReader, Config } from '@backstage/config';
import {
ANNOTATION_KUBERNETES_AUTH_PROVIDER,
ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE,
ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID,
} from '@backstage/plugin-kubernetes-common';
@@ -65,7 +66,9 @@ describe('ConfigClusterLocator', () => {
{
name: 'cluster1',
url: 'http://localhost:8080',
authMetadata: { authProvider: 'serviceAccount' },
authMetadata: {
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount',
},
skipMetricsLookup: false,
skipTLSVerify: false,
caData: undefined,
@@ -106,7 +109,7 @@ describe('ConfigClusterLocator', () => {
dashboardUrl: 'https://k8s.foo.com',
url: 'http://localhost:8080',
authMetadata: {
authProvider: 'serviceAccount',
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount',
serviceAccountToken: 'token',
},
skipTLSVerify: false,
@@ -117,7 +120,7 @@ describe('ConfigClusterLocator', () => {
{
name: 'cluster2',
url: 'http://localhost:8081',
authMetadata: { authProvider: 'google' },
authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google' },
skipTLSVerify: true,
skipMetricsLookup: false,
caData: undefined,
@@ -199,7 +202,9 @@ describe('ConfigClusterLocator', () => {
{
name: 'cluster1',
url: 'http://localhost:8080',
authMetadata: { authProvider: 'serviceAccount' },
authMetadata: {
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount',
},
skipMetricsLookup: false,
skipTLSVerify: false,
caData: undefined,
@@ -235,7 +240,9 @@ describe('ConfigClusterLocator', () => {
{
name: 'cluster1',
url: 'http://localhost:8080',
authMetadata: { authProvider: 'serviceAccount' },
authMetadata: {
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount',
},
skipMetricsLookup: false,
skipTLSVerify: false,
caData: undefined,
@@ -272,7 +279,9 @@ describe('ConfigClusterLocator', () => {
{
name: 'cluster1',
url: 'http://localhost:8080',
authMetadata: { authProvider: 'serviceAccount' },
authMetadata: {
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount',
},
skipMetricsLookup: false,
skipTLSVerify: false,
caData: undefined,
@@ -16,6 +16,7 @@
import { Config } from '@backstage/config';
import {
ANNOTATION_KUBERNETES_AUTH_PROVIDER,
ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE,
ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID,
ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER,
@@ -45,7 +46,7 @@ export class ConfigClusterLocator implements KubernetesClustersSupplier {
caData: c.getOptionalString('caData'),
caFile: c.getOptionalString('caFile'),
authMetadata: {
authProvider,
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: authProvider,
...ConfigClusterLocator.parseAuthMetadata(c),
},
};
@@ -15,8 +15,9 @@
*/
import { Config, ConfigReader } from '@backstage/config';
import { getCombinedClusterSupplier } from './index';
import { CatalogApi } from '@backstage/catalog-client';
import { ANNOTATION_KUBERNETES_AUTH_PROVIDER } from '@backstage/plugin-kubernetes-common';
import { getCombinedClusterSupplier } from './index';
import { ClusterDetails } from '../types/types';
import { AuthenticationStrategy, DispatchStrategy } from '../auth';
@@ -57,12 +58,7 @@ describe('getCombinedClusterSupplier', () => {
const clusterSupplier = getCombinedClusterSupplier(
config,
catalogApi,
new DispatchStrategy({
authStrategyMap: {
serviceAccount: mockStrategy,
google: mockStrategy,
},
}),
mockStrategy,
);
const result = await clusterSupplier.getClusters();
@@ -71,7 +67,7 @@ describe('getCombinedClusterSupplier', () => {
name: 'cluster1',
url: 'http://localhost:8080',
authMetadata: {
authProvider: 'serviceAccount',
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount',
serviceAccountToken: 'token',
},
skipMetricsLookup: false,
@@ -82,7 +78,7 @@ describe('getCombinedClusterSupplier', () => {
{
name: 'cluster2',
url: 'http://localhost:8081',
authMetadata: { authProvider: 'google' },
authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google' },
skipMetricsLookup: false,
skipTLSVerify: false,
caData: undefined,
@@ -17,7 +17,11 @@
import { getVoidLogger } from '@backstage/backend-common';
import { Entity } from '@backstage/catalog-model';
import { Config, ConfigReader } from '@backstage/config';
import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common';
import {
ANNOTATION_KUBERNETES_AUTH_PROVIDER,
ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER,
ObjectsByEntityResponse,
} from '@backstage/plugin-kubernetes-common';
import express from 'express';
import request from 'supertest';
import {
@@ -63,12 +67,17 @@ describe('KubernetesBuilder', () => {
{
name: 'some-cluster',
url: 'https://localhost:1234',
authMetadata: { authProvider: 'serviceAccount' },
authMetadata: {
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount',
},
},
{
name: 'some-other-cluster',
url: 'https://localhost:1235',
authMetadata: { authProvider: 'google' },
authMetadata: {
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'oidc',
[ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER]: 'google',
},
},
];
const clusterSupplier: KubernetesClustersSupplier = {
@@ -116,7 +125,8 @@ describe('KubernetesBuilder', () => {
},
{
name: 'some-other-cluster',
authProvider: 'google',
authProvider: 'oidc',
oidcTokenProvider: 'google',
},
],
});
@@ -190,14 +200,16 @@ describe('KubernetesBuilder', () => {
const someCluster: ClusterDetails = {
name: 'some-cluster',
url: 'https://localhost:1234',
authMetadata: { authProvider: 'serviceAccount' },
authMetadata: {
[ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount',
},
};
const clusters: ClusterDetails[] = [
someCluster,
{
name: 'some-other-cluster',
url: 'https://localhost:1235',
authMetadata: { authProvider: 'google' },
authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google' },
},
];
const clusterSupplier: KubernetesClustersSupplier = {
@@ -15,7 +15,11 @@
*/
import { CatalogApi } from '@backstage/catalog-client';
import { Config } from '@backstage/config';
import { kubernetesPermissions } from '@backstage/plugin-kubernetes-common';
import {
ANNOTATION_KUBERNETES_AUTH_PROVIDER,
ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER,
kubernetesPermissions,
} from '@backstage/plugin-kubernetes-common';
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node';
import express from 'express';
@@ -341,11 +345,12 @@ export class KubernetesBuilder {
const clusterDetails = await this.fetchClusterDetails(clusterSupplier);
res.json({
items: clusterDetails.map(cd => {
const oidcTokenProvider = cd.authMetadata.oidcTokenProvider;
const oidcTokenProvider =
cd.authMetadata[ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER];
return {
name: cd.name,
dashboardUrl: cd.dashboardUrl,
authProvider: cd.authMetadata.authProvider,
authProvider: cd.authMetadata[ANNOTATION_KUBERNETES_AUTH_PROVIDER],
...(oidcTokenProvider && { oidcTokenProvider }),
};
}),