Skip to content

Commit

Permalink
Adding option to always present the certificate when connecting to ES (
Browse files Browse the repository at this point in the history
…#24304) (#24401)

* Adding option to always present the certificate when connecting to ES

* Updating docs

* Adding some more tests

* Adding alwaysPresentCertificate option to monitoring
  • Loading branch information
kobelb authored Oct 23, 2018
1 parent d837b95 commit ec26adf
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 17 deletions.
5 changes: 5 additions & 0 deletions docs/setup/settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ authority for your Elasticsearch instance.
`elasticsearch.ssl.verificationMode:`:: *Default: full* Controls the verification of certificates presented by Elasticsearch. Valid values are `none`, `certificate`, and `full`.
`full` performs hostname verification, and `certificate` does not.

`elasticsearch.ssl.alwaysPresentCertificate:`:: *Default: false* Controls whether to always present the certificate specified
by `elasticsearch.ssl.certificate` when requested. This applies to all requests to Elasticsearch, including requests that are
proxied for end-users. Setting this to `true` when Elasticsearch is using certificates to authenticate users can lead to proxied
requests for end-users being executed as the identity tied to the configured certificate.

`elasticsearch.startupTimeout:`:: *Default: 5000* Time in milliseconds to wait for Elasticsearch at Kibana startup before
retrying.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@
*/

import expect from 'expect.js';
import fs from 'fs';
import { promisify } from 'bluebird';
import { getElasticsearchProxyConfig } from '../elasticsearch_proxy_config';
import https from 'https';
import http from 'http';
import sinon from 'sinon';

const readFileAsync = promisify(fs.readFile, fs);

describe('plugins/console', function () {
describe('#getElasticsearchProxyConfig', function () {

Expand Down Expand Up @@ -118,22 +122,73 @@ describe('plugins/console', function () {
expect(agent.options.ca).to.contain('test ca certificate\n');
});

it(`doesn't set cert and key when certificate and key paths are specified`, function () {
setElasticsearchConfig('ssl.certificate', __dirname + '/fixtures/cert.crt');
setElasticsearchConfig('ssl.key', __dirname + '/fixtures/cert.key');

const { agent } = getElasticsearchProxyConfig(server);
expect(agent.options.cert).to.be(undefined);
expect(agent.options.key).to.be(undefined);
describe('when alwaysPresentCertificate is false', () => {
it(`doesn't set cert and key when certificate and key paths are specified`, function () {
setElasticsearchConfig('ssl.alwaysPresentCertificate', false);
setElasticsearchConfig('ssl.certificate', __dirname + '/fixtures/cert.crt');
setElasticsearchConfig('ssl.key', __dirname + '/fixtures/cert.key');

const { agent } = getElasticsearchProxyConfig(server);
expect(agent.options.cert).to.be(undefined);
expect(agent.options.key).to.be(undefined);
});

it(`doesn't set passphrase when certificate, key and keyPassphrase are specified`, function () {
setElasticsearchConfig('ssl.alwaysPresentCertificate', false);
setElasticsearchConfig('ssl.certificate', __dirname + '/fixtures/cert.crt');
setElasticsearchConfig('ssl.key', __dirname + '/fixtures/cert.key');
setElasticsearchConfig('ssl.keyPassphrase', 'secret');

const { agent } = getElasticsearchProxyConfig(server);
expect(agent.options.passphrase).to.be(undefined);
});
});

it(`doesn't set passphrase when certificate, key and keyPassphrase are specified`, function () {
setElasticsearchConfig('ssl.certificate', __dirname + '/fixtures/cert.crt');
setElasticsearchConfig('ssl.key', __dirname + '/fixtures/cert.key');
setElasticsearchConfig('ssl.keyPassphrase', 'secret');
describe('when alwaysPresentCertificate is true', () => {
it(`sets cert and key when certificate and key paths are specified`, async function () {
const certificatePath = __dirname + '/fixtures/cert.crt';
const keyPath = __dirname + '/fixtures/cert.key';
setElasticsearchConfig('ssl.alwaysPresentCertificate', true);
setElasticsearchConfig('ssl.certificate', certificatePath);
setElasticsearchConfig('ssl.key', keyPath);

const { agent } = getElasticsearchProxyConfig(server);
expect(agent.options.cert).to.be(await readFileAsync(certificatePath, 'utf8'));
expect(agent.options.key).to.be(await readFileAsync(keyPath, 'utf8'));
});

it(`sets passphrase when certificate, key and keyPassphrase are specified`, function () {
setElasticsearchConfig('ssl.alwaysPresentCertificate', true);
setElasticsearchConfig('ssl.certificate', __dirname + '/fixtures/cert.crt');
setElasticsearchConfig('ssl.key', __dirname + '/fixtures/cert.key');
setElasticsearchConfig('ssl.keyPassphrase', 'secret');

const { agent } = getElasticsearchProxyConfig(server);
expect(agent.options.passphrase).to.be('secret');
});

it(`doesn't set cert when only certificate path is specified`, async function () {
const certificatePath = __dirname + '/fixtures/cert.crt';
setElasticsearchConfig('ssl.alwaysPresentCertificate', true);
setElasticsearchConfig('ssl.certificate', certificatePath);
setElasticsearchConfig('ssl.key', undefined);

const { agent } = getElasticsearchProxyConfig(server);
expect(agent.options.cert).to.be(undefined);
expect(agent.options.key).to.be(undefined);
});

it(`doesn't set key when only key path is specified`, async function () {
const keyPath = __dirname + '/fixtures/cert.key';
setElasticsearchConfig('ssl.alwaysPresentCertificate', true);
setElasticsearchConfig('ssl.certificate', undefined);
setElasticsearchConfig('ssl.key', keyPath);

const { agent } = getElasticsearchProxyConfig(server);
expect(agent.options.cert).to.be(undefined);
expect(agent.options.key).to.be(undefined);
});

const { agent } = getElasticsearchProxyConfig(server);
expect(agent.options.passphrase).to.be(undefined);
});
});
});
Expand Down
10 changes: 10 additions & 0 deletions src/core_plugins/console/server/elasticsearch_proxy_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ const createAgent = (server) => {
agentOptions.ca = config.get('elasticsearch.ssl.certificateAuthorities').map(readFile);
}

if (
config.get('elasticsearch.ssl.alwaysPresentCertificate') &&
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');
}

return new https.Agent(agentOptions);
};

Expand Down
3 changes: 2 additions & 1 deletion src/core_plugins/elasticsearch/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export default function (kibana) {
certificateAuthorities: array().single().items(string()),
certificate: string(),
key: string(),
keyPassphrase: string()
keyPassphrase: string(),
alwaysPresentCertificate: boolean().default(false),
}).default();

return object({
Expand Down
5 changes: 4 additions & 1 deletion src/core_plugins/elasticsearch/lib/cluster.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ export class Cluster {

this._clients = new Set();
this._client = this.createClient();
this._noAuthClient = this.createClient({ auth: false }, { ignoreCertAndKey: true });
this._noAuthClient = this.createClient(
{ auth: false },
{ ignoreCertAndKey: !this.getSsl().alwaysPresentCertificate }
);

return this;
}
Expand Down
3 changes: 2 additions & 1 deletion src/core_plugins/elasticsearch/lib/create_agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ export default function (config) {

if (!/^https/.test(target.protocol)) return new http.Agent();

return new https.Agent(parseConfig(config, { ignoreCertAndKey: true }).ssl);
const ignoreCertAndKey = !get(config, 'ssl.alwaysPresentCertificate');
return new https.Agent(parseConfig(config, { ignoreCertAndKey }).ssl);
}
3 changes: 2 additions & 1 deletion x-pack/plugins/monitoring/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ export const config = (Joi) => {
certificateAuthorities: array().single().items(string()),
certificate: string(),
key: string(),
keyPassphrase: string()
keyPassphrase: string(),
alwaysPresentCertificate: boolean().default(false),
}).default(),
apiVersion: string().default('master')
}).default()
Expand Down

0 comments on commit ec26adf

Please sign in to comment.