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

Add support for API keys to access Elasticsearch #38291

Merged
merged 71 commits into from
Feb 5, 2019
Merged

Conversation

bizybot
Copy link
Contributor

@bizybot bizybot commented Feb 4, 2019

X-Pack security supports built-in authentication service token-service that allows
access tokens to be used to access Elasticsearch without using Basic authentication.
The tokens are generated by token-service based on OAuth2 spec. The access token
is a short-lived token (defaults to 20m) and refresh token with a lifetime of 24 hours,
making them unsuitable for long-lived or recurring tasks where the system might go
offline thereby failing refresh of tokens.

This commit introduces a built-in authentication service api-key-service that
adds support for long-lived tokens aka API keys to access Elasticsearch. The api-key-service
is consulted after token-service in the authentication chain. By default, if TLS is enabled
then api-key-service is also enabled. The service can be disabled using the configuration
setting.

The API keys:-

  • by default do not have an expiration but expiration can be configured
    where the API keys need to be expired after a certain amount of time.
  • when generated will keep authentication information of the user that
    generated them.
  • can be defined with a role describing the privileges for accessing
    Elasticsearch and will be limited by the role of the user that generated
    them
  • can be invalidated via invalidation API
  • information can be retrieved via a get API
  • that have been expired or invalidated will be retained for 1 week before
    being deleted. The expired API keys remover task handles this.

Following are the API key management APIs:-

  1. Create API Key - PUT/POST /_security/api_key
  2. Get API key(s) - GET /_security/api_key
  3. Invalidate API Key(s) DELETE /_security/api_key

The API keys can be used to access Elasticsearch using Authorization
header, where the auth scheme is ApiKey and the credentials, is the
base64 encoding of API key Id and API key separated by a colon.
Example:-

curl -H "Authorization: ApiKey YXBpLWtleS1pZDphcGkta2V5" http://localhost:9200/_cluster/health

Closes #34383

jaymode and others added 30 commits November 2, 2018 07:48
In order to support api keys for access to elasticsearch, we need the
ability to generate these api keys. A transport action has been added
along with the request and response objects that allow for the
generation of api keys. The api keys require a name and optionally
allow a role to be specified which defines the amount of access the key
has. Additionally an expiration may also be provided.

This change does not include the restriction that the role needs to be
a subset of the user's permissions, which will be added seperately. As
it exists in this change, the api key is currently not usable which is
another aspect that will come later.

Relates #34383
This change implements the verification of api keys in the
ApiKeyService. There is no integration into the AuthenticationService
as part of this change; this will be done in a future change.

Verification of an API key involves validating the provided key with
the hash stored in the document and then ensuring that the token is not
expired. A conscious decision has been made to always validate the hash
and then check expiration. This is done to prevent leaking that a given
key has expired.
This commit integrates usage of the api key service into the
authentication service for verification of api keys. A bug was fixed in
the validation of api keys where the structure of the document was not
being used properly. Additionally, unit tests have been added for
authentication with api keys.
This change implements a lookup of permissions for API keys when a
request moves to authorization. In order to support this, the
authentication of an API key will attach values as metadata on the
authentication result. The values attached will include the source
of the role descriptors. The authentication service will then copy
this metadata to the authentication object and set the authentication
type to API_KEY. The authorization service will use the authentication
type to make a decision on how the roles should be obtained.
This commit enables api keys to share the same cache for roles that is
already in use for roles from other sources. In order to avoid the
possibility of a key collision with roles that do not belong to api
keys, the key for the roles cache now includes a source field that
prevents these collisions.
This change builds upon the work done in #35970 and adds appropriate
types for anonymous and internal authentication to the
`AuthenticationType` enum.
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-security

Copy link
Contributor

@tvernum tvernum left a comment

Choose a reason for hiding this comment

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

I haven't reviewed enough of the API Key PRs to be able to say whether this is ready or not, but I have no objections.

Copy link
Member

@jaymode jaymode left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@jkakavas jkakavas left a comment

Choose a reason for hiding this comment

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

I didn't go through the whole changeset here but I've reviewed enough of the individual PRs so LGTM

@bizybot bizybot merged commit fe36861 into master Feb 5, 2019
jasontedor added a commit to jasontedor/elasticsearch that referenced this pull request Feb 5, 2019
…-lease-expiration

