From 05206963eac4719cc3cff6133e4bf7c747219e47 Mon Sep 17 00:00:00 2001 From: Brandon Kobel Date: Thu, 19 Apr 2018 14:41:49 -0400 Subject: [PATCH] Revert "Support PKCS#12 encoded certificates (#17261)" (#17801) (#17802) * Revert "Support PKCS#12 encoded certificates (#17261)" This reverts commit de91bd0f09e6c48aa7c4b37ae933f4fe3f7d38e4. * Fixing tests --- docs/setup/production.asciidoc | 9 ---- docs/setup/settings.asciidoc | 9 +--- src/cli/cluster/base_path_proxy.js | 27 +++------- src/cli/cluster/base_path_proxy.test.js | 17 ------ src/cli/serve/serve.js | 2 +- .../server/elasticsearch_proxy_config.js | 5 +- src/core_plugins/elasticsearch/index.js | 52 ++++++++----------- .../lib/__tests__/fixtures/cert.pfx | 1 - .../lib/__tests__/parse_config.js | 22 +------- .../elasticsearch/lib/parse_config.js | 17 +----- src/server/config/config.js | 1 - src/server/config/schema.js | 36 ++++++------- src/server/config/schema.test.js | 44 ++++------------ src/server/config/transform_deprecations.js | 8 +-- .../config/transform_deprecations.test.js | 15 ------ src/server/http/setup_connection.js | 22 ++------ 16 files changed, 67 insertions(+), 220 deletions(-) delete mode 100644 src/cli/cluster/base_path_proxy.test.js delete mode 100644 src/core_plugins/elasticsearch/lib/__tests__/fixtures/cert.pfx diff --git a/docs/setup/production.asciidoc b/docs/setup/production.asciidoc index 8b57669a2085..042b0ff98768 100644 --- a/docs/setup/production.asciidoc +++ b/docs/setup/production.asciidoc @@ -54,15 +54,6 @@ server.ssl.key: /path/to/your/server.key server.ssl.certificate: /path/to/your/server.crt ---- -Alternatively, you can specify a PKCS#12 encoded certificate with the `server.ssl.keystore.path` property in `kibana.yml`: - -[source,text] ----- -# SSL for outgoing requests from the Kibana Server (PKCS#12 formatted) -server.ssl.enabled: true -server.ssl.keystore.path: /path/to/your/server.p12 ----- - If you are using X-Pack Security or a proxy that provides an HTTPS endpoint for Elasticsearch, you can configure Kibana to access Elasticsearch via HTTPS so communications between the Kibana server and Elasticsearch are encrypted. diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 2c47e36edf37..29da3c847bc1 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -23,13 +23,8 @@ To send *no* client-side headers, set this value to [] (an empty list). `elasticsearch.requestTimeout:`:: *Default: 30000* Time in milliseconds to wait for responses from the back end or Elasticsearch. This value must be a positive integer. `elasticsearch.shardTimeout:`:: *Default: 30000* Time in milliseconds for Elasticsearch to wait for responses from shards. Set to 0 to disable. -`elasticsearch.ssl.keystore.path`:: Optional setting that provides the path to the PKCS#12-format SSL Certificate and Key file. This file is used to verify the identity of Kibana -to Elasticsearch. Either this, or `elasticsearch.ssl.certificate`/`elasticsearch.ssl.key` pair is required when `xpack.ssl.verification_mode` in Elasticsearch is set to either -`certificate` or `full`. Specifying both `elasticsearch.ssl.keystore.path` and `elasticsearch.ssl.certificate` is not allowed. `elasticsearch.ssl.certificate:` and `elasticsearch.ssl.key:`:: Optional settings that provide the paths to the PEM-format SSL -certificate and key files. These files are used to verify the identity of Kibana to Elasticsearch. -Either this, or `elasticsearch.ssl.keystore.path` is required when `xpack.ssl.verification_mode` in Elasticsearch is set to either `certificate` or `full`. -Specifying both `elasticsearch.ssl.certificate` and `elasticsearch.ssl.keystore.path` is not allowed. +certificate and key files. These files are used to verify the identity of Kibana to Elasticsearch and are required when `xpack.ssl.verification_mode` in Elasticsearch is set to either `certificate` or `full`. `elasticsearch.ssl.certificateAuthorities:`:: Optional setting that enables you to specify a list of paths to the PEM file for the certificate authority for your Elasticsearch instance. `elasticsearch.ssl.keyPassphrase:`:: The passphrase that will be used to decrypt the private key. This value is optional as the key may not be encrypted. @@ -122,8 +117,6 @@ By turning this off, only the layers that are configured here will be included. `server.port:`:: *Default: 5601* Kibana is served by a back end server. This setting specifies the port to use. `server.ssl.enabled:`:: *Default: "false"* Enables SSL for outgoing requests from the Kibana server to the browser. When set to `true`, `server.ssl.certificate` and `server.ssl.key` are required `server.ssl.certificate:` and `server.ssl.key:`:: Paths to the PEM-format SSL certificate and SSL key files, respectively. -`server.ssl.keystore.path`:: Path to the PKCS#12 encoded SSL certificate and key. This is an alternative to setting `server.ssl.certificate` and `server.ssl.key`. -`server.ssl.keystore.password`:: The password that will be used to decrypt the private key within the keystore. This value is optional as the key may not be encrypted. `server.ssl.certificateAuthorities:`:: List of paths to PEM encoded certificate files that should be trusted. `server.ssl.cipherSuites:`:: *Default: ECDHE-RSA-AES128-GCM-SHA256, ECDHE-ECDSA-AES128-GCM-SHA256, ECDHE-RSA-AES256-GCM-SHA384, ECDHE-ECDSA-AES256-GCM-SHA384, DHE-RSA-AES128-GCM-SHA256, ECDHE-RSA-AES128-SHA256, DHE-RSA-AES128-SHA256, ECDHE-RSA-AES256-SHA384, DHE-RSA-AES256-SHA384, ECDHE-RSA-AES256-SHA256, DHE-RSA-AES256-SHA256, HIGH,!aNULL, !eNULL, !EXPORT, !DES, !RC4, !MD5, !PSK, !SRP, !CAMELLIA*. Details on the format, and the valid options, are available via the [OpenSSL cipher list format documentation](https://www.openssl.org/docs/man1.0.2/apps/ciphers.html#CIPHER-LIST-FORMAT) `server.ssl.keyPassphrase:`:: The passphrase that will be used to decrypt the private key. This value is optional as the key may not be encrypted. diff --git a/src/cli/cluster/base_path_proxy.js b/src/cli/cluster/base_path_proxy.js index 1bc97efdbfdb..d13d87c243ab 100644 --- a/src/cli/cluster/base_path_proxy.js +++ b/src/cli/cluster/base_path_proxy.js @@ -26,28 +26,13 @@ export default class BasePathProxy { const sslEnabled = config.get('server.ssl.enabled'); if (sslEnabled) { - const agentOptions = { - ca: map(config.get('server.ssl.certificateAuthorities'), (certAuthority) => readFileSync(certAuthority)), + this.proxyAgent = new HttpsAgent({ + key: readFileSync(config.get('server.ssl.key')), + passphrase: config.get('server.ssl.keyPassphrase'), + cert: readFileSync(config.get('server.ssl.certificate')), + ca: map(config.get('server.ssl.certificateAuthorities'), readFileSync), rejectUnauthorized: false - }; - - const keystoreConfig = config.get('server.ssl.keystore.path'); - const pemConfig = config.get('server.ssl.certificate'); - - if (keystoreConfig && pemConfig) { - throw new Error(`Invalid Configuration: please specify either "server.ssl.keystore.path" or "server.ssl.certificate", not both.`); - } - - if (keystoreConfig) { - agentOptions.pfx = readFileSync(keystoreConfig); - agentOptions.passphrase = config.get('server.ssl.keystore.password'); - } else { - agentOptions.key = readFileSync(config.get('server.ssl.key')); - agentOptions.cert = readFileSync(pemConfig); - agentOptions.passphrase = config.get('server.ssl.keyPassphrase'); - } - - this.proxyAgent = new HttpsAgent(agentOptions); + }); } if (!this.basePath) { diff --git a/src/cli/cluster/base_path_proxy.test.js b/src/cli/cluster/base_path_proxy.test.js deleted file mode 100644 index ce0aceaa6a9f..000000000000 --- a/src/cli/cluster/base_path_proxy.test.js +++ /dev/null @@ -1,17 +0,0 @@ -import { set } from 'lodash'; -import BasePathProxy from './base_path_proxy'; - -describe('CLI Cluster Manager', function () { - describe('base_path_proxy constructor', function () { - it('should throw an error when both server.ssl.keystore.path and server.ssl.certificate are specified', function () { - const settings = {}; - set(settings, 'server.ssl.keystore.path', '/cert.p12'); - set(settings, 'server.ssl.certificate', './cert.crt'); - set(settings, 'server.ssl.key', './cert.key'); - - expect(() => new BasePathProxy(null, settings)).toThrow( - `Invalid Configuration: please specify either "server.ssl.keystore.path" or "server.ssl.certificate", not both.` - ); - }); - }); -}); diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index dd38d6b181f4..e9b3420bf72d 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -45,7 +45,7 @@ function readServerSettings(opts, extraCliOptions) { set('server.ssl.enabled', true); } - if (opts.ssl && !has('server.ssl.keystore.path') && !has('server.ssl.certificate') && !has('server.ssl.key')) { + if (opts.ssl && !has('server.ssl.certificate') && !has('server.ssl.key')) { set('server.ssl.certificate', DEV_SSL_CERT_PATH); set('server.ssl.key', DEV_SSL_KEY_PATH); } diff --git a/src/core_plugins/console/server/elasticsearch_proxy_config.js b/src/core_plugins/console/server/elasticsearch_proxy_config.js index 9099613ed2d6..110cde0913a5 100644 --- a/src/core_plugins/console/server/elasticsearch_proxy_config.js +++ b/src/core_plugins/console/server/elasticsearch_proxy_config.js @@ -37,10 +37,7 @@ const createAgent = (server) => { } // Add client certificate and key if required by elasticsearch - if (config.get('elasticsearch.ssl.keystore.path')) { - agentOptions.pfx = readFile(config.get('elasticsearch.ssl.keystore.path')); - agentOptions.passphrase = config.get('elasticsearch.ssl.keystore.password'); - } else if (config.get('elasticsearch.ssl.certificate') && config.get('elasticsearch.ssl.key')) { + if (config.get('elasticsearch.ssl.certificate') && config.get('elasticsearch.ssl.key')) { agentOptions.cert = readFile(config.get('elasticsearch.ssl.certificate')); agentOptions.key = readFile(config.get('elasticsearch.ssl.key')); agentOptions.passphrase = config.get('elasticsearch.ssl.keyPassphrase'); diff --git a/src/core_plugins/elasticsearch/index.js b/src/core_plugins/elasticsearch/index.js index 28599a268d63..b7a4eff29ad9 100644 --- a/src/core_plugins/elasticsearch/index.js +++ b/src/core_plugins/elasticsearch/index.js @@ -16,39 +16,33 @@ export default function (kibana) { return new kibana.Plugin({ require: ['kibana'], config(Joi) { - const sslSchema = Joi.object({ - verificationMode: Joi.string().valid('none', 'certificate', 'full').default('full'), - certificateAuthorities: Joi.array().single().items(Joi.string()), - certificate: Joi.string(), - key: Joi.when('certificate', { - is: Joi.exist(), - then: Joi.string().required(), - otherwise: Joi.string().forbidden() - }), - keystore: Joi.object({ - path: Joi.string(), - password: Joi.string() - }).default(), - keyPassphrase: Joi.string() + const { array, boolean, number, object, string, ref } = Joi; + + const sslSchema = object({ + verificationMode: string().valid('none', 'certificate', 'full').default('full'), + certificateAuthorities: array().single().items(string()), + certificate: string(), + key: string(), + keyPassphrase: string() }).default(); - return Joi.object({ - enabled: Joi.boolean().default(true), - url: Joi.string().uri({ scheme: ['http', 'https'] }).default('http://localhost:9200'), - preserveHost: Joi.boolean().default(true), - username: Joi.string(), - password: Joi.string(), - shardTimeout: Joi.number().default(30000), - requestTimeout: Joi.number().default(30000), - requestHeadersWhitelist: Joi.array().items().single().default(DEFAULT_REQUEST_HEADERS), - customHeaders: Joi.object().default({}), - pingTimeout: Joi.number().default(Joi.ref('requestTimeout')), - startupTimeout: Joi.number().default(5000), - logQueries: Joi.boolean().default(false), + return object({ + enabled: boolean().default(true), + url: string().uri({ scheme: ['http', 'https'] }).default('http://localhost:9200'), + preserveHost: boolean().default(true), + username: string(), + password: string(), + shardTimeout: number().default(30000), + requestTimeout: number().default(30000), + requestHeadersWhitelist: array().items().single().default(DEFAULT_REQUEST_HEADERS), + customHeaders: object().default({}), + pingTimeout: number().default(ref('requestTimeout')), + startupTimeout: number().default(5000), + logQueries: boolean().default(false), ssl: sslSchema, apiVersion: Joi.string().default('master'), - healthCheck: Joi.object({ - delay: Joi.number().default(2500) + healthCheck: object({ + delay: number().default(2500) }).default(), tribe: Joi.object({ url: Joi.string().uri({ scheme: ['http', 'https'] }), diff --git a/src/core_plugins/elasticsearch/lib/__tests__/fixtures/cert.pfx b/src/core_plugins/elasticsearch/lib/__tests__/fixtures/cert.pfx deleted file mode 100644 index 7fbaf9874696..000000000000 --- a/src/core_plugins/elasticsearch/lib/__tests__/fixtures/cert.pfx +++ /dev/null @@ -1 +0,0 @@ -test pfx diff --git a/src/core_plugins/elasticsearch/lib/__tests__/parse_config.js b/src/core_plugins/elasticsearch/lib/__tests__/parse_config.js index 0b81094609a6..3cc30d31fc25 100644 --- a/src/core_plugins/elasticsearch/lib/__tests__/parse_config.js +++ b/src/core_plugins/elasticsearch/lib/__tests__/parse_config.js @@ -10,8 +10,7 @@ describe('plugins/elasticsearch', function () { serverConfig = { url: 'https://localhost:9200', ssl: { - verificationMode: 'full', - keystore: {} + verificationMode: 'full' } }; }); @@ -87,25 +86,6 @@ describe('plugins/elasticsearch', function () { const config = parseConfig(serverConfig); expect(config.ssl.passphrase).to.be('secret'); }); - - it(`sets pfx when a PKCS#12 certificate bundle is specified`, function () { - serverConfig.ssl.keystore.path = __dirname + '/fixtures/cert.pfx'; - serverConfig.ssl.keystore.password = 'secret'; - - const config = parseConfig(serverConfig); - expect(Buffer.isBuffer(config.ssl.pfx)).to.be(true); - expect(config.ssl.pfx.toString('utf-8')).to.be('test pfx\n'); - expect(config.ssl.passphrase).to.be('secret'); - }); - - it('throws an error when both pfx and certificate are specified', function () { - serverConfig.ssl.certificate = __dirname + '/fixtures/cert.crt'; - serverConfig.ssl.keystore.path = __dirname + '/fixtures/cert.pfx'; - - expect(() => parseConfig(serverConfig)).to.throwError( - `Invalid Configuration: please specify either "elasticsearch.ssl.keystore.path" or "elasticsearch.ssl.certificate", not both.` - ); - }); }); }); }); diff --git a/src/core_plugins/elasticsearch/lib/parse_config.js b/src/core_plugins/elasticsearch/lib/parse_config.js index 605c4046190f..50d22bb5825e 100644 --- a/src/core_plugins/elasticsearch/lib/parse_config.js +++ b/src/core_plugins/elasticsearch/lib/parse_config.js @@ -5,7 +5,6 @@ import { readFileSync } from 'fs'; import Bluebird from 'bluebird'; const readFile = (file) => readFileSync(file, 'utf8'); -const readBinaryFile = (file) => readFileSync(file); export function parseConfig(serverConfig = {}) { const config = { @@ -57,20 +56,8 @@ export function parseConfig(serverConfig = {}) { } // Add client certificate and key if required by elasticsearch - const keystoreConfig = get(serverConfig, 'ssl.keystore.path'); - const pemConfig = get(serverConfig, 'ssl.certificate'); - - if (keystoreConfig && pemConfig) { - throw new Error( - `Invalid Configuration: please specify either "elasticsearch.ssl.keystore.path" or "elasticsearch.ssl.certificate", not both.` - ); - } - - if (keystoreConfig) { - config.ssl.pfx = readBinaryFile(keystoreConfig); - config.ssl.passphrase = get(serverConfig, 'ssl.keystore.password'); - } else if (pemConfig && get(serverConfig, 'ssl.key')) { - config.ssl.cert = readFile(pemConfig); + if (get(serverConfig, 'ssl.certificate') && get(serverConfig, 'ssl.key')) { + config.ssl.cert = readFile(serverConfig.ssl.certificate); config.ssl.key = readFile(serverConfig.ssl.key); config.ssl.passphrase = serverConfig.ssl.keyPassphrase; } diff --git a/src/server/config/config.js b/src/server/config/config.js index d7c88de85619..61276a645f7d 100644 --- a/src/server/config/config.js +++ b/src/server/config/config.js @@ -134,7 +134,6 @@ export class Config { const child = schema._inner.children[i]; // If the child is an object recurse through it's children and return // true if there's a match - if (child.schema._type === 'object') { if (has(key, child.schema, path.concat([child.key]))) return true; // if the child matches, return true diff --git a/src/server/config/schema.js b/src/server/config/schema.js index 0149ec8aa47f..c54b38ddd524 100644 --- a/src/server/config/schema.js +++ b/src/server/config/schema.js @@ -5,25 +5,6 @@ import os from 'os'; import { fromRoot } from '../../utils'; import { getData } from '../path'; -const sslSchema = Joi.object({ - enabled: Joi.boolean().optional().default(false), - redirectHttpFromPort: Joi.number().default(), - keystore: Joi.object({ - path: Joi.string(), - password: Joi.string() - }).default(), - certificate: Joi.string(), - key: Joi.when('certificate', { - is: Joi.exist(), - then: Joi.string().required(), - otherwise: Joi.string().forbidden() - }), - keyPassphrase: Joi.string(), - certificateAuthorities: Joi.array().single().items(Joi.string()).default([]), - supportedProtocols: Joi.array().items(Joi.string().valid('TLSv1', 'TLSv1.1', 'TLSv1.2')).default([]), - cipherSuites: Joi.array().items(Joi.string()).default(cryptoConstants.defaultCoreCipherList.split(':')) -}); - export default () => Joi.object({ pkg: Joi.object({ version: Joi.string().default(Joi.ref('$version')), @@ -78,7 +59,22 @@ export default () => Joi.object({ otherwise: Joi.default(false), }), customResponseHeaders: Joi.object().unknown(true).default({}), - ssl: sslSchema.default(), + ssl: Joi.object({ + enabled: Joi.boolean().default(false), + redirectHttpFromPort: Joi.number(), + certificate: Joi.string().when('enabled', { + is: true, + then: Joi.required(), + }), + key: Joi.string().when('enabled', { + is: true, + then: Joi.required() + }), + keyPassphrase: Joi.string(), + certificateAuthorities: Joi.array().single().items(Joi.string()).default([]), + supportedProtocols: Joi.array().items(Joi.string().valid('TLSv1', 'TLSv1.1', 'TLSv1.2')), + cipherSuites: Joi.array().items(Joi.string()).default(cryptoConstants.defaultCoreCipherList.split(':')) + }).default(), cors: Joi.when('$dev', { is: true, then: Joi.object().default({ diff --git a/src/server/config/schema.test.js b/src/server/config/schema.test.js index 8d432bb00ea0..a42e5f53020d 100644 --- a/src/server/config/schema.test.js +++ b/src/server/config/schema.test.js @@ -119,6 +119,16 @@ describe('Config schema', function () { const { error } = validate(config); expect(error).toBe(null); }); + + it('is required when ssl is enabled', function () { + const config = {}; + set(config, 'server.ssl.enabled', true); + set(config, 'server.ssl.key', '/path.key'); + const { error } = validate(config); + expect(error).toBeInstanceOf(Object); + expect(error).toHaveProperty('details'); + expect(error.details[0]).toHaveProperty('path', 'server.ssl.certificate'); + }); }); describe('key', function () { @@ -140,40 +150,6 @@ describe('Config schema', function () { }); }); - describe('keystore.path', function () { - it('isn\'t required when ssl isn\'t enabled', function () { - const config = {}; - set(config, 'server.ssl.enabled', false); - const { error } = validate(config); - expect(error).toBe(null); - }); - - it('is allowed when ssl is enabled, and a certificate is not specified', function () { - const config = {}; - set(config, 'server.ssl.enabled', true); - set(config, 'server.ssl.keystore.path', '/path.p12'); - const { error } = validate(config); - expect(error).toBe(null); - }); - }); - - describe('keystore.password', function () { - it('isn\'t required when ssl isn\'t enabled', function () { - const config = {}; - set(config, 'server.ssl.enabled', false); - const { error } = validate(config); - expect(error).toBe(null); - }); - - it('is allowed when ssl is enabled, and a certificate is not specified', function () { - const config = {}; - set(config, 'server.ssl.enabled', true); - set(config, 'server.ssl.keystore.password', 'secret'); - const { error } = validate(config); - expect(error).toBe(null); - }); - }); - describe('keyPassphrase', function () { it('is a possible config value', function () { const config = {}; diff --git a/src/server/config/transform_deprecations.js b/src/server/config/transform_deprecations.js index d191f2d9f499..ecbe4da3976b 100644 --- a/src/server/config/transform_deprecations.js +++ b/src/server/config/transform_deprecations.js @@ -7,13 +7,9 @@ const serverSslEnabled = (settings, log) => { const has = partial(_.has, settings); const set = partial(_.set, settings); - const hasPkcs12Cert = has('server.ssl.keystore.path'); - const hasPemCert = has('server.ssl.certificate') && has('server.ssl.key'); - - if (!has('server.ssl.enabled') && (hasPkcs12Cert || hasPemCert)) { + if (!has('server.ssl.enabled') && has('server.ssl.certificate') && has('server.ssl.key')) { set('server.ssl.enabled', true); - log('Enabling ssl by only specifying server.ssl.keystore.path or server.ssl.certificate/key is deprecated. ' - + 'Please set server.ssl.enabled to true'); + log('Enabling ssl by only specifying server.ssl.certificate and server.ssl.key is deprecated. Please set server.ssl.enabled to true'); } }; diff --git a/src/server/config/transform_deprecations.test.js b/src/server/config/transform_deprecations.test.js index 75c434e31ede..8554c0036ca3 100644 --- a/src/server/config/transform_deprecations.test.js +++ b/src/server/config/transform_deprecations.test.js @@ -18,21 +18,6 @@ describe('server/config', function () { expect(result.server.ssl.enabled).toBe(true); }); - it('sets enabled to true when keystore.path is set', function () { - const settings = { - server: { - ssl: { - keystore: { - path: '/server.pfx' - } - } - } - }; - - const result = transformDeprecations(settings); - expect(result.server.ssl.enabled).toBe(true); - }); - it('logs a message when automatically setting enabled to true', function () { const settings = { server: { diff --git a/src/server/http/setup_connection.js b/src/server/http/setup_connection.js index 377c1de0d4ba..d05c72c560c3 100644 --- a/src/server/http/setup_connection.js +++ b/src/server/http/setup_connection.js @@ -32,28 +32,14 @@ export function setupConnection(server, config) { return; } - const tlsOptions = {}; - const keystoreConfig = config.get('server.ssl.keystore.path'); - const pemConfig = config.get('server.ssl.certificate'); - - if (keystoreConfig && pemConfig) { - throw new Error(`Invalid Configuration: please specify either "server.ssl.keystore.path" or "server.ssl.certificate", not both.`); - } - - if (keystoreConfig) { - tlsOptions.pfx = readFileSync(keystoreConfig); - tlsOptions.passphrase = config.get('server.ssl.keystore.password'); - } else { - tlsOptions.key = readFileSync(config.get('server.ssl.key')); - tlsOptions.cert = readFileSync(pemConfig); - tlsOptions.passphrase = config.get('server.ssl.keyPassphrase'); - } - const connection = server.connection({ ...connectionOptions, tls: { - ...tlsOptions, + key: readFileSync(config.get('server.ssl.key')), + cert: readFileSync(config.get('server.ssl.certificate')), ca: config.get('server.ssl.certificateAuthorities').map(ca => readFileSync(ca, 'utf8')), + passphrase: config.get('server.ssl.keyPassphrase'), + ciphers: config.get('server.ssl.cipherSuites').join(':'), // We use the server's cipher order rather than the client's to prevent the BEAST attack honorCipherOrder: true,