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

Expose ability to check if API Keys are enabled #63454

Merged
merged 13 commits into from
Apr 23, 2020

Conversation

legrego
Copy link
Member

@legrego legrego commented Apr 14, 2020

Summary

Exposes the ability to check if API Keys are enabled in Elasticsearch:

  • New server-side function: await setup.authc.areAPIKeysEnabled()
  • New client-side function: await setup.authc.areAPIKeysEnabled()

Updates existing /internal/security/api_key/privileges route to use ES exception metadata to check if API Keys are enabled (instead of checking error message text).

Resolves #59576

return false;
}

const id = `kibana-api-key-service-test-${uuid.v4()}`;
Copy link
Member Author

Choose a reason for hiding this comment

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

note: we don't want to accidentally invalidate a key that actually exists, but we also want the ID to be descriptive in case someone inspecting the ES audit logs wants to trace this back. By combining descriptive text with a UUID, we can guarantee uniqueness while still being descriptive.

Copy link
Member Author

Choose a reason for hiding this comment

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

updated note: after I wrote this comment, I realized that the key id is generated by ES, and not under the user's control (unlike the key's name). Therefore, there is no need to generate a unique id using UUID. I've updated this to always just use kibana-api-key-service-test instead.

@legrego
Copy link
Member Author

legrego commented Apr 14, 2020

@elasticmachine merge upstream

@legrego legrego added release_note:skip Skip the PR/issue when compiling release notes Team:Security Team focused on: Auth, Users, Roles, Spaces, Audit Logging, and more! v7.8.0 v8.0.0 labels Apr 14, 2020
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-security (Team:Security)

@@ -10,6 +10,7 @@ import { ApiKey, ApiKeyToInvalidate } from '../../../common/model';
interface CheckPrivilegesResponse {
areApiKeysEnabled: boolean;
isAdmin: boolean;
canManage: boolean;
Copy link
Member Author

Choose a reason for hiding this comment

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

note previously, the API Keys app had a dual purpose for areApiKeysEnabled: It was true if and only if both of the following were true:

