diff --git a/packages/core/http/core-http-server-internal/src/http_server.ts b/packages/core/http/core-http-server-internal/src/http_server.ts index 93b63adb3b3af..1361c64bb67ce 100644 --- a/packages/core/http/core-http-server-internal/src/http_server.ts +++ b/packages/core/http/core-http-server-internal/src/http_server.ts @@ -245,13 +245,15 @@ export class HttpServer { .subscribe(([{ ssl: prevSslConfig }, { ssl: newSslConfig }]) => { if (prevSslConfig.enabled !== newSslConfig.enabled) { this.log.warn( - 'Incompatible change in config - TLS cannot be toggled without a full server reboot.' + 'Incompatible TLS config change detected - TLS cannot be toggled without a full server reboot.' ); + return; } - const configChanged = true; // TODO: actually compare the configs + const sameConfig = newSslConfig.isEqualTo(prevSslConfig); - if (configChanged) { + if (!sameConfig) { + this.log.info('TLS configuration change detected - reloading TLS configuration.'); setTlsConfig(this.server!, newSslConfig); } }); diff --git a/packages/kbn-server-http-tools/src/ssl/ssl_config.test.ts b/packages/kbn-server-http-tools/src/ssl/ssl_config.test.ts index 112fcd8a449f7..c6f701ef67a1e 100644 --- a/packages/kbn-server-http-tools/src/ssl/ssl_config.test.ts +++ b/packages/kbn-server-http-tools/src/ssl/ssl_config.test.ts @@ -164,6 +164,79 @@ describe('#SslConfig', () => { expect(configValue.certificate).toEqual('content-of-another-path'); }); }); + + describe('isEqualTo()', () => { + const createEnabledConfig = (obj: any) => + createConfig({ + enabled: true, + key: 'same-key', + certificate: 'same-cert', + ...obj, + }); + + it('compares `enabled`', () => { + const reference = createConfig({ enabled: true, key: 'same-key', certificate: 'same-cert' }); + const same = createConfig({ enabled: true, key: 'same-key', certificate: 'same-cert' }); + const different = createConfig({ enabled: false, key: 'same-key', certificate: 'same-cert' }); + + expect(reference.isEqualTo(same)).toBe(true); + expect(reference.isEqualTo(different)).toBe(false); + }); + + it('compares `key`', () => { + const reference = createEnabledConfig({ key: 'keyA', certificate: 'same-cert' }); + const same = createEnabledConfig({ key: 'keyA', certificate: 'same-cert' }); + const different = createEnabledConfig({ key: 'keyB', certificate: 'same-cert' }); + + expect(reference.isEqualTo(same)).toBe(true); + expect(reference.isEqualTo(different)).toBe(false); + }); + + it('compares `keyPassphrase`', () => { + const reference = createEnabledConfig({ keyPassphrase: 'passA' }); + const same = createEnabledConfig({ keyPassphrase: 'passA' }); + const different = createEnabledConfig({ keyPassphrase: 'passB' }); + + expect(reference.isEqualTo(same)).toBe(true); + expect(reference.isEqualTo(different)).toBe(false); + }); + + it('compares `certificate`', () => { + const reference = createEnabledConfig({ key: 'same-key', certificate: 'cert-a' }); + const same = createEnabledConfig({ key: 'same-key', certificate: 'cert-a' }); + const different = createEnabledConfig({ key: 'same-key', certificate: 'cert-b' }); + + expect(reference.isEqualTo(same)).toBe(true); + expect(reference.isEqualTo(different)).toBe(false); + }); + + it('compares `cipherSuites`', () => { + const reference = createEnabledConfig({ cipherSuites: ['A', 'B'] }); + const same = createEnabledConfig({ cipherSuites: ['A', 'B'] }); + const different = createEnabledConfig({ cipherSuites: ['A', 'C'] }); + + expect(reference.isEqualTo(same)).toBe(true); + expect(reference.isEqualTo(different)).toBe(false); + }); + + it('compares `supportedProtocols`', () => { + const reference = createEnabledConfig({ supportedProtocols: ['TLSv1.1', 'TLSv1.2'] }); + const same = createEnabledConfig({ supportedProtocols: ['TLSv1.1', 'TLSv1.2'] }); + const different = createEnabledConfig({ supportedProtocols: ['TLSv1.1', 'TLSv1.3'] }); + + expect(reference.isEqualTo(same)).toBe(true); + expect(reference.isEqualTo(different)).toBe(false); + }); + + it('compares `clientAuthentication`', () => { + const reference = createEnabledConfig({ clientAuthentication: 'none' }); + const same = createEnabledConfig({ clientAuthentication: 'none' }); + const different = createEnabledConfig({ clientAuthentication: 'required' }); + + expect(reference.isEqualTo(same)).toBe(true); + expect(reference.isEqualTo(different)).toBe(false); + }); + }); }); describe('#sslSchema', () => { diff --git a/packages/kbn-server-http-tools/src/ssl/ssl_config.ts b/packages/kbn-server-http-tools/src/ssl/ssl_config.ts index 53d3616a09a75..a5d43064baa6b 100644 --- a/packages/kbn-server-http-tools/src/ssl/ssl_config.ts +++ b/packages/kbn-server-http-tools/src/ssl/ssl_config.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { isEqual } from 'lodash'; import { schema, TypeOf } from '@kbn/config-schema'; import { readPkcs12Keystore, readPkcs12Truststore } from '@kbn/crypto'; import { constants as cryptoConstants } from 'crypto'; @@ -161,6 +162,13 @@ export class SslConfig { : secureOptions | secureOption; // eslint-disable-line no-bitwise }, 0); } + + public isEqualTo(otherConfig: SslConfig) { + if (this === otherConfig) { + return true; + } + return isEqual(this, otherConfig); + } } const readFile = (file: string) => readFileSync(file, 'utf8');