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

Principal for plugins and extensions #5913

Open
peternied opened this issue Jan 17, 2023 · 11 comments
Open

Principal for plugins and extensions #5913

peternied opened this issue Jan 17, 2023 · 11 comments
Labels
extensions Plugins security Anything security related

Comments

@peternied
Copy link
Member

Use Case

As a user, when I interact with an extension its access is limited by its permissions and my permissions.

Acceptance Criteria

  • Subjects can have a chain of principals, the primary being the user, and following be extensions or plugins
  • When permissions checks are AND'ed during subject checks between the current user and extensions principals.
  • When an extension has permissions, but the user does not, the request is denied
  • When a user has permissions, but the extensions does not, the request is denied
@jimishs
Copy link

jimishs commented Jan 18, 2023

Hi @peternied , Could you share your thoughts on the type of permissions extensions require? Are we talking about permissions to data or permissions to host or something else? Thanks

@peternied
Copy link
Member Author

Permissions are granted to users such as "User Bob can create indexes". Plugins and extensions should have the same permissions grants such as "Extension LogScanner can create indexes".

@jimishs
Copy link

jimishs commented Jan 18, 2023

Thanks @peternied . So you are referring to permissions to data stored in indices and permissions to cluster level actions (eg: check health of a cluster etc). Currently these actions are tied to a user/backend_role.

Are there other actions that are specific only to extensions?

@peternied
Copy link
Member Author

Currently these actions are tied to a user/backend_role.

The identity designs do not leverage existing features or architecture in from the security plugin - clearly there will need to be migration path but during this phase we are designing towards an end state.

Are there other actions that are specific only to extensions?

There are no actions that are specific to extensions.

@shanilpa
Copy link

Just to make sure I understand this clearly.

We are going to require users to migrate to identity if they want to use extensions. We won't support extensions through our current security plugin. Are these statements correct @peternied?

How would having both security models running at the same time impact the acceptance criteria you have above? Does an admin need to completely disable the security plugin to use identity and extensions?

I'm still failing to understand how identity and the security plugin will work together because they will need to since the security plugin supports other use cases outside of extensions which identity won't support.

@dblock
Copy link
Member

dblock commented Jan 27, 2023

We are going to require users to migrate to identity if they want to use extensions. We won't support extensions through our current security plugin.

I have a handwavy answer. I don't think "migrate" would be my preferred term here. I think we will need both to work together, and provide a path where security in core performs functions currently implemented by the security plugin. Thus we can just delete much of the security plugin implementation without any changes to the end user.

@peternied
Copy link
Member Author

peternied commented Jan 30, 2023

@DarshitChanpura I know you were asking about the kinds of workflows, found diagrams for some different workflows on this issue #4485

@DarshitChanpura
Copy link
Member

Securing Extension Request Flow via Identity

Extension   Identity

Steps:

0,1. Register User and Extensions.

User:
{
	username: "user1",
	hash: "",
	extensions: "",
	permissions: ""
}

Extension:
{
	extension: "extension1",
	permissions: ""
}
  1. User user1 makes a GET request to search an index via extension1. This request contains a username and a password.

  2. Intercept the request, and parse user and extension.
    a. user1 is authenticated against identity. If user fails authc check, fail the request with 403. If user passes authc check, generate a token to identify the user.
    b. Next, identify the extension from extension name provided in the API path. Generate a token from extension.
    c. Next propagate this request to appropriate extension. This request contains user token and extension token (or a single token that identifies both)

  3. Once extension receives this request, it parses the request, then calls appropriate transport action request. This request must also contain the extension's own identifier, in addition to the token/s passed in the original request.

  4. Once the core receives this transport request, user and its actions are evaluated for permissions check.
    a. If extension's identifier is not present, reject the request. Send 400.
    b. If extension's identifier is present, but doesn't verify that request is coming from the correct extension, reject the request. Send 400.
    c. Once the verification that extension mentioned in original request and the extension the trasport request is coming from matches:
    - First, verify that user has permissions to execute this action.
    - Next, verify extension has permissions to execute this action.
    - If either or both fail, the request is deemed unauthorized. Send 403.
    - If both pass, proceed with the flow as normal.

  5. Execute the transport action, and return the response to extension. They then process this response to proceed to perform their actions necessary.

  6. Return appropriate response to user1.

These steps work under the assumption that identity is enabled and InternalAuthenticationManager is setup.

PS: Tokens would be JWT (unless decided otherwise)

** Question ** How do we handle NoopAuth?

Proposed solution: Extension will always be evaluated for their permissions for the corresponding action. (Extensions evaluation should never be a NoopAuthorization)

@cwperks @peternied @dblock Would you please review this?

@dblock
Copy link
Member

dblock commented Mar 8, 2023

  1. I think two tokens is a bit of an anti-pattern with authorization. I'd want to be able to pass around a single value/header as needed and avoid knowing that we have 2 identities to verify. A possible alternative could be that the extension signs the user's request instead of sending its own token. OpenSearch can then verify that the signature matches the extension's signature from registration, and then evaluate user's permissions.
  2. I think we should think about how to make this system stateless. The token handed after authentication should carry the permissions that were granted, so that subsequent authorization checks do not need to lookup these permissions but only verify that the token is valid (signed by the authority) and then look into the token for the permissions granted.

@peternied
Copy link
Member Author

peternied commented Mar 8, 2023

Nice diagram!

Extensions.permissions

I think we should change this name to 'allowed_capabilities' and the list is not the same as the kinds of permissions user accounts have. For example during step 3 interact_on_behalf_of_user would be checked if it was supported and only if it was allowed would the user delegated auth token be added to the request to the extension.

However, I think there should be another concept, Service Account? that is an identity that an extension uses whenever it making calls on its own behalf that is nearly identical to a normal user.

Maybe we can link between this issue and opensearch-project/security#2502 to work on the specific design?

3c. Next propagate this request to appropriate extension. This request contains user token and extension token (or a single token that identifies both)

Consideration for what is inside that token (single token) that can be via Bearer Authentication with claims:

  • Issuer, the principal of the OpenSearch cluster (Support multi-backend system)
  • Subject, the principal of the user that made the request.
  • Audience, the principal of the extension
  • Expiration, how long before this token expires (<5 minutes?)

I don't think adding a token id for managing revocation will scale well - as dblock mentioned for us to focus on stateless scenarios. But this would be good to call out when considering the lower level designs.

How do we handle NoopAuth

When the token is received in step 4 by OpenSearch if the issuer, or audience doesn't match it should be rejected. If NoopAuth isn't providing subjects I think these requests should fail on the principal that extensions require identity information.

@cwperks
Copy link
Member

cwperks commented Mar 9, 2023

@DarshitChanpura I like the idea of the token that's passed to the extension as being scoped to the actions it needs to fulfill the request.

The admin should be able to set policies for an extension restricting how requests that originate from an extension could interact with a cluster.

i.e. A policy for an extension that could only read index pattern my-index* could look like a roles definition:

ext1:
  index_permissions:
    - index_patterns:
        - 'my_index*'
      allowed_actions:
        - 'indices:data/read/search*'

In addition, the user that's performing the REST request has permissions to interact with the OpenSearch cluster given through roles.

Imagine that a user in this scenario has:

user1 is mapped to role1

role1:
  cluster_permissions:
    - "cluster:*"
  index_permissions:
    - index_patterns:
        - '*'
      allowed_actions:
        - 'indices_all'

Would it be possible to calculate the intersection of these policies and scope the token accordingly? I know that DLS/FLS can complicate things as well, so it may not be possible to do this with FLS/DLS rules on a role.


There will need to be a mechanism to identify if a REST request comes from an extension. A TLS channel between the cluster and the extension could be a way to identify the origin of the request. A simple approach to identifying the origin of a extension could be to embed extensionId as a claim in the token passed to the extension. When a REST request originates from the extension the privileges could be evaluated twice:

  1. First time would be to verify that the user making the request has the requisite permissions.
  2. Second time would be to verify that the extension is authorized to access the data based on its policy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extensions Plugins security Anything security related
Projects
Status: No status
Development

No branches or pull requests

8 participants