  • User was authorized to retrieve their own API Keys
  • API Keys were in fact enabled

This separates those two concerns into dedicated properties

@legrego legrego marked this pull request as ready for review April 15, 2020 11:44
@legrego legrego requested a review from a team as a code owner April 15, 2020 11:44
@azasypkin
Copy link
Member

ACK: can review tomorrow if no one does it today.

@azasypkin azasypkin self-requested a review April 21, 2020 10:43
Copy link
Member

@azasypkin azasypkin left a comment

Choose a reason for hiding this comment

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

LGTM! Tested locally, everything works as expected. Just left a few questions/nits, but nothing substantial (except for error.body. that we can potentially use instead of JSON.parse).

this.props.notifications.toasts.addDanger(
i18n.translate('xpack.security.management.apiKeys.table.fetchingApiKeysErrorMessage', {
defaultMessage: 'Error checking privileges: {message}',
values: { message: _.get(e, 'body.message', '') },
Copy link
Member

Choose a reason for hiding this comment

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

nit: while you're, let's finally remove lodash from this file:

Suggested change
values: { message: _.get(e, 'body.message', '') },
values: { message: e.body?.message || '' },

Copy link
Member Author

Choose a reason for hiding this comment

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

good idea!

@@ -10,7 +10,7 @@ import { wrapIntoCustomErrorResponse } from '../../errors';
import { createLicensedRouteHandler } from '../licensed_route_handler';
import { RouteDefinitionParams } from '..';

export function defineGetApiKeysRoutes({ router, clusterClient }: RouteDefinitionParams) {
export function defineGetApiKeysRoutes({ router, clusterClient, authc }: RouteDefinitionParams) {
Copy link
Member

Choose a reason for hiding this comment

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

nit: looks like a leftover

Suggested change
export function defineGetApiKeysRoutes({ router, clusterClient, authc }: RouteDefinitionParams) {
export function defineGetApiKeysRoutes({ router, clusterClient }: RouteDefinitionParams) {


export function defineEnabledApiKeysRoutes({
router,
clusterClient,
Copy link
Member

Choose a reason for hiding this comment

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

nit:

Suggested change
clusterClient,

id,
},
});
return true;
Copy link
Member

Choose a reason for hiding this comment

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

question: what does it mean if ES replies with 200 to such request? Does Elasticsearch just ignores unknown API keys? It seems ES works with security tokens differently then elastic/elasticsearch#54532 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

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

question: what does it mean if ES replies with 200 to such request? Does Elasticsearch just ignores unknown API keys? It seems ES works with security tokens differently then elastic/elasticsearch#54532 (comment)

Yeah, it returns a 200 response:
image

Copy link
Member

Choose a reason for hiding this comment

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

I see, thanks for confirming. Just out of curiosity, @jkakavas is there any valid reason to return different status codes for "unknown" api keys and access tokens during invalidation or we just didn't have chance to unify that yet?

Copy link
Member

Choose a reason for hiding this comment

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

It's the latter. I just opened elastic/elasticsearch#55671 to keep track of the work needed for the invalidate api keys API

@@ -247,6 +276,20 @@ export class APIKeys {
return result;
}

private doesErrorIndicateAPIKeysAreDisabled(e: Record<string, any>) {
const responseText = e.response ?? '{}';
Copy link
Member

Choose a reason for hiding this comment

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

question: can't we just use e.body?.error?.['disabled.feature'] and eliminate try/catch here completely?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, you are absolutely right! I don't know why I thought I had to manually parse response to get at this metadata 🤦

@@ -70,16 +109,21 @@ describe('Check API keys privileges', () => {

const error = Boom.notAcceptable('test not acceptable message');
getPrivilegesTest('returns error from cluster client', {
apiResponses: [
callAsCurrrentUserResponses: [
Copy link
Member

Choose a reason for hiding this comment

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

typo:

Suggested change
callAsCurrrentUserResponses: [
callAsCurrentUserResponses: [

Copy link
Member Author

Choose a reason for hiding this comment

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

gah! I hate my broken keyboard!

{ body: { cluster: ['manage_security', 'manage_api_key', 'manage_own_api_key'] } },
],
],
callAsInternalUserAPIArguments: [
Copy link
Member

Choose a reason for hiding this comment

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

question: any reason you didn't want to mock ApiKeys instead to not expose internal impl detail (the fact that we use invalidate key under the hood)? I'm fine with keeping it as is, just curious what is main motivation here.

Copy link
Member Author

Choose a reason for hiding this comment

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

My only motivation here was to follow the pattern that already existed in this test suite. The changes started out small, but it might have been easier to rewrite in hindsight

Copy link
Member

Choose a reason for hiding this comment

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

Got it, makes sense to me.

@@ -13,6 +13,7 @@ export default async function({ readConfigFile }) {
config.esTestCluster.serverArgs = [
'xpack.license.self_generated.type=basic',
'xpack.security.enabled=true',
'xpack.security.authc.api_key.enabled=true',
Copy link
Member

Choose a reason for hiding this comment

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

note: it's too bad we don't have an easy way to reconfigure ES during tests and jest_integration tests are not available in xpack either. Ideally we'd like to check the case when keys are disabled so that we can catch the breaking changes in ES error format, but having a dedicated config just to test this is too much as well. No need to change/improve anything here, just grumbling about imperfect test system we live with.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree! I almost created a dedicated test suite for the disabled case, but like you mentioned, it's not worth the effort/overhead

@legrego
Copy link
Member Author

legrego commented Apr 23, 2020

@elasticmachine merge upstream

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@legrego legrego merged commit 44f9cbc into elastic:master Apr 23, 2020
legrego added a commit to legrego/kibana that referenced this pull request Apr 23, 2020
* expose ability to check if API Keys are enabled

* fix mock

* Fix typo in test name

* simplify key check

* fix privilege check

* remove unused variable

* address PR feedback

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
@legrego legrego deleted the security/api-keys-enabled branch April 23, 2020 19:25
legrego added a commit that referenced this pull request Apr 23, 2020
* expose ability to check if API Keys are enabled

* fix mock

* Fix typo in test name

* simplify key check

* fix privilege check

* remove unused variable

* address PR feedback

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
gmmorris added a commit to gmmorris/kibana that referenced this pull request Apr 24, 2020
* master: (70 commits)
  KQL removes leading zero and breaks query (elastic#62748)
  [FieldFormats] Cleanup: rename IFieldFormatType -> FieldFormatInstanceType (elastic#64193)
  [ML] Changes transforms wizard UI text (elastic#64150)
  [Alerting] change server log action type .log to .server-log in README (elastic#64124)
  [Metrics UI] Design Refresh: Inventory View, Episode 1 (elastic#64026)
  chore(NA): reduce siem bundle size using babel-plugin-transfor… (elastic#63269)
  chore(NA): use core-js instead of babel-polyfill on canvas sha… (elastic#63486)
  skip flaky suite (elastic#61173)
  skip flaky suite (elastic#62497)
  Renamed ilm policy for event log so it is not prefixed with dot (elastic#64262)
  [eslint] no_restricted_paths config cleanup (elastic#63741)
  Add Oil Rig Icon from @elastic/maki (elastic#64364)
  [Maps] Migrate Maps embeddables to NP (elastic#63976)
  [Ingest] Data streams list page (elastic#64134)
  chore(NA): add file-loader into jest moduleNameMapper (elastic#64330)
  [DOCS] Added images to automating report generation (elastic#64333)
  [SIEM][CASE] Api Integration Tests: Configuration (elastic#63948)
  Expose ability to check if API Keys are enabled (elastic#63454)
  [DOCS] Fixes formatting in alerting doc (elastic#64338)
  [data.search.aggs]: Create agg types function for terms agg. (elastic#63541)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release_note:skip Skip the PR/issue when compiling release notes Team:Security Team focused on: Auth, Users, Roles, Spaces, Audit Logging, and more! v7.8.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use exception metadata to determine if APIKeys are enabled
5 participants