From 667f1370819d5bb128459fdf7b2c232d01b0ef6f Mon Sep 17 00:00:00 2001 From: Yun Lai <ylai@squareup.com> Date: Wed, 6 Sep 2023 22:02:34 +1000 Subject: [PATCH] feat: add options to host rules to enable mTLS calls to host (#24155) Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Co-authored-by: Rhys Arkins <rhys@arkins.net> --- docs/usage/configuration-options.md | 18 ++++++++ lib/config/options/index.ts | 30 +++++++++++++ lib/types/host-rules.ts | 3 ++ lib/util/http/host-rules.spec.ts | 65 +++++++++++++++++++++++++++++ lib/util/http/host-rules.ts | 23 ++++++++++ 5 files changed, 139 insertions(+) diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index b0fbe64344..695b889a16 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -1556,6 +1556,24 @@ To adjust it down to 10s for all queries, do this: } ``` +### httpsCertificateAuthority + +By default, Renovate uses the curated list of well-known [CA](https://en.wikipedia.org/wiki/Certificate_authority)s by Mozilla. +You may use another Certificate Authority instead, by setting it in the `httpsCertificateAuthority` config option. + +### httpsPrivateKey + +Specifies the private key in [PEM format](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail) for mTLS authentication. + +<!-- prettier-ignore --> +!!! warning + Do _not_ put your private key into this field, to avoid losing confidentiality completely. + You must use [secrets](https://docs.renovatebot.com/self-hosted-configuration/#secrets) to pass it down securely instead. + +### httpsCertificate + +Specifies the [Certificate chains](https://en.wikipedia.org/wiki/X.509#Certificate_chains_and_cross-certification) in [PEM format](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail) for mTLS authentication. + ## ignoreDeprecated By default, Renovate won't update a dependency version to a deprecated release unless the current version was _itself_ deprecated. diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index d7ae7c55ef..a3cdb0c41f 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -2348,6 +2348,36 @@ const options: RenovateOptions[] = [ cli: false, env: false, }, + { + name: 'httpsCertificateAuthority', + description: 'The overriding trusted CA certificate.', + type: 'string', + stage: 'repository', + parent: 'hostRules', + default: null, + cli: false, + env: false, + }, + { + name: 'httpsPrivateKey', + description: 'The private key in PEM format.', + type: 'string', + stage: 'repository', + parent: 'hostRules', + default: null, + cli: false, + env: false, + }, + { + name: 'httpsCertificate', + description: 'The certificate chains in PEM format.', + type: 'string', + stage: 'repository', + parent: 'hostRules', + default: null, + cli: false, + env: false, + }, { name: 'cacheHardTtlMinutes', description: diff --git a/lib/types/host-rules.ts b/lib/types/host-rules.ts index ac02a813c3..058ed21e1e 100644 --- a/lib/types/host-rules.ts +++ b/lib/types/host-rules.ts @@ -15,6 +15,9 @@ export interface HostRuleSearchResult { dnsCache?: boolean; keepalive?: boolean; artifactAuth?: string[] | null; + httpsCertificateAuthority?: string; + httpsPrivateKey?: string; + httpsCertificate?: string; } export interface HostRule extends HostRuleSearchResult { diff --git a/lib/util/http/host-rules.spec.ts b/lib/util/http/host-rules.spec.ts index aeff4e65d1..6ad1f655b5 100644 --- a/lib/util/http/host-rules.spec.ts +++ b/lib/util/http/host-rules.spec.ts @@ -148,6 +148,71 @@ describe('util/http/host-rules', () => { `); }); + it('certificateAuthority', () => { + hostRules.add({ + hostType: 'maven', + matchHost: 'https://custom.datasource.ca', + httpsCertificateAuthority: 'ca-cert', + }); + + expect( + applyHostRules('https://custom.datasource.ca/data/path', { + ...options, + hostType: 'maven', + }) + ).toMatchInlineSnapshot(` + { + "hostType": "maven", + "https": { + "certificateAuthority": "ca-cert", + }, + } + `); + }); + + it('privateKey', () => { + hostRules.add({ + hostType: 'maven', + matchHost: 'https://custom.datasource.key', + httpsPrivateKey: 'key', + }); + expect( + applyHostRules('https://custom.datasource.key/data/path', { + ...options, + hostType: 'maven', + }) + ).toMatchInlineSnapshot(` + { + "hostType": "maven", + "https": { + "key": "key", + }, + } + `); + }); + + it('certificate', () => { + hostRules.add({ + hostType: 'maven', + matchHost: 'https://custom.datasource.cert', + httpsCertificate: 'cert', + }); + + expect( + applyHostRules('https://custom.datasource.cert/data/path', { + ...options, + hostType: 'maven', + }) + ).toMatchInlineSnapshot(` + { + "hostType": "maven", + "https": { + "certificate": "cert", + }, + } + `); + }); + it('no fallback to github', () => { hostRules.add({ hostType: 'github-tags', diff --git a/lib/util/http/host-rules.ts b/lib/util/http/host-rules.ts index bf88e5e888..577afb5976 100644 --- a/lib/util/http/host-rules.ts +++ b/lib/util/http/host-rules.ts @@ -30,6 +30,7 @@ export type HostRulesGotOptions = Pick< | 'lookup' | 'agent' | 'http2' + | 'https' >; export function findMatchingRules<GotOptions extends HostRulesGotOptions>( @@ -162,6 +163,28 @@ export function applyHostRules<GotOptions extends HostRulesGotOptions>( if (!hasProxy() && foundRules.enableHttp2 === true) { options.http2 = true; } + + if (is.nonEmptyString(foundRules.httpsCertificateAuthority)) { + options.https = { + ...(options.https ?? {}), + certificateAuthority: foundRules.httpsCertificateAuthority, + }; + } + + if (is.nonEmptyString(foundRules.httpsPrivateKey)) { + options.https = { + ...(options.https ?? {}), + key: foundRules.httpsPrivateKey, + }; + } + + if (is.nonEmptyString(foundRules.httpsCertificate)) { + options.https = { + ...(options.https ?? {}), + certificate: foundRules.httpsCertificate, + }; + } + return options; } -- GitLab