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

RBAC Phase 1 #19723

Merged
merged 85 commits into from
Jul 24, 2018
Merged
Show file tree
Hide file tree
Changes from 84 commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
01b5cf0
partial implementation for OLS Phase 1
legrego Mar 26, 2018
7cee640
Allow Saved Objects Client to be wrapped
legrego Apr 17, 2018
0afd1c1
Add placeholder "kibana.namespace" configuration property
legrego Apr 17, 2018
30e86d1
revert changes to saved objects client
legrego Apr 18, 2018
936180b
Remove circular dependency
legrego Apr 19, 2018
4d4f946
Removing namespace setting, we're using xpack.security.rbac.application
kobelb Apr 24, 2018
df569df
Adding config.getDefault
kobelb Apr 24, 2018
9979fb9
Expose SavedObjectsClientProvider on the server for easy plugin consu…
legrego Apr 25, 2018
646a80a
migrate x-pack changes into kibana
legrego Apr 25, 2018
d679cf5
Beginning to use the ES APIs to insert/check privileges (#18645)
kobelb May 16, 2018
36e7a67
Adding built-in types and alphabetizing (#19306)
kobelb May 22, 2018
06eb784
Filtering out non-default resource Kibana privileges (#19321)
kobelb May 22, 2018
767fb27
Removing unused file
kobelb May 29, 2018
203ec3e
Adding kibana_rbac_dashboard_only_user to dashboard only mode roles (…
kobelb May 29, 2018
d818cc6
Adding create default roles test (#19505)
kobelb May 29, 2018
813a816
Merge remote-tracking branch 'upstream/master' into rbac-phase-1
kobelb May 30, 2018
66226d6
Merge remote-tracking branch 'upstream/master' into rbac-phase-1
kobelb May 30, 2018
d8d9810
RBAC - SecurityAuditLogger (#19571)
kobelb Jun 1, 2018
3e8e694
RBAC Integration Tests (#19647)
kobelb Jun 4, 2018
74b8486
Merge remote-tracking branch 'upstream/master' into rbac-phase-1
kobelb Jun 5, 2018
1231c70
Fixing "conflicts" after merging master
kobelb Jun 5, 2018
99d70b9
Removing some white-space differences
kobelb Jun 6, 2018
db18d1e
Deleting files that got left behind in a merge
kobelb Jun 6, 2018
d793056
Adding the RBAC API Integration Tests
kobelb Jun 6, 2018
7f2c9b0
SavedObjectClient.find filtering (#19708)
kobelb Jun 7, 2018
b6093bc
Trying to isolate cause of rbac test failures
kobelb Jun 7, 2018
4abf5ed
Adding .toLowerCase() to work around capitalization issue
kobelb Jun 7, 2018
d951a20
No longer exposing the auditLogger, we don't need it like that right now
kobelb Jun 7, 2018
8920425
Removing some unused code
kobelb Jun 7, 2018
91d04e4
Removing defaultSettings from test that doesn't utilize them
kobelb Jun 7, 2018
430d72c
Fixing misspelling
kobelb Jun 7, 2018
7977f00
Don't need an explicit login privilege when we have them all
kobelb Jun 7, 2018
60d5917
Removing unused code, fixing misspelling, adding comment
kobelb Jun 7, 2018
4b3c6ba
Putting a file back
kobelb Jun 7, 2018
117b0d4
No longer creating the roles on start-up (#19799)
kobelb Jun 11, 2018
c42635b
Removing kibana_rbac_dashboard_only_user from dashboard only role
kobelb Jun 12, 2018
e887076
Fixing small issue with editing Kibana privileges
kobelb Jun 12, 2018
a76e4a5
[RBAC Phase 1] - Update application privileges when XPack license cha…
legrego Jun 13, 2018
7ef5850
RBAC Legacy Fallback (#19818)
kobelb Jun 13, 2018
9941eb2
Fixing checkLicenses tests since we added RBAC
kobelb Jun 13, 2018
8667ebd
[Flaky Test] - wait for page load to complete (#19895)
legrego Jun 14, 2018
b0e6998
[Flaky Test] Fixes flaky role test (#19899)
legrego Jun 14, 2018
84f4a8d
Merge remote-tracking branch 'upstream/master' into security-app-privs
kobelb Jun 14, 2018
b464f03
Now with even easier repository access
kobelb Jun 14, 2018
e02c5bb
Sample was including login/version privileges, which was occasionally…
kobelb Jun 14, 2018
9cdf641
Dynamic types (#19925)
kobelb Jun 15, 2018
a53e7d0
start to address feedback
legrego Jun 19, 2018
e11d86b
Merge remote-tracking branch 'upstream/master' into security-app-privs
kobelb Jun 26, 2018
f875cec
Fix RBAC Phase 1 merge from master (#20226)
legrego Jun 26, 2018
c899985
Merge branch 'master' into security-app-privs
legrego Jun 27, 2018
be6445c
Retrying initialize 20 times with a scaling backoff (#20297)
kobelb Jun 28, 2018
e3c1a99
Alternate legacy fallback (#20322)
kobelb Jun 29, 2018
a2cc325
Merge remote-tracking branch 'upstream/master' into security-app-privs
kobelb Jun 29, 2018
b8a110b
Setting the status to red on the first error then continually (#20343)
kobelb Jul 2, 2018
8696030
Renaming get*Privilege to get*Action
kobelb Jul 2, 2018
a56af65
Adding "instance" to alert about other application privileges
kobelb Jul 2, 2018
19a7d6f
Revising some of the naming for the edit roles screen
kobelb Jul 2, 2018
33a153d
One more edit role variable renamed
kobelb Jul 2, 2018
5d8745f
hasPrivileges is now checkPrivileges
kobelb Jul 2, 2018
c1689f7
Revising check_license tests
kobelb Jul 2, 2018
c7ae3e8
Adding 2 more privileges tests
kobelb Jul 2, 2018
03f7931
Moving the other _find method to be near his friend
kobelb Jul 2, 2018
98acdc0
Spelling "returning" correctly, whoops
kobelb Jul 2, 2018
3a95af3
Adding Privileges tests
kobelb Jul 2, 2018
3299a0a
tests for Elasticsearch's privileges APIs
legrego Jul 5, 2018
6942034
Switching the hard-coded resource from 'default' to *
kobelb Jul 5, 2018
19ddaea
Throw error before we execute a POST privilege call that won't work
kobelb Jul 5, 2018
1f48041
Resolving issue when initially registering privileges
kobelb Jul 5, 2018
98ea1b5
Logging legacy fallback deprecation warning on login (#20493)
kobelb Jul 6, 2018
7cef606
Deriving application from Kibana index (#20614)
kobelb Jul 10, 2018
fb724d2
Validate ES has_privileges response before trusting it (#20682)
legrego Jul 12, 2018
c65908b
Removing unused setting
kobelb Jul 12, 2018
3e6c057
Merge remote-tracking branch 'upstream/master' into security-app-privs
kobelb Jul 13, 2018
a597976
Public Role APIs (#20732)
kobelb Jul 13, 2018
36f4b2f
Adding setting to allow the user to turn off the legacy fallback (#20…
kobelb Jul 13, 2018
6fc19e6
Pulling the version from the kibana server
kobelb Jul 17, 2018
e170337
Deleting unused file
kobelb Jul 17, 2018
95dbb99
Add API integration tests for roles with index and app privileges (#2…
kobelb Jul 20, 2018
759330e
Rbac phase1 functional UI tests (#20949)
rashmivkulkarni Jul 20, 2018
beabf5d
Merge remote-tracking branch 'upstream/master' into security-app-privs
kobelb Jul 20, 2018
40aab3f
Merge remote-tracking branch 'upstream/master' into security-app-privs
kobelb Jul 23, 2018
c33ab6c
Fixing role management API from users
kobelb Jul 23, 2018
f8645f3
Set a timeout when we try/catch a find, so it doesn't pause a long time
kobelb Jul 23, 2018
3e248ba
Changing the way we detect if a user is reserved for the ftr
kobelb Jul 23, 2018
066ec5b
Skipping flaky test
kobelb Jul 23, 2018
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 @@ -17,6 +17,7 @@
* under the License.
*/

import { getRootPropertiesObjects } from '../../mappings';
import { SavedObjectsRepository, ScopedSavedObjectsClientProvider, SavedObjectsRepositoryProvider } from './lib';
import { SavedObjectsClient } from './saved_objects_client';

Expand Down Expand Up @@ -58,15 +59,16 @@ export function createSavedObjectsService(server) {
}
};

const mappings = server.getKibanaIndexMappingsDsl();
const repositoryProvider = new SavedObjectsRepositoryProvider({
index: server.config().get('kibana.index'),
mappings: server.getKibanaIndexMappingsDsl(),
mappings,
onBeforeWrite,
});

const scopedClientProvider = new ScopedSavedObjectsClientProvider({
index: server.config().get('kibana.index'),
mappings: server.getKibanaIndexMappingsDsl(),
mappings,
onBeforeWrite,
defaultClientFactory({
request,
Expand All @@ -81,6 +83,7 @@ export function createSavedObjectsService(server) {
});

return {
types: Object.keys(getRootPropertiesObjects(mappings)),
SavedObjectsClient,
SavedObjectsRepository,
getSavedObjectsRepository: (...args) =>
Expand Down
7 changes: 7 additions & 0 deletions x-pack/plugins/security/common/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* 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.
*/

export const ALL_RESOURCE = '*';
77 changes: 66 additions & 11 deletions x-pack/plugins/security/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@ import { resolve } from 'path';
import { getUserProvider } from './server/lib/get_user';
import { initAuthenticateApi } from './server/routes/api/v1/authenticate';
import { initUsersApi } from './server/routes/api/v1/users';
import { initRolesApi } from './server/routes/api/v1/roles';
import { initPublicRolesApi } from './server/routes/api/public/roles';
import { initIndicesApi } from './server/routes/api/v1/indices';
import { initLoginView } from './server/routes/views/login';
import { initLogoutView } from './server/routes/views/logout';
import { validateConfig } from './server/lib/validate_config';
import { authenticateFactory } from './server/lib/auth_redirect';
import { checkLicense } from './server/lib/check_license';
import { initAuthenticator } from './server/lib/authentication/authenticator';
import { mirrorPluginStatus } from '../../server/lib/mirror_plugin_status';
import { initPrivilegesApi } from './server/routes/api/v1/privileges';
import { SecurityAuditLogger } from './server/lib/audit_logger';
import { AuditLogger } from '../../server/lib/audit_logger';
import { SecureSavedObjectsClient } from './server/lib/saved_objects_client/secure_saved_objects_client';
import { initAuthorizationService, registerPrivilegesWithCluster } from './server/lib/authorization';
import { watchStatusAndLicenseToInitialize } from './server/lib/watch_status_and_license_to_initialize';

export const security = (kibana) => new kibana.Plugin({
id: 'security',
Expand All @@ -37,6 +42,14 @@ export const security = (kibana) => new kibana.Plugin({
hostname: Joi.string().hostname(),
port: Joi.number().integer().min(0).max(65535)
}).default(),
authorization: Joi.object({
legacyFallback: Joi.object({
enabled: Joi.boolean().default(true)
}).default()
}).default(),
audit: Joi.object({
enabled: Joi.boolean().default(false)
}).default(),
}).default();
},

Expand Down Expand Up @@ -64,21 +77,24 @@ export const security = (kibana) => new kibana.Plugin({

return {
secureCookies: config.get('xpack.security.secureCookies'),
sessionTimeout: config.get('xpack.security.sessionTimeout')
sessionTimeout: config.get('xpack.security.sessionTimeout'),
};
}
},

async init(server) {
const thisPlugin = this;
const plugin = this;

const config = server.config();
const xpackMainPlugin = server.plugins.xpack_main;
mirrorPluginStatus(xpackMainPlugin, thisPlugin);
const xpackInfo = xpackMainPlugin.info;

const xpackInfoFeature = xpackInfo.feature(plugin.id);

// Register a function that is called whenever the xpack info changes,
// to re-compute the license check results for this plugin
xpackMainPlugin.info.feature(thisPlugin.id).registerLicenseCheckResultsGenerator(checkLicense);
xpackInfoFeature.registerLicenseCheckResultsGenerator(checkLicense);

const config = server.config();
validateConfig(config, message => server.log(['security', 'warning'], message));

// Create a Hapi auth scheme that should be applied to each request.
Expand All @@ -88,20 +104,59 @@ export const security = (kibana) => new kibana.Plugin({
// automatically assigned to all routes that don't contain an auth config.
server.auth.strategy('session', 'login', 'required');

// exposes server.plugins.security.authorization
initAuthorizationService(server);

watchStatusAndLicenseToInitialize(xpackMainPlugin, plugin, async (license) => {
if (license.allowRbac) {
await registerPrivilegesWithCluster(server);
}
});

const auditLogger = new SecurityAuditLogger(server.config(), new AuditLogger(server, 'security'));

const { savedObjects } = server;
savedObjects.setScopedSavedObjectsClientFactory(({
request,
}) => {
const adminCluster = server.plugins.elasticsearch.getCluster('admin');
const { callWithRequest, callWithInternalUser } = adminCluster;
const callCluster = (...args) => callWithRequest(request, ...args);

const callWithRequestRepository = savedObjects.getSavedObjectsRepository(callCluster);

if (!xpackInfoFeature.getLicenseCheckResults().allowRbac) {
return new savedObjects.SavedObjectsClient(callWithRequestRepository);
}

const { authorization } = server.plugins.security;
const checkPrivileges = authorization.checkPrivilegesWithRequest(request);
const internalRepository = savedObjects.getSavedObjectsRepository(callWithInternalUser);

return new SecureSavedObjectsClient({
internalRepository,
callWithRequestRepository,
errors: savedObjects.SavedObjectsClient.errors,
checkPrivileges,
auditLogger,
savedObjectTypes: savedObjects.types,
actions: authorization.actions,
});
});

getUserProvider(server);

await initAuthenticator(server);
initAuthenticateApi(server);
initUsersApi(server);
initRolesApi(server);
initPublicRolesApi(server);
initIndicesApi(server);
initPrivilegesApi(server);
initLoginView(server, xpackMainPlugin);
initLogoutView(server);

server.injectUiAppVars('login', () => {
const pluginId = 'security';
const xpackInfo = server.plugins.xpack_main.info;
const { showLogin, loginMessage, allowLogin } = xpackInfo.feature(pluginId).getLicenseCheckResults() || {};
const { showLogin, loginMessage, allowLogin } = xpackInfo.feature(plugin.id).getLicenseCheckResults() || {};

return {
loginState: {
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/security/public/lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import chrome from 'ui/chrome';

const usersUrl = chrome.addBasePath('/api/security/v1/users');
const rolesUrl = chrome.addBasePath('/api/security/v1/roles');
const rolesUrl = chrome.addBasePath('/api/security/role');

export const createApiClient = (httpClient) => {
return {
Expand Down
14 changes: 14 additions & 0 deletions x-pack/plugins/security/public/services/application_privilege.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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.
*/

import 'angular-resource';
import { uiModules } from 'ui/modules';

const module = uiModules.get('security', ['ngResource']);
module.service('ApplicationPrivileges', ($resource, chrome) => {
const baseUrl = chrome.addBasePath('/api/security/v1/privileges');
return $resource(baseUrl);
});
3 changes: 2 additions & 1 deletion x-pack/plugins/security/public/services/shield_privileges.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ module.constant('shieldPrivileges', {
'create_index',
'view_index_metadata',
'read_cross_cluster',
]
],
applications: []
});
11 changes: 10 additions & 1 deletion x-pack/plugins/security/public/services/shield_role.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@
*/

import 'angular-resource';
import { omit } from 'lodash';
import angular from 'angular';
import { uiModules } from 'ui/modules';

const module = uiModules.get('security', ['ngResource']);
module.service('ShieldRole', ($resource, chrome) => {
return $resource(chrome.addBasePath('/api/security/v1/roles/:name'), {
return $resource(chrome.addBasePath('/api/security/role/:name'), {
name: '@name'
}, {
save: {
method: 'PUT',
transformRequest(data) {
return angular.toJson(omit(data, 'name', 'transient_metadata', '_unrecognized_applications'));
}
}
});
});
47 changes: 41 additions & 6 deletions x-pack/plugins/security/public/views/management/edit_role.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<kbn-management-app section="security" omit-breadcrumb-pages="['edit']">
<!-- This content gets injected below the localNav. -->
<div class="kuiViewContent kuiViewContent--constrainedWidth kuiViewContentItem">

<!-- Subheader -->
<div class="kuiBar kuiVerticalRhythm">

<div class="kuiBarSection">
<!-- Title -->
<h1 class="kuiTitle">
Expand Down Expand Up @@ -39,6 +41,18 @@ <h1 class="kuiTitle">
</div>
</div>

<div class="kuiBar kuiVerticalRhythm" ng-if="otherApplications.length > 0">
<div class="kuiInfoPanel kuiInfoPanel--warning">
<div class="kuiInfoPanelHeader">
<span class="kuiInfoPanelHeader__icon kuiIcon kuiIcon--warning fa-warning"></span>
<span class="kuiInfoPanelHeader__title">
This role contains application privileges for the {{ otherApplications.join(', ') }} application(s) that can't be edited.
If they are for other instances of Kibana, you must manage those privileges on that Kibana instance.
</span>
</div>
</div>
</div>

<!-- Form -->
<form name="form" novalidate class="kuiVerticalRhythm">
<!-- Name -->
Expand All @@ -56,7 +70,7 @@ <h1 class="kuiTitle">
ng-model="role.name"
required
pattern="[a-zA-Z_][a-zA-Z0-9_@\-\$\.]*"
maxlength="30"
maxlength="1024"
Copy link
Contributor

Choose a reason for hiding this comment

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

Is 1024 the max length of the role names in Elasticsearch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

data-test-subj="roleFormNameInput"
/>

Expand Down Expand Up @@ -87,23 +101,44 @@ <h1 class="kuiTitle">
<input
class="kuiCheckBox"
type="checkbox"
ng-checked="includes(role.cluster, privilege)"
ng-click="toggle(role.cluster, privilege)"
ng-checked="includes(role.elasticsearch.cluster, privilege)"
ng-click="toggle(role.elasticsearch.cluster, privilege)"
ng-disabled="role.metadata._reserved || !isRoleEnabled(role)"
data-test-subj="clusterPrivileges-{{privilege}}"
/>
<span class="kuiOptionLabel">{{privilege}}</span>
</label>
</div>
</div>

<!-- Kibana custom privileges -->
<div class="kuiFormSection">
<label class="kuiFormLabel">
Kibana Privileges
</label>

<div ng-repeat="(key, value) in kibanaPrivilegesViewModel">
<label>
<input
class="kuiCheckBox"
type="checkbox"
ng-model="kibanaPrivilegesViewModel[key]"
ng-disabled="role.metadata._reserved || !isRoleEnabled(role)"
data-test-subj="kibanaPrivileges-{{key}}"
/>
<span class="kuiOptionLabel">{{key}}</span>
</label>
</div>
</div>

<!-- Run-as privileges -->
<div class="kuiFormSection">
<label class="kuiFormLabel">
Run As Privileges
</label>
<ui-select
multiple
ng-model="role.run_as"
ng-model="role.elasticsearch.run_as"
ng-disabled="role.metadata._reserved || !isRoleEnabled(role)"
>
<ui-select-match placeholder="Add a user...">
Expand All @@ -119,7 +154,7 @@ <h1 class="kuiTitle">
<div class="kuiFormSection">
<kbn-index-privileges-form
is-new-role="editRole.isNewRole"
indices="role.indices"
indices="role.elasticsearch.indices"
index-patterns="indexPatterns"
privileges="privileges"
field-options="editRole.fieldOptions"
Expand All @@ -140,7 +175,7 @@ <h1 class="kuiTitle">
class="kuiButton kuiButton--primary"
ng-click="saveRole(role)"
ng-if="!role.metadata._reserved && isRoleEnabled(role)"
ng-disabled="form.$invalid || !areIndicesValid(role.indices)"
ng-disabled="form.$invalid || !areIndicesValid(role.elasticsearch.indices)"
data-test-subj="roleFormSaveButton"
>
Save
Expand Down
Loading