Skip to content

Allow users to Update API Keys#146237

Merged
kc13greiner merged 29 commits intoelastic:mainfrom
kc13greiner:feature/api_keys_update
Dec 14, 2022
Merged

Allow users to Update API Keys#146237
kc13greiner merged 29 commits intoelastic:mainfrom
kc13greiner:feature/api_keys_update

Conversation

@kc13greiner
Copy link
Contributor

@kc13greiner kc13greiner commented Nov 23, 2022

Summary

API keys can now be updated via the API Keys Management screen

Release Note

API Keys can now be updated with new Role Descriptors and Metadata via the API Keys Management screen.

Testing Instructions

Login as elastic

Navigate to Roles and create a new role with the read_security cluster privilege:
Screen Shot 2022-11-30 at 9 42 31 AM

Create a new user and assign that new role, viewer, and kibana_admin:
Screen Shot 2022-11-30 at 9 43 10 AM

Navigate to Dev Tools and run the following:

POST /_security/api_key/grant
{
  "grant_type": "password",
  "username" : "elastic",  
  "password" : "changeme",  
  "run_as": "elastic",  
  "api_key" : {
    "name": "test-expired-key",
    "expiration": "1ms"
  }
}

POST /_security/api_key/grant
{
  "grant_type": "password",
  "username" : "elastic",  
  "password" : "changeme",  
  "run_as": "test_user",  
  "api_key" : {
    "name": "test-user-key",
    "expiration": "1d"
  }
}

The first command will create an API key for the elastic user that expires immediately.

The second command will create an API key for test_user.

Navigate to the API Key page, click the name column links to see a readonly view for the 2 previously created keys as users cannot update an API key that belongs to another user nor an API key that is expired.

Create a new API key:
Screen Shot 2022-11-30 at 9 44 52 AM

Click the name link for the newly created API key to see the Update API key flyout.

Update the fields and click submit:
Screen Shot 2022-11-30 at 9 45 59 AM

If the update was successful:
Screen Shot 2022-11-30 at 9 46 42 AM

Now click the name link again for the updated key and click submit without making changes. You should see a warning:
Screen Shot 2022-11-30 at 9 46 52 AM

Logout the elastic user and login as test_user

Navigate to API Keys and click the existing API Key to see a readonly view flyout:
Screen Shot 2022-11-30 at 9 58 25 AM

Thanks for reviewing!

@kc13greiner kc13greiner added Team:Security Platform Security: Auth, Users, Roles, Spaces, Audit Logging, etc t// v8.7.0 release_note:feature Makes this part of the condensed release notes labels Nov 23, 2022
const doesMetadataExist = Object.keys(selectedApiKey.metadata).length > 0;
const doCustomPrivilegesExist = Object.keys(selectedApiKey.role_descriptors ?? 0).length > 0;
const daysUntilExpiration = moment(selectedApiKey.expiration).diff(moment(), 'days', true);
const roundedDaysUntilExpiration =
Copy link
Contributor Author

@kc13greiner kc13greiner Nov 28, 2022

Choose a reason for hiding this comment

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

Question to reviewer: Do you think this is an appropriate expiration value to display?

Copy link
Contributor

Choose a reason for hiding this comment

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

The expiration summary on the table page is certainly more natural to interpret (i.e. number of hours or mins). I noticed we're limited to days in the flyout (reason?), but I could see this being a more free-form input like we see in other duration/time-based controls (like in discover for example).

If we don't want to change the control to more than just days (e.g. weeks or months), I would suggest displaying either the originally configured lifetime OR the remaining number of whole days (if possible a special case of "<1" for less than 1 day but more than 0). And then always show the "expires in"/"expired" summary text underneath the control (same as what's in the table).

Right now it will also display negative days after a key has expired, which I am not sure was intended. Is it useful to know how long ago a key expired? If so, I would just leave the lifetime at zero and add a text summary (e.g. "expired 3 hours ago"). I think this would be more intuitive than negative floating-point days.
Screen Shot 2022-12-05 at 12 08 41 PM

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for the suggestion on this - it looks so much cleaner now with the Status

@kc13greiner kc13greiner linked an issue Nov 28, 2022 that may be closed by this pull request
@kc13greiner kc13greiner marked this pull request as ready for review November 30, 2022 14:59
@kc13greiner kc13greiner requested a review from a team as a code owner November 30, 2022 14:59
@elasticmachine
Copy link
Contributor

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

Copy link
Contributor

@jeramysoucy jeramysoucy left a comment

Choose a reason for hiding this comment

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

Looks good! As discussed, let's ping Thom to get his thoughts on a couple of things.