* elastic/master: (24 commits)
  Add support for API keys to access Elasticsearch (elastic#38291)
  Add typless client side GetIndexRequest calls and response class (elastic#37778)
  Limit token expiry to 1 hour maximum (elastic#38244)
  add docs saying mixed-cluster ILM is not supported (elastic#37954)
  Skip unsupported languages for tests (elastic#38328)
  Deprecate `_type` in simulate pipeline requests (elastic#37949)
  Mute testCannotShrinkLeaderIndex (elastic#38374)
  Tighten mapping syncing in ccr remote restore (elastic#38071)
  Add test for `PutFollowAction` on a closed index (elastic#38236)
  Fix SSLContext pinning to TLSV1.2 in reload tests (elastic#38341)
  Mute RareClusterStateIT.testDelayedMappingPropagationOnReplica (elastic#38357)
  Deprecate types in rollover index API (elastic#38039)
  Types removal - fix FullClusterRestartIT warning expectations (elastic#38310)
  Fix ILM explain response to allow unknown fields (elastic#38054)
  Mute testFollowIndexAndCloseNode (elastic#38360)
  Docs: Drop inline callout from scroll example (elastic#38340)
  Deprecate HLRC security methods (elastic#37883)
  Remove types from Monitoring plugin "backend" code (elastic#37745)
  Add Composite to AggregationBuilders (elastic#38207)
  Clarify slow cluster-state log messages (elastic#38302)
  ...
bizybot added a commit to bizybot/elasticsearch that referenced this pull request Feb 5, 2019
X-Pack security supports built-in authentication service
`token-service` that allows access tokens to be used to
access Elasticsearch without using Basic authentication.
The tokens are generated by `token-service` based on
OAuth2 spec. The access token is a short-lived token
(defaults to 20m) and refresh token with a lifetime of 24 hours,
making them unsuitable for long-lived or recurring tasks where
the system might go offline thereby failing refresh of tokens.

This commit introduces a built-in authentication service
`api-key-service` that adds support for long-lived tokens aka API
keys to access Elasticsearch. The `api-key-service` is consulted
after `token-service` in the authentication chain. By default,
if TLS is enabled then `api-key-service` is also enabled.
The service can be disabled using the configuration setting.

The API keys:-
- by default do not have an expiration but expiration can be
  configured where the API keys need to be expired after a
  certain amount of time.
- when generated will keep authentication information of the user that
   generated them.
- can be defined with a role describing the privileges for accessing
   Elasticsearch and will be limited by the role of the user that
   generated them
- can be invalidated via invalidation API
- information can be retrieved via a get API
- that have been expired or invalidated will be retained for 1 week
  before being deleted. The expired API keys remover task handles this.

Following are the API key management APIs:-
1. Create API Key - `PUT/POST /_security/api_key`
2. Get API key(s) - `GET /_security/api_key`
3. Invalidate API Key(s) `DELETE /_security/api_key`

The API keys can be used to access Elasticsearch using `Authorization`
header, where the auth scheme is `ApiKey` and the credentials, is the
base64 encoding of API key Id and API key separated by a colon.
Example:-
```
curl -H "Authorization: ApiKey YXBpLWtleS1pZDphcGkta2V5" http://localhost:9200/_cluster/health
```

Closes elastic#34383
bizybot added a commit that referenced this pull request Feb 6, 2019
X-Pack security supports built-in authentication service
`token-service` that allows access tokens to be used to
access Elasticsearch without using Basic authentication.
The tokens are generated by `token-service` based on
OAuth2 spec. The access token is a short-lived token
(defaults to 20m) and refresh token with a lifetime of 24 hours,
making them unsuitable for long-lived or recurring tasks where
the system might go offline thereby failing refresh of tokens.

This commit introduces a built-in authentication service
`api-key-service` that adds support for long-lived tokens aka API
keys to access Elasticsearch. The `api-key-service` is consulted
after `token-service` in the authentication chain. By default,
if TLS is enabled then `api-key-service` is also enabled.
The service can be disabled using the configuration setting.

The API keys:-
- by default do not have an expiration but expiration can be
  configured where the API keys need to be expired after a
  certain amount of time.
- when generated will keep authentication information of the user that
   generated them.
- can be defined with a role describing the privileges for accessing
   Elasticsearch and will be limited by the role of the user that
   generated them
- can be invalidated via invalidation API
- information can be retrieved via a get API
- that have been expired or invalidated will be retained for 1 week
  before being deleted. The expired API keys remover task handles this.

Following are the API key management APIs:-
1. Create API Key - `PUT/POST /_security/api_key`
2. Get API key(s) - `GET /_security/api_key`
3. Invalidate API Key(s) `DELETE /_security/api_key`

The API keys can be used to access Elasticsearch using `Authorization`
header, where the auth scheme is `ApiKey` and the credentials, is the
base64 encoding of API key Id and API key separated by a colon.
Example:-
```
curl -H "Authorization: ApiKey YXBpLWtleS1pZDphcGkta2V5" http://localhost:9200/_cluster/health
```

Closes #34383
jasontedor added a commit to jasontedor/elasticsearch that referenced this pull request Feb 6, 2019
* 6.x: (25 commits)
  Backport of types removal for Put/Get index templates (elastic#38465)
  Add support for API keys to access Elasticsearch (elastic#38291) (elastic#38399)
  Deprecate support for internal versioning for concurrency control (elastic#38451)
  Deprecate types in rollover index API (elastic#38389) (elastic#38458)
  Add typless client side GetIndexRequest calls and response class (elastic#38422)
  [ML] Report index unavailable instead of waiting for lazy node (elastic#38444)
  await fix CurtIT#testIndex until elastic#38451 is merged (elastic#38466)
  Update ilm-api.asciidoc, point to REMOVE policy (elastic#38235) (elastic#38464)
  SQL: Fix esType for DATETIME/DATE and INTERVALS (elastic#38179)
  Clean up duplicate follow config parameter code (elastic#37688) (elastic#38443)
  Deprecation check for No Master Block setting (elastic#38383)
  Bubble-up exceptions from scheduler (elastic#38441)
  Lift retention lease expiration to index shard (elastic#38391)
  Deprecate maxRetryTimeout in RestClient and increase default value (elastic#38425)
  Update Rollup Caps to allow unknown fields (elastic#38446)
  Backport of elastic#38411: `if_seq_no` and `if_primary_term` parameters aren't wired correctly in REST Client's CRUD API
  Support unknown fields in ingest pipeline map configuration (elastic#38429)
  SQL: Implement CURRENT_DATE (elastic#38175)
  Backport changes to the release notes script. (elastic#38346)
  Fix ILM explain response to allow unknown fields (elastic#38363)
  ...
@bizybot bizybot deleted the security_api_keys branch February 7, 2019 00:10
@karmi
Copy link
Contributor

karmi commented Jul 13, 2019

I was recently adding support for the API Key authentication to the Go client (elastic/go-elasticsearch@3b68c0f), and I think there's a small, but nice usability optimization: it would help if the API would return also the base64-encoded value for the key, so the users (or the client) doesn't have to perform the encoding themselves.

@albertzaharovits
Copy link
Contributor

@karmi I see in the ES code that the key (api_key field in the response to POST _security/api_key) is base64 url encoded. Are we talking about the same thing?

@karmi
Copy link
Contributor

karmi commented Jul 16, 2019

@albertzaharovits , what I mean is the output (ie. result) of the "Create API Key" API:

docker run \
  --env "discovery.type=single-node" \
  --env "xpack.security.enabled=true" \
  --env "xpack.security.authc.api_key.enabled=true" \
  --env "xpack.license.self_generated.type=trial" \
  --env "ELASTIC_PASSWORD=elastic" \
  --publish 9200:9200 \
  --rm -it \
  docker.elastic.co/elasticsearch/elasticsearch:8.0.0-SNAPSHOT

curl -s -X POST \
        -H 'Content-Type: application/json' \
        http://elastic:elastic@localhost:9200/_security/api_key -d \
        '{"name":"test-key", "role_descriptors":{}}' \
| jq '.'

Output:

{
  "id": "ZquG-WsBx1ePiPP47oig",
  "name": "test-key",
  "api_key": "ipRxILiWT7udFhKgb69O4Q"
}

Ie. the API returns the id and api_key value, but not the base64-encoded version which has to be passed in the Authorization header. Is it more clear?

@albertzaharovits
Copy link
Contributor

Thank you @karmi .
I understand that in this case you have to concatenate id with : and api_key , encode base64, and then append to ApiKey to get the value of the Authorization header. And you are asking why isn't there a value in the response that I can put in the header as is.

I was under the impression that ApiKey concatenated with $api_key was the way to build the credentials in this case. But I am wrong.

@bizybot Do you think it would be feasible to achieve what @karmi is asking for? Either by adding another field in the response or make ES not require the id to be concatenated to the api_key, and only use the api_key?

@karmi
Copy link
Contributor

karmi commented Jul 16, 2019

And you are asking why isn't there a value in the response that I can put in the header as is.

Yes, exactly — with the goal of increasing the usability. If the response contains the fully-encoded value, the user can just copy&paste that value into the client in a single step.

Either by adding another field in the response (...)

Yes, that's what I had in mind — adding a property like value, encoded, credentials (not sure about the naming in this case...) in addition to existing properties.

@bizybot
Copy link
Contributor Author

bizybot commented Jul 16, 2019

Hi @karmi and @albertzaharovits,
I think this is feasible, we could indeed send out encoded_credentials, I do not see a problem there.
I think the same would be useful in case of native user creation as well, though we never sent credentials out. I like this as it could be useful in our REST integration test cases where we can just parse the value from the response and use it later in the next calls. We can create a discuss issue and take it forward if everyone agrees, wdyt?
Thank you for bringing up @karmi and thanks for the reminder for it @albertzaharovits. I had seen this on mobile and then I could not remember where the message came from as this was a closed PR.

@karmi
Copy link
Contributor

karmi commented Jul 16, 2019

We can create a discuss issue and take it forward if everyone agrees, wdyt?

Yes, please! Thanks for catching it, @bizybot !

@tvernum
Copy link
Contributor

tvernum commented Jul 16, 2019

make ES not require the id to be concatenated to the api_key, and only use the api_key

This part is not feasible. The id is needed so that we can find the document in the index so that we can check the hash. (We used salted hashes when storing the api_key, so it is not possible to do a search using only the key, and not the id).

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

Successfully merging this pull request may close these issues.

Long lived api keys/tokens
8 participants