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

[Actions][Cases] Case Connector RBAC Discussion #94498

Open
jonathan-buttner opened this issue Mar 11, 2021 · 11 comments
Open

[Actions][Cases] Case Connector RBAC Discussion #94498

jonathan-buttner opened this issue Mar 11, 2021 · 11 comments
Labels
estimate:needs-research Estimated as too large and requires research to break down into workable issues Feature:Actions/ConnectorTypes Issues related to specific Connector Types on the Actions Framework Feature:Actions/Framework Issues related to the Actions Framework Feature:Actions Feature:Cases Cases feature NeededFor:Security Solution SIEM, Endpoint, Timeline, Analyzer, Cases security Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams)

Comments

@jonathan-buttner
Copy link
Contributor

jonathan-buttner commented Mar 11, 2021

This issue is to follow up on a discussion the Cases team had with Mike and Gidi about the case connector RBAC implementation. I'll try to give a high level overview of how we expect the Case RBAC solution to work and how it will interact with the case connector.

Background

Attaching alerts to a case using the case connector

To attach an alert to a case, a user can leverage the case connector .case and provide a case ID to the connector's _execute API. To create a case connector the following would be provided in a post request:

POST /api/actions/action
{
    name: 'A case connector',
    actionTypeId: '.case',
    config: {},
}

To add an alert to a case the following call can be made:

POST /api/actions/action/<case action ID created above>/_execute
{
    params: {
        subAction: 'addComment',
        subActionParams: {
        caseId: <case ID>,
        comment: {<alert info>},
        },
    },
}

The case connector's execute function handles adding the provided alert information within the comment field to the specified caseId.

Case RBAC

Case Class

To represent multiple types of cases within a single saved object type, we leverage a field called owner within the saved object to indicate the type of case. If a case is created in the Observability plugin we will set the owner field to observability. If a case is created in the Security Solution plugin we will set the owner field to securitySolution. This field will be passed as a parameter to the API that handles creating a case.

When a plugin registers a feature, it can specify which owners of cases a user could be given access to when granted that specific feature privilege. For now we can assume that a single feature will only register a single owner of cases. For example, in the observability plugin, a new feature privilege will be created called Cases which when granted will give a user access to the observability owner of cases. This will be very similar within the Security Solution plugin. When a user is granted access to the Security feature within the Security Solution plugin they will be granted access to the securitySolution owner of cases.

A single user can be given access to multiple features and therefore could have access to multiple owners of cases.

Creating a Case

When a case is created, the owner field must be specified as part of the request. The cases RBAC implementation will use the owner to build a URI like cases:1.0.0:securitySolution/create. This URI will be provided to the security plugin to determine if the user making the request has the correct permissions to create a securitySolution owner of cases. If the user has only been granted access to the observability owner of cases then authorization will fail.

Finding a Case

When a request is made to retrieve a list of cases, a query parameter indicating the owner of cases will be provided. The cases RBAC implementation will use the owner to build a URI like cases:1.0.0:observability/find. This URI will be provided to the security plugin to determine if the user making the request has the necessary permissions to view an observability owner of cases. If the user is authorized to view the specified owner of cases, a KQL filter will be constructed and passed to the saved object client to only retrieve cases of the specified owner. In the future it could be possible for multiple owners to be provided in the find's query parameters if we provide a view for multiple owners of cases at one time. For now we can assume that only a single string will be provided.

Authorization within the Case Connector Execute Method

When the case connector's execute method is called, the RBAC implementation will retrieve the case's owner using the provided caseId. It will then build the URI using that owner and provide it to the security plugin to determine if the user making the request has the correct permissions to perform the subAction specified. To do this, some request or callback mechanism must be provided to the execute method.

Global Case Connector

The case connector is a little different from other supported connectors in that there should only be a single case connector per space within Kibana. The case connector does not have any configured fields and all the parameters are passed when the _execute API is called. Ideally, the case connector should probably be created on boot up of kibana.

Case Connector Scenarios

This section will go through some scenarios and explain what the ideal behavior should be.

No Case Permissions

Permissions

  • Observability
    • Logs
  • Actions and Connectors

If a user without permissions to view any owner of cases attempts to create a case connector, the actions plugins should return an error. As I mentioned before, the case connector should really be created by the system on boot up anyway. If a user without permissions to view any owner of cases attempts to call the _execute API, the actions plugin should return an error. I don't think this functionality is necessary to provide a fully secure system but it would provide a better user experience. As mentioned above the execute method could handle authorizing if the user has the correct permissions. Unfortunately we wouldn't be able to provide any information to the UI since the case connector action would happen outside of the alerting UI flow.

