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

[7.x] [Security Solution] [Detections] Adds scripts to create users + roles based on specific privileges (#81866) #83861

Merged
merged 1 commit into from
Nov 19, 2020
Merged
Show file tree
Hide file tree
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 @@ -3,6 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { AlertAction } from '../../../alerts/common';

export type RuleAlertAction = Omit<AlertAction, 'actionTypeId'> & {
Expand Down
18 changes: 18 additions & 0 deletions x-pack/plugins/security_solution/common/test/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

// For the source of these roles please consult the PR these were introduced https://github.com/elastic/kibana/pull/81866#issue-511165754
export enum ROLES {
t1_analyst = 't1_analyst',
t2_analyst = 't2_analyst',
hunter = 'hunter',
rule_author = 'rule_author',
soc_manager = 'soc_manager',
platform_engineer = 'platform_engineer',
detections_admin = 'detections_admin',
}

export type RolesType = keyof typeof ROLES;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { loginAndWaitForPageWithoutDateRange } from '../tasks/login';
import { ROLES } from '../../common/test';
import { deleteRoleAndUser, loginAndWaitForPageWithoutDateRange } from '../tasks/login';
import { DETECTIONS_URL } from '../urls/navigation';
import {
waitForAlertsPanelToBeLoaded,
Expand All @@ -24,7 +25,7 @@ import {
deleteValueListsFile,
exportValueList,
} from '../tasks/lists';
import { VALUE_LISTS_TABLE, VALUE_LISTS_ROW } from '../screens/lists';
import { VALUE_LISTS_TABLE, VALUE_LISTS_ROW, VALUE_LISTS_MODAL_ACTIVATOR } from '../screens/lists';

describe('value lists', () => {
describe('management modal', () => {
Expand Down Expand Up @@ -220,4 +221,19 @@ describe('value lists', () => {
});
});
});

describe('user with restricted access role', () => {
beforeEach(() => {
loginAndWaitForPageWithoutDateRange(DETECTIONS_URL, ROLES.t1_analyst);
goToManageAlertsDetectionRules();
});

afterEach(() => {
deleteRoleAndUser(ROLES.t1_analyst);
});

it('Does not allow a t1 analyst user to upload a value list', () => {
cy.get(VALUE_LISTS_MODAL_ACTIVATOR).should('have.attr', 'disabled');
});
});
});
110 changes: 100 additions & 10 deletions x-pack/plugins/security_solution/cypress/tasks/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
*/

import * as yaml from 'js-yaml';
import Url, { UrlObject } from 'url';

import { RolesType } from '../../common/test';
import { TIMELINE_FLYOUT_BODY } from '../screens/timeline';

/**
Expand Down Expand Up @@ -42,6 +45,89 @@ const ELASTICSEARCH_PASSWORD = 'ELASTICSEARCH_PASSWORD';
*/
const LOGIN_API_ENDPOINT = '/internal/security/login';

/**
* cy.visit will default to the baseUrl which uses the default kibana test user
* This function will override that functionality in cy.visit by building the baseUrl
* directly from the environment variables set up in x-pack/test/security_solution_cypress/runner.ts
*
* @param role string role/user to log in with
* @param route string route to visit
*/
export const getUrlWithRoute = (role: RolesType, route: string) => {
const theUrl = `${Url.format({
auth: `${role}:changeme`,
username: role,
password: 'changeme',
protocol: Cypress.env('protocol'),
hostname: Cypress.env('hostname'),
port: Cypress.env('configport'),
} as UrlObject)}${route.startsWith('/') ? '' : '/'}${route}`;
cy.log(`origin: ${theUrl}`);
return theUrl;
};

export const getCurlScriptEnvVars = () => ({
ELASTICSEARCH_URL: Cypress.env('ELASTICSEARCH_URL'),
ELASTICSEARCH_USERNAME: Cypress.env('ELASTICSEARCH_USERNAME'),
ELASTICSEARCH_PASSWORD: Cypress.env('ELASTICSEARCH_PASSWORD'),
KIBANA_URL: Cypress.env('KIBANA_URL'),
});

export const postRoleAndUser = (role: RolesType) => {
const env = getCurlScriptEnvVars();
const detectionsRoleScriptPath = `./server/lib/detection_engine/scripts/roles_users/${role}/post_detections_role.sh`;
const detectionsRoleJsonPath = `./server/lib/detection_engine/scripts/roles_users/${role}/detections_role.json`;
const detectionsUserScriptPath = `./server/lib/detection_engine/scripts/roles_users/${role}/post_detections_user.sh`;
const detectionsUserJsonPath = `./server/lib/detection_engine/scripts/roles_users/${role}/detections_user.json`;

// post the role
cy.exec(`bash ${detectionsRoleScriptPath} ${detectionsRoleJsonPath}`, {
env,
});

// post the user associated with the role to elasticsearch
cy.exec(`bash ${detectionsUserScriptPath} ${detectionsUserJsonPath}`, {
env,
});
};

export const deleteRoleAndUser = (role: RolesType) => {
const env = getCurlScriptEnvVars();
const detectionsUserDeleteScriptPath = `./server/lib/detection_engine/scripts/roles_users/${role}/delete_detections_user.sh`;

// delete the role
cy.exec(`bash ${detectionsUserDeleteScriptPath}`, {
env,
});
};

export const loginWithRole = async (role: RolesType) => {
postRoleAndUser(role);
const theUrl = Url.format({
auth: `${role}:changeme`,
username: role,
password: 'changeme',
protocol: Cypress.env('protocol'),
hostname: Cypress.env('hostname'),
port: Cypress.env('configport'),
} as UrlObject);
cy.log(`origin: ${theUrl}`);
cy.request({
body: {
providerType: 'basic',
providerName: 'basic',
currentURL: '/',
params: {
username: role,
password: 'changeme',
},
},
headers: { 'kbn-xsrf': 'cypress-creds-via-config' },
method: 'POST',
url: getUrlWithRoute(role, LOGIN_API_ENDPOINT),
});
};

/**
* Authenticates with Kibana using, if specified, credentials specified by
* environment variables. The credentials in `kibana.dev.yml` will be used
Expand All @@ -50,8 +136,10 @@ const LOGIN_API_ENDPOINT = '/internal/security/login';
* To speed the execution of tests, prefer this non-interactive authentication,
* which is faster than authentication via Kibana's interactive login page.
*/
export const login = () => {
if (credentialsProvidedByEnvironment()) {
export const login = (role?: RolesType) => {
if (role != null) {
loginWithRole(role);
} else if (credentialsProvidedByEnvironment()) {
loginViaEnvironmentCredentials();
} else {
loginViaConfig();
Expand Down Expand Up @@ -129,26 +217,28 @@ const loginViaConfig = () => {
* Authenticates with Kibana, visits the specified `url`, and waits for the
* Kibana global nav to be displayed before continuing
*/
export const loginAndWaitForPage = (url: string) => {
login();
export const loginAndWaitForPage = (url: string, role?: RolesType) => {
login(role);
cy.viewport('macbook-15');
cy.visit(
`${url}?timerange=(global:(linkTo:!(timeline),timerange:(from:1547914976217,fromStr:'2019-01-19T16:22:56.217Z',kind:relative,to:1579537385745,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1547914976217,fromStr:'2019-01-19T16:22:56.217Z',kind:relative,to:1579537385745,toStr:now)))`
);
cy.get('[data-test-subj="headerGlobalNav"]');
};

export const loginAndWaitForPageWithoutDateRange = (url: string) => {
login();
export const loginAndWaitForPageWithoutDateRange = (url: string, role?: RolesType) => {
login(role);
cy.viewport('macbook-15');
cy.visit(url);
cy.visit(role ? getUrlWithRoute(role, url) : url);
cy.get('[data-test-subj="headerGlobalNav"]', { timeout: 120000 });
};

export const loginAndWaitForTimeline = (timelineId: string) => {
login();
export const loginAndWaitForTimeline = (timelineId: string, role?: RolesType) => {
const route = `/app/security/timelines?timeline=(id:'${timelineId}',isOpen:!t)`;

login(role);
cy.viewport('macbook-15');
cy.visit(`/app/security/timelines?timeline=(id:'${timelineId}',isOpen:!t)`);
cy.visit(role ? getUrlWithRoute(role, route) : route);
cy.get('[data-test-subj="headerGlobalNav"]');
cy.get(TIMELINE_FLYOUT_BODY).should('be.visible');
};
2 changes: 1 addition & 1 deletion x-pack/plugins/security_solution/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"build-graphql-types": "node scripts/generate_types_from_graphql.js",
"cypress:open": "../../../node_modules/.bin/cypress open --config-file ./cypress/cypress.json",
"cypress:open-as-ci": "node ../../../scripts/functional_tests --config ../../test/security_solution_cypress/visual_config.ts",
"cypress:run": "../../../node_modules/.bin/cypress run --browser chrome --headless --spec ./cypress/integration/**/*.spec.ts --config-file ./cypress/cypress.json --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json; status=$?; ../../node_modules/.bin/mochawesome-merge ../../../target/kibana-security-solution/cypress/results/mochawesome*.json > ../../../target/kibana-security-solution/cypress/results/output.json; ../../../node_modules/.bin/marge ../../../target/kibana-security-solution/cypress/results/output.json --reportDir ../../../target/kibana-security-solution/cypress/results; mkdir -p ../../../target/junit && cp ../../../target/kibana-security-solution/cypress/results/*.xml ../../../target/junit/ && exit $status;",
"cypress:run": "../../../node_modules/.bin/cypress run --browser chrome --headless --spec ./cypress/integration/**/*.spec.ts --config-file ./cypress/cypress.json --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json; status=$?; ../../../node_modules/.bin/mochawesome-merge ../../../target/kibana-security-solution/cypress/results/mochawesome*.json > ../../../target/kibana-security-solution/cypress/results/output.json; ../../../node_modules/.bin/marge ../../../target/kibana-security-solution/cypress/results/output.json --reportDir ../../../target/kibana-security-solution/cypress/results; mkdir -p ../../../target/junit && cp ../../../target/kibana-security-solution/cypress/results/*.xml ../../../target/junit/ && exit $status;",
"cypress:run-as-ci": "node --max-old-space-size=2048 ../../../scripts/functional_tests --config ../../test/security_solution_cypress/cli_config.ts",
"test:generate": "node scripts/endpoint/resolver_generator"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
1. When first starting up elastic, detections will not be available until you visit the page with a SOC Manager role or Platform Engineer role
2. I gave the Hunter role "all" privileges for saved objects management and builtInAlerts so that they can create rules.
3. Rule Author has the ability to create rules and create value lists

| Role | Data Sources | Security Solution ML Jobs/Results | Lists | Rules/Exceptions | Action Connectors | Signals/Alerts |
| :------------------------------------------: | :----------: | :-------------------------------: | :---------: | :--------------: | :---------------: | :------------------------------: |
| T1 Analyst | read | read | none | read | read | read, write |
| T2 Analyst | read | read | read | read | read | read, write |
| Hunter / T3 Analyst | read, write | read | read | read, write | read | read, write |
| Rule Author / Manager / Detections Engineer | read, write | read | read, write | read, write | read | read, write, view_index_metadata |
| SOC Manager | read, write | read | read, write | read, write | all | read, write, manage |
| Platform Engineer (data ingest, cluster ops) | read, write | all | all | read, write | all | all |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This user contains all the possible privileges listed in our detections privileges docs https://www.elastic.co/guide/en/security/current/detections-permissions-section.html This user has higher privileges than the Platform Engineer user
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

#
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
# or more contributor license agreements. Licensed under the Elastic License;
# you may not use this file except in compliance with the Elastic License.
#

curl -v -H 'Content-Type: application/json' -H 'kbn-xsrf: 123'\
-u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \
-XDELETE ${ELASTICSEARCH_URL}/_security/user/detections_admin
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"elasticsearch": {
"cluster": ["manage"],
"indices": [
{
"names": [
".siem-signals-*",
".lists*",
".items*",
"apm-*-transaction*",
"auditbeat-*",
"endgame-*",
"filebeat-*",
"logs-*",
"packetbeat-*",
"winlogbeat-*"
],
"privileges": ["manage", "write", "read"]
}
]
},
"kibana": [
{
"feature": {
"ml": ["all"],
"siem": ["all"],
"actions": ["read"],
"builtInAlerts": ["all"],
"dev_tools": ["all"],
"savedObjectsManagement": ["all"]
},
"spaces": ["*"]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"password": "changeme",
"roles": ["detections_admin"],
"full_name": "Detections User",
"email": "[email protected]"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

#
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
# or more contributor license agreements. Licensed under the Elastic License;
# you may not use this file except in compliance with the Elastic License.
#

curl -H 'Content-Type: application/json' -H 'kbn-xsrf: 123'\
-u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \
-XGET ${KIBANA_URL}/api/security/role/detections_admin | jq -S .
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

#
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
# or more contributor license agreements. Licensed under the Elastic License;
# you may not use this file except in compliance with the Elastic License.
#

curl -H 'Content-Type: application/json' -H 'kbn-xsrf: 123'\
-u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \
-XPUT ${KIBANA_URL}/api/security/role/detections_admin \
-d @detections_role.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

#
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
# or more contributor license agreements. Licensed under the Elastic License;
# you may not use this file except in compliance with the Elastic License.
#

USER=(${@:-./detections_user.json})

curl -H 'Content-Type: application/json' -H 'kbn-xsrf: 123'\
-u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \
${ELASTICSEARCH_URL}/_security/user/detections_admin \
-d @${USER}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
This user can CRUD rules and signals. The main difference here is the user has

```json
"builtInAlerts": ["all"],
"savedObjectsManagement": ["all"]
```

privileges whereas the T1 and T2 have "read" privileges which prevents them from creating rules

| Role | Data Sources | Security Solution ML Jobs/Results | Lists | Rules/Exceptions | Action Connectors | Signals/Alerts |
| :-----------------: | :----------: | :------------------: | :---: | :--------------: | :---------------: | :------------: |
| Hunter / T3 Analyst | read, write | read | read | read, write | read | read, write |
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

#
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
# or more contributor license agreements. Licensed under the Elastic License;
# you may not use this file except in compliance with the Elastic License.
#

curl -v -H 'Content-Type: application/json' -H 'kbn-xsrf: 123'\
-u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \
-XDELETE ${ELASTICSEARCH_URL}/_security/user/hunter
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"elasticsearch": {
"cluster": [],
"indices": [
{
"names": [
"apm-*-transaction*",
"auditbeat-*",
"endgame-*",
"filebeat-*",
"logs-*",
"packetbeat-*",
"winlogbeat-*"
],
"privileges": ["read", "write"]
},
{
"names": [".siem-signals-*"],
"privileges": ["read", "write"]
},
{
"names": [".lists*", ".items*"],
"privileges": ["read", "write"]
}
]
},
"kibana": [
{
"feature": {
"ml": ["read"],
"siem": ["all"],
"actions": ["read"],
"builtInAlerts": ["all"],
"savedObjectsManagement": ["all"]
},
"spaces": ["*"]
}
]
}
Loading