Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,10 @@ export class KubeConfig implements SecurityAuthentication {
agentOptions.key = opts.key;
agentOptions.pfx = opts.pfx;
agentOptions.passphrase = opts.passphrase;
agentOptions.rejectUnauthorized = opts.rejectUnauthorized;
// Only set rejectUnauthorized if explicitly configured. When not set, fetch will use NODE_TLS_REJECT_UNAUTHORIZED env var
if (opts.rejectUnauthorized !== undefined) {
agentOptions.rejectUnauthorized = opts.rejectUnauthorized;
}
// The ws docs say that it accepts anything that https.RequestOptions accepts,
// but Typescript doesn't understand that idea (yet) probably could be fixed in
// the typings, but for now just cast to any
Expand Down Expand Up @@ -259,7 +262,10 @@ export class KubeConfig implements SecurityAuthentication {
agentOptions.key = httpsOptions.key;
agentOptions.pfx = httpsOptions.pfx;
agentOptions.passphrase = httpsOptions.passphrase;
agentOptions.rejectUnauthorized = httpsOptions.rejectUnauthorized;
// Only set rejectUnauthorized if explicitly configured. When not set, fetch will use NODE_TLS_REJECT_UNAUTHORIZED env var
if (httpsOptions.rejectUnauthorized !== undefined) {
agentOptions.rejectUnauthorized = httpsOptions.rejectUnauthorized;
}

context.setAgent(this.createAgent(cluster, agentOptions));
}
Expand Down
96 changes: 95 additions & 1 deletion src/config_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import mockfs from 'mock-fs';

import { Authenticator } from './auth.js';
import { Headers } from 'node-fetch';
import fetch, { Headers } from 'node-fetch';
import { HttpMethod } from './index.js';
import { assertRequestAgentsEqual, assertRequestOptionsEqual } from './test/match-buffer.js';
import { CoreV1Api, RequestContext } from './api.js';
Expand All @@ -27,6 +27,7 @@
import { ExecAuth } from './exec_auth.js';
import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent';
import { SocksProxyAgent } from 'socks-proxy-agent';
import { AddressInfo } from 'node:net';

const kcFileName = 'testdata/kubeconfig.yaml';
const kc2FileName = 'testdata/kubeconfig-2.yaml';
Expand All @@ -40,6 +41,9 @@
const kcInvalidClusterFileName = 'testdata/empty-cluster-kubeconfig.yaml';
const kcTlsServerNameFileName = 'testdata/tls-server-name-kubeconfig.yaml';

const testCertFileName = 'testdata/certs/test-cert.pem';
const testKeyFileName = 'testdata/certs/test-key.pem';

const __dirname = dirname(fileURLToPath(import.meta.url));

describe('Config', () => {});
Expand Down Expand Up @@ -491,6 +495,61 @@

strictEqual(rc.getAgent() instanceof https.Agent, true);
});

it('should apply NODE_TLS_REJECT_UNAUTHORIZED from environment to agent', async () => {
const { server, host, port } = await createTestHttpsServer((req, res) => {
res.setHeader('Content-Type', 'application/json');
if (req.url?.includes('/api/v1/namespaces')) {
res.writeHead(200);
res.end(
JSON.stringify({
apiVersion: 'v1',
kind: 'NamespaceList',
items: [
{
apiVersion: 'v1',
kind: 'Namespace',
metadata: { name: 'default' },
},
],
}),
);
} else {
res.writeHead(200);
res.end('ok');
}
});

const originalValue = process.env.NODE_TLS_REJECT_UNAUTHORIZED;
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // lgtm[js/disabling-certificate-validation]
after(() => {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = originalValue;
server.close();
});

const kc = new KubeConfig();
kc.loadFromClusterAndUser(
{
name: 'test-cluster',
server: `https://${host}:${port}`,
// ignore skipTLSVerify specified from environment variables
} as Cluster,
{
name: 'test-user',
token: 'test-token',
},
);
const coreV1Api = kc.makeApiClient(CoreV1Api);
const namespaceList = await coreV1Api.listNamespace();

strictEqual(namespaceList.kind, 'NamespaceList');
strictEqual(namespaceList.items.length, 1);
strictEqual(namespaceList.items[0].metadata?.name, 'default');

const res2 = await fetch(`https://${host}:${port}`, await kc.applyToFetchOptions({}));
strictEqual(res2.status, 200);
strictEqual(await res2.text(), 'ok');
});
});

describe('loadClusterConfigObjects', () => {
Expand Down Expand Up @@ -1827,3 +1886,38 @@
});
});
});

