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

Hide management sections based on cluster/index privileges #67791

Merged
merged 31 commits into from
Sep 14, 2020
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bda8e2e
Hide management sections based on ES privileges
legrego May 29, 2020
54af4aa
add manage_templates as a required cluster privilege for index manage…
legrego Aug 5, 2020
14ad75e
Merge branch 'master' of github.com:elastic/kibana into fc/hide-manag…
legrego Aug 5, 2020
0cd465b
fix cluster privilege name
legrego Aug 6, 2020
d68ba6b
Merge branch 'master' of github.com:elastic/kibana into fc/hide-manag…
legrego Aug 6, 2020
0eb691b
Merge branch 'master' into fc/hide-management
elasticmachine Aug 10, 2020
3006fbe
Merge branch 'master' into fc/hide-management
elasticmachine Aug 17, 2020
e70b472
addressing first round of PR feedback
legrego Sep 1, 2020
0603510
Merge branch 'master' of github.com:elastic/kibana into fc/hide-manag…
legrego Sep 1, 2020
776bac2
additional check_privileges tests
legrego Sep 1, 2020
c2274e8
started adding additional disable_ui_capabilities tests
legrego Sep 1, 2020
5e67ede
Merge branch 'fc/hide-management' of github.com:legrego/kibana into f…
legrego Sep 1, 2020
303d20b
fixing the build
legrego Sep 1, 2020
820ddf9
doc updates
legrego Sep 1, 2020
d3f30aa
tweak short-circuit logic for disabling capabilities
legrego Sep 2, 2020
2a07fbe
dont conditionally register ml management app
legrego Sep 2, 2020
920406b
fixes from merge
legrego Sep 2, 2020
688e420
documenting required privileges
legrego Sep 2, 2020
b0dd152
Merge branch 'master' of github.com:elastic/kibana into fc/hide-manag…
legrego Sep 2, 2020
96c0665
Merge branch 'master' into fc/hide-management
elasticmachine Sep 3, 2020
679eaa1
Merge branch 'master' of github.com:elastic/kibana into fc/hide-manag…
legrego Sep 3, 2020
a50ec42
you'll float too
legrego Sep 3, 2020
19e1e00
fix unrelated typo in migration docs
legrego Sep 3, 2020
987c6f4
Addressing second round of feedback
legrego Sep 3, 2020
fc5eb68
Merge branch 'master' into fc/hide-management
elasticmachine Sep 8, 2020
f862899
updating ML access tests
legrego Sep 9, 2020
d28ecd6
ML user should not access the management interface
legrego Sep 9, 2020
fac5cfe
Merge branch 'master' into fc/hide-management
elasticmachine Sep 10, 2020
b28a951
Merge branch 'master' into fc/hide-management
elasticmachine Sep 10, 2020
607f633
Merge branch 'master' of github.com:elastic/kibana into fc/hide-manag…
legrego Sep 14, 2020
1246bd1
Merge branch 'fc/hide-management' of github.com:legrego/kibana into f…
legrego Sep 14, 2020
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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@
/x-pack/plugins/encrypted_saved_objects/ @elastic/kibana-security
/x-pack/plugins/security/ @elastic/kibana-security
/x-pack/test/api_integration/apis/security/ @elastic/kibana-security
/x-pack/test/ui_capabilities/ @elastic/kibana-security
/x-pack/test/encrypted_saved_objects_api_integration/ @elastic/kibana-security
/x-pack/test/functional/apps/security/ @elastic/kibana-security
/x-pack/test/kerberos_api_integration/ @elastic/kibana-security
Expand Down
48 changes: 24 additions & 24 deletions docs/developer/architecture/security/feature-registration.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@ Registering features also gives your plugin access to “UI Capabilities”. The

=== Registering a feature

Feature registration is controlled via the built-in `xpack_main` plugin. To register a feature, call `xpack_main`'s `registerFeature` function from your plugin's `init` function, and provide the appropriate details:
Feature registration is controlled via the built-in `features` plugin. To register a feature, call `features`'s `registerKibanaFeature` function from your plugin's `setup` lifecycle function, and provide the appropriate details:

