mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
# Backport This will backport the following commits from `main` to `8.8`: - [Improve keystore CLI (#157359)](https://github.com/elastic/kibana/pull/157359) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Alex Szabo","email":"alex.szabo@elastic.co"},"sourceCommit":{"committedDate":"2023-05-16T14:21:25Z","message":"Improve keystore CLI (#157359)\n\n## Summary\r\n\r\nRelates to: #113217\r\n\r\n- Add extra documentation to highlight behaviour of the kibana keystore\r\n(for #113217)\r\n- Fix/Tidy-up commands (`create`, `list`) where the extra unused\r\narguments were preventing the `options` from being passed to the\r\nfunctions. Also remove unnecessary `async` keyword from the `remove`\r\ncommand.\r\n- Added new `show` command\r\n```\r\nUsage: bin/kibana-keystore show [options] <key>\r\n\r\nDisplays the value of a single setting in the keystore. Pass the -o (or --output) parameter to write the setting to a file.\r\n\r\nOptions:\r\n -s, --silent prevent all logging\r\n -o, --output <file> output value to a file\r\n -h, --help output usage information\r\n```\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n- [x]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n### For maintainers\r\n\r\n- [x] This was checked for breaking API changes and was [labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n---------\r\n\r\nCo-authored-by: Kaarina Tungseth <kaarina.tungseth@elastic.co>","sha":"6ebfb8aa3ecd28ba1059e40ea8f9fea62ad52368","branchLabelMapping":{"^v8.9.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Operations","release_note:skip","v8.8.0","v8.9.0"],"number":157359,"url":"https://github.com/elastic/kibana/pull/157359","mergeCommit":{"message":"Improve keystore CLI (#157359)\n\n## Summary\r\n\r\nRelates to: #113217\r\n\r\n- Add extra documentation to highlight behaviour of the kibana keystore\r\n(for #113217)\r\n- Fix/Tidy-up commands (`create`, `list`) where the extra unused\r\narguments were preventing the `options` from being passed to the\r\nfunctions. Also remove unnecessary `async` keyword from the `remove`\r\ncommand.\r\n- Added new `show` command\r\n```\r\nUsage: bin/kibana-keystore show [options] <key>\r\n\r\nDisplays the value of a single setting in the keystore. Pass the -o (or --output) parameter to write the setting to a file.\r\n\r\nOptions:\r\n -s, --silent prevent all logging\r\n -o, --output <file> output value to a file\r\n -h, --help output usage information\r\n```\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n- [x]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n### For maintainers\r\n\r\n- [x] This was checked for breaking API changes and was [labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n---------\r\n\r\nCo-authored-by: Kaarina Tungseth <kaarina.tungseth@elastic.co>","sha":"6ebfb8aa3ecd28ba1059e40ea8f9fea62ad52368"}},"sourceBranch":"main","suggestedTargetBranches":["8.8"],"targetPullRequestStates":[{"branch":"8.8","label":"v8.8.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.9.0","labelRegex":"^v8.9.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/157359","number":157359,"mergeCommit":{"message":"Improve keystore CLI (#157359)\n\n## Summary\r\n\r\nRelates to: #113217\r\n\r\n- Add extra documentation to highlight behaviour of the kibana keystore\r\n(for #113217)\r\n- Fix/Tidy-up commands (`create`, `list`) where the extra unused\r\narguments were preventing the `options` from being passed to the\r\nfunctions. Also remove unnecessary `async` keyword from the `remove`\r\ncommand.\r\n- Added new `show` command\r\n```\r\nUsage: bin/kibana-keystore show [options] <key>\r\n\r\nDisplays the value of a single setting in the keystore. Pass the -o (or --output) parameter to write the setting to a file.\r\n\r\nOptions:\r\n -s, --silent prevent all logging\r\n -o, --output <file> output value to a file\r\n -h, --help output usage information\r\n```\r\n\r\n### Checklist\r\n\r\nDelete any items that are not applicable to this PR.\r\n\r\n- [x]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n### For maintainers\r\n\r\n- [x] This was checked for breaking API changes and was [labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n---------\r\n\r\nCo-authored-by: Kaarina Tungseth <kaarina.tungseth@elastic.co>","sha":"6ebfb8aa3ecd28ba1059e40ea8f9fea62ad52368"}}]}] BACKPORT--> Co-authored-by: Alex Szabo <alex.szabo@elastic.co>
This commit is contained in:
parent
0953d02ccc
commit
e7e0a58578
8 changed files with 188 additions and 5 deletions
|
@ -5,7 +5,12 @@ Some settings are sensitive, and relying on filesystem permissions to protect
|
|||
their values is not sufficient. For this use case, Kibana provides a
|
||||
keystore, and the `kibana-keystore` tool to manage the settings in the keystore.
|
||||
|
||||
NOTE: All commands here should be run as the user which will run Kibana.
|
||||
[NOTE]
|
||||
====
|
||||
* Run all commands as the user who runs {kib}.
|
||||
* Only the settings with the `(Secure)` qualifier should be stored in the keystore.
|
||||
Unsupported, extraneous or invalid JSON-string settings cause {kib} to fail to start up.
|
||||
====
|
||||
|
||||
[float]
|
||||
[[creating-keystore]]
|
||||
|
@ -36,7 +41,8 @@ bin/kibana-keystore list
|
|||
[[add-string-to-keystore]]
|
||||
=== Add string settings
|
||||
|
||||
NOTE: Your input will be JSON-parsed to allow for object/array input configurations. To enforce string values, use "double quotes" around your input.
|
||||
NOTE: Your input will be JSON-parsed to allow for object/array input configurations.
|
||||
To enforce string values, use "double quotes" around your input.
|
||||
|
||||
Sensitive string settings, like authentication credentials for Elasticsearch
|
||||
can be added using the `add` command:
|
||||
|
@ -75,3 +81,14 @@ To remove a setting from the keystore, use the `remove` command:
|
|||
----------------------------------------------------------------
|
||||
bin/kibana-keystore remove the.setting.name.to.remove
|
||||
----------------------------------------------------------------
|
||||
|
||||
[float]
|
||||
[[read-settings]]
|
||||
=== Read settings
|
||||
|
||||
To display the configured setting values, use the `show` command:
|
||||
|
||||
[source, sh]
|
||||
----------------------------------------------------------------
|
||||
bin/kibana-keystore show setting.key
|
||||
----------------------------------------------------------------
|
||||
|
|
|
@ -17,6 +17,7 @@ import { createCli } from './create';
|
|||
import { listCli } from './list';
|
||||
import { addCli } from './add';
|
||||
import { removeCli } from './remove';
|
||||
import { showCli } from './show';
|
||||
|
||||
const argv = process.argv.slice();
|
||||
const program = new Command('bin/kibana-keystore');
|
||||
|
@ -31,6 +32,7 @@ createCli(program, keystore);
|
|||
listCli(program, keystore);
|
||||
addCli(program, keystore);
|
||||
removeCli(program, keystore);
|
||||
showCli(program, keystore);
|
||||
|
||||
program
|
||||
.command('help <command>')
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import { Logger } from '../cli/logger';
|
||||
import { confirm } from './utils';
|
||||
|
||||
export async function create(keystore, command, options) {
|
||||
export async function create(keystore, options) {
|
||||
const logger = new Logger(options);
|
||||
|
||||
if (keystore.exists()) {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import { Logger } from '../cli/logger';
|
||||
|
||||
export function list(keystore, command, options = {}) {
|
||||
export function list(keystore, options = {}) {
|
||||
const logger = new Logger(options);
|
||||
|
||||
if (!keystore.exists()) {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export async function remove(keystore, key) {
|
||||
export function remove(keystore, key) {
|
||||
keystore.remove(key);
|
||||
keystore.save();
|
||||
}
|
||||
|
|
101
src/cli_keystore/show.test.ts
Normal file
101
src/cli_keystore/show.test.ts
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This data blob has 3 key/values set:
|
||||
* - foo: "turbo2000"
|
||||
* - bar: {"sub": 0}
|
||||
* - num: 12345
|
||||
*/
|
||||
const mockKeystoreData =
|
||||
'1:ae/OomiywlzhXnR8DnGLHheyAklj4WcvDUOzeIyeQIHEmrY' +
|
||||
'MIYOYHvduos7NDOgw3TFAuh7xs6z9i0juEo1zFeJeIr8yoyIxdGi1J8GUCO0/' +
|
||||
'OeaKxvLjTjczwoxiy34kM6CzlnJhjwnALAMiBvbehMUaCVzxf3Fu/3Gk2qeux0OPhidJ4Pn/RPjdMA==';
|
||||
|
||||
jest.mock('fs', () => ({
|
||||
readFileSync: jest.fn().mockImplementation(() => JSON.stringify(mockKeystoreData)),
|
||||
existsSync: jest.fn().mockImplementation((fileName) => {
|
||||
if (fileName === 'non-existent-file.txt') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}),
|
||||
writeFileSync: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../cli/logger');
|
||||
|
||||
import { Logger } from '../cli/logger';
|
||||
const mockLogFn = jest.fn();
|
||||
Logger.prototype.log = mockLogFn;
|
||||
const mockErrFn = jest.fn();
|
||||
Logger.prototype.error = mockErrFn;
|
||||
|
||||
import { Keystore } from '../cli/keystore';
|
||||
import { show } from './show';
|
||||
|
||||
describe('Kibana keystore: show', () => {
|
||||
const keystore = new Keystore('mock-path', '');
|
||||
|
||||
it('reads stored strings', () => {
|
||||
const exitCode = show(keystore, 'foo', {});
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
expect(mockLogFn).toHaveBeenCalledWith('turbo2000');
|
||||
expect(mockErrFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('reads stored numbers', () => {
|
||||
const exitCode = show(keystore, 'num', {});
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
expect(mockLogFn).toHaveBeenCalledWith('12345');
|
||||
expect(mockErrFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('reads stored objecs', () => {
|
||||
const exitCode = show(keystore, 'bar', {});
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
expect(mockLogFn).toHaveBeenCalledWith(JSON.stringify({ sub: 0 }));
|
||||
expect(mockErrFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('outputs to a file when the arg is passed', () => {
|
||||
const exitCode = show(keystore, 'foo', { output: 'non-existent-file.txt' });
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
expect(mockLogFn).toHaveBeenCalledWith('Writing output to file: non-existent-file.txt');
|
||||
expect(mockErrFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('logs and terminates with an error when output file exists', () => {
|
||||
const exitCode = show(keystore, 'foo', { output: 'existing-file.txt' });
|
||||
|
||||
expect(exitCode).toBe(-1);
|
||||
expect(mockErrFn).toHaveBeenCalledWith(
|
||||
'ERROR: Output file already exists. Remove it before retrying.'
|
||||
);
|
||||
expect(mockLogFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("logs and terminates with an error when the store doesn't have the key", () => {
|
||||
const exitCode = show(keystore, 'no-key');
|
||||
|
||||
expect(exitCode).toBe(-1);
|
||||
expect(mockErrFn).toHaveBeenCalledWith("ERROR: Kibana keystore doesn't have requested key.");
|
||||
expect(mockLogFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockLogFn.mockReset();
|
||||
mockErrFn.mockReset();
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
});
|
62
src/cli_keystore/show.ts
Normal file
62
src/cli_keystore/show.ts
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { writeFileSync, existsSync } from 'fs';
|
||||
|
||||
import { Keystore } from '../cli/keystore';
|
||||
import { Logger } from '../cli/logger';
|
||||
|
||||
interface ShowOptions {
|
||||
silent?: boolean;
|
||||
output?: string;
|
||||
}
|
||||
|
||||
export function show(keystore: Keystore, key: string, options: ShowOptions = {}): number | void {
|
||||
const { silent, output } = options;
|
||||
const logger = new Logger({ silent });
|
||||
|
||||
if (!keystore.exists()) {
|
||||
logger.error("ERROR: Kibana keystore not found. Use 'create' command to create one.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!keystore.has(key)) {
|
||||
logger.error("ERROR: Kibana keystore doesn't have requested key.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const value = keystore.data[key];
|
||||
const valueAsString = typeof value === 'string' ? value : JSON.stringify(value);
|
||||
|
||||
if (output) {
|
||||
if (existsSync(output)) {
|
||||
logger.error('ERROR: Output file already exists. Remove it before retrying.');
|
||||
return -1;
|
||||
} else {
|
||||
writeFileSync(output, valueAsString);
|
||||
logger.log('Writing output to file: ' + output);
|
||||
}
|
||||
} else {
|
||||
logger.log(valueAsString);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function showCli(program: any, keystore: Keystore) {
|
||||
program
|
||||
.command('show <key>')
|
||||
.description(
|
||||
'Displays the value of a single setting in the keystore. Pass the -o (or --output) parameter to write the setting to a file.'
|
||||
)
|
||||
.option('-s, --silent', 'prevent all logging')
|
||||
.option('-o, --output <file>', 'output value to a file')
|
||||
.action((key: string, options: ShowOptions) => {
|
||||
process.exitCode = show(keystore, key, options) || 0;
|
||||
});
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
"keystore/**/*",
|
||||
"utils/**/*",
|
||||
"*.js",
|
||||
"*.ts",
|
||||
],
|
||||
"kbn_references": [
|
||||
{ "path": "../setup_node_env/tsconfig.json" },
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue