-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Osquery] RBAC #106669
Conversation
Pinging @elastic/security-asset-management (Team:Asset Management) |
@snide it's just Kibana management, there is nothing to review for @elastic/security-design |
@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? |
@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
You're looking at the feature privilege. "Custom" is selected from the base privileges at the top. |
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. |
There was a problem hiding this 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', |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
all: [savedQuerySavedObjectType], | ||
read: [savedQuerySavedObjectType], |
There was a problem hiding this comment.
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:
all: [savedQuerySavedObjectType], | |
read: [savedQuerySavedObjectType], | |
all: [savedQuerySavedObjectType], | |
read: [], |
all: [packSavedObjectType], | ||
read: [packSavedObjectType], |
There was a problem hiding this comment.
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:
all: [packSavedObjectType], | |
read: [packSavedObjectType], | |
all: [packSavedObjectType], | |
read: [], |
There was a problem hiding this 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!
features.registerKibanaFeature({ | ||
id: 'osquery', | ||
name: i18n.translate('xpack.features.osqueryFeatureName', { | ||
defaultMessage: 'Osquery', |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
@@ -71,7 +71,7 @@ const previouslyRegisteredTypes = [ | |||
'ml-telemetry', | |||
'monitoring-telemetry', | |||
'osquery-saved-query', | |||
'osquery-usage-metric', | |||
'osquery-manager-usage-metric', |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed, Thank you @joshdover!
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Core changes LGTM
There was a problem hiding this 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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
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); |
There was a problem hiding this comment.
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 objectsincrementCounter
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');
...
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
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({ |
There was a problem hiding this comment.
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 😄
I totally agree, @lykkin is working on setup Cypress tests with Elastic agent, so we can test privileges e2e :) |
💚 Build SucceededMetrics [docs]Module Count
Async chunks
Page load bundle
Saved Objects .kibana field count
Unknown metric groupsAPI count
API count missing comments
History
To update your PR or re-run it, just comment with: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
@jportner Thank you for all the effort and support we have got from you while working on this PR 🙏 |
💚 Backport successful
This backport PR will be merged automatically after passing CI. |
onError: (error: Error) => | ||
setErrorToast(error, { | ||
title: i18n.translate('xpack.osquery.osquery_integration.fetchError', { | ||
defaultMessage: 'Error while fetching osquery integration', |
There was a problem hiding this comment.
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', |
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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." |
There was a problem hiding this comment.
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." |
There was a problem hiding this comment.
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', |
There was a problem hiding this comment.
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', |
There was a problem hiding this comment.
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', |
There was a problem hiding this comment.
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)
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. |
Co-authored-by: Patryk Kopyciński <[email protected]>
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)