["source","javascript"]
-----------
init(server) {
const xpackMainPlugin = server.plugins.xpack_main;
xpackMainPlugin.registerFeature({
setup(core, { features }) {
features.registerKibanaFeature({
// feature details here.
});
}
Expand Down Expand Up @@ -45,12 +44,12 @@ Registering a feature consists of the following fields. For more information, co
|An array of applications this feature enables. Typically, all of your plugin's apps (from `uiExports`) will be included here.

|`privileges` (required)
|{kib-repo}blob/{branch}/x-pack/plugins/features/common/feature.ts[`FeatureConfig`].
|{kib-repo}blob/{branch}/x-pack/plugins/features/common/feature.ts[`KibanaFeatureConfig`].
|See <<example-1-canvas,Example 1>> and <<example-2-dev-tools,Example 2>>
|The set of privileges this feature requires to function.

|`subFeatures` (optional)
|{kib-repo}blob/{branch}/x-pack/plugins/features/common/feature.ts[`FeatureConfig`].
|{kib-repo}blob/{branch}/x-pack/plugins/features/common/feature.ts[`KibanaFeatureConfig`].
|See <<example-3-discover,Example 3>>
|The set of subfeatures that enables finer access control than the `all` and `read` feature privileges. These options are only available in the Gold subscription level and higher.

Expand All @@ -73,25 +72,26 @@ For a full explanation of fields and options, consult the {kib-repo}blob/{branch
=== Using UI Capabilities

UI Capabilities are available to your public (client) plugin code. These capabilities are read-only, and are used to inform the UI. This object is namespaced by feature id. For example, if your feature id is “foo”, then your UI Capabilities are stored at `uiCapabilities.foo`.
To access capabilities, import them from `ui/capabilities`:
Capabilities can be accessed from your plugin's `start` lifecycle from the `core.application` service:

["source","javascript"]
-----------
import { uiCapabilities } from 'ui/capabilities';
public start(core) {
const { capabilities } = core.application;

const canUserSave = uiCapabilities.foo.save;
if (canUserSave) {
// show save button
const canUserSave = capabilities.foo.save;
if (canUserSave) {
// show save button
}
}
-----------

[[example-1-canvas]]
=== Example 1: Canvas Application
["source","javascript"]
-----------
init(server) {
const xpackMainPlugin = server.plugins.xpack_main;
xpackMainPlugin.registerFeature({
public setup(core, { features }) {
features.registerKibanaFeature({
id: 'canvas',
name: 'Canvas',
icon: 'canvasApp',
Expand Down Expand Up @@ -130,11 +130,13 @@ The `all` privilege defines a single “save” UI Capability. To access this in

["source","javascript"]
-----------
import { uiCapabilities } from 'ui/capabilities';
public start(core) {
const { capabilities } = core.application;

const canUserSave = uiCapabilities.canvas.save;
if (canUserSave) {
// show save button
const canUserSave = capabilities.canvas.save;
if (canUserSave) {
// show save button
}
}
-----------

Expand All @@ -145,9 +147,8 @@ Because the `read` privilege does not define the `save` capability, users with r

["source","javascript"]
-----------
init(server) {
const xpackMainPlugin = server.plugins.xpack_main;
xpackMainPlugin.registerFeature({
public setup(core, { features }) {
features.registerKibanaFeature({
id: 'dev_tools',
name: i18n.translate('xpack.features.devToolsFeatureName', {
defaultMessage: 'Dev Tools',
Expand Down Expand Up @@ -206,9 +207,8 @@ a single "Create Short URLs" subfeature privilege is defined, which allows users

["source","javascript"]
-----------
init(server) {
const xpackMainPlugin = server.plugins.xpack_main;
xpackMainPlugin.registerFeature({
public setup(core, { features }) {
features.registerKibanaFeature({
{
id: 'discover',
name: i18n.translate('xpack.features.discoverFeatureName', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,10 @@ created index. For more information, see {ref}/indices-templates.html[Index temp
* *Delete a policy.* You can’t delete a policy that is currently in use or
recover a deleted index.

[float]
=== Required permissions

The `manage_ilm` cluster privilege is required to access *Index lifecycle policies*.

You can add these privileges in *Stack Management > Security > Roles*.

7 changes: 7 additions & 0 deletions docs/management/managing-ccr.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ image::images/cross-cluster-replication-list-view.png[][Cross-cluster replicatio
* The Elasticsearch version of the local cluster must be the same as or newer than the remote cluster.
Refer to {ref}/ccr-overview.html[this document] for more information.

[float]
=== Required permissions

The `manage` and `manage_ccr` cluster privileges are required to access *Cross-Cluster Replication*.

You can add these privileges in *Stack Management > Security > Roles*.

[float]
[[configure-replication]]
=== Configure replication
Expand Down
7 changes: 7 additions & 0 deletions docs/management/managing-licenses.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ See {ref}/encrypting-communications.html[Encrypting communications].
{kib} and the {ref}/start-basic.html[start basic API] provide a list of all of
the features that will no longer be supported if you revert to a basic license.

[float]
=== Required permissions

The `manage` cluster privilege is required to access *License Management*.

You can add this privilege in *Stack Management > Security > Roles*.

[discrete]
[[update-license]]
=== Update your license
Expand Down
7 changes: 7 additions & 0 deletions docs/management/managing-remote-clusters.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ To get started, open the menu, then go to *Stack Management > Data > Remote Clus
[role="screenshot"]
image::images/remote-clusters-list-view.png[Remote Clusters list view, including Add a remote cluster button]

[float]
=== Required permissions

The `manage` cluster privilege is required to access *Remote Clusters*.

You can add this privilege in *Stack Management > Security > Roles*.

[float]
[[managing-remote-clusters]]
=== Add a remote cluster
Expand Down
7 changes: 7 additions & 0 deletions docs/management/rollups/create_and_manage_rollups.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ image::images/management_rollup_list.png[][List of currently active rollup jobs]
Before using this feature, you should be familiar with how rollups work.
{ref}/xpack-rollup.html[Rolling up historical data] is a good source for more detailed information.

[float]
=== Required permissions

The `manage_rollup` cluster privilege is required to access *Rollup jobs*.

You can add this privilege in *Stack Management > Security > Roles*.

[float]
[[create-and-manage-rollup-job]]
=== Create a rollup job
Expand Down
8 changes: 8 additions & 0 deletions docs/management/upgrade-assistant/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ Before you upgrade, make sure that you are using the latest released minor
version of {es} to see the most up-to-date deprecation issues.
For example, if you want to upgrade to to 7.0, make sure that you are using 6.8.

[float]
=== Required permissions

The `manage` cluster privilege is required to access the *Upgrade assistant*.
Additional privileges may be needed to perform certain actions.

You can add this privilege in *Stack Management > Security > Roles*.

[float]
=== Reindexing

Expand Down
14 changes: 13 additions & 1 deletion docs/migration/migrate_8_0.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ URL that it derived from the actual server address and `xpack.security.public` s

*Impact:* Any workflow that involved manually clearing generated bundles will have to be updated with the new path.

[float]]
[float]
=== kibana.keystore has moved from the `data` folder to the `config` folder
*Details:* By default, kibana.keystore has moved from the configured `path.data` folder to `<root>/config` for archive distributions
and `/etc/kibana` for package distributions. If a pre-existing keystore exists in the data directory that path will continue to be used.
Expand All @@ -136,6 +136,18 @@ custom roles with {kibana-ref}/kibana-privileges.html[{kib} privileges].
instead be assigned the `kibana_admin` role to maintain their current
access level.

[float]
=== `kibana_dashboard_only_user` role has been removed.

*Details:* The `kibana_dashboard_only_user` role has been removed.
If you wish to restrict access to just the Dashboard feature, create
custom roles with {kibana-ref}/kibana-privileges.html[{kib} privileges].

*Impact:* Any users currently assigned the `kibana_dashboard_only_user` role will need to be assigned a custom role which only grants access to the Dashboard feature.

Granting additional cluster or index privileges may enable certain
**Stack Monitoring** features.

[float]
[[breaking_80_reporting_changes]]
=== Reporting changes
Expand Down
2 changes: 1 addition & 1 deletion examples/alerting_example/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class AlertingExamplePlugin implements Plugin<void, void, AlertingExample
alerts.registerType(alwaysFiringAlert);
alerts.registerType(peopleInSpaceAlert);

features.registerFeature({
features.registerKibanaFeature({
id: ALERTING_EXAMPLE_APP_ID,
name: i18n.translate('alertsExample.featureRegistry.alertsExampleFeatureName', {
defaultMessage: 'Alerts Example',
Expand Down
2 changes: 1 addition & 1 deletion src/core/MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -1284,7 +1284,7 @@ _See also: [Server's CoreSetup API Docs](/docs/development/core/server/kibana-pl

| Legacy Platform | New Platform | Notes |
| ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ----- |
| `server.plugins.xpack_main.registerFeature` | [`plugins.features.registerFeature`](x-pack/plugins/features/server/plugin.ts) | |
| `server.plugins.xpack_main.registerFeature` | [`plugins.features.registerKibanaFeature`](x-pack/plugins/features/server/plugin.ts) | |
| `server.plugins.xpack_main.feature(pluginID).registerLicenseCheckResultsGenerator` | [`x-pack licensing plugin`](/x-pack/plugins/licensing/README.md) | |

#### UI Exports
Expand Down
20 changes: 20 additions & 0 deletions src/plugins/management/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

import { i18n } from '@kbn/i18n';
import { BehaviorSubject } from 'rxjs';
import { ManagementSetup, ManagementStart } from './types';
import { FeatureCatalogueCategory, HomePublicPluginSetup } from '../../home/public';
import {
Expand All @@ -27,6 +28,9 @@ import {
DEFAULT_APP_CATEGORIES,
PluginInitializerContext,
AppMountParameters,
AppUpdater,
AppStatus,
AppNavLinkStatus,
} from '../../../core/public';

import {
Expand All @@ -41,6 +45,8 @@ interface ManagementSetupDependencies {
export class ManagementPlugin implements Plugin<ManagementSetup, ManagementStart> {
private readonly managementSections = new ManagementSectionsService();

private readonly appUpdater = new BehaviorSubject<AppUpdater>(() => ({}));

constructor(private initializerContext: PluginInitializerContext) {}

public setup(core: CoreSetup, { home }: ManagementSetupDependencies) {
Expand Down Expand Up @@ -70,6 +76,7 @@ export class ManagementPlugin implements Plugin<ManagementSetup, ManagementStart
order: 9040,
euiIconType: 'managementApp',
category: DEFAULT_APP_CATEGORIES.management,
updater$: this.appUpdater,
async mount(params: AppMountParameters) {
const { renderApp } = await import('./application');
const [coreStart] = await core.getStartServices();
Expand All @@ -89,6 +96,19 @@ export class ManagementPlugin implements Plugin<ManagementSetup, ManagementStart

public start(core: CoreStart) {
this.managementSections.start({ capabilities: core.application.capabilities });
const hasAnyEnabledApps = getSectionsServiceStartPrivate()
.getSectionsEnabled()
.some((section) => section.getAppsEnabled().length > 0);

if (!hasAnyEnabledApps) {
this.appUpdater.next(() => {
return {
status: AppStatus.inaccessible,
navLinkStatus: AppNavLinkStatus.hidden,
};
});
}

return {};
}
}
4 changes: 2 additions & 2 deletions test/common/services/security/test_user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ export async function createTestUserService(
}

return new (class TestUser {
async restoreDefaults() {
async restoreDefaults(shouldRefreshBrowser: boolean = true) {
if (isEnabled()) {
await this.setRoles(config.get('security.defaultRoles'));
await this.setRoles(config.get('security.defaultRoles'), shouldRefreshBrowser);
}
}

Expand Down
2 changes: 2 additions & 0 deletions test/functional/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { FilterBarProvider } from './filter_bar';
import { FlyoutProvider } from './flyout';
import { GlobalNavProvider } from './global_nav';
import { InspectorProvider } from './inspector';
import { ManagementMenuProvider } from './management';
import { QueryBarProvider } from './query_bar';
import { RemoteProvider } from './remote';
import { RenderableProvider } from './renderable';
Expand Down Expand Up @@ -91,4 +92,5 @@ export const services = {
savedQueryManagementComponent: SavedQueryManagementComponentProvider,
elasticChart: ElasticChartProvider,
supertest: KibanaSupertestProvider,
managementMenu: ManagementMenuProvider,
};
20 changes: 20 additions & 0 deletions test/functional/services/management/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export { ManagementMenuProvider } from './management_menu';
51 changes: 51 additions & 0 deletions test/functional/services/management/management_menu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { FtrProviderContext } from 'test/functional/ftr_provider_context';

export function ManagementMenuProvider({ getService }: FtrProviderContext) {
const find = getService('find');

class ManagementMenu {
public async getSections() {
const sectionsElements = await find.allByCssSelector(
'.mgtSideBarNav > .euiSideNav__content > .euiSideNavItem'
);

const sections = [];

for (const el of sectionsElements) {
const sectionId = await (await el.findByClassName('euiSideNavItemButton')).getAttribute(
'data-test-subj'
);
const sectionLinks = await Promise.all(
(await el.findAllByCssSelector('.euiSideNavItem > a.euiSideNavItemButton')).map((item) =>
item.getAttribute('data-test-subj')
)
);

sections.push({ sectionId, sectionLinks });
}

return sections;
}
}

return new ManagementMenu();
}
Loading