Observability Case Class Permissions

Permissions

  • Observability
    • Logs
    • Cases
  • Actions and Connectors

Available Cases

  • ObservabilityCase1
    • Class: observability
  • SecurityCase1
    • Class: securitySolution

Originating Plugin: Observability

A user with the above permissions should be able to either create a new case with owner: observability or retrieve ObservabilityCase1. Either can be used as the caseId to add alerts with the _execute API.

Security Solution Case Class Permissions

Permissions

  • Security Solution
    • Cases
  • Actions and Connectors

Available Cases

  • ObservabilityCase1
    • Class: observability
  • SecurityCase1
    • Class: securitySolution

Originating Plugin: Security Solution

This scenario is essentially the same as the observability one above, except that the user should only be able to select/create an owner: securitySolution case.

Unprivileged User Update

User: PrivilegedObsUser

Permissions

  • Observability
    • Logs
    • Cases
  • Actions and Connectors

User: UnprivilegedObsUser

Permissions

  • Observability
    • Logs
  • Actions and Connectors

Let's say user PrivilegedObsUser creates an alert and chooses case as the connector. If the unprivileged user UnprivilegedObsUser attempts to update the alert, ideally the update should return an error. This is because the API key will be updated to the unprivileged user which will cause a failure when the alert fires and the cases RBAC implementation checks the user making the original request to add an alert to a case.

To enforce this we'd probably need the alert's update method to make a call through the specified connector to determine if the user doing the update is authorized to use the connector (from the connector's point of view). The update method would need to provide the caseId and the user making the update request. It could then retrieve the owner of the case and determine if the user making the update request has access to that owner of cases (in this case it wouldn't).

If we don't enforce it in the update method the case RBAC implementation will throw a forbidden when the execute method is called. The system will still be secured but the user experience isn't ideal since we'd just log the error but nothing would be displayed in the UI.

Another option would be to retain two separate users, one for executing the action's connector and another for the alerting framework.

Almost Privileged User Update

User: PrivilegedObsUser

Permissions

  • Observability
    • Logs
    • Cases
  • Actions and Connectors

User: PrivilegedSecUser

Permissions

  • Observability
    • Logs
  • Security Solution
    • Cases
  • Actions and Connectors

Let's say user PrivilegedObsUser creates an alert and chooses case as the connector. If the unprivileged user PrivilegedSecUser attempts to update the alert, ideally the update should return an error like the scenario above. Again we could accomplish this using the call-into-configured-connector approach to determine if the user doing the update is privileged enough according to the connector.

Mismatched Create

Permissions

  • Observability
    • Logs
  • Security Solution
    • Cases
  • Actions and Connectors

Originating Plugin: Observability

The user with the above permissions can create an alert, but it'd probably be ideal if we hid the case connector as an option in the UI. This would be ideal because the user does not have the necessary permissions in the originating plugin of the alert. To successfully attach the generated alerts to the observability owner of cases, the user needs the Cases privilege within the Observability feature. If the user were doing this all through the API then the case RBAC implementation would have to catch it. To implement this functionality in the UI we'd need some mechanism to call into the configured connector like in the previous scenarios to determine if the user making the request has the appropriate privileges within a particular view (in this scenario the observability view).

Creating an Alert through the Management Page

If a user creates an alert through the alerts management page and has the necessary privileges to use the case connector, the owner should be alerting.

Conclusion

Given that a user that lacks the cases privileges for an owner of cases can arbitrarily make a request to the case connector's _execute API with a caseId, the execute implementation must be able to authorize the request. I might be missing something but I think given the current API implementation for connectors, it needs to be up to the connector to handle the authorization instead of pushing that logic up into the action framework.

The security plugin's API contract requires a KibanaRequest object to authorize the user:

https://github.com/elastic/kibana/blob/master/x-pack/plugins/security/server/authorization/check_privileges_dynamically.ts#L17-L19

export type CheckPrivilegesDynamicallyWithRequest = (
  request: KibanaRequest
) => CheckPrivilegesDynamically;

In addition to this, connectors that leverage hidden saved objects need a way to construct a saved object client with access to specific hidden types. This could be accomplished using the raw context or maybe a callback method within the framework to retrieve a saved objects client given an array of strings representing the needed hidden types.

@jonathan-buttner jonathan-buttner added Feature:Actions Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams) Team:Threat Hunting Security Solution Threat Hunting Team Feature:Cases Cases feature Feature:Cases-RAC-RBAC labels Mar 11, 2021
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-alerting-services (Team:Alerting Services)

@elasticmachine
Copy link
Contributor

