-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[ResponseOps] Allow users authenticated with an API keys to manage alerting rules #154189
Conversation
Pinging @elastic/response-ops (Team:ResponseOps) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SO changes LGTM. If not needed for search/aggregations, I'd avoid adding it to the mappings.
…nto alerting/auth-api-key
Trying out the _update_api_key API, via the following, doesn't seem to work. Am I holding it wrong? $ curl -X POST "http://localhost:5601/internal/alerting/rule/4f0a4ec0-d3cf-11ed-8173-855da63578db/_update_api_key" -H "Authorization: ApiKey ${API_KEY}" -H 'kbn-xsrf: true'
{"statusCode":400,"error":"Bad Request","message":"Error updating API key for rule: could not create API key - Unsupported scheme \"ApiKey\" for granting API Key"} Seems like it should not have tried to create an API key in this case, but didn't look in the code to see what was going on ... |
Resolved in this commit 47d83e6 |
Still reviewing, no blockers yet, however there is one potentially big thing I'd like added. Doesn't neccessarily need to be in this PR, but I think we'd want to do it before 8.8. More function tests. :-). What I'd like to see is a bunch of the following scenarios:
I'd like to see this where we run ever combination of methods changed, where when we create the rule, and run the method, we use every combination of api-key / login. So, something like this: for (const createType of ['api-key', 'login']) {
for (const mutateType of ['api-key', 'login']) {
for (const method of ['bulk_delete', 'bulk_edit', ... ]) {
test(createType, mutateType, method);
}
}
} |
I created an issue to add functional tests #154584 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lots of comments, generally LGTM. I think the most critical comment is on transform_rule_for_export.test.ts
, to add some more tests. If anything else makes sense and is easy, cool. I'm interested in getting this merged soon-ish so we can start hammering on it, so if anything is "too big", I think we can do in a follow-up PR.
createdAPIKey = shouldUpdateApiKey | ||
? await context.createAPIKey(generateAPIKeyName(ruleType.id, attributes.name)) | ||
? isAuthTypeApiKey | ||
? await context.getAuthenticationAPIKey(name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the name here is just added to the return object of getAuthenticationAPIKey()
, not otherwise used. AFAIK, we don't display this name anywhere in alerting UX - I think it's primary use is when you are scrolling through the API Keys UX, for the keys we generate, so you can tell what rules they were for.
If so, I think this is fine.
I just don't want to confuse customers by suggesting there is an API key with that name. Maybe we should add something to the name though anyway, in this case. Could be useful while diagnosing problems ... like prefix/postfix with "(user-created)" or similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh okay that makes sense, I can add something like that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved in this commit bc37396
@@ -91,6 +91,7 @@ describe('transform rule for export', () => { | |||
enabled: false, | |||
apiKey: null, | |||
apiKeyOwner: null, | |||
apiKeyCreatedByUser: null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels like we should have a test for apiKeyCreatedByUser: true
in here, to make sure it's getting exported as null
(like the other api key-related properties).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved in this commit bc37396
@@ -8,6 +8,7 @@ | |||
import { SavedObjectsTypeMappingDefinition } from '@kbn/core/server'; | |||
|
|||
export const alertMappings: SavedObjectsTypeMappingDefinition = { | |||
dynamic: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@XavierM I'm guessing you're adding this in your SO refactor PR; heads up that we're doing it here to add a new property that doesn't need to be indexed.
@@ -96,17 +96,22 @@ export async function clone<Params extends RuleTypeParams = never>( | |||
const lastRunTimestamp = new Date(); | |||
const legacyId = Semver.lt(context.kibanaVersion, '8.0.0') ? id : null; | |||
let createdAPIKey = null; | |||
let isAuthTypeApiKey = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These blocks of code are very similar between the various client methods - wonder if there's anyway we could arrange to do most of this work in a common function, to cut down on the boilerplate. Even it it was just useful for most of the methods, would probably be useful ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved in this commit bc37396
The only client method I didn't update was create.ts
context.logger, | ||
context.unsecuredSavedObjectsClient | ||
); | ||
throw e; | ||
} | ||
|
||
if (apiKeyToInvalidate) { | ||
if (apiKeyToInvalidate && !apiKeyCreatedByUser) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we rename these to have a "previous" or "old" prefix. My first thought on seeing these was - which "keyCreatedByUser"? It's not the newly created one, right? No, it's not, but I had to scroll to the top to see where these were assigned from the original rule. I think putting a prefix on them will keep me from wondering in the future :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved in this commit bc37396
@@ -313,6 +353,21 @@ describe('bulkDelete', () => { | |||
); | |||
}); | |||
|
|||
test('should not mark API keys for invalidation if the user is authenticated using an api key', async () => { | |||
unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ | |||
statuses: [{ id: 'id3', type: 'alert', success: true }], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we add id1 and id2 here as well, ensure that they get passed to the bulkKeyInvalidation function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved in this commit bc37396
const user = await securityPluginStart.authc.getCurrentUser(request); | ||
return user && user.authentication_type ? user.authentication_type === 'api_key' : false; | ||
}, | ||
async getAuthenticationAPIKey(name: string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe either of these methods needs to be async, technically. I'm seeing a squiggle under the await
for securityPluginStart.authc.getCurrentUser(request)
indicating 'await' has no effect on the type of this expression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh my bad, I will fix this!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved in this commit bc37396
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Infra changes LGTM!
💚 Build Succeeded
Metrics [docs]Public APIs missing comments
Page load bundle
Unknown metric groupsAPI count
ESLint disabled line counts
Total ESLint disabled count
History
To update your PR or re-run it, just comment with: |
Resolves #152140
Summary
Updates the following functions in the Rules Client to re-use the API key in context and avoid having the system invalidate them when no longer in use:
Also adds a new field to the rule SO to help determine when whether an api key was created by a user or created by us.
Checklist
To verify
"api_key_created_by_user":true
"api_key_created_by_user":false
when you remove the api key header and add-u ${USERNAME}:${PASSWORD}
to authenticate