Add a googleServiceAccountCredentials json config. Uses the credentials if present else fallback to default application credentials

Signed-off-by: Raghunandan Balachandran <raghunandan@spotify.com>
This commit is contained in:
Raghunandan Balachandran
2025-08-07 10:29:32 +02:00
parent 4ba9f986d2
commit 1bd09be1e4
3 changed files with 61 additions and 3 deletions
+7
View File
@@ -98,6 +98,13 @@ export interface Config {
plural: string;
}>;
/**
* (Optional) Google Service Account credentials for authentication
* JSON string containing the service account key
* @visibility secret
*/
googleServiceAccountCredentials?: string;
/**
* (Optional) API Version Overrides
* If set, the specified api version will be used to make requests for the corresponding object.
@@ -20,19 +20,70 @@ import {
KubernetesCredential,
} from '@backstage/plugin-kubernetes-node';
import * as container from '@google-cloud/container';
import { Config } from '@backstage/config';
/**
* GoogleServiceAccountStrategy provides authentication using Google Service Account credentials.
*
* Credentials can be provided via configuration:
* ```yaml
* kubernetes:
* googleServiceAccountCredentials: |
* {
* "type": "service_account",
* "project_id": "your-project-id",
* "private_key_id": "key-id",
* "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
* "client_email": "your-service-account@your-project.iam.gserviceaccount.com",
* "client_id": "client-id",
* "auth_uri": "https://accounts.google.com/o/oauth2/auth",
* "token_uri": "https://oauth2.googleapis.com/token",
* "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
* "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/..."
* }
* ```
*
* If no credentials are provided in config, falls back to GOOGLE_APPLICATION_CREDENTIALS or ADC.
*
* @public
*/
export class GoogleServiceAccountStrategy implements AuthenticationStrategy {
private readonly credentials?: string;
constructor(config: Config) {
this.credentials = config.getOptionalString(
'kubernetes.googleServiceAccountCredentials',
);
}
public async getCredential(): Promise<KubernetesCredential> {
const client = new container.v1.ClusterManagerClient();
let client: container.v1.ClusterManagerClient;
if (this.credentials) {
// Use credentials from config
try {
const credentialsObject = JSON.parse(this.credentials);
client = new container.v1.ClusterManagerClient({
credentials: credentialsObject,
scopes: ['https://www.googleapis.com/auth/cloud-platform'],
});
} catch (error) {
throw new Error(
`Failed to parse Google Service Account credentials from config: ${
error instanceof Error ? error.message : 'Invalid JSON'
}`,
);
}
} else {
// Fall back to Application Default Credentials or GOOGLE_APPLICATION_CREDENTIALS
client = new container.v1.ClusterManagerClient();
}
const token = await client.auth.getAccessToken();
if (!token) {
throw new Error(
'Unable to obtain access token for the current Google Application Default Credentials',
'Unable to obtain access token for Google Cloud authentication. Check your credentials configuration.',
);
}
return { type: 'bearer token', token };
@@ -462,7 +462,7 @@ export class KubernetesBuilder {
aws: new AwsIamStrategy({ config: this.env.config }),
azure: new AzureIdentityStrategy(this.env.logger),
google: new GoogleStrategy(),
googleServiceAccount: new GoogleServiceAccountStrategy(),
googleServiceAccount: new GoogleServiceAccountStrategy(this.env.config),
localKubectlProxy: new AnonymousStrategy(),
oidc: new OidcStrategy(),
serviceAccount: new ServiceAccountStrategy(),