Pinging @elastic/security-threat-hunting (Team:Threat Hunting)

@jonathan-buttner
Copy link
Contributor Author

@XavierM @cnasikas @mikecote @gmmorris let me know if you're thinking along the same lines as the scenarios above or if I'm missing anything

@mikecote
Copy link
Contributor

@jonathan-buttner thanks! We will review 🙏

cc @kobelb

@mikecote
Copy link
Contributor

I did a first pass read, which is in line with what I was thinking for the RBAC expectations. This will be useful input for #70303.

Do we have an idea when you want the case connector to ship? With RAC, I'm guessing this is delayed?

@jonathan-buttner
Copy link
Contributor Author

Thanks for taking a look Mike! @XavierM can you chime in on the roadmap? I think we were hoping to complete the connector and RAC stuff in the same release

@XavierM
Copy link
Contributor

XavierM commented Mar 17, 2021

We have a meeting tomorrow with our PO about case connector in 7.13.0 for security solutions and we will be able to talk about it with them. However, I do think that we will need case connector sometimes for 7.last because Case without alert(s) won't be really useful. @mikecote Which version of 7.x will be realistic for you to have this feature? And we might be able to give a hand in 7.14.0

@mikecote
Copy link
Contributor

Let me know how the meeting goes tomorrow. If you can confirm this is critical for 7.x, I'll discuss with the @elastic/kibana-alerting-services team about researching this. Then, come up with a proposal and a list of questions that we'll need to answer before moving on to the implementation stage. Let's make sure the automatic case creation is a priority first (on top of the manual "create a case" button).

From a high level, this seems like a medium to large size effort and we've been tracking it with #70303.

@gmmorris
Copy link
Contributor

Thanks for the summary @jonathan-buttner

I gave it a first pass and nothing jumped out at me, so without going into the details of it, this sounds well aligned with what we discussed.
Given these requirements, I think we can follow our original direction for #70303 where each solution can specify the Connector Type they wish to grant privileges for and the level of privilege.

There is one thing that does warrant some research - we currently treat execute as a read operation as actions have historically been either external to the Stack. This means that if you grant read to a role it won't be able to create a Case, but it would be able to execute the a Case Action (using a Case Connector) which might try to create case and fail *.
The way around this would be to avoid granting read of the Case Connector to roles that only have read to the Case Feature, but that would mean a read-only user in Case won't be able to view a rule that has a Case Connector connected to it - this doesn't feel right.

It might mean we need to separate the execute privilege from read and make it an explicit privilege group along side all and read. We would still want to make it possible to grant execute to read-only users, but it sounds like Case would require a slightly different model.

We recognised this complicated need a while back as part of #69442, but haven't had a concrete need to prioritise that work until now.
It might be time 😬 but as @mikecote said, this isn't a small piece of work, and could span a couple of steps across a couple of minors. If we need this for 7.x, then we likely need to pull this research up.

* For the record, the same happens if a user adds an ES Index connector and points it at an index they don't have write privileges for

@cnasikas cnasikas mentioned this issue Mar 30, 2021
12 tasks
@gmmorris gmmorris added Feature:Actions/ConnectorTypes Issues related to specific Connector Types on the Actions Framework Feature:Actions/Framework Issues related to the Actions Framework NeededFor:Security Solution SIEM, Endpoint, Timeline, Analyzer, Cases labels Jul 1, 2021
@gmmorris gmmorris added loe:needs-research This issue requires some research before it can be worked on or estimated security labels Aug 11, 2021
@gmmorris gmmorris added the estimate:needs-research Estimated as too large and requires research to break down into workable issues label Aug 18, 2021
@gmmorris gmmorris removed the loe:needs-research This issue requires some research before it can be worked on or estimated label Sep 2, 2021
@elasticmachine
Copy link
Contributor

Pinging @elastic/security-threat-hunting-cases (Team:Threat Hunting:Cases)

@kobelb kobelb added the needs-team Issues missing a team label label Jan 31, 2022
@botelastic botelastic bot removed the needs-team Issues missing a team label label Jan 31, 2022
@cnasikas
Copy link
Member

Will be handled by #160367

@Zacqary Zacqary mentioned this issue Feb 5, 2024
15 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
estimate:needs-research Estimated as too large and requires research to break down into workable issues Feature:Actions/ConnectorTypes Issues related to specific Connector Types on the Actions Framework Feature:Actions/Framework Issues related to the Actions Framework Feature:Actions Feature:Cases Cases feature NeededFor:Security Solution SIEM, Endpoint, Timeline, Analyzer, Cases security Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams)
Projects
None yet
Development

No branches or pull requests

7 participants