[Ingest Manager] Fix invalidating agent output api key (#68021)
This commit is contained in:
parent
d661d66faa
commit
642800c98e
4 changed files with 152 additions and 3 deletions
|
@ -30,6 +30,7 @@ export async function agentCheckin(
|
|||
const updateData: {
|
||||
last_checkin: string;
|
||||
default_api_key?: string;
|
||||
default_api_key_id?: string;
|
||||
local_metadata?: AgentMetadata;
|
||||
current_error_events?: string;
|
||||
} = {
|
||||
|
@ -51,11 +52,13 @@ export async function agentCheckin(
|
|||
// Assign output API keys
|
||||
// We currently only support default ouput
|
||||
if (!defaultApiKey) {
|
||||
updateData.default_api_key = await APIKeysService.generateOutputApiKey(
|
||||
const outputAPIKey = await APIKeysService.generateOutputApiKey(
|
||||
soClient,
|
||||
'default',
|
||||
agent.id
|
||||
);
|
||||
updateData.default_api_key = outputAPIKey.key;
|
||||
updateData.default_api_key_id = outputAPIKey.id;
|
||||
}
|
||||
// Mutate the config to set the api token for this agent
|
||||
config.outputs.default.api_key = defaultApiKey || updateData.default_api_key;
|
||||
|
|
|
@ -17,7 +17,7 @@ export async function generateOutputApiKey(
|
|||
soClient: SavedObjectsClientContract,
|
||||
outputId: string,
|
||||
agentId: string
|
||||
): Promise<string> {
|
||||
): Promise<{ key: string; id: string }> {
|
||||
const name = `${agentId}:${outputId}`;
|
||||
const key = await createAPIKey(soClient, name, {
|
||||
'fleet-output': {
|
||||
|
@ -35,7 +35,7 @@ export async function generateOutputApiKey(
|
|||
throw new Error('Unable to create an output api key');
|
||||
}
|
||||
|
||||
return `${key.id}:${key.api_key}`;
|
||||
return { key: `${key.id}:${key.api_key}`, id: key.id };
|
||||
}
|
||||
|
||||
export async function generateAccessApiKey(
|
||||
|
|
145
x-pack/test/api_integration/apis/fleet/agent_flow.ts
Normal file
145
x-pack/test/api_integration/apis/fleet/agent_flow.ts
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { setupIngest, getSupertestWithoutAuth } from './agents/services';
|
||||
|
||||
export default function (providerContext: FtrProviderContext) {
|
||||
const { getService } = providerContext;
|
||||
const esArchiver = getService('esArchiver');
|
||||
const supertest = getService('supertest');
|
||||
const supertestWithoutAuth = getSupertestWithoutAuth(providerContext);
|
||||
const esClient = getService('es');
|
||||
|
||||
describe('fleet_agent_flow', () => {
|
||||
before(async () => {
|
||||
await esArchiver.load('empty_kibana');
|
||||
});
|
||||
setupIngest(providerContext);
|
||||
after(async () => {
|
||||
await esArchiver.unload('empty_kibana');
|
||||
});
|
||||
|
||||
it('should work', async () => {
|
||||
// 1. Get enrollment token
|
||||
const { body: enrollmentApiKeysResponse } = await supertest
|
||||
.get(`/api/ingest_manager/fleet/enrollment-api-keys`)
|
||||
.expect(200);
|
||||
|
||||
expect(enrollmentApiKeysResponse.list).length(1);
|
||||
const { body: enrollmentApiKeyResponse } = await supertest
|
||||
.get(
|
||||
`/api/ingest_manager/fleet/enrollment-api-keys/${enrollmentApiKeysResponse.list[0].id}`
|
||||
)
|
||||
.expect(200);
|
||||
|
||||
expect(enrollmentApiKeyResponse.item).to.have.key('api_key');
|
||||
const enrollmentAPIToken = enrollmentApiKeyResponse.item.api_key;
|
||||
// 2. Enroll agent
|
||||
const { body: enrollmentResponse } = await supertestWithoutAuth
|
||||
.post(`/api/ingest_manager/fleet/agents/enroll`)
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Authorization', `ApiKey ${enrollmentAPIToken}`)
|
||||
.send({
|
||||
type: 'PERMANENT',
|
||||
metadata: {
|
||||
local: {},
|
||||
user_provided: {},
|
||||
},
|
||||
})
|
||||
.expect(200);
|
||||
expect(enrollmentResponse.success).to.eql(true);
|
||||
|
||||
const agentAccessAPIKey = enrollmentResponse.item.access_api_key;
|
||||
|
||||
// 3. agent checkin
|
||||
const { body: checkinApiResponse } = await supertestWithoutAuth
|
||||
.post(`/api/ingest_manager/fleet/agents/${enrollmentResponse.item.id}/checkin`)
|
||||
.set('kbn-xsrf', 'xx')
|
||||
.set('Authorization', `ApiKey ${agentAccessAPIKey}`)
|
||||
.send({
|
||||
events: [],
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(checkinApiResponse.success).to.eql(true);
|
||||
expect(checkinApiResponse.actions).length(1);
|
||||
expect(checkinApiResponse.actions[0].type).be('CONFIG_CHANGE');
|
||||
const configChangeAction = checkinApiResponse.actions[0];
|
||||
const defaultOutputApiKey = configChangeAction.data.config.outputs.default.api_key;
|
||||
|
||||
// 4. ack actions
|
||||
const { body: ackApiResponse } = await supertestWithoutAuth
|
||||
.post(`/api/ingest_manager/fleet/agents/${enrollmentResponse.item.id}/acks`)
|
||||
.set('Authorization', `ApiKey ${agentAccessAPIKey}`)
|
||||
.set('kbn-xsrf', 'xx')
|
||||
|
||||
.send({
|
||||
events: [
|
||||
{
|
||||
type: 'ACTION_RESULT',
|
||||
subtype: 'CONFIG',
|
||||
timestamp: '2019-01-04T14:32:03.36764-05:00',
|
||||
action_id: configChangeAction.id,
|
||||
agent_id: enrollmentResponse.item.id,
|
||||
message: 'hello',
|
||||
payload: 'payload',
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(200);
|
||||
expect(ackApiResponse.success).to.eql(true);
|
||||
|
||||
// 4. second agent checkin
|
||||
const { body: secondCheckinApiResponse } = await supertestWithoutAuth
|
||||
.post(`/api/ingest_manager/fleet/agents/${enrollmentResponse.item.id}/checkin`)
|
||||
.set('kbn-xsrf', 'xx')
|
||||
.set('Authorization', `ApiKey ${agentAccessAPIKey}`)
|
||||
.send({
|
||||
events: [],
|
||||
})
|
||||
.expect(200);
|
||||
expect(secondCheckinApiResponse.success).to.eql(true);
|
||||
expect(secondCheckinApiResponse.actions).length(0);
|
||||
|
||||
// 5. unenroll agent
|
||||
const { body: unenrollResponse } = await supertest
|
||||
.post(`/api/ingest_manager/fleet/agents/${enrollmentResponse.item.id}/unenroll`)
|
||||
.set('kbn-xsrf', 'xx')
|
||||
.expect(200);
|
||||
expect(unenrollResponse.success).to.eql(true);
|
||||
|
||||
// 6. Checkin after unenrollment
|
||||
await supertestWithoutAuth
|
||||
.post(`/api/ingest_manager/fleet/agents/${enrollmentResponse.item.id}/checkin`)
|
||||
.set('kbn-xsrf', 'xx')
|
||||
.set('Authorization', `ApiKey ${agentAccessAPIKey}`)
|
||||
.send({
|
||||
events: [],
|
||||
})
|
||||
.expect(401);
|
||||
|
||||
// very api key are invalidated
|
||||
const {
|
||||
body: { api_keys: accessAPIKeys },
|
||||
} = await esClient.security.getApiKey({
|
||||
id: Buffer.from(agentAccessAPIKey, 'base64').toString('utf8').split(':')[0],
|
||||
});
|
||||
expect(accessAPIKeys).length(1);
|
||||
expect(accessAPIKeys[0].invalidated).eql(true);
|
||||
|
||||
const {
|
||||
body: { api_keys: outputAPIKeys },
|
||||
} = await esClient.security.getApiKey({
|
||||
id: defaultOutputApiKey.split(':')[0],
|
||||
});
|
||||
expect(outputAPIKeys).length(1);
|
||||
expect(outputAPIKeys[0].invalidated).eql(true);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -17,5 +17,6 @@ export default function loadTests({ loadTestFile }) {
|
|||
loadTestFile(require.resolve('./install'));
|
||||
loadTestFile(require.resolve('./agents/actions'));
|
||||
loadTestFile(require.resolve('./setup'));
|
||||
loadTestFile(require.resolve('./agent_flow'));
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue