Skip to content

Allow creation of API keys on behalf of other users #48716

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

Closed
peterschretlen opened this issue Oct 30, 2019 · 21 comments
Closed

Allow creation of API keys on behalf of other users #48716

peterschretlen opened this issue Oct 30, 2019 · 21 comments
Assignees
Labels
>enhancement :Security/Authentication Logging in, Usernames/passwords, Realms (Native/LDAP/AD/SAML/PKI/etc) Top Ask

Comments

@peterschretlen
Copy link

peterschretlen commented Oct 30, 2019

The manage_own_api_key role allows creating a point-in-time snapshot of an authenticated user's permissions, that does not expire. This is ideal for Kibana alerting which runs scheduled background alert checks where permissions need to be enforced but the authenticated user isn't around.

However most users won't have the manage_own_api_key role. Generally this should be an explicitly granted privilege.

Would it be possible to allow a user (like the kibana system user) to create API keys on behalf of other users (similar to the token api )?

The user of a service like alerting would then require no special privileges. They would not need access to (or even awareness of) the API keys created on their behalf. The system user could be restricted to creating keys for users whose credentials they have ( like a user submitting a request to create an alert, for example ).

@peterschretlen peterschretlen added >enhancement :Security/Authentication Logging in, Usernames/passwords, Realms (Native/LDAP/AD/SAML/PKI/etc) labels Oct 30, 2019
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-security (:Security/Authentication)

@bytebilly
Copy link
Contributor

@peterschretlen I'm not sure I'm getting what you mean when you say "API keys created on their behalf". If they don't need to access and manage those keys, which is the difference if the keys are created by the kibana user or on behalf of another user?

What I think is important is the set of privileges, and those are not following the "original" user anyway.

Even if creating keys on behalf of another user, they would never get more privileges than the current user (the one performing the request), or it could gain those privileges too.

Could you please help to clarify? Thanks!

@peterschretlen
Copy link
Author

I'm not sure I'm getting what you mean when you say "API keys created on their behalf". If they don't need to access and manage those keys, which is the difference if the keys are created by the kibana user or on behalf of another user?

The difference is the API key would be a privilege snapshot of the 'target' user, not a privilege snapshot of the user who is making the request to elasticsearch.

The idea is an internal kibana system user ( which has very limited privileges - it only has read/write access to the system indices it needs to operate) could take create an API key of the end-user logged into Kibana (who will have privileges to data they want to run background jobs on) when they request a background job to be created and run.

Even if creating keys on behalf of another user, they would never get more privileges than the current user (the one performing the request), or it could gain those privileges too.

The API key should represent the 'target' user permissions, so yes there's risk that the 'requesting' user captures that key and now has expanded privileges. That's one way to look at what the internal Kibana system user would be doing, but this action must be initiated by the target authenticated user, with the intent of creating a background task owned by that target user.

In general we want users to have API keys, but not require users to be able to create their own API keys.

cc @mikecote @tvernum

@bytebilly
Copy link
Contributor

The API key should represent the 'target' user permissions, so yes there's risk that the 'requesting' user captures that key and now has expanded privileges.