@@ -62,6 +71,3 @@ created by which user in which realm.
If you have only the `manage_own_api_key` permission, you see only a list of your own keys.
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems to also be true if you have the 'read_sec' permission and access to the API key's screen (via kibana admin or viewer role)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great catch! I've added a line in the docs to reference the readonly view. @gchaps Would you mind reviewing the new sentence I added?


To update an API key, open the main menu, then click *Stack Management > API Keys*, then click on the name of an existing API key.

Only the `Restrict privileges` and `metadata` fields can be updated.
Copy link
Contributor

Choose a reason for hiding this comment

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

Just for my own knowledge, is it pretty typical (on other platforms/apis) that expiration dates are locked once an API key is created?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The original ticket said only those fields could be updated (that appears to be all ES allows). I think the process if a key is expired is to invalidate it and re- create

Copy link
Contributor

Choose a reason for hiding this comment

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

If Elasticsearch allows updating expiration time then we should support it in the UI as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Elasticsearch only allows those fields in the request body

});
});

it('updateApiKey() calls correct endpoint', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Complete nit, but the rest of the tests use 'queries the correct endpoint' language.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

defaultValues?: ApiKeyFormValues;
onSuccess?: (apiKey: CreateApiKeyResponse) => void;
onSuccess?: (
createdApiKeyResponse: CreateApiKeyResponse | undefined,
Copy link
Contributor

Choose a reason for hiding this comment

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

Consistency nit

Suggested change
createdApiKeyResponse: CreateApiKeyResponse | undefined,
createApiKeyResponse: CreateApiKeyResponse | undefined,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

const doesMetadataExist = Object.keys(selectedApiKey.metadata).length > 0;
const doCustomPrivilegesExist = Object.keys(selectedApiKey.role_descriptors ?? 0).length > 0;
const daysUntilExpiration = moment(selectedApiKey.expiration).diff(moment(), 'days', true);
const roundedDaysUntilExpiration =
Copy link
Contributor

Choose a reason for hiding this comment

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

The expiration summary on the table page is certainly more natural to interpret (i.e. number of hours or mins). I noticed we're limited to days in the flyout (reason?), but I could see this being a more free-form input like we see in other duration/time-based controls (like in discover for example).

If we don't want to change the control to more than just days (e.g. weeks or months), I would suggest displaying either the originally configured lifetime OR the remaining number of whole days (if possible a special case of "<1" for less than 1 day but more than 0). And then always show the "expires in"/"expired" summary text underneath the control (same as what's in the table).

Right now it will also display negative days after a key has expired, which I am not sure was intended. Is it useful to know how long ago a key expired? If so, I would just leave the lifetime at zero and add a text summary (e.g. "expired 3 hours ago"). I think this would be more intuitive than negative floating-point days.
Screen Shot 2022-12-05 at 12 08 41 PM

expect(await findByText('You do not have permission to create API keys')).toBeInTheDocument();
expect(queryByText('Create API key')).toBeNull();
});

Copy link
Contributor

Choose a reason for hiding this comment

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

Should we include cases to check for manage-own vs. manage all view? Test callouts?

Copy link
Contributor Author

@kc13greiner kc13greiner Dec 8, 2022

Choose a reason for hiding this comment

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

Since we are mocking the data from ES it will show whatever we put in the mock. Looking at the routes/api-keys/get.ts it passes an isAdmin value which I believe is the flag that determines if the user gets all the keys or just theirs.

}

return result;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

There's no api_key_flyout.test.tsx file. Should we add one that tests the flyout in readonly vs. create vs. edit mode?

EDIT: Looks like this is all tested by the functional tests in x-pack/test/functional/apps/api_keys/home_page.ts

@azasypkin azasypkin requested a review from gchaps December 6, 2022 09:18
@azasypkin
Copy link
Contributor

Tagging @gchaps for the docs changes.

Copy link
Contributor

@gchaps gchaps left a comment

Choose a reason for hiding this comment

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

LGTM with a few minor comments

