Skip to content

Commit

Permalink
Allow tests to use SSL between Kibana and Elasticsearch
Browse files Browse the repository at this point in the history
  • Loading branch information
mikecote committed Aug 7, 2019
1 parent aaea567 commit da2f92f
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 22 deletions.
3 changes: 2 additions & 1 deletion packages/kbn-test/src/es/es_test_cluster.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export function createEsTestCluster(options = {}) {
esFrom = esTestConfig.getBuildFrom(),
dataArchive,
esArgs,
ssl,
} = options;

const randomHash = Math.random()
Expand All @@ -54,7 +55,7 @@ export function createEsTestCluster(options = {}) {
esArgs,
};

const cluster = new Cluster({ log });
const cluster = new Cluster({ log, ssl });

return new (class EsTestCluster {
getStartTimeout() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ export const schema = Joi.object()
serverArgs: Joi.array(),
serverEnvVars: Joi.object(),
dataArchive: Joi.string(),
ssl: Joi.boolean().default(false),
})
.default(),

Expand Down
59 changes: 50 additions & 9 deletions packages/kbn-test/src/functional_tests/lib/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,40 @@
* under the License.
*/

import fs from 'fs';
import util from 'util';
import { format as formatUrl } from 'url';

import request from 'request';
import { delay } from 'bluebird';

export const DEFAULT_SUPERUSER_PASS = 'changeme';