The caller will always be able to create an API key on behalf of another user (let's say elastic), and access its value. Then the caller can use this API key to run any other call with the elastic privileges.
If the caller is not able to access this value, nobody else will and they key cannot be used.

That's one way to look at what the internal Kibana system user would be doing, but this action must be initiated by the target authenticated user, with the intent of creating a background task owned by that target user.

From an Elasticsearch point of view, it's not important how the action starts in Kibana, but who authenticates to make the request. In this case, it would be an "unprivileged" user that will receive a key that can be used for potentially "privileged" requests.

Maybe I'm missing something, so please be patient if I don't see the point. I understand the need, but I'm not sure this is the safe way to address it.

What do you think?

In general we want users to have API keys, but not require users to be able to create their own API keys.

Having a key means just knowing the id/value, and there is no real connection with the user once created (except for the ownership relationship that is used by the manage_own_api_key

@peterschretlen
Copy link
Author

The hope is for something similar to the token API. Since the logged-in user is initiating the request (and assume the kibana system has the credentials in some form), then I don't see it as much different than the token API:

POST /_security/oauth2/token
{
  "grant_type" : "password",
  "username" : "test_admin",
  "password" : "x-pack-test-password"
}

We'd use token API (without needing kibana system at all) except for the fact that tokens have an expiry, and these background alerting jobs may run indefinitely.

@bytebilly
Copy link
Contributor

Thanks @peterschretlen, now I can see the full picture and how it is supposed to work. I was missing using the current target credentials in the request.

@mikecote
Copy link

@tvernum from our previous conversation a few weeks ago, you were waiting to know what time frame we would be able to test this feature and ensure what is built is suitable for our needs. I have an answer for this now which would be late January (7.7 scope). This will give us enough time to also implement the feature on our side within the same release. Let me know what you think and we will reserve time for testing / validating.

@albertzaharovits
Copy link
Contributor

I would like to float an idea which is a bit on the wilder side:

Instead of having the kibana_system have the privilege to generate API Keys for other users (given their credentials, which could be a short lived token in the SAML/OIDC realm case), could the user be able to generate API Keys for himself without requiring any privilege? In essence, could we be deprecating the manage_own_api_key privilege and grant the permission to everyone?

@tvernum
Copy link
Contributor

tvernum commented Dec 16, 2019

could we be deprecating the manage_own_api_key privilege and grant the permission to everyone?

No, we absolutely don't want to do that.

If everyone can create API Keys then they become a backdoor for avoiding the authentication controls that the admin has put in place (MFA/PKI). We have intentionally made them an opt-in feature per user.

As an example, if you configure your cluster to require SAML in order to satisfy certain security policies (MFA, password policies, account locking, etc) but your SAML users are allowed to create API Keys, then they can simply by-pass all of those protections.
The only option to solve that is to turn off API-keys across the board, but then you can't use alerting.

The option proposed here is safe because the user never gets access to the API key secret. Alerting actually "owns" the API key and protects it so that the user doesn't have direct access to the cluster, but Alerting can run tasks on their behalf.

@peterschretlen
Copy link
Author

Perhaps the scope of this needs to be both create and invalidate ?

When we update an alert, we also update the API key on the alert to reflect any changes in the user's privileges. To prevent a lot of 'dangling' API keys we'd also like to invalidate the old key, or at least prevent it from cluttering the API key UI view in Kibana.

See elastic/kibana#54525 for an example of this, where the alerts for SIEM detection engine in 7.6 can be updated, but they leave behind 'dangling' keys when the user has only the manage_own_api_key privilege.

@peterschretlen
Copy link
Author

@tvernum from our previous conversation a few weeks ago, you were waiting to know what time frame we would be able to test this feature and ensure what is built is suitable for our needs. I have an answer for this now which would be late January (7.7 scope). This will give us enough time to also implement the feature on our side within the same release. Let me know what you think and we will reserve time for testing / validating.

@tvernum @bytebilly since we're about to start 7.7, I wanted to make sure this is still part of your 7.7 plans? We still expect to be able to test this by late January.

@tvernum
Copy link
Contributor

tvernum commented Jan 15, 2020

@peterschretlen Yes, this is still at the top of our 7.7 plans, and I haven't heard of anything coming down the pipeline that is likely to push it out.

@tvernum
Copy link
Contributor

tvernum commented Jan 15, 2020

Proposal

Add new endpoint

POST /_security/oauth2/api_key

The body will mimic the body for /_security/oauth2/token, with the following changes:

  • The grant_type may be password or access_token, no other grant types are supported
  • Depending on the grant type, the body should have username and password fields, or an access_token field.
  • The scope may optionally be provided validated according to the same rules as the existing token endpoint.
  • A new api_key nested object with the same content as the body of the POST /_security/api_key endpoint.

Internally this API will call a new Action with a name of cluster:admin/xpack/security/api_key/grant. That action will work like the CreateTokenAction, but generate API keys instead of short lived tokens

A new cluster privilege called grant_api_key will be added that allows the user to call this new action.
We may decide to exclude the new action from the existing manage_api_key privilege, but I'm leaning towards not doing that. (TBC).
The manage_own_api_key privilege will not allow access to the new action.

The kibana_system role will be given the new grant_api_key system privilege and the cluster:admin/xpack/security/api_key/invalidate privilege.
This will allow Kibana to:

  • create new api keys on behalf of users when it has access to their credentials (username/password, or an access token)
  • get information about an API key by authenticating with that API key
  • invalidate any API key

We can discuss alternatives for those last 2 if anyone sees an issue, but I think we're comfortable with Kibana being able to invalidate all API keys. At a worse case it's a DoS risk, but there's no privilege escalation risk.


@elastic/es-security , @peterschretlen , @elastic/kibana-security
Can you review and provide feedback on the proposal above?

@jkakavas
Copy link
Member

I like Tim's proposal in general and I'd like to suggest some changes. If these look like implementation details we can defer discussion to the actual PR, I just noted what I thought about. In general, it's a +1 from me.

  • I don't see a reason to overload the _security/oauth2 namespace since there is nothing oauth2-like or oauth2-specific about this API. I propose we use /_security/api_key/grant or /_security/api_key/user ( and we could also allow introduce /_security/api_key/self as an alias to /_security/api_key ). I hold no strong opinions for this, we could go with a totally new endpoint under _security too .

  • I don't think we need scope for something. IIRC we added to the token endpoint to be closer to the oAuth2 standard but we don't use it anyhow.

We may decide to exclude the new action from the existing manage_api_key privilege, but I'm leaning towards not doing that.

++ I see no reason to exclude this. Given that the knowledge/possession of valid credentials/token is required either way to call the new API, there is no additional permission a user with manage_api_key gets with the inclusion of grant_api_key. User A with manage_api_key could already authenticate as user B and get an API key for user B by calling _security/api_key.

The kibana_system role will be given the new grant_api_key system privilege and the cluster:admin/xpack/security/api_key/invalidate privilege.

If we don't exclude grant_api_key from manage_api_key wouldn't it be equivalent to give manage_api_key to kibana_system role ? With the difference that the latter will allow kibana_system to get information about API keys without the user's credentials. I don't think this is problematic but argument can be made in favor of least privilege principle.

@kobelb
Copy link
Contributor

kobelb commented Jan 16, 2020

@tvernum's proposal with or without the changes that @jkakavas suggested look great to me! I I don't have much to add besides that. All of the current auth providers in Kibana are either token based or username/password based, so we should be able to use this for all authenticated users.

@peterschretlen
Copy link
Author

Thanks @tvernum, the proposal looks good to me, it covers the requirements Kibana has.

@albertzaharovits
Copy link
Contributor

@tvernum your proposal LGTM .
Two questions:

  • Who "owns" the API Key, the target user or the caller of the API (the system user)? I am leaning for the user, because in the end this is a core aspect that distinguishes long lived API keys from authn tokens, that the user has a view of the sessions impersonating him.

  • From Allow creation of API keys on behalf of other users #48716 (comment) I agree creating your own API key is undesirable, but how about invalidating own API keys? Can we grant the privilege to invalidate owned API keys to every user? In this case, if the kibana system creates api keys from credentials under the ownership of the user, the user is aware of them and can invalidate them? Related, if API keys can invalidate themselves, then I don't believe kibana system requires the privilege to invalidate all.

@bytebilly
Copy link
Contributor

I like the overall plan!

I don't see a reason to overload the _security/oauth2 namespace since there is nothing oauth2-like or oauth2-specific about this API.

I agree on this point, if it's not an "extension" of OAuth2 we should not use that namespace

@tvernum tvernum self-assigned this Feb 3, 2020
@tvernum
Copy link
Contributor

tvernum commented Feb 25, 2020

Who "owns" the API Key, the target user or the caller of the API (the system user)?

The target user. It holds their privileges, and is operating on their behalf. That is the user that we want to show in audit logs, etc.

but how about invalidating own API keys? Can we grant the privilege to invalidate owned API keys to every user?

We debated this when adding the manage_own_api_key privilege, and my recollection is that we didn't have a compelling reason either way, except least privilege is better, so we opted for a model where it was possible to define an API key that cannot invalidate itself (but they typically can because the owning user would have that privilege and would pass it on to the key).

If we reversed that, it would solve this problem, but it would also be a backwards incompatible change to security which bothers me.

@jowiho
Copy link
Contributor

jowiho commented Feb 25, 2020

The cloud platform team would be very happy with this feature. We will be rolling out our "public API" feature in the near future, that allows user to manage their ESS deployments through our API while authenticating with API keys.

We'll be managing all users and their API keys in our "security cluster". We use a system user to interact with the security cluster (not unlike Kibana). Users don't get direct access to that cluster, but we still try to lock down things as much as possible. So ideally the system user could create API keys for users without us having to grant those users the manage_own_api_key role. Same for invalidating API keys.

Would this feature also allow us to create API keys on behalf of users from external realms like SAML, assuming that we explicitly specify the desired permissions when creating a key?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
>enhancement :Security/Authentication Logging in, Usernames/passwords, Realms (Native/LDAP/AD/SAML/PKI/etc) Top Ask
Projects
None yet
Development

No branches or pull requests

10 participants