Additional validation for elasticsearch username (#48247)

* Additional validation for elasticsearch username

If "elastic" user is set in config:
* In dev mode, throws an error
* In prod mode, logs a deprecation warning

* Fix user for functional tests

* Revert last two commits

Revert "Fix user for functional tests" and
"Fix user for plugin functional tests in Jenkinsfile"

* Change elasticsearch creds for test server

Now uses "kibana" user instead of "elastic" user

* Fix plugin API functional tests

* Fix PKI API integration test

* Change log messages, now conditional on `dist: false` not `dev: true`
This commit is contained in:
Joe Portner 2019-11-18 10:21:11 -05:00 committed by GitHub
parent 34c99cb1df
commit bde28957d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 54 additions and 17 deletions

View file

@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`#username throws if equal to "elastic", only while running from source 1`] = `"[username]: value of \\"elastic\\" is forbidden. This is a superuser account that can obfuscate privilege-related issues. You should use the \\"kibana\\" user instead."`;

View file

@ -107,3 +107,11 @@ test('#ssl.certificateAuthorities accepts both string and array of strings', ()
);
expect(configValue.ssl.certificateAuthorities).toEqual(['some-path', 'another-path']);
});
test('#username throws if equal to "elastic", only while running from source', () => {
const obj = {
username: 'elastic',
};
expect(() => config.schema.validate(obj, { dist: false })).toThrowErrorMatchingSnapshot();
expect(() => config.schema.validate(obj, { dist: true })).not.toThrow();
});

View file

@ -19,6 +19,7 @@
import { schema, TypeOf } from '@kbn/config-schema';
import { Duration } from 'moment';
import { Logger } from '../logging';
const hostURISchema = schema.uri({ scheme: ['http', 'https'] });
@ -39,7 +40,23 @@ export const config = {
defaultValue: 'http://localhost:9200',
}),
preserveHost: schema.boolean({ defaultValue: true }),
username: schema.maybe(schema.string()),
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'],
@ -166,7 +183,7 @@ export class ElasticsearchConfig {
*/
public readonly customHeaders: ElasticsearchConfigType['customHeaders'];
constructor(rawConfig: ElasticsearchConfigType) {
constructor(rawConfig: ElasticsearchConfigType, log?: Logger) {
this.ignoreVersionMismatch = rawConfig.ignoreVersionMismatch;
this.apiVersion = rawConfig.apiVersion;
this.logQueries = rawConfig.logQueries;
@ -195,5 +212,14 @@ export class ElasticsearchConfig {
...rawConfig.ssl,
certificateAuthorities,
};
if (this.username === 'elastic' && log !== undefined) {
// logger is optional / not used during tests
// TODO: logger can be removed when issue #40255 is resolved to support deprecations in NP config service
log.warn(
`Setting the elasticsearch username to "elastic" is deprecated. You should use the "kibana" user instead.`,
{ tags: ['deprecation'] }
);
}
}
}

View file

@ -51,7 +51,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)));
.pipe(map(rawConfig => new ElasticsearchConfig(rawConfig, coreContext.logger.get('config'))));
}
public async setup(deps: SetupDeps): Promise<InternalElasticsearchServiceSetup> {

View file

@ -270,8 +270,8 @@ export function createTestServers({
// Override provided configs, we know what the elastic user is now
kbnSettings.elasticsearch = {
hosts: [esTestConfig.getUrl()],
username: esTestConfig.getUrlParts().username,
password: esTestConfig.getUrlParts().password,
username: kibanaServerTestUser.username,
password: kibanaServerTestUser.password,
};
}
@ -279,8 +279,8 @@ export function createTestServers({
stop: async () => await es.cleanup(),
es,
hosts: [esTestConfig.getUrl()],
username: esTestConfig.getUrlParts().username,
password: esTestConfig.getUrlParts().password,
username: kibanaServerTestUser.username,
password: kibanaServerTestUser.password,
};
},
startKibana: async () => {

View file

@ -19,7 +19,7 @@
import path from 'path';
import { format as formatUrl } from 'url';
import { OPTIMIZE_BUNDLE_DIR, esTestConfig, kbnTestConfig } from '@kbn/test';
import { OPTIMIZE_BUNDLE_DIR, esTestConfig, kbnTestConfig, kibanaServerTestUser } from '@kbn/test';
import { services } from './services';
export default function () {
@ -53,8 +53,8 @@ export default function () {
'--status.allowAnonymous=true',
'--optimize.enabled=true',
`--elasticsearch.hosts=${formatUrl(servers.elasticsearch)}`,
`--elasticsearch.username=${servers.elasticsearch.username}`,
`--elasticsearch.password=${servers.elasticsearch.password}`,
`--elasticsearch.username=${kibanaServerTestUser.username}`,
`--elasticsearch.password=${kibanaServerTestUser.password}`,
`--kibana.disableWelcomeScreen=true`,
'--telemetry.banner=false',
`--server.maxPayloadBytes=1679958`,

View file

@ -113,7 +113,7 @@ export default function({ getService }: FtrProviderContext) {
enabled: true,
metadata: {
pki_delegated_by_realm: 'reserved',
pki_delegated_by_user: 'elastic',
pki_delegated_by_user: 'kibana',
pki_dn: 'CN=first_client',
},
authentication_realm: { name: 'pki1', type: 'pki' },
@ -155,7 +155,7 @@ export default function({ getService }: FtrProviderContext) {
enabled: true,
metadata: {
pki_delegated_by_realm: 'reserved',
pki_delegated_by_user: 'elastic',
pki_delegated_by_user: 'kibana',
pki_dn: 'CN=second_client',
},
authentication_realm: { name: 'pki1', type: 'pki' },

View file

@ -41,7 +41,7 @@ export default function TaskTestingAPI(kibana) {
const callCluster = server.plugins.elasticsearch.getCluster('admin').callWithInternalUser;
await callCluster('index', {
index: '.task_manager_test_result',
index: '.kibana_task_manager_test_result',
body: {
type: 'task',
taskId: taskInstance.id,

View file

@ -16,7 +16,7 @@ export default function ({ getService }) {
const log = getService('log');
const retry = getService('retry');
const config = getService('config');
const testHistoryIndex = '.task_manager_test_result';
const testHistoryIndex = '.kibana_task_manager_test_result';
const supertest = supertestAsPromised(url.format(config.get('servers.kibana')));
describe('scheduling and running tasks', () => {

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { esTestConfig, kbnTestConfig } from '@kbn/test';
import { esTestConfig, kbnTestConfig, kibanaServerTestUser } from '@kbn/test';
import { format as formatUrl } from 'url';
import { getApiIntegrationConfig } from '../../api_integration/config';
import { getReportingApiConfig } from './api';
@ -35,8 +35,8 @@ export default async function ({ readConfigFile }) {
`--server.maxPayloadBytes=1679958`,
`--server.port=${kbnTestConfig.getPort()}`,
`--elasticsearch.hosts=${formatUrl(servers.elasticsearch)}`,
`--elasticsearch.password=${servers.elasticsearch.password}`,
`--elasticsearch.username=${servers.elasticsearch.username}`,
`--elasticsearch.username=${kibanaServerTestUser.username}`,
`--elasticsearch.password=${kibanaServerTestUser.password}`,
`--xpack.reporting.csv.enablePanelActionDownload=true`,
`--xpack.reporting.csv.maxSizeBytes=2850`,
`--xpack.reporting.queue.pollInterval=3000`,