From e19f88a950c9e2236bb862bc9383c0f43931c1e0 Mon Sep 17 00:00:00 2001 From: "Stephen Weatherford (MSFT)" Date: Tue, 20 Nov 2018 05:23:35 +0000 Subject: [PATCH] Easier certificate settings (#638) * Prepare for 0.4.0 release * Fix link * PR issues * Easier certificate settings * asdf --- README.md | 22 +++++++++++---- dockerExtension.ts | 2 +- package.json | 44 ++++++++++++++++++++---------- utils/getTrustedCertificates.ts | 48 +++++++++++++++++++++++---------- 4 files changed, 82 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index a652261fa9..00c1d88d3e 100644 --- a/README.md +++ b/README.md @@ -94,11 +94,23 @@ This build includes preview support for connecting to private registries (such a ## Self-signed and corporate certificates -If you are using a self-signed or corporate CA certificate (e.g. for a private Docker registry) and have the certificate authority's certificate registered in the Windows or Mac certificate store, you will need to set the `docker.useCertificateStore` setting to true in order for that certificate to be trusted by the extension. If you're on Linux, you will need to specify your certificate folder(s) and/or file(s) using the `docker.certificatePaths` setting. The exact folder to use will depend on the Linux distribution, but we suggest trying `["/etc/ssl/certs/ca-certificates", "/etc/openssl/certs", "/etc/pki/tls/certs", "/usr/local/share/certs"]` first. - -Note that currently if you specify either of these settings, Node.js's internal certificate list will be ignored. - -We will likely set default values for these in the future. +If you are using a self-signed or corporate CA certificate (e.g. for a private Docker registry) and have the certificate authority's certificate registered in the Windows or Mac certificate store, you will want to use the following setting: +```json +"docker.importCertificates": true +``` +This causes the extension automatically pick up system-wide certificates. Leaving it at the default `false` means the default Node.js list of trusted certificates will be used. You can fine-tune the values this way: +```json + "docker.importCertificates":{ + "useCertificateStore": true, + "certificatePaths": [ + "/etc/ssl/certs/ca-certificates", + "/etc/openssl/certs", + "/etc/pki/tls/certs", + "/usr/local/share/certs" + ] + } +``` +The exact folder to use for certificatePaths on Linux will depend on the distribution. ## Debugging .NET Core (Preview) diff --git a/dockerExtension.ts b/dockerExtension.ts index a055e7bf4d..7b37f4d81d 100644 --- a/dockerExtension.ts +++ b/dockerExtension.ts @@ -213,7 +213,7 @@ async function setRequestDefaults(): Promise { let error = <{ cause?: { code?: string } }>err; if (error && error.cause && error.cause.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') { - err = wrapError(err, `There was a problem verifying a certificate. This could be caused by a self-signed or corporate certificate. You may need to set the 'docker.useCertificateStore' or 'docker.certificatePaths' setting.`) + err = wrapError(err, `There was a problem verifying a certificate. This could be caused by a self-signed or corporate certificate. You may need to set the 'docker.importCertificates' setting to true.`) } throw err; diff --git a/package.json b/package.json index 51378b0128..eaa862690a 100644 --- a/package.json +++ b/package.json @@ -471,21 +471,37 @@ "default": "", "description": "Host to connect to (same as setting the DOCKER_HOST environment variable)" }, - "docker.certificatePaths": { - "type": [ - "array", - "null" + "docker.importCertificates": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "useCertificateStore": { + "type": "boolean", + "default": true, + "description": "On Mac and Windows, indicates whether to automatically import certificates from the system certificate store. Ignored on Linux." + }, + "certificatePaths": { + "type": "array", + "items": { + "type": "string" + }, + "default": [ + "/etc/ssl/certs/ca-certificates", + "/etc/openssl/certs", + "/etc/pki/tls/certs", + "/usr/local/share/certs" + ], + "description": "Paths to files or folders containing certificates to import. For Linux, the correct path to pick up system-wide certificates will depend on the distribution." + } + } + } ], - "items": { - "type": "string" - }, - "description": "Paths to files or folders containing certificates to import. For Linux, the correct path to pick up system-wide certificates will depend on the distribution. The list [\"/etc/ssl/certs/ca-certificates\", \"/etc/openssl/certs\", \"/etc/pki/tls/certs\", \"/usr/local/share/certs\"] may suffice for many.", - "default": null - }, - "docker.useCertificateStore": { - "type": "boolean", - "description": "On Mac and Windows, indicates whether to automatically import certificates from the system certificate store. Ignored on Linux.", - "default": false + "default": false, + "description": "True causes the extension to attempt to find system-wide certificates, false indicates that the default Node.js trusted certificates list will be used. Use an object to get more fine-grained control." }, "docker.languageserver.diagnostics.deprecatedMaintainer": { "scope": "resource", diff --git a/utils/getTrustedCertificates.ts b/utils/getTrustedCertificates.ts index fcfeef53fd..433a58299d 100644 --- a/utils/getTrustedCertificates.ts +++ b/utils/getTrustedCertificates.ts @@ -14,29 +14,49 @@ import { isLinux, isMac, isWindows } from '../helpers/osVersion'; let _systemCertificates: (string | Buffer)[] | undefined; +type ImportCertificatesSetting = boolean | { + useCertificateStore: boolean, + certificatePaths: string[] +}; + +const defaultCertificatePaths: string[] = [ + "/etc/ssl/certs/ca-certificates", + "/etc/openssl/certs", + "/etc/pki/tls/certs", + "/usr/local/share/certs" +]; + export async function getTrustedCertificates(): Promise<(string | Buffer)[]> { // tslint:disable-next-line:no-function-expression return callWithTelemetryAndErrorHandling('docker.certificates', async function (this: IActionContext): Promise<(string | Buffer)[] | undefined> { this.suppressTelemetry = true; - let useCertificateStore: boolean = !!vscode.workspace.getConfiguration('docker').get('useCertificateStore'); - this.properties.useCertStore = String(useCertificateStore); - let systemCerts: (string | Buffer)[] | undefined = useCertificateStore ? getCertificatesFromSystem() : undefined; - - let certificatePaths: string[] = vscode.workspace.getConfiguration('docker').get('certificatePaths'); - let filesCerts: Buffer[] | undefined; - if (Array.isArray(certificatePaths)) { - this.properties.certPathsCount = String(certificatePaths.length); - filesCerts = await getCertificatesFromPaths(certificatePaths); + let importSetting = vscode.workspace.getConfiguration('docker').get('importCertificates'); + if (importSetting === false) { + // Use default Node.js behavior + this.properties.importCertificates = 'false'; + return undefined; } - if (systemCerts === undefined && filesCerts === undefined) { - // If neither setting is set, be sure to return undefined to get Node.js's default list of trusted certificates - return undefined; + let useCertificateStore: boolean; + let certificatePaths: string[]; + + if (importSetting === true) { + this.properties.importCertificates = 'true'; + useCertificateStore = true; + certificatePaths = defaultCertificatePaths; + } else { + this.properties.importCertificates = 'custom'; + useCertificateStore = !!importSetting.useCertificateStore; + certificatePaths = importSetting.certificatePaths || []; } - systemCerts = systemCerts || []; - filesCerts = filesCerts || []; + this.properties.useCertStore = String(useCertificateStore); + let systemCerts: (string | Buffer)[] = useCertificateStore ? getCertificatesFromSystem() : []; + + let filesCerts: Buffer[]; + this.properties.certPathsCount = String(certificatePaths.length); + filesCerts = await getCertificatesFromPaths(certificatePaths); this.properties.systemCertsCount = String(systemCerts.length); this.properties.fileCertsCount = String(filesCerts.length);