async function updateCredentials(port, auth, username, password, retries = 10) {
const readFile = util.promisify(fs.readFile);

async function updateCredentials({
port,
auth,
username,
password,
retries = 10,
protocol,
caCert,
}) {
const result = await new Promise((resolve, reject) =>
request(
{
method: 'PUT',
uri: formatUrl({
protocol: 'http:',
protocol: `${protocol}:`,
auth,
hostname: 'localhost',
port,
pathname: `/_security/user/${username}/_password`,
}),
json: true,
body: { password },
ca: caCert,
},
(err, httpResponse, body) => {
if (err) return reject(err);
Expand All @@ -55,26 +68,35 @@ async function updateCredentials(port, auth, username, password, retries = 10) {

if (retries > 0) {
await delay(2500);
return await updateCredentials(port, auth, username, password, retries - 1);
return await updateCredentials({
port,
auth,
username,
password,
retries: retries - 1,
protocol,
caCert,
});
}

throw new Error(`${statusCode} response, expected 200 -- ${JSON.stringify(body)}`);
}

export async function setupUsers(log, esPort, updates) {
export async function setupUsers({ log, esPort, updates, protocol = 'http', caPath }) {
// track the current credentials for the `elastic` user as
// they will likely change as we apply updates
let auth = `elastic:${DEFAULT_SUPERUSER_PASS}`;
const caCert = caPath && (await readFile(caPath));

for (const { username, password, roles } of updates) {
// If working with a built-in user, just change the password
if (['logstash_system', 'elastic', 'kibana'].includes(username)) {
await updateCredentials(esPort, auth, username, password);
await updateCredentials({ port: esPort, auth, username, password, protocol, caCert });
log.info('setting %j user password to %j', username, password);

// If not a builtin user, add them
} else {
await insertUser(esPort, auth, username, password, roles);
await insertUser({ port: esPort, auth, username, password, roles, protocol, caCert });
log.info('Added %j user with password to %j', username, password);
}

Expand All @@ -84,20 +106,30 @@ export async function setupUsers(log, esPort, updates) {
}
}

async function insertUser(port, auth, username, password, roles = [], retries = 10) {
async function insertUser({
port,
auth,
username,
password,
roles = [],
retries = 10,
protocol,
caCert,
}) {
const result = await new Promise((resolve, reject) =>
request(
{
method: 'POST',
uri: formatUrl({
protocol: 'http:',
protocol: `${protocol}:`,
auth,
hostname: 'localhost',
port,
pathname: `/_security/user/${username}`,
}),
json: true,
body: { password, roles },
ca: caCert,
},
(err, httpResponse, body) => {
if (err) return reject(err);
Expand All @@ -114,7 +146,16 @@ async function insertUser(port, auth, username, password, roles = [], retries =

if (retries > 0) {
await delay(2500);
return await insertUser(port, auth, username, password, retries - 1);
return await insertUser({
port,
auth,
username,
password,
roles,
retries: retries - 1,
protocol,
caCert,
});
}

throw new Error(`${statusCode} response, expected 200 -- ${JSON.stringify(body)}`);
Expand Down
20 changes: 16 additions & 4 deletions packages/kbn-test/src/functional_tests/lib/run_elasticsearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { setupUsers, DEFAULT_SUPERUSER_PASS } from './auth';

export async function runElasticsearch({ config, options }) {
const { log, esFrom } = options;
const ssl = config.get('esTestCluster.ssl');
const license = config.get('esTestCluster.license');
const esArgs = config.get('esTestCluster.serverArgs');
const esEnvVars = config.get('esTestCluster.serverEnvVars');
Expand All @@ -41,16 +42,27 @@ export async function runElasticsearch({ config, options }) {
esFrom: esFrom || config.get('esTestCluster.from'),
dataArchive: config.get('esTestCluster.dataArchive'),
esArgs,
ssl,
});

await cluster.start(esArgs, esEnvVars);

if (isSecurityEnabled) {
await setupUsers(log, config.get('servers.elasticsearch.port'), [
config.get('servers.elasticsearch'),
config.get('servers.kibana'),
]);
await setupUsers({
log,
esPort: config.get('servers.elasticsearch.port'),
updates: [config.get('servers.elasticsearch'), config.get('servers.kibana')],
protocol: config.get('servers.elasticsearch').protocol,
caPath: getRelativeCertificateAuthorityPath(config.get('kbnTestServer.serverArgs')),
});
}

return cluster;
}

function getRelativeCertificateAuthorityPath(esConfig = []) {
const caConfig = esConfig.find(
config => config.indexOf('--elasticsearch.ssl.certificateAuthorities') === 0
);
return caConfig ? caConfig.split('=')[1] : undefined;
}
18 changes: 11 additions & 7 deletions src/test_utils/kbn_server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,17 @@ export function createTestServers({
await es.start();

if (['gold', 'trial'].includes(license)) {
await setupUsers(log, esTestConfig.getUrlParts().port, [
...usersToBeAdded,
// user elastic
esTestConfig.getUrlParts(),
// user kibana
kbnTestConfig.getUrlParts(),
]);
await setupUsers({
log,
esPort: esTestConfig.getUrlParts().port,
updates: [
...usersToBeAdded,
// user elastic
esTestConfig.getUrlParts(),
// user kibana
kbnTestConfig.getUrlParts(),
],
});

// Override provided configs, we know what the elastic user is now
kbnSettings.elasticsearch = {
Expand Down
13 changes: 12 additions & 1 deletion x-pack/test/api_integration/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@ import { SLACK_ACTION_SIMULATOR_URI } from './fixtures/plugins/actions';
export async function getApiIntegrationConfig({ readConfigFile }) {
const xPackFunctionalTestsConfig = await readConfigFile(require.resolve('../functional/config.js'));

const servers = {
...xPackFunctionalTestsConfig.get('servers'),
elasticsearch: {
...xPackFunctionalTestsConfig.get('servers').elasticsearch,
protocol: 'https',
},
};

return {
testFiles: [require.resolve('./apis')],
services,
servers: xPackFunctionalTestsConfig.get('servers'),
servers,
esArchiver: xPackFunctionalTestsConfig.get('esArchiver'),
junit: {
reportName: 'X-Pack API Integration Tests',
Expand All @@ -28,10 +36,13 @@ export async function getApiIntegrationConfig({ readConfigFile }) {
`--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`,
`--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'actions')}`,
`--server.xsrf.whitelist=${JSON.stringify([SLACK_ACTION_SIMULATOR_URI])}`,
`--elasticsearch.hosts=${servers.elasticsearch.protocol}://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`,
`--elasticsearch.ssl.certificateAuthorities=${path.resolve(__dirname, '../../../test/dev_certs/ca.crt')}`,
],
},
esTestCluster: {
...xPackFunctionalTestsConfig.get('esTestCluster'),
ssl: true,
serverArgs: [
...xPackFunctionalTestsConfig.get('esTestCluster.serverArgs'),
'node.attr.name=apiIntegrationTestNode'
Expand Down

0 comments on commit da2f92f

Please sign in to comment.