diff --git a/package-lock.json b/package-lock.json index 28d0a2b63b..db188ef135 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,12 +16,14 @@ "@types/tar": "^6.1.1", "@types/ws": "^8.5.4", "form-data": "^4.0.0", + "hpagent": "^1.2.0", "isomorphic-ws": "^5.0.0", "js-yaml": "^4.1.0", "jsonpath-plus": "^10.2.0", "node-fetch": "^2.6.9", "openid-client": "^6.1.3", "rfc4648": "^1.3.0", + "socks-proxy-agent": "^8.0.4", "stream-buffers": "^3.0.2", "tar": "^7.0.0", "tmp-promise": "^3.0.2", @@ -818,6 +820,15 @@ "@types/node": "*" } }, + "node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -1491,6 +1502,15 @@ "he": "bin/he" } }, + "node_modules/hpagent": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", + "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -1546,6 +1566,25 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause" + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -1748,6 +1787,12 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT" + }, "node_modules/jsep": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", @@ -2743,6 +2788,63 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -3907,6 +4009,11 @@ "@types/node": "*" } }, + "agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==" + }, "ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -4394,6 +4501,11 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "hpagent": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", + "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==" + }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -4432,6 +4544,22 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "requires": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "dependencies": { + "sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + } + } + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -4575,6 +4703,11 @@ } } }, + "jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, "jsep": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", @@ -5271,6 +5404,48 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==" }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, + "socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "requires": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "requires": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + } + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", diff --git a/package.json b/package.json index 239b81a941..b4df512474 100644 --- a/package.json +++ b/package.json @@ -65,12 +65,14 @@ "@types/tar": "^6.1.1", "@types/ws": "^8.5.4", "form-data": "^4.0.0", + "hpagent": "^1.2.0", "isomorphic-ws": "^5.0.0", "js-yaml": "^4.1.0", "jsonpath-plus": "^10.2.0", "node-fetch": "^2.6.9", "openid-client": "^6.1.3", "rfc4648": "^1.3.0", + "socks-proxy-agent": "^8.0.4", "stream-buffers": "^3.0.2", "tar": "^7.0.0", "tmp-promise": "^3.0.2", diff --git a/src/config.ts b/src/config.ts index f8237710de..a3c1603e91 100644 --- a/src/config.ts +++ b/src/config.ts @@ -33,6 +33,8 @@ import { import { OpenIDConnectAuth } from './oidc_auth.js'; import WebSocket from 'isomorphic-ws'; import child_process from 'node:child_process'; +import { SocksProxyAgent } from 'socks-proxy-agent'; +import { HttpProxyAgent, HttpProxyAgentOptions, HttpsProxyAgent, HttpsProxyAgentOptions } from 'hpagent'; const SERVICEACCOUNT_ROOT: string = '/var/run/secrets/kubernetes.io/serviceaccount'; const SERVICEACCOUNT_CA_PATH: string = SERVICEACCOUNT_ROOT + '/ca.crt'; @@ -171,6 +173,7 @@ export class KubeConfig implements SecurityAuthentication { public async applyToHTTPSOptions(opts: https.RequestOptions | WebSocket.ClientOptions): Promise { const user = this.getCurrentUser(); + const cluster = this.getCurrentCluster(); await this.applyOptions(opts); @@ -205,7 +208,7 @@ export class KubeConfig implements SecurityAuthentication { agentOptions.secureProtocol = opts.secureProtocol; agentOptions.sessionIdContext = opts.sessionIdContext; - opts.agent = new https.Agent(agentOptions); + opts.agent = this.createAgent(cluster, agentOptions); } /** @@ -248,7 +251,7 @@ export class KubeConfig implements SecurityAuthentication { agentOptions.passphrase = httpsOptions.passphrase; agentOptions.rejectUnauthorized = httpsOptions.rejectUnauthorized; - context.setAgent(new https.Agent(agentOptions)); + context.setAgent(this.createAgent(cluster, agentOptions)); } /** @@ -509,6 +512,32 @@ export class KubeConfig implements SecurityAuthentication { return this.getContextObject(this.currentContext); } + private createAgent( + cluster: Cluster | null, + agentOptions: https.AgentOptions, + ): https.Agent | SocksProxyAgent | HttpProxyAgent | HttpsProxyAgent { + let agent: https.Agent | SocksProxyAgent | HttpProxyAgent | HttpsProxyAgent; + + if (cluster && cluster.proxyUrl) { + if (cluster.proxyUrl.startsWith('socks')) { + agent = new SocksProxyAgent(cluster.proxyUrl, agentOptions); + } else if (cluster.server.startsWith('https')) { + const httpsProxyAgentOptions: HttpsProxyAgentOptions = agentOptions as HttpsProxyAgentOptions; + httpsProxyAgentOptions.proxy = cluster.proxyUrl; + agent = new HttpsProxyAgent(httpsProxyAgentOptions); + } else if (cluster.server.startsWith('http')) { + const httpProxyAgentOptions: HttpProxyAgentOptions = agentOptions as HttpProxyAgentOptions; + httpProxyAgentOptions.proxy = cluster.proxyUrl; + agent = new HttpProxyAgent(httpProxyAgentOptions); + } else { + throw new Error('Unsupported proxy type'); + } + } else { + agent = new https.Agent(agentOptions); + } + return agent; + } + private applyHTTPSOptions(opts: https.RequestOptions | WebSocket.ClientOptions): void { const cluster = this.getCurrentCluster(); const user = this.getCurrentUser(); diff --git a/src/config_test.ts b/src/config_test.ts index 40f70fafbe..262893c35a 100644 --- a/src/config_test.ts +++ b/src/config_test.ts @@ -15,12 +15,15 @@ import { CoreV1Api, RequestContext } from './api.js'; import { bufferFromFileOrString, findHomeDir, findObject, KubeConfig, makeAbsolutePath } from './config.js'; import { ActionOnInvalid, Cluster, newClusters, newContexts, newUsers, User } from './config_types.js'; import { ExecAuth } from './exec_auth.js'; +import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent'; +import { SocksProxyAgent } from 'socks-proxy-agent'; const kcFileName = 'testdata/kubeconfig.yaml'; const kc2FileName = 'testdata/kubeconfig-2.yaml'; const kcDupeCluster = 'testdata/kubeconfig-dupe-cluster.yaml'; const kcDupeContext = 'testdata/kubeconfig-dupe-context.yaml'; const kcDupeUser = 'testdata/kubeconfig-dupe-user.yaml'; +const kcProxyUrl = 'testdata/kubeconfig-proxy-url.yaml'; const kcNoUserFileName = 'testdata/empty-user-kubeconfig.yaml'; const kcInvalidContextFileName = 'testdata/empty-context-kubeconfig.yaml'; @@ -43,6 +46,7 @@ function validateFileLoad(kc: KubeConfig) { expect(cluster1.name).to.equal('cluster1'); expect(cluster1.caData).to.equal('Q0FEQVRB'); expect(cluster1.server).to.equal('http://example.com'); + expect(cluster1.proxyUrl).to.equal('socks5://localhost:1181'); expect(cluster2.name).to.equal('cluster2'); expect(cluster2.caData).to.equal('Q0FEQVRBMg=='); expect(cluster2.server).to.equal('http://example2.com'); @@ -358,6 +362,69 @@ describe('KubeConfig', () => { assertRequestOptionsEqual(opts, expectedOptions); }); + it('should apply socks proxy', async () => { + const kc = new KubeConfig(); + kc.loadFromFile(kcProxyUrl); + kc.setCurrentContext('contextA'); + + const testServerName = 'https://example.com'; + const rc = new RequestContext(testServerName, HttpMethod.GET); + + await kc.applySecurityAuthentication(rc); + const expectedCA = Buffer.from('CADAT@', 'utf-8'); + const expectedProxyHost = 'example'; + const expectedProxyPort = 1187; + + expect(rc.getAgent()).to.be.instanceOf(SocksProxyAgent); + const agent = rc.getAgent() as SocksProxyAgent; + expect(agent.options.ca?.toString()).to.equal(expectedCA.toString()); + expect(agent.proxy.host).to.equal(expectedProxyHost); + expect(agent.proxy.port).to.equal(expectedProxyPort); + }); + it('should apply https proxy', async () => { + const kc = new KubeConfig(); + kc.loadFromFile(kcProxyUrl); + kc.setCurrentContext('contextB'); + + const testServerName = 'https://example.com'; + const rc = new RequestContext(testServerName, HttpMethod.GET); + + await kc.applySecurityAuthentication(rc); + const expectedCA = Buffer.from('CADAT@', 'utf-8'); + const expectedProxyHref = 'http://example:9443/'; + + expect(rc.getAgent()).to.be.instanceOf(HttpsProxyAgent); + const agent = rc.getAgent() as HttpsProxyAgent; + expect(agent.options.ca?.toString()).to.equal(expectedCA.toString()); + expect(agent.proxy.href).to.equal(expectedProxyHref); + }); + it('should apply http proxy', async () => { + const kc = new KubeConfig(); + kc.loadFromFile(kcProxyUrl); + kc.setCurrentContext('contextC'); + + const testServerName = 'https://example.com'; + const rc = new RequestContext(testServerName, HttpMethod.GET); + + await kc.applySecurityAuthentication(rc); + const expectedCA = Buffer.from('CADAT@', 'utf-8'); + const expectedProxyHref = 'http://example:8080/'; + + expect(rc.getAgent()).to.be.instanceOf(HttpProxyAgent); + const agent = rc.getAgent() as HttpProxyAgent; + expect(agent.options.ca?.toString()).to.equal(expectedCA.toString()); + expect(agent.proxy.href).to.equal(expectedProxyHref); + }); + it('should throw an error if proxy-url is provided but the server protocol is not http or https', async () => { + const kc = new KubeConfig(); + kc.loadFromFile(kcProxyUrl); + kc.setCurrentContext('contextD'); + + const testServerName = 'https://example.com'; + const rc = new RequestContext(testServerName, HttpMethod.GET); + + return expect(kc.applySecurityAuthentication(rc)).to.be.rejectedWith('Unsupported proxy type'); + }); }); describe('loadClusterConfigObjects', () => { diff --git a/src/config_types.ts b/src/config_types.ts index e35ae6f7cf..f628e1ad68 100644 --- a/src/config_types.ts +++ b/src/config_types.ts @@ -22,6 +22,7 @@ export interface Cluster { readonly server: string; readonly tlsServerName?: string; readonly skipTLSVerify: boolean; + readonly proxyUrl?: string; } export function newClusters(a: any, opts?: Partial): Cluster[] { @@ -43,6 +44,7 @@ export function exportCluster(cluster: Cluster): any { 'certificate-authority': cluster.caFile, 'insecure-skip-tls-verify': cluster.skipTLSVerify, 'tls-server-name': cluster.tlsServerName, + 'proxy-url': cluster.proxyUrl, }, }; } @@ -68,6 +70,7 @@ function clusterIterator( server: elt.cluster.server.replace(/\/$/, ''), skipTLSVerify: elt.cluster['insecure-skip-tls-verify'] === true, tlsServerName: elt.cluster['tls-server-name'], + proxyUrl: elt.cluster['proxy-url'], }; } catch (err) { switch (onInvalidEntry) { diff --git a/testdata/kubeconfig-proxy-url.yaml b/testdata/kubeconfig-proxy-url.yaml new file mode 100644 index 0000000000..8d88117af9 --- /dev/null +++ b/testdata/kubeconfig-proxy-url.yaml @@ -0,0 +1,61 @@ +apiVersion: v1 +clusters: + - cluster: + certificate-authority-data: Q0FEQVRA + server: http://example1.com + proxy-url: socks5://example:1187 + name: clusterA + - cluster: + certificate-authority-data: Q0FEQVRA + server: https://example2.com + proxy-url: http://example:9443 + name: clusterB + - cluster: + certificate-authority-data: Q0FEQVRA + server: http://example3.com + proxy-url: http://example:8080 + name: clusterC + - cluster: + certificate-authority-data: Q0FEQVRA + server: htto://exampleerror.com + proxy-url: http://example:8080 + name: clusterD + +contexts: + - context: + cluster: clusterA + user: userA + name: contextA + - context: + cluster: clusterB + user: userB + name: contextB + - context: + cluster: clusterC + user: userC + name: contextC + - context: + cluster: clusterD + user: userD + name: contextD + +current-context: contextA +kind: Config +preferences: {} +users: + - name: userA + user: + client-certificate-data: XVNFUl9DQURBVEE= + client-key-data: XVNFUl9DS0RBVEE= + - name: userB + user: + client-certificate-data: XVNFUl9DQURBVEE= + client-key-data: XVNFUl9DS0RBVEE= + - name: userC + user: + client-certificate-data: XVNFUl9DQURBVEE= + client-key-data: XVNFUl9DS0RBVEE= + - name: userD + user: + client-certificate-data: XVNFUl9DQURBVEE= + client-key-data: XVNFUl9DS0RBVEE= diff --git a/testdata/kubeconfig.yaml b/testdata/kubeconfig.yaml index 7b9e0dfca0..94ffdc1347 100644 --- a/testdata/kubeconfig.yaml +++ b/testdata/kubeconfig.yaml @@ -1,9 +1,10 @@ apiVersion: v1 clusters: - cluster: - certificate-authority-data: Q0FEQVRB - server: http://example.com - name: cluster1 + certificate-authority-data: Q0FEQVRB + server: http://example.com + proxy-url: socks5://localhost:1181 + name: cluster1 - cluster: certificate-authority-data: Q0FEQVRBMg== server: http://example2.com @@ -12,9 +13,9 @@ clusters: contexts: - context: - cluster: cluster1 + cluster: cluster1 user: user1 - name: context1 + name: context1 - context: cluster: cluster2 namespace: namespace2 @@ -25,7 +26,7 @@ contexts: user: user3 name: passwd -current-context: context2 +current-context: context2 kind: Config preferences: {} users: @@ -40,4 +41,4 @@ users: - name: user3 user: username: foo - password: bar \ No newline at end of file + password: bar