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

[Osquery] RBAC #106669

Merged
merged 40 commits into from
Aug 10, 2021
Merged

Conversation

patrykkopycinski
Copy link
Contributor

Summary

Adds RBAC for Osquery plugin

The idea is to allow the non-superusers to access Osquery independently from Fleet and also to allow for finer grain control over specific Osquery features.

Use case:
SOC Analyst 1 should be able to run only Saved queries (he should not be able to type the query directly as in some cases it may have an impact on the performance)

SOC Manager should be able to run any queries and also be able to setup Scheduled query groups (it's going to be renamed to packs, that's why the permission name is using that name)

image (12)

@patrykkopycinski patrykkopycinski added v8.0.0 Team:Asset Management Security Asset Management Team Feature:Osquery Security Solution Osquery feature release_note:feature Makes this part of the condensed release notes auto-backport Deprecated - use backport:version if exact versions are needed v7.15.0 labels Jul 26, 2021
@patrykkopycinski patrykkopycinski requested review from jportner and a team July 26, 2021 06:55
@patrykkopycinski patrykkopycinski self-assigned this Jul 26, 2021
@patrykkopycinski patrykkopycinski requested a review from a team as a code owner July 26, 2021 06:55
@elasticmachine
Copy link
Contributor

Pinging @elastic/security-asset-management (Team:Asset Management)

@snide snide requested a review from a team July 26, 2021 12:35
@patrykkopycinski
Copy link
Contributor Author

@snide it's just Kibana management, there is nothing to review for @elastic/security-design

@snide
Copy link
Contributor

snide commented Jul 26, 2021

@patrykkopycinski The @elastic/security-design team is likely the most knowledgable of OSQuery and the need for the management controls. The @elastic/kibana-design likely would have familiarity with the management controls themselves. Either way from your screens it looks like some design feedback might help.

Here's some quick feedback after checking it locally myself.

I'm guessing the UI controls were built out in another PR and this was just turning that UI on?

image

@snide
Copy link
Contributor

snide commented Jul 26, 2021

Also. I think the UX in here can be a bit confusing. When setting up these controls they are essentially custom roles, rather than targeted ones. For example, I could set these controls in both "All" and "Read" but they would essentially be the same. Shouldn't it maybe read as "Custom"?

image

@jportner
Copy link
Contributor

I'm guessing the UI controls were built out in another PR and this was just turning that UI on?

@snide These UI controls are generated programmatically by the Security plugin, based on the features and privileges that were registered by the consumer (in this case the Osquery plugin).

Thanks for the feedback, happy to address any and all UI concerns for the Privileges flyout but all of that (besides the sentence case comment) should probably be split out into a separate issue with the Team:Security label so it drops onto our project board.

Also. I think the UX in here can be a bit confusing. When setting up these controls they are essentially custom roles, rather than targeted ones. For example, I could set these controls in both "All" and "Read" but they would essentially be the same. Shouldn't it maybe read as "Custom"?

You're looking at the feature privilege. "Custom" is selected from the base privileges at the top.

@snide
Copy link
Contributor

snide commented Jul 26, 2021

Valid that this is on the @elastic/kibana-security team. I'll write up an issue. The "sub-privileges" distinction vs. the predefined ones though seems like a pretty big UX hole especially when everything is collapsed.

Copy link
Contributor

@jportner jportner left a comment

Choose a reason for hiding this comment

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

It is not possible to comprehensively review this in a vacuum. I don't have any context around the Osquery plugin or what it is intended to do. It would be helpful to understand how Osquery is intended to be used (is it part of Fleet?)

Ultimately I think it's a bad idea to attempt to add feature privileges on their own, you should also be adding the corresponding controls to your plugin (lock down HTTP routes with api tags, dynamically change React components based on UI capabilities, and ideally add some amount of end-to-end integration tests and/or functional tests that exercise the different combinations of privileges that can be used).

A couple other things to note:

  • I just wanted to mention that sub-feature privileges are only available with a Gold license level by default. Just in case you are not aware; if you leave this as-is, you should ensure that Osquery on its own is usable with a Basic license because the sub-feature privileges will not be configurable.
  • If the Osquery feature itself is only intended to be available in a Gold+ license level, then you should specify that via the minimumLicense field.
  • At the moment, the Osquery plugin requires the Security plugin. That means if the Security plugin is disabled, the Osquery plugin will not be available. Is this intended?

Looking forward to chatting more about this and helping out any way I can. If it makes more sense to take this offline and have a conversation via Slack or something else, that's fine too, let me know!

