Skip to content

Commit 837bcdd

Browse files
authored
[7.3] [@kbn/es] Add a predefined list of Elasticsearch secure settings to be added into keystore. Re-enable OIDC tests. (#42425)
1 parent 34f32f0 commit 837bcdd

12 files changed

Lines changed: 174 additions & 16 deletions

File tree

packages/kbn-es/src/cluster.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const {
3232
const { createCliError } = require('./errors');
3333
const { promisify } = require('util');
3434
const treeKillAsync = promisify(require('tree-kill'));
35+
const { parseSettings, SettingsFilter } = require('./settings');
3536

3637
// listen to data on stream until map returns anything but undefined
3738
const first = (stream, map) =>
@@ -250,9 +251,13 @@ exports.Cluster = class Cluster {
250251
this._log.info(chalk.bold('Starting'));
251252
this._log.indent(4);
252253

253-
const args = extractConfigFiles(options.esArgs || [], installPath, {
254-
log: this._log,
255-
}).reduce((acc, cur) => acc.concat(['-E', cur]), []);
254+
const args = parseSettings(
255+
extractConfigFiles(options.esArgs || [], installPath, { log: this._log }),
256+
{ filter: SettingsFilter.NonSecureOnly }
257+
).reduce(
258+
(acc, [settingName, settingValue]) => acc.concat(['-E', `${settingName}=${settingValue}`]),
259+
[]
260+
);
256261

257262
this._log.debug('%s %s', ES_BIN, args.join(' '));
258263

packages/kbn-es/src/install/archive.js

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const url = require('url');
2626
const { log: defaultLog, decompress } = require('../utils');
2727
const { BASE_PATH, ES_CONFIG, ES_KEYSTORE_BIN } = require('../paths');
2828
const { Artifact } = require('../artifact');
29+
const { parseSettings, SettingsFilter } = require('../settings');
2930

3031
/**
3132
* Extracts an ES archive and optionally installs plugins
@@ -45,6 +46,7 @@ exports.installArchive = async function installArchive(archive, options = {}) {
4546
installPath = path.resolve(basePath, path.basename(archive, '.tar.gz')),
4647
log = defaultLog,
4748
bundledJDK = false,
49+
esArgs = [],
4850
} = options;
4951

5052
let dest = archive;
@@ -69,7 +71,10 @@ exports.installArchive = async function installArchive(archive, options = {}) {
6971
await appendToConfig(installPath, 'xpack.security.enabled', 'true');
7072

7173
await appendToConfig(installPath, 'xpack.license.self_generated.type', license);
72-
await configureKeystore(installPath, password, log, bundledJDK);
74+
await configureKeystore(installPath, log, bundledJDK, [
75+
['bootstrap.password', password],
76+
...parseSettings(esArgs, { filter: SettingsFilter.SecureOnly }),
77+
]);
7378
}
7479

7580
return { installPath };
@@ -90,21 +95,33 @@ async function appendToConfig(installPath, key, value) {
9095
* Creates and configures Keystore
9196
*
9297
* @param {String} installPath
93-
* @param {String} password
9498
* @param {ToolingLog} log
99+
* @param {boolean} bundledJDK
100+
* @param {Array<[string, string]>} secureSettings List of custom Elasticsearch secure settings to
101+
* add into the keystore.
95102
*/
96-
async function configureKeystore(installPath, password, log = defaultLog, bundledJDK = false) {
97-
log.info('setting bootstrap password to %s', chalk.bold(password));
98-
103+
async function configureKeystore(
104+
installPath,
105+
log = defaultLog,
106+
bundledJDK = false,
107+
secureSettings
108+
) {
99109
const env = {};
100110
if (bundledJDK) {
101111
env.JAVA_HOME = '';
102112
}
103113
await execa(ES_KEYSTORE_BIN, ['create'], { cwd: installPath, env });
104114

105-
await execa(ES_KEYSTORE_BIN, ['add', 'bootstrap.password', '-x'], {
106-
input: password,
107-
cwd: installPath,
108-
env,
109-
});
115+
for (const [secureSettingName, secureSettingValue] of secureSettings) {
116+
log.info(
117+
`setting secure setting %s to %s`,
118+
chalk.bold(secureSettingName),
119+
chalk.bold(secureSettingValue)
120+
);
121+
await execa(ES_KEYSTORE_BIN, ['add', secureSettingName, '-x'], {
122+
input: secureSettingValue,
123+
cwd: installPath,
124+
env,
125+
});
126+
}
110127
}

packages/kbn-es/src/install/snapshot.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ exports.installSnapshot = async function installSnapshot({
7373
installPath = path.resolve(basePath, version),
7474
log = defaultLog,
7575
bundledJDK = true,
76+
esArgs,
7677
}) {
7778
const { downloadPath } = await exports.downloadSnapshot({
7879
license,
@@ -89,5 +90,6 @@ exports.installSnapshot = async function installSnapshot({
8990
installPath,
9091
log,
9192
bundledJDK,
93+
esArgs,
9294
});
9395
};

packages/kbn-es/src/install/source.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ exports.installSource = async function installSource({
5050
basePath = BASE_PATH,
5151
installPath = path.resolve(basePath, 'source'),
5252
log = defaultLog,
53+
esArgs,
5354
}) {
5455
log.info('source path: %s', chalk.bold(sourcePath));
5556
log.info('install path: %s', chalk.bold(installPath));
@@ -75,6 +76,7 @@ exports.installSource = async function installSource({
7576
basePath,
7677
installPath,
7778
log,
79+
esArgs,
7880
});
7981
};
8082

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import { parseSettings, SettingsFilter } from './settings';
21+
22+
const mockSettings = [
23+
'abc.def=1',
24+
'xpack.security.authc.realms.oidc.oidc1.rp.client_secret=secret',
25+
'xpack.security.authc.realms.oidc.oidc1.rp.client_id=client id',
26+
'discovery.type=single-node',
27+
];
28+
29+
test('`parseSettings` parses and returns all settings by default', () => {
30+
expect(parseSettings(mockSettings)).toEqual([
31+
['abc.def', '1'],
32+
['xpack.security.authc.realms.oidc.oidc1.rp.client_secret', 'secret'],
33+
['xpack.security.authc.realms.oidc.oidc1.rp.client_id', 'client id'],
34+
['discovery.type', 'single-node'],
35+
]);
36+
});
37+
38+
test('`parseSettings` parses and returns all settings with `SettingsFilter.All` filter', () => {
39+
expect(parseSettings(mockSettings, { filter: SettingsFilter.All })).toEqual([
40+
['abc.def', '1'],
41+
['xpack.security.authc.realms.oidc.oidc1.rp.client_secret', 'secret'],
42+
['xpack.security.authc.realms.oidc.oidc1.rp.client_id', 'client id'],
43+
['discovery.type', 'single-node'],
44+
]);
45+
});
46+
47+
test('`parseSettings` parses and returns only secure settings with `SettingsFilter.SecureOnly` filter', () => {
48+
expect(parseSettings(mockSettings, { filter: SettingsFilter.SecureOnly })).toEqual([
49+
['xpack.security.authc.realms.oidc.oidc1.rp.client_secret', 'secret'],
50+
]);
51+
});
52+
53+
test('`parseSettings` parses and returns only non-secure settings with `SettingsFilter.NonSecureOnly` filter', () => {
54+
expect(parseSettings(mockSettings, { filter: SettingsFilter.NonSecureOnly })).toEqual([
55+
['abc.def', '1'],
56+
['xpack.security.authc.realms.oidc.oidc1.rp.client_id', 'client id'],
57+
['discovery.type', 'single-node'],
58+
]);
59+
});

packages/kbn-es/src/settings.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
/**
21+
* List of the patterns for the settings names that are supposed to be secure and stored in the keystore.
22+
*/
23+
const SECURE_SETTINGS_LIST = [
24+
/^xpack\.security\.authc\.realms\.oidc\.[a-zA-Z0-9_]+\.rp\.client_secret$/,
25+
];
26+
27+
function isSecureSetting(settingName: string) {
28+
return SECURE_SETTINGS_LIST.some(secureSettingNameRegex =>
29+
secureSettingNameRegex.test(settingName)
30+
);
31+
}
32+
33+
export enum SettingsFilter {
34+
All = 'all',
35+
SecureOnly = 'secure-only',
36+
NonSecureOnly = 'non-secure-only',
37+
}
38+
39+
/**
40+
* Accepts an array of `esSettingName=esSettingValue` strings and parses them into an array of
41+
* [esSettingName, esSettingValue] tuples optionally filter out secure or non-secure settings.
42+
* @param rawSettingNameValuePairs Array of strings to parse
43+
* @param [filter] Optional settings filter.
44+
*/
45+
export function parseSettings(
46+
rawSettingNameValuePairs: string[],
47+
{ filter }: { filter: SettingsFilter } = { filter: SettingsFilter.All }
48+
) {
49+
const settings: Array<[string, string]> = [];
50+
for (const rawSettingNameValuePair of rawSettingNameValuePairs) {
51+
const [settingName, settingValue] = rawSettingNameValuePair.split('=');
52+
53+
const includeSetting =
54+
filter === SettingsFilter.All ||
55+
(filter === SettingsFilter.SecureOnly && isSecureSetting(settingName)) ||
56+
(filter === SettingsFilter.NonSecureOnly && !isSecureSetting(settingName));
57+
if (includeSetting) {
58+
settings.push([settingName, settingValue]);
59+
}
60+
}
61+
62+
return settings;
63+
}

packages/kbn-es/tsconfig.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
"include": [
4+
"src/**/*.ts"
5+
]
6+
}

packages/kbn-test/src/es/es_test_cluster.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export function createEsTestCluster(options = {}) {
3737
basePath = resolve(KIBANA_ROOT, '.es'),
3838
esFrom = esTestConfig.getBuildFrom(),
3939
dataArchive,
40+
esArgs,
4041
} = options;
4142

4243
const randomHash = Math.random()
@@ -50,6 +51,7 @@ export function createEsTestCluster(options = {}) {
5051
password,
5152
license,
5253
basePath,
54+
esArgs,
5355
};
5456

5557
const cluster = new Cluster(log);

packages/kbn-test/src/functional_tests/lib/run_elasticsearch.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export async function runElasticsearch({ config, options }) {
4040
basePath: resolve(KIBANA_ROOT, '.es'),
4141
esFrom: esFrom || config.get('esTestCluster.from'),
4242
dataArchive: config.get('esTestCluster.dataArchive'),
43+
esArgs,
4344
});
4445

4546
await cluster.start(esArgs, esEnvVars);

scripts/es.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717
* under the License.
1818
*/
1919

20+
require('../src/setup_node_env');
21+
2022
var resolve = require('path').resolve;
2123
var pkg = require('../package.json');
2224
var kbnEs = require('@kbn/es');
2325

24-
require('../src/setup_node_env');
25-
2626
kbnEs
2727
.run({
2828
license: 'basic',

0 commit comments

Comments
 (0)