Deprecate using elasticsearch.ssl.certificate
without elasticsearch.ssl.key
and vice versa (#54392)
This commit is contained in:
parent
8ef560902b
commit
80b6dd8e15
|
@ -208,35 +208,4 @@ describe('core deprecations', () => {
|
|||
).toEqual([`worker-src blob:`]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('elasticsearchUsernameDeprecation', () => {
|
||||
it('logs a warning if elasticsearch.username is set to "elastic"', () => {
|
||||
const { messages } = applyCoreDeprecations({
|
||||
elasticsearch: {
|
||||
username: 'elastic',
|
||||
},
|
||||
});
|
||||
expect(messages).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"Setting elasticsearch.username to \\"elastic\\" is deprecated. You should use the \\"kibana\\" user instead.",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('does not log a warning if elasticsearch.username is set to something besides "elastic"', () => {
|
||||
const { messages } = applyCoreDeprecations({
|
||||
elasticsearch: {
|
||||
username: 'otheruser',
|
||||
},
|
||||
});
|
||||
expect(messages).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('does not log a warning if elasticsearch.username is unset', () => {
|
||||
const { messages } = applyCoreDeprecations({
|
||||
elasticsearch: {},
|
||||
});
|
||||
expect(messages).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -91,16 +91,6 @@ const cspRulesDeprecation: ConfigDeprecation = (settings, fromPath, log) => {
|
|||
return settings;
|
||||
};
|
||||
|
||||
const elasticsearchUsernameDeprecation: ConfigDeprecation = (settings, _fromPath, log) => {
|
||||
const username: string | undefined = get(settings, 'elasticsearch.username');
|
||||
if (username === 'elastic') {
|
||||
log(
|
||||
`Setting elasticsearch.username to "elastic" is deprecated. You should use the "kibana" user instead.`
|
||||
);
|
||||
}
|
||||
return settings;
|
||||
};
|
||||
|
||||
export const coreDeprecationProvider: ConfigDeprecationProvider = ({
|
||||
unusedFromRoot,
|
||||
renameFromRoot,
|
||||
|
@ -120,5 +110,4 @@ export const coreDeprecationProvider: ConfigDeprecationProvider = ({
|
|||
dataPathDeprecation,
|
||||
rewriteBasePathDeprecation,
|
||||
cspRulesDeprecation,
|
||||
elasticsearchUsernameDeprecation,
|
||||
];
|
||||
|
|
|
@ -23,19 +23,32 @@ import {
|
|||
mockReadPkcs12Truststore,
|
||||
} from './elasticsearch_config.test.mocks';
|
||||
|
||||
import { ElasticsearchConfig, config, ElasticsearchConfigType } from './elasticsearch_config';
|
||||
import { loggingServiceMock } from '../mocks';
|
||||
import { Logger } from '../logging';
|
||||
import { ElasticsearchConfig, config } from './elasticsearch_config';
|
||||
import { applyDeprecations, configDeprecationFactory } from '../config/deprecation';
|
||||
|
||||
const createElasticsearchConfig = (rawConfig: ElasticsearchConfigType, log?: Logger) => {
|
||||
if (!log) {
|
||||
log = loggingServiceMock.create().get('config');
|
||||
}
|
||||
return new ElasticsearchConfig(rawConfig, log);
|
||||
const CONFIG_PATH = 'elasticsearch';
|
||||
|
||||
const applyElasticsearchDeprecations = (settings: Record<string, any> = {}) => {
|
||||
const deprecations = config.deprecations!(configDeprecationFactory);
|
||||
const deprecationMessages: string[] = [];
|
||||
const _config: any = {};
|
||||
_config[CONFIG_PATH] = settings;
|
||||
const migrated = applyDeprecations(
|
||||
_config,
|
||||
deprecations.map(deprecation => ({
|
||||
deprecation,
|
||||
path: CONFIG_PATH,
|
||||
})),
|
||||
msg => deprecationMessages.push(msg)
|
||||
);
|
||||
return {
|
||||
messages: deprecationMessages,
|
||||
migrated,
|
||||
};
|
||||
};
|
||||
|
||||
test('set correct defaults', () => {
|
||||
const configValue = createElasticsearchConfig(config.schema.validate({}));
|
||||
const configValue = new ElasticsearchConfig(config.schema.validate({}));
|
||||
expect(configValue).toMatchInlineSnapshot(`
|
||||
ElasticsearchConfig {
|
||||
"apiVersion": "master",
|
||||
|
@ -70,17 +83,17 @@ test('set correct defaults', () => {
|
|||
});
|
||||
|
||||
test('#hosts accepts both string and array of strings', () => {
|
||||
let configValue = createElasticsearchConfig(
|
||||
let configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({ hosts: 'http://some.host:1234' })
|
||||
);
|
||||
expect(configValue.hosts).toEqual(['http://some.host:1234']);
|
||||
|
||||
configValue = createElasticsearchConfig(
|
||||
configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({ hosts: ['http://some.host:1234'] })
|
||||
);
|
||||
expect(configValue.hosts).toEqual(['http://some.host:1234']);
|
||||
|
||||
configValue = createElasticsearchConfig(
|
||||
configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({
|
||||
hosts: ['http://some.host:1234', 'https://some.another.host'],
|
||||
})
|
||||
|
@ -89,17 +102,17 @@ test('#hosts accepts both string and array of strings', () => {
|
|||
});
|
||||
|
||||
test('#requestHeadersWhitelist accepts both string and array of strings', () => {
|
||||
let configValue = createElasticsearchConfig(
|
||||
let configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({ requestHeadersWhitelist: 'token' })
|
||||
);
|
||||
expect(configValue.requestHeadersWhitelist).toEqual(['token']);
|
||||
|
||||
configValue = createElasticsearchConfig(
|
||||
configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({ requestHeadersWhitelist: ['token'] })
|
||||
);
|
||||
expect(configValue.requestHeadersWhitelist).toEqual(['token']);
|
||||
|
||||
configValue = createElasticsearchConfig(
|
||||
configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({
|
||||
requestHeadersWhitelist: ['token', 'X-Forwarded-Proto'],
|
||||
})
|
||||
|
@ -122,7 +135,7 @@ describe('reads files', () => {
|
|||
});
|
||||
|
||||
it('reads certificate authorities when ssl.keystore.path is specified', () => {
|
||||
const configValue = createElasticsearchConfig(
|
||||
const configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({ ssl: { keystore: { path: 'some-path' } } })
|
||||
);
|
||||
expect(mockReadPkcs12Keystore).toHaveBeenCalledTimes(1);
|
||||
|
@ -130,7 +143,7 @@ describe('reads files', () => {
|
|||
});
|
||||
|
||||
it('reads certificate authorities when ssl.truststore.path is specified', () => {
|
||||
const configValue = createElasticsearchConfig(
|
||||
const configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({ ssl: { truststore: { path: 'some-path' } } })
|
||||
);
|
||||
expect(mockReadPkcs12Truststore).toHaveBeenCalledTimes(1);
|
||||
|
@ -138,21 +151,21 @@ describe('reads files', () => {
|
|||
});
|
||||
|
||||
it('reads certificate authorities when ssl.certificateAuthorities is specified', () => {
|
||||
let configValue = createElasticsearchConfig(
|
||||
let configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({ ssl: { certificateAuthorities: 'some-path' } })
|
||||
);
|
||||
expect(mockReadFileSync).toHaveBeenCalledTimes(1);
|
||||
expect(configValue.ssl.certificateAuthorities).toEqual(['content-of-some-path']);
|
||||
|
||||
mockReadFileSync.mockClear();
|
||||
configValue = createElasticsearchConfig(
|
||||
configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({ ssl: { certificateAuthorities: ['some-path'] } })
|
||||
);
|
||||
expect(mockReadFileSync).toHaveBeenCalledTimes(1);
|
||||
expect(configValue.ssl.certificateAuthorities).toEqual(['content-of-some-path']);
|
||||
|
||||
mockReadFileSync.mockClear();
|
||||
configValue = createElasticsearchConfig(
|
||||
configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({
|
||||
ssl: { certificateAuthorities: ['some-path', 'another-path'] },
|
||||
})
|
||||
|
@ -165,7 +178,7 @@ describe('reads files', () => {
|
|||
});
|
||||
|
||||
it('reads certificate authorities when ssl.keystore.path, ssl.truststore.path, and ssl.certificateAuthorities are specified', () => {
|
||||
const configValue = createElasticsearchConfig(
|
||||
const configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({
|
||||
ssl: {
|
||||
keystore: { path: 'some-path' },
|
||||
|
@ -185,7 +198,7 @@ describe('reads files', () => {
|
|||
});
|
||||
|
||||
it('reads a private key and certificate when ssl.keystore.path is specified', () => {
|
||||
const configValue = createElasticsearchConfig(
|
||||
const configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({ ssl: { keystore: { path: 'some-path' } } })
|
||||
);
|
||||
expect(mockReadPkcs12Keystore).toHaveBeenCalledTimes(1);
|
||||
|
@ -194,7 +207,7 @@ describe('reads files', () => {
|
|||
});
|
||||
|
||||
it('reads a private key when ssl.key is specified', () => {
|
||||
const configValue = createElasticsearchConfig(
|
||||
const configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({ ssl: { key: 'some-path' } })
|
||||
);
|
||||
expect(mockReadFileSync).toHaveBeenCalledTimes(1);
|
||||
|
@ -202,7 +215,7 @@ describe('reads files', () => {
|
|||
});
|
||||
|
||||
it('reads a certificate when ssl.certificate is specified', () => {
|
||||
const configValue = createElasticsearchConfig(
|
||||
const configValue = new ElasticsearchConfig(
|
||||
config.schema.validate({ ssl: { certificate: 'some-path' } })
|
||||
);
|
||||
expect(mockReadFileSync).toHaveBeenCalledTimes(1);
|
||||
|
@ -225,8 +238,8 @@ describe('throws when config is invalid', () => {
|
|||
|
||||
it('throws if key is invalid', () => {
|
||||
const value = { ssl: { key: '/invalid/key' } };
|
||||
expect(() =>
|
||||
createElasticsearchConfig(config.schema.validate(value))
|
||||
expect(
|
||||
() => new ElasticsearchConfig(config.schema.validate(value))
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"ENOENT: no such file or directory, open '/invalid/key'"`
|
||||
);
|
||||
|
@ -234,8 +247,8 @@ describe('throws when config is invalid', () => {
|
|||
|
||||
it('throws if certificate is invalid', () => {
|
||||
const value = { ssl: { certificate: '/invalid/cert' } };
|
||||
expect(() =>
|
||||
createElasticsearchConfig(config.schema.validate(value))
|
||||
expect(
|
||||
() => new ElasticsearchConfig(config.schema.validate(value))
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"ENOENT: no such file or directory, open '/invalid/cert'"`
|
||||
);
|
||||
|
@ -243,34 +256,40 @@ describe('throws when config is invalid', () => {
|
|||
|
||||
it('throws if certificateAuthorities is invalid', () => {
|
||||
const value = { ssl: { certificateAuthorities: '/invalid/ca' } };
|
||||
expect(() =>
|
||||
createElasticsearchConfig(config.schema.validate(value))
|
||||
expect(
|
||||
() => new ElasticsearchConfig(config.schema.validate(value))
|
||||
).toThrowErrorMatchingInlineSnapshot(`"ENOENT: no such file or directory, open '/invalid/ca'"`);
|
||||
});
|
||||
|
||||
it('throws if keystore path is invalid', () => {
|
||||
const value = { ssl: { keystore: { path: '/invalid/keystore' } } };
|
||||
expect(() =>
|
||||
createElasticsearchConfig(config.schema.validate(value))
|
||||
expect(
|
||||
() => new ElasticsearchConfig(config.schema.validate(value))
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"ENOENT: no such file or directory, open '/invalid/keystore'"`
|
||||
);
|
||||
});
|
||||
|
||||
it('throws if keystore does not contain a key or certificate', () => {
|
||||
it('throws if keystore does not contain a key', () => {
|
||||
mockReadPkcs12Keystore.mockReturnValueOnce({});
|
||||
const value = { ssl: { keystore: { path: 'some-path' } } };
|
||||
expect(() =>
|
||||
createElasticsearchConfig(config.schema.validate(value))
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Did not find key or certificate in Elasticsearch keystore."`
|
||||
);
|
||||
expect(
|
||||
() => new ElasticsearchConfig(config.schema.validate(value))
|
||||
).toThrowErrorMatchingInlineSnapshot(`"Did not find key in Elasticsearch keystore."`);
|
||||
});
|
||||
|
||||
it('throws if keystore does not contain a certificate', () => {
|
||||
mockReadPkcs12Keystore.mockReturnValueOnce({ key: 'foo' });
|
||||
const value = { ssl: { keystore: { path: 'some-path' } } };
|
||||
expect(
|
||||
() => new ElasticsearchConfig(config.schema.validate(value))
|
||||
).toThrowErrorMatchingInlineSnapshot(`"Did not find certificate in Elasticsearch keystore."`);
|
||||
});
|
||||
|
||||
it('throws if truststore path is invalid', () => {
|
||||
const value = { ssl: { keystore: { path: '/invalid/truststore' } } };
|
||||
expect(() =>
|
||||
createElasticsearchConfig(config.schema.validate(value))
|
||||
expect(
|
||||
() => new ElasticsearchConfig(config.schema.validate(value))
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"ENOENT: no such file or directory, open '/invalid/truststore'"`
|
||||
);
|
||||
|
@ -291,31 +310,47 @@ describe('throws when config is invalid', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('logs warnings', () => {
|
||||
let logger: ReturnType<typeof loggingServiceMock.create>;
|
||||
let log: Logger;
|
||||
|
||||
beforeAll(() => {
|
||||
mockReadFileSync.mockResolvedValue('foo');
|
||||
describe('deprecations', () => {
|
||||
it('logs a warning if elasticsearch.username is set to "elastic"', () => {
|
||||
const { messages } = applyElasticsearchDeprecations({ username: 'elastic' });
|
||||
expect(messages).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"Setting [${CONFIG_PATH}.username] to \\"elastic\\" is deprecated. You should use the \\"kibana\\" user instead.",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
logger = loggingServiceMock.create();
|
||||
log = logger.get('config');
|
||||
it('does not log a warning if elasticsearch.username is set to something besides "elastic"', () => {
|
||||
const { messages } = applyElasticsearchDeprecations({ username: 'otheruser' });
|
||||
expect(messages).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('warns if ssl.key is set and ssl.certificate is not', () => {
|
||||
createElasticsearchConfig(config.schema.validate({ ssl: { key: 'some-path' } }), log);
|
||||
expect(loggingServiceMock.collect(logger).warn[0][0]).toMatchInlineSnapshot(
|
||||
`"Detected a key without a certificate; mutual TLS authentication is disabled."`
|
||||
);
|
||||
it('does not log a warning if elasticsearch.username is unset', () => {
|
||||
const { messages } = applyElasticsearchDeprecations({});
|
||||
expect(messages).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('warns if ssl.certificate is set and ssl.key is not', () => {
|
||||
createElasticsearchConfig(config.schema.validate({ ssl: { certificate: 'some-path' } }), log);
|
||||
expect(loggingServiceMock.collect(logger).warn[0][0]).toMatchInlineSnapshot(
|
||||
`"Detected a certificate without a key; mutual TLS authentication is disabled."`
|
||||
);
|
||||
it('logs a warning if ssl.key is set and ssl.certificate is not', () => {
|
||||
const { messages } = applyElasticsearchDeprecations({ ssl: { key: '' } });
|
||||
expect(messages).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"Setting [${CONFIG_PATH}.ssl.key] without [${CONFIG_PATH}.ssl.certificate] is deprecated. This has no effect, you should use both settings to enable TLS client authentication to Elasticsearch.",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('logs a warning if ssl.certificate is set and ssl.key is not', () => {
|
||||
const { messages } = applyElasticsearchDeprecations({ ssl: { certificate: '' } });
|
||||
expect(messages).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"Setting [${CONFIG_PATH}.ssl.certificate] without [${CONFIG_PATH}.ssl.key] is deprecated. This has no effect, you should use both settings to enable TLS client authentication to Elasticsearch.",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('does not log a warning if both ssl.key and ssl.certificate are set', () => {
|
||||
const { messages } = applyElasticsearchDeprecations({ ssl: { key: '', certificate: '' } });
|
||||
expect(messages).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -20,92 +20,120 @@
|
|||
import { schema, TypeOf } from '@kbn/config-schema';
|
||||
import { Duration } from 'moment';
|
||||
import { readFileSync } from 'fs';
|
||||
import { ConfigDeprecationProvider } from 'src/core/server';
|
||||
import { readPkcs12Keystore, readPkcs12Truststore } from '../../utils';
|
||||
import { Logger } from '../logging';
|
||||
import { ServiceConfigDescriptor } from '../internal_types';
|
||||
|
||||
const hostURISchema = schema.uri({ scheme: ['http', 'https'] });
|
||||
|
||||
export const DEFAULT_API_VERSION = 'master';
|
||||
|
||||
export type ElasticsearchConfigType = TypeOf<typeof config.schema>;
|
||||
export type ElasticsearchConfigType = TypeOf<typeof configSchema>;
|
||||
type SslConfigSchema = ElasticsearchConfigType['ssl'];
|
||||
|
||||
export const config = {
|
||||
path: 'elasticsearch',
|
||||
schema: schema.object({
|
||||
sniffOnStart: schema.boolean({ defaultValue: false }),
|
||||
sniffInterval: schema.oneOf([schema.duration(), schema.literal(false)], {
|
||||
defaultValue: false,
|
||||
}),
|
||||
sniffOnConnectionFault: schema.boolean({ defaultValue: false }),
|
||||
hosts: schema.oneOf([hostURISchema, schema.arrayOf(hostURISchema, { minSize: 1 })], {
|
||||
defaultValue: 'http://localhost:9200',
|
||||
}),
|
||||
preserveHost: schema.boolean({ defaultValue: true }),
|
||||
username: schema.maybe(
|
||||
schema.conditional(
|
||||
schema.contextRef('dist'),
|
||||
false,
|
||||
schema.string({
|
||||
validate: rawConfig => {
|
||||
if (rawConfig === 'elastic') {
|
||||
return (
|
||||
'value of "elastic" is forbidden. This is a superuser account that can obfuscate ' +
|
||||
'privilege-related issues. You should use the "kibana" user instead.'
|
||||
);
|
||||
}
|
||||
},
|
||||
}),
|
||||
schema.string()
|
||||
)
|
||||
),
|
||||
password: schema.maybe(schema.string()),
|
||||
requestHeadersWhitelist: schema.oneOf([schema.string(), schema.arrayOf(schema.string())], {
|
||||
defaultValue: ['authorization'],
|
||||
}),
|
||||
customHeaders: schema.recordOf(schema.string(), schema.string(), { defaultValue: {} }),
|
||||
shardTimeout: schema.duration({ defaultValue: '30s' }),
|
||||
requestTimeout: schema.duration({ defaultValue: '30s' }),
|
||||
pingTimeout: schema.duration({ defaultValue: schema.siblingRef('requestTimeout') }),
|
||||
startupTimeout: schema.duration({ defaultValue: '5s' }),
|
||||
logQueries: schema.boolean({ defaultValue: false }),
|
||||
ssl: schema.object(
|
||||
{
|
||||
verificationMode: schema.oneOf(
|
||||
[schema.literal('none'), schema.literal('certificate'), schema.literal('full')],
|
||||
{ defaultValue: 'full' }
|
||||
),
|
||||
certificateAuthorities: schema.maybe(
|
||||
schema.oneOf([schema.string(), schema.arrayOf(schema.string(), { minSize: 1 })])
|
||||
),
|
||||
certificate: schema.maybe(schema.string()),
|
||||
key: schema.maybe(schema.string()),
|
||||
keyPassphrase: schema.maybe(schema.string()),
|
||||
keystore: schema.object({
|
||||
path: schema.maybe(schema.string()),
|
||||
password: schema.maybe(schema.string()),
|
||||
}),
|
||||
truststore: schema.object({
|
||||
path: schema.maybe(schema.string()),
|
||||
password: schema.maybe(schema.string()),
|
||||
}),
|
||||
alwaysPresentCertificate: schema.boolean({ defaultValue: false }),
|
||||
},
|
||||
{
|
||||
const configSchema = schema.object({
|
||||
sniffOnStart: schema.boolean({ defaultValue: false }),
|
||||
sniffInterval: schema.oneOf([schema.duration(), schema.literal(false)], {
|
||||
defaultValue: false,
|
||||
}),
|
||||
sniffOnConnectionFault: schema.boolean({ defaultValue: false }),
|
||||
hosts: schema.oneOf([hostURISchema, schema.arrayOf(hostURISchema, { minSize: 1 })], {
|
||||
defaultValue: 'http://localhost:9200',
|
||||
}),
|
||||
preserveHost: schema.boolean({ defaultValue: true }),
|
||||
username: schema.maybe(
|
||||
schema.conditional(
|
||||
schema.contextRef('dist'),
|
||||
false,
|
||||
schema.string({
|
||||
validate: rawConfig => {
|
||||
if (rawConfig.key && rawConfig.keystore.path) {
|
||||
return 'cannot use [key] when [keystore.path] is specified';
|
||||
}
|
||||
if (rawConfig.certificate && rawConfig.keystore.path) {
|
||||
return 'cannot use [certificate] when [keystore.path] is specified';
|
||||
if (rawConfig === 'elastic') {
|
||||
return (
|
||||
'value of "elastic" is forbidden. This is a superuser account that can obfuscate ' +
|
||||
'privilege-related issues. You should use the "kibana" user instead.'
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
apiVersion: schema.string({ defaultValue: DEFAULT_API_VERSION }),
|
||||
healthCheck: schema.object({ delay: schema.duration({ defaultValue: 2500 }) }),
|
||||
ignoreVersionMismatch: schema.boolean({ defaultValue: false }),
|
||||
}),
|
||||
schema.string()
|
||||
)
|
||||
),
|
||||
password: schema.maybe(schema.string()),
|
||||
requestHeadersWhitelist: schema.oneOf([schema.string(), schema.arrayOf(schema.string())], {
|
||||
defaultValue: ['authorization'],
|
||||
}),
|
||||
customHeaders: schema.recordOf(schema.string(), schema.string(), { defaultValue: {} }),
|
||||
shardTimeout: schema.duration({ defaultValue: '30s' }),
|
||||
requestTimeout: schema.duration({ defaultValue: '30s' }),
|
||||
pingTimeout: schema.duration({ defaultValue: schema.siblingRef('requestTimeout') }),
|
||||
startupTimeout: schema.duration({ defaultValue: '5s' }),
|
||||
logQueries: schema.boolean({ defaultValue: false }),
|
||||
ssl: schema.object(
|
||||
{
|
||||
verificationMode: schema.oneOf(
|
||||
[schema.literal('none'), schema.literal('certificate'), schema.literal('full')],
|
||||
{ defaultValue: 'full' }
|
||||
),
|
||||
certificateAuthorities: schema.maybe(
|
||||
schema.oneOf([schema.string(), schema.arrayOf(schema.string(), { minSize: 1 })])
|
||||
),
|
||||
certificate: schema.maybe(schema.string()),
|
||||
key: schema.maybe(schema.string()),
|
||||
keyPassphrase: schema.maybe(schema.string()),
|
||||
keystore: schema.object({
|
||||
path: schema.maybe(schema.string()),
|
||||
password: schema.maybe(schema.string()),
|
||||
}),
|
||||
truststore: schema.object({
|
||||
path: schema.maybe(schema.string()),
|
||||
password: schema.maybe(schema.string()),
|
||||
}),
|
||||
alwaysPresentCertificate: schema.boolean({ defaultValue: false }),
|
||||
},
|
||||
{
|
||||
validate: rawConfig => {
|
||||
if (rawConfig.key && rawConfig.keystore.path) {
|
||||
return 'cannot use [key] when [keystore.path] is specified';
|
||||
}
|
||||
if (rawConfig.certificate && rawConfig.keystore.path) {
|
||||
return 'cannot use [certificate] when [keystore.path] is specified';
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
apiVersion: schema.string({ defaultValue: DEFAULT_API_VERSION }),
|
||||
healthCheck: schema.object({ delay: schema.duration({ defaultValue: 2500 }) }),
|
||||
ignoreVersionMismatch: schema.boolean({ defaultValue: false }),
|
||||
});
|
||||
|
||||
const deprecations: ConfigDeprecationProvider = () => [
|
||||
(settings, fromPath, log) => {
|
||||
const es = settings[fromPath];
|
||||
if (!es) {
|
||||
return settings;
|
||||
}
|
||||
if (es.username === 'elastic') {
|
||||
log(
|
||||
`Setting [${fromPath}.username] to "elastic" is deprecated. You should use the "kibana" user instead.`
|
||||
);
|
||||
}
|
||||
if (es.ssl?.key !== undefined && es.ssl?.certificate === undefined) {
|
||||
log(
|
||||
`Setting [${fromPath}.ssl.key] without [${fromPath}.ssl.certificate] is deprecated. This has no effect, you should use both settings to enable TLS client authentication to Elasticsearch.`
|
||||
);
|
||||
} else if (es.ssl?.certificate !== undefined && es.ssl?.key === undefined) {
|
||||
log(
|
||||
`Setting [${fromPath}.ssl.certificate] without [${fromPath}.ssl.key] is deprecated. This has no effect, you should use both settings to enable TLS client authentication to Elasticsearch.`
|
||||
);
|
||||
}
|
||||
return settings;
|
||||
},
|
||||
];
|
||||
|
||||
export const config: ServiceConfigDescriptor<ElasticsearchConfigType> = {
|
||||
path: 'elasticsearch',
|
||||
schema: configSchema,
|
||||
deprecations,
|
||||
};
|
||||
|
||||
export class ElasticsearchConfig {
|
||||
|
@ -205,7 +233,7 @@ export class ElasticsearchConfig {
|
|||
*/
|
||||
public readonly customHeaders: ElasticsearchConfigType['customHeaders'];
|
||||
|
||||
constructor(rawConfig: ElasticsearchConfigType, log: Logger) {
|
||||
constructor(rawConfig: ElasticsearchConfigType) {
|
||||
this.ignoreVersionMismatch = rawConfig.ignoreVersionMismatch;
|
||||
this.apiVersion = rawConfig.apiVersion;
|
||||
this.logQueries = rawConfig.logQueries;
|
||||
|
@ -227,12 +255,6 @@ export class ElasticsearchConfig {
|
|||
const { alwaysPresentCertificate, verificationMode } = rawConfig.ssl;
|
||||
const { key, keyPassphrase, certificate, certificateAuthorities } = readKeyAndCerts(rawConfig);
|
||||
|
||||
if (key && !certificate) {
|
||||
log.warn(`Detected a key without a certificate; mutual TLS authentication is disabled.`);
|
||||
} else if (certificate && !key) {
|
||||
log.warn(`Detected a certificate without a key; mutual TLS authentication is disabled.`);
|
||||
}
|
||||
|
||||
this.ssl = {
|
||||
alwaysPresentCertificate,
|
||||
key,
|
||||
|
@ -261,8 +283,10 @@ const readKeyAndCerts = (rawConfig: ElasticsearchConfigType) => {
|
|||
rawConfig.ssl.keystore.path,
|
||||
rawConfig.ssl.keystore.password
|
||||
);
|
||||
if (!keystore.key && !keystore.cert) {
|
||||
throw new Error(`Did not find key or certificate in Elasticsearch keystore.`);
|
||||
if (!keystore.key) {
|
||||
throw new Error(`Did not find key in Elasticsearch keystore.`);
|
||||
} else if (!keystore.cert) {
|
||||
throw new Error(`Did not find certificate in Elasticsearch keystore.`);
|
||||
}
|
||||
key = keystore.key;
|
||||
certificate = keystore.cert;
|
||||
|
|
|
@ -52,7 +52,7 @@ export class ElasticsearchService implements CoreService<InternalElasticsearchSe
|
|||
this.log = coreContext.logger.get('elasticsearch-service');
|
||||
this.config$ = coreContext.configService
|
||||
.atPath<ElasticsearchConfigType>('elasticsearch')
|
||||
.pipe(map(rawConfig => new ElasticsearchConfig(rawConfig, coreContext.logger.get('config'))));
|
||||
.pipe(map(rawConfig => new ElasticsearchConfig(rawConfig)));
|
||||
}
|
||||
|
||||
public async setup(deps: SetupDeps): Promise<InternalElasticsearchServiceSetup> {
|
||||
|
|
|
@ -450,11 +450,11 @@ export interface AuthToolkit {
|
|||
export class BasePath {
|
||||
// @internal
|
||||
constructor(serverBasePath?: string);
|
||||
get: (request: KibanaRequest<unknown, unknown, unknown, any> | LegacyRequest) => string;
|
||||
get: (request: LegacyRequest | KibanaRequest<unknown, unknown, unknown, any>) => string;
|
||||
prepend: (path: string) => string;
|
||||
remove: (path: string) => string;
|
||||
readonly serverBasePath: string;
|
||||
set: (request: KibanaRequest<unknown, unknown, unknown, any> | LegacyRequest, requestSpecificBasePath: string) => void;
|
||||
set: (request: LegacyRequest | KibanaRequest<unknown, unknown, unknown, any>, requestSpecificBasePath: string) => void;
|
||||
}
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "BootstrapArgs" needs to be exported by the entry point index.d.ts
|
||||
|
|
|
@ -256,6 +256,10 @@ export class Server {
|
|||
];
|
||||
|
||||
this.configService.addDeprecationProvider(rootConfigPath, coreDeprecationProvider);
|
||||
this.configService.addDeprecationProvider(
|
||||
elasticsearchConfig.path,
|
||||
elasticsearchConfig.deprecations!
|
||||
);
|
||||
this.configService.addDeprecationProvider(
|
||||
uiSettingsConfig.path,
|
||||
uiSettingsConfig.deprecations!
|
||||
|
|
Loading…
Reference in a new issue