'xpack.security.accountManagement.createApiKey.customExpirationInputLabel',
'xpack.security.accountManagement.apiKeyFlyout.customExpirationInputLabel',
{
defaultMessage: 'Lifetime (days)',
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we remove (days) here as the word "days" is included in the field?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gchaps Just the days in the label? or on the input box as well?

Copy link
Contributor

Choose a reason for hiding this comment

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

Just the days in the label.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(days) removed in latest commit!

kc13greiner and others added 5 commits December 7, 2022 22:38
Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>
Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>
Copy link
Contributor

@thomheymann thomheymann left a comment

Choose a reason for hiding this comment

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

All working well, a few comments below.

The "View API key" button doesn't make any sense (what would it do if it was enabled?) - I would change it to "Close":

Screenshot 2022-12-08 at 11 27 27

I appreciate that you tried to be consistent with the Create API key flow here but that flow is an exception since we need to show the token of the generated API key. Normal updates and errors should be shown using toast notifications so the behaviour is consistent with the rest of Kibana:

Screenshot 2022-12-08 at 11 29 14

Screenshot 2022-12-08 at 11 29 32

The "no update has been made" warning is an unnecessary detail. I would either disable the submit button until a change has been made (similar to user profile form) or show a success toast irregardless of whether the API key actually changed or not:
Screenshot 2022-12-08 at 12 22 50

@thomheymann
Copy link
Contributor

Forgot to mention, can we move the "Status" field before or after the two checkboxes so the UI looks a bit neater?

Screenshot 2022-12-08 at 12 27 05

@gchaps
Copy link
Contributor

gchaps commented Dec 12, 2022

Some comments on copy.

Can we eliminate the back-to-back "API keys" text in the intro? Maybe something like

Manage your API keys, which send requests on behalf of the user.

Open to suggestions for the second half of the sentence.

Also, instead of "View API key" for the title of the flyout, how about "API key details"?

@kc13greiner
Copy link
Contributor Author

All working well, a few comments below.

The "View API key" button doesn't make any sense (what would it do if it was enabled?) - I would change it to "Close":

Screenshot 2022-12-08 at 11 27 27

I appreciate that you tried to be consistent with the Create API key flow here but that flow is an exception since we need to show the token of the generated API key. Normal updates and errors should be shown using toast notifications so the behaviour is consistent with the rest of Kibana:

Screenshot 2022-12-08 at 11 29 14 Screenshot 2022-12-08 at 11 29 32

The "no update has been made" warning is an unnecessary detail. I would either disable the submit button until a change has been made (similar to user profile form) or show a success toast irregardless of whether the API key actually changed or not: Screenshot 2022-12-08 at 12 22 50

All fixed in latest commit! I chose to leave the 'Update' button clickable and have it return 'Success' even when no updates were made; the Users and Roles screens appear to follow that pattern.

@kc13greiner
Copy link
Contributor Author

Forgot to mention, can we move the "Status" field before or after the two checkboxes so the UI looks a bit neater?

Screenshot 2022-12-08 at 12 27 05

Fixed in latest commit!

@kc13greiner
Copy link
Contributor Author

Some comments on copy.

Can we eliminate the back-to-back "API keys" text in the intro? Maybe something like

Manage your API keys, which send requests on behalf of the user.

Open to suggestions for the second half of the sentence.

Also, instead of "View API key" for the title of the flyout, how about "API key details"?

Fixed in latest commit!

@kc13greiner
Copy link
Contributor Author

@elasticmachine merge upstream

@kibana-ci
Copy link

💚 Build Succeeded

Metrics [docs]

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
security 90 91 +1

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
security 549.6KB 553.1KB +3.5KB
Unknown metric groups

API count

id before after diff
security 250 251 +1

ESLint disabled in files

id before after diff
osquery 1 2 +1

ESLint disabled line counts

id before after diff
enterpriseSearch 19 21 +2
fleet 60 66 +6
osquery 109 115 +6
securitySolution 445 451 +6
total +20

Total ESLint disabled count

id before after diff
enterpriseSearch 20 22 +2
fleet 69 75 +6
osquery 110 117 +7
securitySolution 521 527 +6
total +21

History

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

Copy link
Contributor

@thomheymann thomheymann left a comment

Choose a reason for hiding this comment

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

All looking good! 🎉

@kc13greiner kc13greiner merged commit 9a6985e into elastic:main Dec 14, 2022
@kibanamachine kibanamachine added the backport:skip This PR does not require backporting label Dec 14, 2022
@kc13greiner kc13greiner deleted the feature/api_keys_update branch December 14, 2022 12:58
jloleysens added a commit to jloleysens/kibana that referenced this pull request Dec 14, 2022
* main: (21 commits)
  [Profiling] Remove link to 'Other' bucket (elastic#147523)
  [Synthetics UI] Add missing configuration options to the add/edit monitor forms (elastic#147265)
  [DOCS] Updates what's new pages (elastic#147483)
  [Fleet][Endpoint][RBAC V2] Update fleet router and config to allow API access via RBAC controls (elastic#145361)
  [Guided onboarding] Update guide IDs (elastic#147348)
  [Synthetics] Add synthetics settings alerting default (elastic#147339)
  [Security Solution][Endpoint] Fix Policy form being displayed as Read Only when displayed in Fleet pages (elastic#147212)
  [Cases] Save draft user comment (elastic#146327)
  [API Docs] Fix `--plugin` filter (elastic#147500)
  [Fleet] added a logic to use `destinationId` when tagging imported SOs (elastic#147439)
  Do not skip UPDATE_TARGET_MAPPINGS if upgrading to a newer stack version (elastic#147503)
  [Discover] Validate if Data View time field exists on Alert creation / editing (elastic#146324)
  [Discover] Fix Discover navigation from Lens embeddable (elastic#147000)
  Allow users to Update API Keys (elastic#146237)
  Update dependency xstate to ^4.35.0 (main) (elastic#147463)
  [Behavioral Analytics] Remove feature flag to hide functionality (elastic#147429)
  [Fleet] Add agent policy `inactivity_timeout`experimental setting (elastic#147432)
  [APM] Switching service groups from grid to flex layout (elastic#147448)
  [Fleet] Add missing endpoints to openApi specs (elastic#147452)
  [AO] Allow providing custom time range for Alert Summary Widget (elastic#147253)
  ...
nreese pushed a commit to nreese/kibana that referenced this pull request Dec 16, 2022
## Summary

API keys can now be updated via the API Keys Management screen

## Release Note

API Keys can now be updated with new Role Descriptors and Metadata via
the API Keys Management screen.

## Testing Instructions

Login as `elastic`

Navigate to Roles and create a new role with the `read_security` cluster
privilege:
<img width="962" alt="Screen Shot 2022-11-30 at 9 42 31 AM"
src="https://user-images.githubusercontent.com/21210601/204826868-a8f6bf03-acf8-404c-90c8-e2b9ab62dc11.png">


Create a new user and assign that new role, `viewer`, and
`kibana_admin`:
<img width="936" alt="Screen Shot 2022-11-30 at 9 43 10 AM"
src="https://user-images.githubusercontent.com/21210601/204827030-e5f97f8e-6676-4c18-8a46-f6afee87ba12.png">


Navigate to Dev Tools and run the following:

```json
POST /_security/api_key/grant
{
  "grant_type": "password",
  "username" : "elastic",  
  "password" : "changeme",  
  "run_as": "elastic",  
  "api_key" : {
    "name": "test-expired-key",
    "expiration": "1ms"
  }
}

POST /_security/api_key/grant
{
  "grant_type": "password",
  "username" : "elastic",  
  "password" : "changeme",  
  "run_as": "test_user",  
  "api_key" : {
    "name": "test-user-key",
    "expiration": "1d"
  }
}
```

The first command will create an API key for the `elastic` user that
expires immediately.

The second command will create an API key for `test_user`.

Navigate to the API Key page, click the name column links to see a
readonly view for the 2 previously created keys as users cannot update
an API key that belongs to another user nor an API key that is expired.

Create a new API key:
<img width="632" alt="Screen Shot 2022-11-30 at 9 44 52 AM"
src="https://user-images.githubusercontent.com/21210601/204829114-672c6583-8801-4af0-bfa8-64ae1072ef46.png">

Click the name link for the newly created API key to see the Update API
key flyout.

Update the fields and click submit:
<img width="642" alt="Screen Shot 2022-11-30 at 9 45 59 AM"
src="https://user-images.githubusercontent.com/21210601/204829914-9fb1f8e6-8b3f-4acc-b63f-d7e4a0906727.png">

If the update was successful:
<img width="904" alt="Screen Shot 2022-11-30 at 9 46 42 AM"
src="https://user-images.githubusercontent.com/21210601/204830133-1dcb083b-f945-4980-9e91-19081c224b55.png">

Now click the name link again for the updated key and click submit
without making changes. You should see a warning:
<img width="895" alt="Screen Shot 2022-11-30 at 9 46 52 AM"
src="https://user-images.githubusercontent.com/21210601/204830570-2ca5e2e0-19b6-43ce-b7e4-ae594be6a86b.png">

Logout the `elastic` user and login as `test_user`

Navigate to API Keys and click the existing API Key to see a readonly
view flyout:
<img width="639" alt="Screen Shot 2022-11-30 at 9 58 25 AM"
src="https://user-images.githubusercontent.com/21210601/204832019-640ecd2e-4bcb-402b-a164-e8b8eb9f8848.png">


Thanks for reviewing!

Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting release_note:feature Makes this part of the condensed release notes Team:Security Platform Security: Auth, Users, Roles, Spaces, Audit Logging, etc t// v8.7.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow API Keys to be updated

8 participants