// create a self-signed HTTPS test server
async function createTestHttpsServer(
requestHandler?: (req: http.IncomingMessage, res: http.ServerResponse) => void,
): Promise<{
server: https.Server;
host: string;
port: number;
ca: string;
}> {
const host = 'localhost';

const cert = readFileSync(testCertFileName, 'utf8');
const key = readFileSync(testKeyFileName, 'utf8');

const defaultHandler = (req: http.IncomingMessage, res: http.ServerResponse) => {
res.writeHead(200);
res.end('ok');
};

const server = https.createServer({ key, cert }, requestHandler ?? defaultHandler);

const port = await new Promise<number>((resolve) => {
server.listen(0, () => {
resolve((server.address() as AddressInfo).port);
});
});

return {
server,
host,
port,
ca: cert, // ca is the same as cert here
};
}
19 changes: 19 additions & 0 deletions testdata/certs/test-cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDCzCCAfOgAwIBAgIUPTyeIJ44dN2PZYW0a3WGYfcB6iwwDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTI1MDkwNjEwNDAzN1oYDzQ3NjMw
ODAzMTA0MDM3WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQCdDiYdfXRhzDLum5pqa6BICCPfQ+vqTfF3aYrqAwV1
C63hYs/yU+IK83ohiPScmShmAP2ofHsP/8R9HK7LEWkvO5ZlGxebE9ARkXa51Gs9
g8IBjH+10EL5BcTHnb+T187rTlSaSpM59LVXhlsI/zzDB6VnvApPyLFpYJ0YoYau
4gA4rMrkZGkziCx85ONdWxYyjh4RemwNxOIzmEHg5R7v7g5yPxmNcmK4BQ0XLFAf
4KgMAlhIpGz03vOz8mP/JTKO8PoB9rmKmsEANB3MQW9C/n4yosVjqN9lyaJXLII3
6QPRi7bxqH5sq2rRfNNA9KbiszySWda7jupB8JgiBcnDAgMBAAGjUzBRMB0GA1Ud
DgQWBBTuleDZd59erSUzMOu46Yz1q9iDoDAfBgNVHSMEGDAWgBTuleDZd59erSUz
MOu46Yz1q9iDoDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBB
dfUNSeJj5oZi9QCFkjqIW0Zr3x1ODjaPVtlvp0lfcRF2qUBbaA8qvvDTbhWrS4Xl
NLzgK+aFhgJOcTj13BYNy1yag7ZnkwunInzsEGYJgC/JgZ93De/gWs88icOUHTo0
Eg/eco6usqykz/1ZDbUwNf5rOItdXt+cp6kpWkrapz4RISddgN0kIdwEOjCKh0+b
EvJ5lH/UUwVrfZ2KI4kz1A1gQzgA1flqwLm7CNxZtRywfZR4F2mpX9dafBFqzm4w
Y9jCrrhS7Y9p3Q0muHLjOOXOAYO+w/Z0av3JqvbQC1bxz3ybjSPjL8bhP3ptJarW
yd4YH2zt3+0omzYwHfRs
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions testdata/certs/test-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCdDiYdfXRhzDLu
m5pqa6BICCPfQ+vqTfF3aYrqAwV1C63hYs/yU+IK83ohiPScmShmAP2ofHsP/8R9
HK7LEWkvO5ZlGxebE9ARkXa51Gs9g8IBjH+10EL5BcTHnb+T187rTlSaSpM59LVX
hlsI/zzDB6VnvApPyLFpYJ0YoYau4gA4rMrkZGkziCx85ONdWxYyjh4RemwNxOIz
mEHg5R7v7g5yPxmNcmK4BQ0XLFAf4KgMAlhIpGz03vOz8mP/JTKO8PoB9rmKmsEA
NB3MQW9C/n4yosVjqN9lyaJXLII36QPRi7bxqH5sq2rRfNNA9KbiszySWda7jupB
8JgiBcnDAgMBAAECggEAD0Uk55EfE7Mq8JAof1hfiSFhe3+7HFjftWCJpR8OFMdB
7LwSw9jsDWyG32PVhLRPfTtzbkJMJM4VaKS1SgEzXOhKQyJTNTzD6jFefcrtclmx
Lz1d3WuWV2f8LfxkeBdvgulmyGmfzu7AAvaJO2K1obDIoEFkL0WwGjLOk2qBEde4
V3hXEoBiHkoEE5mEgfUarCL8tLmyiIc0gpE231vKrbuSjyi1V/nV2elYujeVmJ/F
23c5/SodcQnI/tUrN+rIvhBoP6V0ddrieTBtzf/jKrAvvYge3o+X/Z0idIQowyQs
boUD2XHieImMEXwfuGyKj2dtCd8rbhOI5Mfroqa04QKBgQDZWOO1iv2vrz8VevCn
se4n3mBaxfScdbVLNKnwe/7FW+4UKuxB5F5lMMAWPwgN85+NSH7YbcvUkFcLf/Ge
zBPXtDrvkTeQxyzAfvmjrD+1dMgP6wM5PDJ1e7Cz2yo4Hsql1VJ1H+nd1JFfJysL
YwkcDcrIx6aEAdw8qxUZLDdOVwKBgQC4/Fz9IS1UKpuYoU60YPSKABB7JqAJCUlm
trS6eI8qwJW9vpg+9w1T/y+lOYPiYq16u+rF59vdh2883mwJnYiR8QCsv5VfRPuR
dLzZAMMqWtqSXnLbHMHXdyZEZOxh6Qfix0tSRd0A6y876kWE1OkDCi6ARkXVAWnC
oPLxHeNkdQKBgG2v0GskE9b/yARdIOpgf2IbdeEZmdMEDFRB5al5yh9rv4DqEIVI
bOMAcVBIyxXPZyvz9B/heUZy+ZrSHOwY7cKkMEIKtVIZUlprOi0Blr1KjFSMM/pE
iOqFW63I40ujLn32ZEC7tFjBGAQ/ThfXCRfhVf9x0nU4Qx9S77jeeaLNAoGBALVL
N0MpkcgsHeQfKwhjASaCW6SmPS+99z8ADu21m/I1XkvgkEsdSuWociSG0rc7KHPh
2Xxt+LAKvL0160IdLyyAur2S4azF6Zsrgq1WLu/CrPXINN6DN4KYlltvYa+vd3gN
A8e1CpyM4fTha5J8K4U8JEi5FlVklicWICKovSPFAoGAYSgPvteAo2RAN6su9d8O
s7oLXnFLqaF+Fo9vdc9uEKzzdROf7GCpz/6uOb9NCiRFpu8bNyDKK4UpNqMbO97E
Km+QQuBOms16ic/lOUT6sWVe3V6FIs18xBxNNE7LrfPfa8Vory7YoVsXji6SWikT
oLTjd9Tt7SOW/v7q9GHW798=
-----END PRIVATE KEY-----