From 8fc2f5709261029d2f5a7d192702e7be00203ab8 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 15 Apr 2025 11:24:22 -0400 Subject: [PATCH] config: support username impersonation This commit adds support for username impersonation. This does not implement group, UID, or extra impersonation. Refs: https://github.com/kubernetes-client/javascript/issues/2355 --- src/config.ts | 5 +++++ src/config_test.ts | 39 +++++++++++++++++++++++++++++++++++++++ src/config_types.ts | 3 +++ 3 files changed, 47 insertions(+) diff --git a/src/config.ts b/src/config.ts index 81bbd6f17b..526ce20861 100644 --- a/src/config.ts +++ b/src/config.ts @@ -582,6 +582,11 @@ export class KubeConfig implements SecurityAuthentication { if (key) { opts.key = key; } + + if (user.impersonateUser != null) { + opts.headers ??= {}; + opts.headers['Impersonate-User'] = user.impersonateUser; + } } private async applyAuthorizationHeader( diff --git a/src/config_test.ts b/src/config_test.ts index 400906d54d..c2544a82e8 100644 --- a/src/config_test.ts +++ b/src/config_test.ts @@ -643,6 +643,24 @@ describe('KubeConfig', () => { strictEqual(username, users[0].username); strictEqual(name, users[0].name); }); + it('should load impersonation information', () => { + const users = newUsers([ + { + name: 'some-name-1', + user: { + as: 'impersonated-user', + }, + }, + { + name: 'some-name-2', + user: {}, + }, + ]); + strictEqual('some-name-1', users[0].name); + strictEqual('impersonated-user', users[0].impersonateUser); + strictEqual('some-name-2', users[1].name); + strictEqual(undefined, users[1].impersonateUser); + }); }); describe('findHome', () => { @@ -1787,4 +1805,25 @@ describe('KubeConfig', () => { strictEqual(opts.headers!.Authorization, 'Bearer test-token'); }); }); + + describe('Impersonation', () => { + it('injects Impersonate-User header', async () => { + const kc = new KubeConfig(); + const cluster: Cluster = { + name: 'test-cluster', + server: 'https://localhost:6443', + skipTLSVerify: false, + }; + const user: User = { + name: 'test-user', + authProvider: 'custom', + impersonateUser: 'impersonate-user', + }; + + kc.loadFromClusterAndUser(cluster, user); + const opts: RequestOptions = {}; + await kc.applyToHTTPSOptions(opts); + strictEqual(opts.headers!['Impersonate-User'], 'impersonate-user'); + }); + }); }); diff --git a/src/config_types.ts b/src/config_types.ts index eed9e1b052..6b08084ab4 100644 --- a/src/config_types.ts +++ b/src/config_types.ts @@ -97,6 +97,7 @@ export interface User { readonly token?: string; readonly username?: string; readonly password?: string; + readonly impersonateUser?: string; } export function newUsers(a: any, opts?: Partial): User[] { @@ -113,6 +114,7 @@ export function exportUser(user: User): any { return { name: user.name, user: { + as: user.impersonateUser, 'auth-provider': user.authProvider, 'client-certificate-data': user.certData, 'client-certificate': user.certFile, @@ -143,6 +145,7 @@ function userIterator(onInvalidEntry: ActionOnInvalid): (elt: any, i: number, li token: findToken(elt.user), password: elt.user ? elt.user.password : null, username: elt.user ? elt.user.username : null, + impersonateUser: elt.user ? elt.user.as : null, }; } catch (err) { switch (onInvalidEntry) {