Kibana request headers (#79218)

* Adding X-Kibana header for the legacy client requests

* Specifying `X-Kibana: true` header for all requests coming from Kibana

* Dev Tools now override the X-Kibana header to false

* DevTools doesn't need to do anything, it's not using the ES client

* Switching from `X-Kibana: true` to `User-Agent: Kibana`

* Switching from `X-Kibana: true` to `User-Agent: Kibana`

* Adding a constant

* Starting to add unit tests...

We currently allow end-users to set whatever headers they'd like to be
forwarded to Elasticsearch with `elasticsearch.customHeaders` and
`elasticsearch.requestHeadersWhitelist`. This is potentially problematic
with us always specifying `User-Agent: kibana` as it could interfere
with what our end-users have done...

* Switching from user-agent to X-elastic-product-origin

* Adding some tests

* Adding and updating the legacy client unit tests
T#

* /s/KIBANA_HEADERS/DEFAULT_HEADERS and a deepFreeze

* Adding comment for why `x-elastic-product-origin` exists
This commit is contained in:
Brandon Kobel 2020-10-06 06:40:08 -07:00 committed by GitHub
parent 9794188cbf
commit 1ad68fdef7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 470 additions and 309 deletions

View file

@ -19,6 +19,7 @@
import { duration } from 'moment';
import { ElasticsearchClientConfig, parseClientOptions } from './client_config';
import { DEFAULT_HEADERS } from '../default_headers';
const createConfig = (
parts: Partial<ElasticsearchClientConfig> = {}
@ -36,6 +37,18 @@ const createConfig = (
};
describe('parseClientOptions', () => {
it('includes headers designing the HTTP request as originating from Kibana by default', () => {
const config = createConfig({});
expect(parseClientOptions(config, false)).toEqual(
expect.objectContaining({
headers: {
...DEFAULT_HEADERS,
},
})
);
});
describe('basic options', () => {
it('`customHeaders` option', () => {
const config = createConfig({
@ -48,6 +61,7 @@ describe('parseClientOptions', () => {
expect(parseClientOptions(config, false)).toEqual(
expect.objectContaining({
headers: {
...DEFAULT_HEADERS,
foo: 'bar',
hello: 'dolly',
},
@ -55,6 +69,25 @@ describe('parseClientOptions', () => {
);
});
it('`customHeaders` take precedence to default kibana headers', () => {
const customHeader = {
[Object.keys(DEFAULT_HEADERS)[0]]: 'foo',
};
const config = createConfig({
customHeaders: {
...customHeader,
},
});
expect(parseClientOptions(config, false)).toEqual(
expect.objectContaining({
headers: {
...customHeader,
},
})
);
});
it('`keepAlive` option', () => {
expect(parseClientOptions(createConfig({ keepAlive: true }), false)).toEqual(
expect.objectContaining({ agent: { keepAlive: true } })

View file

@ -22,6 +22,7 @@ import { URL } from 'url';
import { Duration } from 'moment';
import { ClientOptions, NodeOptions } from '@elastic/elasticsearch';
import { ElasticsearchConfig } from '../elasticsearch_config';
import { DEFAULT_HEADERS } from '../default_headers';
/**
* Configuration options to be used to create a {@link IClusterClient | cluster client} using the
@ -61,7 +62,10 @@ export function parseClientOptions(
const clientOptions: ClientOptions = {
sniffOnStart: config.sniffOnStart,
sniffOnConnectionFault: config.sniffOnConnectionFault,
headers: config.customHeaders,
headers: {
...DEFAULT_HEADERS,
...config.customHeaders,
},
};
if (config.pingTimeout != null) {

View file

@ -24,6 +24,7 @@ import { GetAuthHeaders } from '../../http';
import { elasticsearchClientMock } from './mocks';
import { ClusterClient } from './cluster_client';
import { ElasticsearchClientConfig } from './client_config';
import { DEFAULT_HEADERS } from '../default_headers';
const createConfig = (
parts: Partial<ElasticsearchClientConfig> = {}
@ -127,7 +128,7 @@ describe('ClusterClient', () => {
expect(scopedClient.child).toHaveBeenCalledTimes(1);
expect(scopedClient.child).toHaveBeenCalledWith({
headers: { foo: 'bar', 'x-opaque-id': expect.any(String) },
headers: { ...DEFAULT_HEADERS, foo: 'bar', 'x-opaque-id': expect.any(String) },
});
});
@ -147,7 +148,7 @@ describe('ClusterClient', () => {
expect(scopedClient.child).toHaveBeenCalledTimes(1);
expect(scopedClient.child).toHaveBeenCalledWith({
headers: { authorization: 'auth', 'x-opaque-id': expect.any(String) },
headers: { ...DEFAULT_HEADERS, authorization: 'auth', 'x-opaque-id': expect.any(String) },
});
});
@ -171,7 +172,7 @@ describe('ClusterClient', () => {
expect(scopedClient.child).toHaveBeenCalledTimes(1);
expect(scopedClient.child).toHaveBeenCalledWith({
headers: { authorization: 'auth', 'x-opaque-id': expect.any(String) },
headers: { ...DEFAULT_HEADERS, authorization: 'auth', 'x-opaque-id': expect.any(String) },
});
});
@ -193,6 +194,7 @@ describe('ClusterClient', () => {
expect(scopedClient.child).toHaveBeenCalledTimes(1);
expect(scopedClient.child).toHaveBeenCalledWith({
headers: {
...DEFAULT_HEADERS,
foo: 'bar',
hello: 'dolly',
'x-opaque-id': expect.any(String),
@ -214,6 +216,7 @@ describe('ClusterClient', () => {
expect(scopedClient.child).toHaveBeenCalledTimes(1);
expect(scopedClient.child).toHaveBeenCalledWith({
headers: {
...DEFAULT_HEADERS,
'x-opaque-id': 'my-fake-id',
},
});
@ -239,6 +242,7 @@ describe('ClusterClient', () => {
expect(scopedClient.child).toHaveBeenCalledTimes(1);
expect(scopedClient.child).toHaveBeenCalledWith({
headers: {
...DEFAULT_HEADERS,
foo: 'auth',
hello: 'dolly',
'x-opaque-id': expect.any(String),
@ -266,6 +270,7 @@ describe('ClusterClient', () => {
expect(scopedClient.child).toHaveBeenCalledTimes(1);
expect(scopedClient.child).toHaveBeenCalledWith({
headers: {
...DEFAULT_HEADERS,
foo: 'request',
hello: 'dolly',
'x-opaque-id': expect.any(String),
@ -273,6 +278,52 @@ describe('ClusterClient', () => {
});
});
it('respect the precedence of config headers over default headers', () => {
const headerKey = Object.keys(DEFAULT_HEADERS)[0];
const config = createConfig({
customHeaders: {
[headerKey]: 'foo',
},
});
getAuthHeaders.mockReturnValue({});
const clusterClient = new ClusterClient(config, logger, getAuthHeaders);
const request = httpServerMock.createKibanaRequest();
clusterClient.asScoped(request);
expect(scopedClient.child).toHaveBeenCalledTimes(1);
expect(scopedClient.child).toHaveBeenCalledWith({
headers: {
[headerKey]: 'foo',
'x-opaque-id': expect.any(String),
},
});
});
it('respect the precedence of request headers over default headers', () => {
const headerKey = Object.keys(DEFAULT_HEADERS)[0];
const config = createConfig({
requestHeadersWhitelist: [headerKey],
});
getAuthHeaders.mockReturnValue({});
const clusterClient = new ClusterClient(config, logger, getAuthHeaders);
const request = httpServerMock.createKibanaRequest({
headers: { [headerKey]: 'foo' },
});
clusterClient.asScoped(request);
expect(scopedClient.child).toHaveBeenCalledTimes(1);
expect(scopedClient.child).toHaveBeenCalledWith({
headers: {
[headerKey]: 'foo',
'x-opaque-id': expect.any(String),
},
});
});
it('respect the precedence of x-opaque-id header over config headers', () => {
const config = createConfig({
customHeaders: {
@ -292,6 +343,7 @@ describe('ClusterClient', () => {
expect(scopedClient.child).toHaveBeenCalledTimes(1);
expect(scopedClient.child).toHaveBeenCalledWith({
headers: {
...DEFAULT_HEADERS,
'x-opaque-id': 'from request',
},
});
@ -315,7 +367,7 @@ describe('ClusterClient', () => {
expect(scopedClient.child).toHaveBeenCalledTimes(1);
expect(scopedClient.child).toHaveBeenCalledWith({
headers: { authorization: 'auth' },
headers: { ...DEFAULT_HEADERS, authorization: 'auth' },
});
});
@ -339,7 +391,7 @@ describe('ClusterClient', () => {
expect(scopedClient.child).toHaveBeenCalledTimes(1);
expect(scopedClient.child).toHaveBeenCalledWith({
headers: { foo: 'bar' },
headers: { ...DEFAULT_HEADERS, foo: 'bar' },
});
});
});

View file

@ -26,6 +26,7 @@ import { ElasticsearchClient } from './types';
import { configureClient } from './configure_client';
import { ElasticsearchClientConfig } from './client_config';
import { ScopedClusterClient, IScopedClusterClient } from './scoped_cluster_client';
import { DEFAULT_HEADERS } from '../default_headers';
const noop = () => undefined;
@ -108,6 +109,7 @@ export class ClusterClient implements ICustomClusterClient {
}
return {
...DEFAULT_HEADERS,
...this.config.customHeaders,
...scopedHeaders,
};

View file

@ -0,0 +1,27 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { deepFreeze } from '@kbn/std';
export const DEFAULT_HEADERS = deepFreeze({
// Elasticsearch uses this to identify when a request is coming from Kibana, to allow Kibana to
// access system indices using the standard ES APIs without logging a warning. After migrating to
// use the new system index APIs, this header can be removed.
'x-elastic-product-origin': 'kibana',
});

View file

@ -23,6 +23,7 @@ import {
LegacyElasticsearchClientConfig,
parseElasticsearchClientConfig,
} from './elasticsearch_client_config';
import { DEFAULT_HEADERS } from '../default_headers';
const logger = loggingSystemMock.create();
afterEach(() => jest.clearAllMocks());
@ -41,26 +42,27 @@ test('parses minimally specified config', () => {
logger.get()
)
).toMatchInlineSnapshot(`
Object {
"apiVersion": "master",
"hosts": Array [
Object {
"headers": Object {
"xsrf": "something",
},
"host": "localhost",
"path": "/elasticsearch",
"port": "80",
"protocol": "http:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": false,
"sniffOnStart": false,
}
`);
"apiVersion": "master",
"hosts": Array [
Object {
"headers": Object {
"x-elastic-product-origin": "kibana",
"xsrf": "something",
},
"host": "localhost",
"path": "/elasticsearch",
"port": "80",
"protocol": "http:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": false,
"sniffOnStart": false,
}
`);
});
test('parses fully specified config', () => {
@ -104,63 +106,66 @@ test('parses fully specified config', () => {
expect(elasticsearchConfig.ssl).not.toBe(elasticsearchClientConfig.ssl);
expect(elasticsearchClientConfig).toMatchInlineSnapshot(`
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"auth": "elastic:changeme",
"headers": Object {
"xsrf": "something",
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"auth": "elastic:changeme",
"headers": Object {
"x-elastic-product-origin": "kibana",
"xsrf": "something",
},
"host": "localhost",
"path": "/elasticsearch",
"port": "80",
"protocol": "http:",
"query": null,
},
Object {
"auth": "elastic:changeme",
"headers": Object {
"x-elastic-product-origin": "kibana",
"xsrf": "something",
},
"host": "domain.com",
"path": "/elasticsearch",
"port": "1234",
"protocol": "http:",
"query": null,
},
Object {
"auth": "elastic:changeme",
"headers": Object {
"x-elastic-product-origin": "kibana",
"xsrf": "something",
},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"pingTimeout": 12345,
"requestTimeout": 54321,
"sniffInterval": 11223344,
"sniffOnConnectionFault": true,
"sniffOnStart": true,
"ssl": Object {
"ca": Array [
"content-of-ca-path-1",
"content-of-ca-path-2",
],
"cert": "content-of-certificate-path",
"checkServerIdentity": [Function],
"key": "content-of-key-path",
"passphrase": "key-pass",
"rejectUnauthorized": true,
},
"host": "localhost",
"path": "/elasticsearch",
"port": "80",
"protocol": "http:",
"query": null,
},
Object {
"auth": "elastic:changeme",
"headers": Object {
"xsrf": "something",
},
"host": "domain.com",
"path": "/elasticsearch",
"port": "1234",
"protocol": "http:",
"query": null,
},
Object {
"auth": "elastic:changeme",
"headers": Object {
"xsrf": "something",
},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"pingTimeout": 12345,
"requestTimeout": 54321,
"sniffInterval": 11223344,
"sniffOnConnectionFault": true,
"sniffOnStart": true,
"ssl": Object {
"ca": Array [
"content-of-ca-path-1",
"content-of-ca-path-2",
],
"cert": "content-of-certificate-path",
"checkServerIdentity": [Function],
"key": "content-of-key-path",
"passphrase": "key-pass",
"rejectUnauthorized": true,
},
}
`);
}
`);
});
test('parses config timeouts of moment.Duration type', () => {
@ -181,29 +186,30 @@ test('parses config timeouts of moment.Duration type', () => {
logger.get()
)
).toMatchInlineSnapshot(`
Object {
"apiVersion": "master",
"hosts": Array [
Object {
"headers": Object {
"xsrf": "something",
},
"host": "localhost",
"path": "/elasticsearch",
"port": "9200",
"protocol": "http:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"pingTimeout": 100,
"requestTimeout": 30000,
"sniffInterval": 60000,
"sniffOnConnectionFault": false,
"sniffOnStart": false,
}
`);
"apiVersion": "master",
"hosts": Array [
Object {
"headers": Object {
"x-elastic-product-origin": "kibana",
"xsrf": "something",
},
"host": "localhost",
"path": "/elasticsearch",
"port": "9200",
"protocol": "http:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"pingTimeout": 100,
"requestTimeout": 30000,
"sniffInterval": 60000,
"sniffOnConnectionFault": false,
"sniffOnStart": false,
}
`);
});
describe('#auth', () => {
@ -225,36 +231,38 @@ describe('#auth', () => {
{ auth: false }
)
).toMatchInlineSnapshot(`
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"headers": Object {
"xsrf": "something",
},
"host": "localhost",
"path": "/elasticsearch",
"port": "80",
"protocol": "http:",
"query": null,
},
Object {
"headers": Object {
"xsrf": "something",
},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": true,
"sniffOnStart": true,
}
`);
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"headers": Object {
"x-elastic-product-origin": "kibana",
"xsrf": "something",
},
"host": "localhost",
"path": "/elasticsearch",
"port": "80",
"protocol": "http:",
"query": null,
},
Object {
"headers": Object {
"x-elastic-product-origin": "kibana",
"xsrf": "something",
},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": true,
"sniffOnStart": true,
}
`);
});
test('is not set if username is not specified', () => {
@ -274,26 +282,27 @@ Object {
{ auth: true }
)
).toMatchInlineSnapshot(`
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"headers": Object {
"xsrf": "something",
},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": true,
"sniffOnStart": true,
}
`);
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"headers": Object {
"x-elastic-product-origin": "kibana",
"xsrf": "something",
},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": true,
"sniffOnStart": true,
}
`);
});
test('is not set if password is not specified', () => {
@ -313,26 +322,48 @@ Object {
{ auth: true }
)
).toMatchInlineSnapshot(`
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"headers": Object {
"xsrf": "something",
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"headers": Object {
"x-elastic-product-origin": "kibana",
"xsrf": "something",
},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": true,
"sniffOnStart": true,
}
`);
});
});
describe('#customHeaders', () => {
test('override the default headers', () => {
const headerKey = Object.keys(DEFAULT_HEADERS)[0];
const parsedConfig = parseElasticsearchClientConfig(
{
apiVersion: 'master',
customHeaders: { [headerKey]: 'foo' },
logQueries: false,
sniffOnStart: false,
sniffOnConnectionFault: false,
hosts: ['http://localhost/elasticsearch'],
requestHeadersWhitelist: [],
},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": true,
"sniffOnStart": true,
}
`);
logger.get()
);
expect(parsedConfig.hosts[0].headers).toEqual({
[headerKey]: 'foo',
});
});
});
@ -361,24 +392,24 @@ describe('#log', () => {
expect(typeof esLogger.close).toBe('function');
expect(loggingSystemMock.collect(logger)).toMatchInlineSnapshot(`
Object {
"debug": Array [],
"error": Array [
Array [
"some-error",
],
],
"fatal": Array [],
"info": Array [],
"log": Array [],
"trace": Array [],
"warn": Array [
Array [
"some-warning",
],
],
}
`);
Object {
"debug": Array [],
"error": Array [
Array [
"some-error",
],
],
"fatal": Array [],
"info": Array [],
"log": Array [],
"trace": Array [],
"warn": Array [
Array [
"some-warning",
],
],
}
`);
});
test('default logger with #logQueries = true', () => {
@ -407,35 +438,35 @@ Object {
expect(typeof esLogger.close).toBe('function');
expect(loggingSystemMock.collect(logger)).toMatchInlineSnapshot(`
Object {
"debug": Array [
Array [
"304
METHOD /some-path
?query=2",
Object {
"tags": Array [
"query",
"debug": Array [
Array [
"304
METHOD /some-path
?query=2",
Object {
"tags": Array [
"query",
],
},
],
],
},
],
],
"error": Array [
Array [
"some-error",
],
],
"fatal": Array [],
"info": Array [],
"log": Array [],
"trace": Array [],
"warn": Array [
Array [
"some-warning",
],
],
}
`);
"error": Array [
Array [
"some-error",
],
],
"fatal": Array [],
"info": Array [],
"log": Array [],
"trace": Array [],
"warn": Array [
Array [
"some-warning",
],
],
}
`);
});
test('custom logger', () => {
@ -476,28 +507,30 @@ describe('#ssl', () => {
logger.get()
)
).toMatchInlineSnapshot(`
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"headers": Object {},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": true,
"sniffOnStart": true,
"ssl": Object {
"ca": undefined,
"rejectUnauthorized": false,
},
}
`);
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"headers": Object {
"x-elastic-product-origin": "kibana",
},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": true,
"sniffOnStart": true,
"ssl": Object {
"ca": undefined,
"rejectUnauthorized": false,
},
}
`);
});
test('#verificationMode = certificate', () => {
@ -521,29 +554,31 @@ Object {
).toBeUndefined();
expect(clientConfig).toMatchInlineSnapshot(`
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"headers": Object {},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": true,
"sniffOnStart": true,
"ssl": Object {
"ca": undefined,
"checkServerIdentity": [Function],
"rejectUnauthorized": true,
},
}
`);
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"headers": Object {
"x-elastic-product-origin": "kibana",
},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": true,
"sniffOnStart": true,
"ssl": Object {
"ca": undefined,
"checkServerIdentity": [Function],
"rejectUnauthorized": true,
},
}
`);
});
test('#verificationMode = full', () => {
@ -562,28 +597,30 @@ Object {
logger.get()
)
).toMatchInlineSnapshot(`
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"headers": Object {},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": true,
"sniffOnStart": true,
"ssl": Object {
"ca": undefined,
"rejectUnauthorized": true,
},
}
`);
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"headers": Object {
"x-elastic-product-origin": "kibana",
},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": true,
"sniffOnStart": true,
"ssl": Object {
"ca": undefined,
"rejectUnauthorized": true,
},
}
`);
});
test('#verificationMode is unknown', () => {
@ -628,30 +665,32 @@ Object {
{ ignoreCertAndKey: true }
)
).toMatchInlineSnapshot(`
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"headers": Object {},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": true,
"sniffOnStart": true,
"ssl": Object {
"ca": Array [
"content-of-ca-path",
],
"checkServerIdentity": [Function],
"rejectUnauthorized": true,
},
}
`);
Object {
"apiVersion": "v7.0.0",
"hosts": Array [
Object {
"headers": Object {
"x-elastic-product-origin": "kibana",
},
"host": "es.local",
"path": "/",
"port": "443",
"protocol": "https:",
"query": null,
},
],
"keepAlive": true,
"log": [Function],
"sniffOnConnectionFault": true,
"sniffOnStart": true,
"ssl": Object {
"ca": Array [
"content-of-ca-path",
],
"checkServerIdentity": [Function],
"rejectUnauthorized": true,
},
}
`);
});
});

View file

@ -25,6 +25,7 @@ import url from 'url';
import { pick } from '@kbn/std';
import { Logger } from '../../logging';
import { ElasticsearchConfig } from '../elasticsearch_config';
import { DEFAULT_HEADERS } from '../default_headers';
/**
* @privateRemarks Config that consumers can pass to the Elasticsearch JS client is complex and includes
@ -130,7 +131,10 @@ export function parseElasticsearchClientConfig(
protocol: uri.protocol,
path: uri.pathname,
query: uri.query,
headers: config.customHeaders,
headers: {
...DEFAULT_HEADERS,
...config.customHeaders,
},
};
if (needsAuth) {