Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[APM] Update script with new roles/users #72599

Merged
merged 3 commits into from
Jul 21, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,21 @@

/* eslint-disable no-console */

import yaml from 'js-yaml';
import axios, { AxiosRequestConfig, AxiosError } from 'axios';
import fs from 'fs';
import { union, difference, once } from 'lodash';
import path from 'path';
import { argv } from 'yargs';

const config = yaml.safeLoad(
fs.readFileSync(
path.join(__filename, '../../../../../../config/kibana.dev.yml'),
'utf8'
)
);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the magic around reading creds from the existing kibana.yml file. Now everything must be passed in as cli args. A little more tedious but a lot more clear what happens


const KIBANA_INDEX = config['kibana.index'] as string;
const TASK_MANAGER_INDEX = config['xpack.task_manager.index'] as string;
const KIBANA_ROLE_SUFFIX = argv.roleSuffix as string;
const KIBANA_ROLE_SUFFIX = argv.roleSuffix as string | undefined;
const ELASTICSEARCH_USERNAME = (argv.username as string) || 'elastic';
const ELASTICSEARCH_PASSWORD = (argv.password ||
config['elasticsearch.password']) as string;
const KIBANA_BASE_URL = (argv.kibanaUrl as string) || 'http://localhost:5601';
const ELASTICSEARCH_PASSWORD = argv.password as string | undefined;
const KIBANA_BASE_URL = argv.kibanaUrl as string | undefined;

console.log({
KIBANA_ROLE_SUFFIX,
ELASTICSEARCH_USERNAME,
ELASTICSEARCH_PASSWORD,
KIBANA_BASE_URL,
});

interface User {
username: string;
Expand Down Expand Up @@ -76,33 +70,26 @@ init().catch((e) => {
});

async function init() {
const version = await getKibanaVersion();
console.log(`Connected to Kibana ${version}`);

const isKibanaLocal = KIBANA_BASE_URL.startsWith('http://localhost');

// kibana.index must be different from `.kibana`
if (isKibanaLocal && KIBANA_INDEX === '.kibana') {
if (!ELASTICSEARCH_PASSWORD) {
console.log(
'kibana.dev.yml: Please use a custom "kibana.index". Example: "kibana.index: .kibana-john"'
'Please specify credentials for elasticsearch: `--username elastic --password abcd` '
);
return;
}

if (isKibanaLocal && !KIBANA_INDEX.startsWith('.kibana')) {
if (!KIBANA_BASE_URL) {
console.log(
'kibana.dev.yml: "kibana.index" must be prefixed with `.kibana`. Example: "kibana.index: .kibana-john"'
'Please specify the url for Kibana: `--kibana-url http://localhost:5601` '
);
return;
}

if (
isKibanaLocal &&
TASK_MANAGER_INDEX &&
!TASK_MANAGER_INDEX.startsWith('.kibana')
!KIBANA_BASE_URL.startsWith('https://') &&
!KIBANA_BASE_URL.startsWith('http://')
) {
console.log(
'kibana.dev.yml: "xpack.task_manager.index" must be prefixed with `.kibana`. Example: "xpack.task_manager.index: .kibana-task-manager-john"'
'Kibana url must be prefixed with http(s):// `--kibana-url http://localhost:5601`'
);
return;
}
Expand All @@ -114,35 +101,50 @@ async function init() {
return;
}

const version = await getKibanaVersion();
console.log(`Connected to Kibana ${version}`);

const isEnabled = await isSecurityEnabled();
if (!isEnabled) {
console.log('Security must be enabled!');
return;
}

const APM_READ_ROLE = `apm_read_${KIBANA_ROLE_SUFFIX}`;
const KIBANA_READ_ROLE = `kibana_read_${KIBANA_ROLE_SUFFIX}`;
const KIBANA_WRITE_ROLE = `kibana_write_${KIBANA_ROLE_SUFFIX}`;
const APM_USER_ROLE = 'apm_user';

// create roles
await createRole({ roleName: KIBANA_READ_ROLE, privilege: 'read' });
await createRole({ roleName: KIBANA_WRITE_ROLE, privilege: 'all' });
await createRole({
roleName: APM_READ_ROLE,
kibanaPrivileges: { feature: { apm: ['read'] } },
});
await createRole({
roleName: KIBANA_READ_ROLE,
kibanaPrivileges: { base: ['read'] },
});
await createRole({
roleName: KIBANA_WRITE_ROLE,
kibanaPrivileges: { base: ['all'] },
});

// read/write access to all apps + apm index access
// read access only to APM + apm index access
await createOrUpdateUser({
username: 'apm_write_user',
roles: ['apm_user', KIBANA_WRITE_ROLE],
username: 'apm_read_user',
roles: [APM_USER_ROLE, APM_READ_ROLE],
});

// read access to all apps + apm index access
await createOrUpdateUser({
username: 'apm_read_user',
roles: ['apm_user', KIBANA_READ_ROLE],
username: 'kibana_read_user',
roles: [APM_USER_ROLE, KIBANA_READ_ROLE],
});

// read/write access to all apps (no apm index access)
// read/write access to all apps + apm index access
await createOrUpdateUser({
username: 'kibana_write_user',
roles: [KIBANA_WRITE_ROLE],
roles: [APM_USER_ROLE, KIBANA_WRITE_ROLE],
});
}

Expand All @@ -159,26 +161,31 @@ async function isSecurityEnabled() {

async function callKibana<T>(options: AxiosRequestConfig): Promise<T> {
const kibanaBasePath = await getKibanaBasePath();
const reqOptions = {

if (!ELASTICSEARCH_PASSWORD) {
throw new Error('Missing `--password`');
}

const { data } = await axios.request({
...options,
baseURL: KIBANA_BASE_URL + kibanaBasePath,
auth: {
username: ELASTICSEARCH_USERNAME,
password: ELASTICSEARCH_PASSWORD,
},
headers: { 'kbn-xsrf': 'true', ...options.headers },
};

const { data } = await axios.request(reqOptions);
});
return data;
}

type Privilege = [] | ['read'] | ['all'];

async function createRole({
roleName,
privilege,
kibanaPrivileges,
}: {
roleName: string;
privilege: 'read' | 'all';
kibanaPrivileges: { base?: Privilege; feature?: Record<string, Privilege> };
}) {
const role = await getRole(roleName);
if (role) {
Expand All @@ -192,11 +199,21 @@ async function createRole({
data: {
metadata: { version: 1 },
elasticsearch: { cluster: [], indices: [] },
kibana: [{ base: [privilege], feature: {}, spaces: ['*'] }],
kibana: [
{
base: kibanaPrivileges.base ?? [],
feature: kibanaPrivileges.feature ?? {},
spaces: ['*'],
},
],
},
});

console.log(`Created role "${roleName}" with privilege "${privilege}"`);
console.log(
`Created role "${roleName}" with privilege "${JSON.stringify(
kibanaPrivileges
)}"`
);
}

async function createOrUpdateUser(newUser: User) {
Expand Down