I'm not my team's expert on Kibana Feature Privileges, that would be @legrego -- I'd like for him to take another pass on this and make sure I didn't miss anything.


const registerFeatures = (features: SetupPlugins['features']) => {
features.registerKibanaFeature({
id: 'osquery',
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: not 100% necessary but I'd suggest replacing instances of 'osquery' and the like with constants.

name: i18n.translate('xpack.features.osqueryFeatureName', {
defaultMessage: 'Osquery',
}),
order: 1300,
Copy link
Contributor

@jportner jportner Jul 28, 2021

Choose a reason for hiding this comment

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

Just FYI, the Dev Tools feature already has order: 1300. If two features have the same order, they are sorted alphabetically in the Kibana Privilege UI. This is probably fine for something in stack management, but it begs the question, where do you want this to go in the UI exactly? Depending on your answer, you may not need to change this 😄

Edit: I checked the code and actually, if two features have the same order, it appears there is no second-level sorting. So this may appear before or after Dev Tools. You should probably pick a different order but I will defer to @legrego since we don't have any validation on this field.

Copy link
Member

Choose a reason for hiding this comment

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

We want this feature to appear consistently within Kibana's primary navigation, and the feature listing on the spaces/role management screens. If we intend for Osquery to appear before Dev Tools, then this order should be less than that of Dev Tools. Similarly, if we want Osquery to appear after Dev Toos, then this order should be greater than that of Dev Tools. We don't want the order of any feature to collide with the order of another feature.

You're right that we don't have validation around this today, but that would be good for us to add to the features plugin.

x-pack/plugins/osquery/server/plugin.ts Outdated Show resolved Hide resolved
x-pack/plugins/osquery/server/plugin.ts Outdated Show resolved Hide resolved
Comment on lines 123 to 124
all: [savedQuerySavedObjectType],
read: [savedQuerySavedObjectType],
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't need to grant both all and read SO privileges for a given type:

Suggested change
all: [savedQuerySavedObjectType],
read: [savedQuerySavedObjectType],
all: [savedQuerySavedObjectType],
read: [],

Comment on lines 155 to 156
all: [packSavedObjectType],
read: [packSavedObjectType],
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't need to grant both all and read SO privileges for a given type:

Suggested change
all: [packSavedObjectType],
read: [packSavedObjectType],
all: [packSavedObjectType],
read: [],

x-pack/plugins/osquery/server/plugin.ts Outdated Show resolved Hide resolved
Copy link
Member

@legrego legrego left a comment

Choose a reason for hiding this comment

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

I did a quick pass through -- I agree with all of @jportner's comments, and have a couple additional thoughts below. Happy to chat about this if that would be helpful!

x-pack/plugins/osquery/server/config.ts Outdated Show resolved Hide resolved
features.registerKibanaFeature({
id: 'osquery',
name: i18n.translate('xpack.features.osqueryFeatureName', {
defaultMessage: 'Osquery',
Copy link
Member

@legrego legrego Jul 29, 2021

Choose a reason for hiding this comment

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

I don't know much about osquery, but their website suggests that this is all lowercase (osquery rather than Osquery).

I assume, perhaps incorrectly, that osquery is short for operating system query. If that's true, then using sentence case for an initialism doesn't seem right to me, but I'll ultimately defer to @elastic/kibana-docs: Should this be osquery, Osquery, OSquery, or something else entirely?

Copy link
Contributor

@gchaps gchaps Aug 10, 2021

Choose a reason for hiding this comment

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

On the Security side for the Osquery Manager docs, and the approach is to use osquery when referring to the open source tool but to use Osquery Manager when referring to our integration.

x-pack/plugins/osquery/server/plugin.ts Outdated Show resolved Hide resolved
@patrykkopycinski patrykkopycinski requested a review from a team as a code owner August 1, 2021 09:13
@botelastic botelastic bot added the Team:Fleet Team label for Observability Data Collection Fleet team label Aug 1, 2021
…ery-rbac' of github.com:patrykkopycinski/kibana into feat/osquery-rbac
@@ -71,7 +71,7 @@ const previouslyRegisteredTypes = [
'ml-telemetry',
'monitoring-telemetry',
'osquery-saved-query',
'osquery-usage-metric',
'osquery-manager-usage-metric',
Copy link
Contributor

Choose a reason for hiding this comment

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

@patrykkopycinski if we released a Kibana version with this SO type name then we need to add the old name to the array here to delete the old objects when the user upgrades: https://github.com/elastic/kibana/blob/master/src/core/server/saved_objects/migrations/core/elastic_index.ts#L34

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed, Thank you @joshdover!

Copy link
Contributor

Choose a reason for hiding this comment

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

@patrykkopycinski You know what I forgot to mention that I think the old type name actually needs to be in both arrays or a test is going to fail that ensures that all items in REMOVED_TYPES is also contained in this previouslyRegisteredTypes array.

Copy link
Contributor

@joshdover joshdover left a comment

Choose a reason for hiding this comment

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

Core changes LGTM

Copy link
Contributor

@jportner jportner left a comment

Choose a reason for hiding this comment

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

A few comments but otherwise it's looking good!

Also, I can't stress enough:

ideally add some amount of end-to-end integration tests and/or functional tests that exercise the different combinations of privileges that can be used

If you absolutely don't have time to do this now, it would be good to open an issue in your team's backlog so you can pay down this tech debt in the future.

@@ -47,6 +52,8 @@ export const createActionRoute = (router: IRouter, osqueryContext: OsqueryAppCon
return response.badRequest({ body: new Error('No agents found for selection') });
}

// TODO: Add check for `runSavedQueries` only
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you elaborate on this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right now there is no way for the user with runSavedQueries-only privileges to run custom query from UI, but in the future when we will make the public API we need to make sure that we validate the query the user tries to run is coming from the Saved Queries library

Comment on lines 35 to 41
const esClient = context.core.elasticsearch.client.asCurrentUser;
const soClient = context.core.savedObjects.client;
const esClient = context.core.elasticsearch.client.asInternalUser;
const soClient = await getInternalSavedObjectsClient(osqueryContext.getStartServices);
Copy link
Contributor

@jportner jportner Aug 9, 2021

Choose a reason for hiding this comment

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

This change means that the internal user (Kibana system user) is used for accessing saved objects. This effectively bypasses any authZ checks and skips Kibana audit logs.

If I understand correctly, it looks like:

  • parseAgentSelection below should continue to use the current user for accessing saved objects
  • incrementCounter below should use the internal user for accessing saved objects

If so, this needs to be changed to something like:

const savedObjectsClient = context.core.savedObjects.client;
const internalSavedObjectsClient = await getInternalSavedObjectsClient(osqueryContext.getStartServices);
...
const selectedAgents = await parseAgentSelection(
  esClient,
  savedObjectsClient,
  osqueryContext,
  agentSelection
);
incrementCount(internalSavedObjectsClient, 'live_query');
if (!selectedAgents.length) {
  incrementCount(internalSavedObjectsClient, 'live_query', 'errors');
...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

parseAgentSelection is accessing .fleet-agents index, so for that we also want to use .asInternalUser

so I believe there are no changes needed

Copy link
Contributor

Choose a reason for hiding this comment

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

parseAgentSelection() also uses the saved objects client to find "ingest-package-policies" objects via packagePolicyService.list(), just wanted to be sure that is not overlooked 👍 as currently written, access to those saved objects will not be authorized or audited. If that is intended, then this is fine as-is!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you're right 🤦 Fixed it, Thank you a ton @jportner!

import { PLUGIN_ID } from '../common';

const registerFeatures = (features: SetupPlugins['features']) => {
features.registerKibanaFeature({
Copy link
Contributor

Choose a reason for hiding this comment

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

I thought you were going to use order: 2300 here, did it get removed on accident or on purpose?
Just wanted to double check 😄

@patrykkopycinski
Copy link
Contributor Author

A few comments but otherwise it's looking good!

Also, I can't stress enough:

ideally add some amount of end-to-end integration tests and/or functional tests that exercise the different combinations of privileges that can be used

If you absolutely don't have time to do this now, it would be good to open an issue in your team's backlog so you can pay down this tech debt in the future.

I totally agree, @lykkin is working on setup Cypress tests with Elastic agent, so we can test privileges e2e :)

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
osquery 241 245 +4

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
osquery 912.4KB 922.3KB +9.9KB

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
osquery 14.1KB 13.0KB -1.1KB

Saved Objects .kibana field count

Every field in each saved object type adds overhead to Elasticsearch. Kibana needs to keep the total field count below Elasticsearch's default limit of 1000 fields. Only specify field mappings for the fields you wish to search on or query. See https://www.elastic.co/guide/en/kibana/master/development-plugin-saved-objects.html#_mappings

id before after diff
osquery-manager-usage-metric - 3 +3
osquery-usage-metric 3 - -3
total -0
Unknown metric groups

API count

id before after diff
fleet 1149 1153 +4

API count missing comments

id before after diff
fleet 1049 1052 +3

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @patrykkopycinski

@jportner jportner self-requested a review August 10, 2021 14:32
Copy link
Contributor

@jportner jportner left a comment

Choose a reason for hiding this comment

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

LGTM!

@patrykkopycinski
Copy link
Contributor Author

@jportner Thank you for all the effort and support we have got from you while working on this PR 🙏

@patrykkopycinski patrykkopycinski merged commit 9edcf9e into elastic:master Aug 10, 2021
kibanamachine pushed a commit to kibanamachine/kibana that referenced this pull request Aug 10, 2021
@kibanamachine
Copy link
Contributor

💚 Backport successful

Status Branch Result
7.x

This backport PR will be merged automatically after passing CI.

@patrykkopycinski patrykkopycinski deleted the feat/osquery-rbac branch August 10, 2021 14:44
onError: (error: Error) =>
setErrorToast(error, {
title: i18n.translate('xpack.osquery.osquery_integration.fetchError', {
defaultMessage: 'Error while fetching osquery integration',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggest:

Error fetching osquery integration

<EuiFlexItem>
<EuiCallOut
title={i18n.translate('xpack.osquery.fleetIntegration.saveIntegrationCalloutTitle', {
defaultMessage: 'Save the integration to access the options below',
Copy link
Contributor

Choose a reason for hiding this comment

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

Add an ending period.

Save the integration to access the options below.

<h2>
<FormattedMessage
id="xpack.osquery.permissionDeniedErrorTitle"
defaultMessage="Permission denied"
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of "Permission denied" what about giving the user information on how to get access to this feature?

Title: Request access to xxxx

Description: Ask your administrator to add xxxx.

where xxx is the name of the feature.

Copy link
Contributor

Choose a reason for hiding this comment

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

I like the idea of including info about how to resolve the issue, but I also want to let the user know what the problem is (i.e. that permission is denied). What about something like this @gchaps?

Title: Permission denied

Description: You are not authorized to access this page. Ask your administrator to give you osquery Kibana privileges.

Copy link
Contributor

Choose a reason for hiding this comment

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

Here is what @melissaburpo and I brainstormed:

Title: Permission denied
Description: To access this page, ask your administrator for osquery Kibana privileges.

<p>
<FormattedMessage
id="xpack.osquery.permissionDeniedErrorMessage"
defaultMessage="You are not authorized to access this page."
Copy link
Contributor

Choose a reason for hiding this comment

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

See comment above.

id="xpack.osquery.savedQueries.form.scheduledQueryGroupConfigSection.title"
defaultMessage="Scheduled query group configuration"
id="xpack.osquery.savedQueries.form.scheduledQueryGroupConfigSection.description"
defaultMessage="The options listed below are optional and are only applied when the query is assigned to a scheduled query group."
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion:

These options are applied when the query is assigned to a scheduled query group.

Interval(s) > Intervals

onError: (error: Error) =>
setErrorToast(error, {
title: i18n.translate('xpack.osquery.action_results_privileges.fetchError', {
defaultMessage: 'Error while fetching action results privileges',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggest:

Error fetching action results privileges

features.registerKibanaFeature({
id: 'osquery',
name: i18n.translate('xpack.features.osqueryFeatureName', {
defaultMessage: 'Osquery',
Copy link
Contributor

@gchaps gchaps Aug 10, 2021

Choose a reason for hiding this comment

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

On the Security side for the Osquery Manager docs, and the approach is to use osquery when referring to the open source tool but to use Osquery Manager when referring to our integration.

api: [`${PLUGIN_ID}-runSavedQueries`],
id: 'run_saved_queries',
name: i18n.translate('xpack.osquery.features.runSavedQueriesPrivilegeName', {
defaultMessage: 'Run Saved queries',
Copy link
Contributor

Choose a reason for hiding this comment

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

Run saved queries (lowercase S)

@kibanamachine kibanamachine added the backport missing Added to PRs automatically when the are determined to be missing a backport. label Aug 12, 2021
@kibanamachine
Copy link
Contributor

Looks like this PR has a backport PR but it still hasn't been merged. Please merge it ASAP to keep the branches relatively in sync.

@kibanamachine kibanamachine removed the backport missing Added to PRs automatically when the are determined to be missing a backport. label Aug 12, 2021
kibanamachine added a commit that referenced this pull request Aug 12, 2021
Co-authored-by: Patryk Kopyciński <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auto-backport Deprecated - use backport:version if exact versions are needed Feature:Osquery Security Solution Osquery feature release_note:feature Makes this part of the condensed release notes Team:Asset Management Security Asset Management Team Team:Fleet Team label for Observability Data Collection Fleet team v7.15.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.