mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* Add userCurrentUser hook * Use EuiFieldText instead of input element * Display error messages in the UI when creating agent keys * Remove default agent key name * Prefix createAgentKeyRoute with /api * Fix issue where you cannot invalidate API keys when you only have manage_own_api_key privilege Co-authored-by: Casper Hübertz <casper@formgeist.com> Co-authored-by: Giorgos Bamparopoulos <georgios.bamparopoulos@elastic.co> Co-authored-by: Casper Hübertz <casper@formgeist.com>
This commit is contained in:
parent
8da7e923bd
commit
bc5533b022
10 changed files with 179 additions and 146 deletions
22
x-pack/plugins/apm/common/privilege_type.ts
Normal file
22
x-pack/plugins/apm/common/privilege_type.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
export const enum PrivilegeType {
|
||||
SOURCEMAP = 'sourcemap:write',
|
||||
EVENT = 'event:write',
|
||||
AGENT_CONFIG = 'config_agent:read',
|
||||
}
|
||||
|
||||
export const privilegesTypeRt = t.array(
|
||||
t.union([
|
||||
t.literal(PrivilegeType.SOURCEMAP),
|
||||
t.literal(PrivilegeType.EVENT),
|
||||
t.literal(PrivilegeType.AGENT_CONFIG),
|
||||
])
|
||||
);
|
|
@ -82,7 +82,7 @@ export function AgentKeysTable({ agentKeys, onKeyDelete }: Props) {
|
|||
description: i18n.translate(
|
||||
'xpack.apm.settings.agentKeys.table.deleteActionDescription',
|
||||
{
|
||||
defaultMessage: 'Delete this agent key',
|
||||
defaultMessage: 'Delete this APM agent key',
|
||||
}
|
||||
),
|
||||
icon: 'trash',
|
||||
|
@ -144,7 +144,7 @@ export function AgentKeysTable({ agentKeys, onKeyDelete }: Props) {
|
|||
tableCaption={i18n.translate(
|
||||
'xpack.apm.settings.agentKeys.tableCaption',
|
||||
{
|
||||
defaultMessage: 'Agent keys',
|
||||
defaultMessage: 'APM agent keys',
|
||||
}
|
||||
)}
|
||||
items={agentKeys ?? []}
|
||||
|
|
|
@ -34,14 +34,14 @@ export function ConfirmDeleteModal({ agentKey, onCancel, onConfirm }: Props) {
|
|||
});
|
||||
toasts.addSuccess(
|
||||
i18n.translate('xpack.apm.settings.agentKeys.invalidate.succeeded', {
|
||||
defaultMessage: 'Deleted agent key "{name}"',
|
||||
defaultMessage: 'Deleted APM agent key "{name}"',
|
||||
values: { name },
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
toasts.addDanger(
|
||||
i18n.translate('xpack.apm.settings.agentKeys.invalidate.failed', {
|
||||
defaultMessage: 'Error deleting agent key "{name}"',
|
||||
defaultMessage: 'Error deleting APM agent key "{name}"',
|
||||
values: { name },
|
||||
})
|
||||
);
|
||||
|
@ -53,7 +53,7 @@ export function ConfirmDeleteModal({ agentKey, onCancel, onConfirm }: Props) {
|
|||
title={i18n.translate(
|
||||
'xpack.apm.settings.agentKeys.deleteConfirmModal.title',
|
||||
{
|
||||
defaultMessage: 'Delete agent key "{name}"?',
|
||||
defaultMessage: 'Delete APM agent key "{name}"?',
|
||||
values: { name },
|
||||
}
|
||||
)}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
EuiButton,
|
||||
|
@ -28,30 +28,31 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { callApmApi } from '../../../../services/rest/createCallApmApi';
|
||||
import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public';
|
||||
import { ApmPluginStartDeps } from '../../../../plugin';
|
||||
import { CreateApiKeyResponse } from '../../../../../common/agent_key_types';
|
||||
import { useCurrentUser } from '../../../../hooks/use_current_user';
|
||||
import { PrivilegeType } from '../../../../../common/privilege_type';
|
||||
|
||||
interface Props {
|
||||
onCancel: () => void;
|
||||
onSuccess: (agentKey: CreateApiKeyResponse) => void;
|
||||
onError: (keyName: string) => void;
|
||||
onError: (keyName: string, message: string) => void;
|
||||
}
|
||||
|
||||
export function CreateAgentKeyFlyout({ onCancel, onSuccess, onError }: Props) {
|
||||
const {
|
||||
services: { security },
|
||||
} = useKibana<ApmPluginStartDeps>();
|
||||
|
||||
const [username, setUsername] = useState('');
|
||||
|
||||
const [formTouched, setFormTouched] = useState(false);
|
||||
const [keyName, setKeyName] = useState('');
|
||||
const [agentConfigChecked, setAgentConfigChecked] = useState(true);
|
||||
const [eventWriteChecked, setEventWriteChecked] = useState(true);
|
||||
const [sourcemapChecked, setSourcemapChecked] = useState(true);
|
||||
|
||||
const isInputInvalid = isEmpty(keyName);
|
||||
const [agentKeyBody, setAgentKeyBody] = useState({
|
||||
name: '',
|
||||
sourcemap: true,
|
||||
event: true,
|
||||
agentConfig: true,
|
||||
});
|
||||
|
||||
const { name, sourcemap, event, agentConfig } = agentKeyBody;
|
||||
|
||||
const currentUser = useCurrentUser();
|
||||
|
||||
const isInputInvalid = isEmpty(name);
|
||||
const isFormInvalid = formTouched && isInputInvalid;
|
||||
|
||||
const formError = i18n.translate(
|
||||
|
@ -59,21 +60,9 @@ export function CreateAgentKeyFlyout({ onCancel, onSuccess, onError }: Props) {
|
|||
{ defaultMessage: 'Enter a name' }
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const getCurrentUser = async () => {
|
||||
try {
|
||||
const authenticatedUser = await security?.authc.getCurrentUser();
|
||||
setUsername(authenticatedUser?.username || '');
|
||||
} catch {
|
||||
setUsername('');
|
||||
}
|
||||
};
|
||||
getCurrentUser();
|
||||
}, [security?.authc]);
|
||||
|
||||
const createAgentKeyTitle = i18n.translate(
|
||||
'xpack.apm.settings.agentKeys.createKeyFlyout.createAgentKey',
|
||||
{ defaultMessage: 'Create agent key' }
|
||||
{ defaultMessage: 'Create APM agent key' }
|
||||
);
|
||||
|
||||
const createAgentKey = async () => {
|
||||
|
@ -83,22 +72,33 @@ export function CreateAgentKeyFlyout({ onCancel, onSuccess, onError }: Props) {
|
|||
}
|
||||
|
||||
try {
|
||||
const privileges: PrivilegeType[] = [];
|
||||
if (sourcemap) {
|
||||
privileges.push(PrivilegeType.SOURCEMAP);
|
||||
}
|
||||
|
||||
if (event) {
|
||||
privileges.push(PrivilegeType.EVENT);
|
||||
}
|
||||
|
||||
if (agentConfig) {
|
||||
privileges.push(PrivilegeType.AGENT_CONFIG);
|
||||
}
|
||||
|
||||
const { agentKey } = await callApmApi({
|
||||
endpoint: 'POST /apm/agent_keys',
|
||||
endpoint: 'POST /api/apm/agent_keys',
|
||||
signal: null,
|
||||
params: {
|
||||
body: {
|
||||
name: keyName,
|
||||
sourcemap: sourcemapChecked,
|
||||
event: eventWriteChecked,
|
||||
agentConfig: agentConfigChecked,
|
||||
name,
|
||||
privileges,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
onSuccess(agentKey);
|
||||
} catch (error) {
|
||||
onError(keyName);
|
||||
onError(name, error.body?.message || error.message);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -112,14 +112,14 @@ export function CreateAgentKeyFlyout({ onCancel, onSuccess, onError }: Props) {
|
|||
|
||||
<EuiFlyoutBody>
|
||||
<EuiForm isInvalid={isFormInvalid} error={formError}>
|
||||
{username && (
|
||||
{currentUser && (
|
||||
<EuiFormRow
|
||||
label={i18n.translate(
|
||||
'xpack.apm.settings.agentKeys.createKeyFlyout.userTitle',
|
||||
{ defaultMessage: 'User' }
|
||||
)}
|
||||
>
|
||||
<EuiText>{username}</EuiText>
|
||||
<EuiText>{currentUser?.username}</EuiText>
|
||||
</EuiFormRow>
|
||||
)}
|
||||
<EuiFormRow
|
||||
|
@ -146,7 +146,9 @@ export function CreateAgentKeyFlyout({ onCancel, onSuccess, onError }: Props) {
|
|||
defaultMessage: 'e.g. apm-key',
|
||||
}
|
||||
)}
|
||||
onChange={(e) => setKeyName(e.target.value)}
|
||||
onChange={(e) =>
|
||||
setAgentKeyBody((state) => ({ ...state, name: e.target.value }))
|
||||
}
|
||||
isInvalid={isFormInvalid}
|
||||
onBlur={() => setFormTouched(true)}
|
||||
/>
|
||||
|
@ -174,8 +176,13 @@ export function CreateAgentKeyFlyout({ onCancel, onSuccess, onError }: Props) {
|
|||
<EuiCheckbox
|
||||
id={htmlIdGenerator()()}
|
||||
label="config_agent:read"
|
||||
checked={agentConfigChecked}
|
||||
onChange={() => setAgentConfigChecked((state) => !state)}
|
||||
checked={agentConfig}
|
||||
onChange={() =>
|
||||
setAgentKeyBody((state) => ({
|
||||
...state,
|
||||
agentConfig: !state.agentConfig,
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiSpacer size="s" />
|
||||
|
@ -190,8 +197,13 @@ export function CreateAgentKeyFlyout({ onCancel, onSuccess, onError }: Props) {
|
|||
<EuiCheckbox
|
||||
id={htmlIdGenerator()()}
|
||||
label="event:write"
|
||||
checked={eventWriteChecked}
|
||||
onChange={() => setEventWriteChecked((state) => !state)}
|
||||
checked={event}
|
||||
onChange={() =>
|
||||
setAgentKeyBody((state) => ({
|
||||
...state,
|
||||
event: !state.event,
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiSpacer size="s" />
|
||||
|
@ -206,8 +218,13 @@ export function CreateAgentKeyFlyout({ onCancel, onSuccess, onError }: Props) {
|
|||
<EuiCheckbox
|
||||
id={htmlIdGenerator()()}
|
||||
label="sourcemap:write"
|
||||
checked={sourcemapChecked}
|
||||
onChange={() => setSourcemapChecked((state) => !state)}
|
||||
checked={sourcemap}
|
||||
onChange={() =>
|
||||
setAgentKeyBody((state) => ({
|
||||
...state,
|
||||
sourcemap: !state.sourcemap,
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiSpacer size="s" />
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
EuiCallOut,
|
||||
EuiButtonIcon,
|
||||
EuiCopy,
|
||||
EuiFormControlLayout,
|
||||
EuiFieldText,
|
||||
} from '@elastic/eui';
|
||||
|
||||
interface Props {
|
||||
|
@ -43,9 +43,15 @@ export function AgentKeyCallOut({ name, token }: Props) {
|
|||
}
|
||||
)}
|
||||
</p>
|
||||
<EuiFormControlLayout
|
||||
style={{ backgroundColor: 'transparent' }}
|
||||
<EuiFieldText
|
||||
readOnly
|
||||
value={token}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.apm.settings.agentKeys.copyAgentKeyField.agentKeyLabel',
|
||||
{
|
||||
defaultMessage: 'APM agent key',
|
||||
}
|
||||
)}
|
||||
prepend="Base64"
|
||||
append={
|
||||
<EuiCopy textToCopy={token}>
|
||||
|
@ -65,20 +71,7 @@ export function AgentKeyCallOut({ name, token }: Props) {
|
|||
)}
|
||||
</EuiCopy>
|
||||
}
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
className="euiFieldText euiFieldText--inGroup"
|
||||
readOnly
|
||||
value={token}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.apm.settings.agentKeys.copyAgentKeyField.agentKeyLabel',
|
||||
{
|
||||
defaultMessage: 'Agent key',
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</EuiFormControlLayout>
|
||||
/>
|
||||
</EuiCallOut>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
|
|
|
@ -75,7 +75,7 @@ export function AgentKeys() {
|
|||
<EuiText color="subdued">
|
||||
{i18n.translate('xpack.apm.settings.agentKeys.descriptionText', {
|
||||
defaultMessage:
|
||||
'View and delete agent keys. An agent key sends requests on behalf of a user.',
|
||||
'View and delete APM agent keys. An APM agent key sends requests on behalf of a user.',
|
||||
})}
|
||||
</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
|
@ -84,7 +84,7 @@ export function AgentKeys() {
|
|||
<EuiTitle>
|
||||
<h2>
|
||||
{i18n.translate('xpack.apm.settings.agentKeys.title', {
|
||||
defaultMessage: 'Agent keys',
|
||||
defaultMessage: 'APM agent keys',
|
||||
})}
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
|
@ -99,7 +99,7 @@ export function AgentKeys() {
|
|||
{i18n.translate(
|
||||
'xpack.apm.settings.agentKeys.createAgentKeyButton',
|
||||
{
|
||||
defaultMessage: 'Create agent key',
|
||||
defaultMessage: 'Create APM agent key',
|
||||
}
|
||||
)}
|
||||
</EuiButton>
|
||||
|
@ -123,11 +123,12 @@ export function AgentKeys() {
|
|||
setIsFlyoutVisible(false);
|
||||
refetchAgentKeys();
|
||||
}}
|
||||
onError={(keyName: string) => {
|
||||
onError={(keyName: string, message: string) => {
|
||||
toasts.addDanger(
|
||||
i18n.translate('xpack.apm.settings.agentKeys.crate.failed', {
|
||||
defaultMessage: 'Error creating agent key "{keyName}"',
|
||||
values: { keyName },
|
||||
defaultMessage:
|
||||
'Error creating APM agent key "{keyName}". Error: "{message}"',
|
||||
values: { keyName, message },
|
||||
})
|
||||
);
|
||||
setIsFlyoutVisible(false);
|
||||
|
@ -184,7 +185,7 @@ function AgentKeysContent({
|
|||
{i18n.translate(
|
||||
'xpack.apm.settings.agentKeys.agentKeysLoadingPromptTitle',
|
||||
{
|
||||
defaultMessage: 'Loading Agent keys...',
|
||||
defaultMessage: 'Loading APM agent keys...',
|
||||
}
|
||||
)}
|
||||
</h2>
|
||||
|
@ -202,7 +203,7 @@ function AgentKeysContent({
|
|||
{i18n.translate(
|
||||
'xpack.apm.settings.agentKeys.agentKeysErrorPromptTitle',
|
||||
{
|
||||
defaultMessage: 'Could not load agent keys.',
|
||||
defaultMessage: 'Could not load APM agent keys.',
|
||||
}
|
||||
)}
|
||||
</h2>
|
||||
|
@ -235,7 +236,7 @@ function AgentKeysContent({
|
|||
<p>
|
||||
{i18n.translate('xpack.apm.settings.agentKeys.emptyPromptBody', {
|
||||
defaultMessage:
|
||||
'Create keys to authorize agent requests to the APM Server.',
|
||||
'Create APM agent keys to authorize APM agent requests to the APM Server.',
|
||||
})}
|
||||
</p>
|
||||
}
|
||||
|
@ -248,7 +249,7 @@ function AgentKeysContent({
|
|||
{i18n.translate(
|
||||
'xpack.apm.settings.agentKeys.createAgentKeyButton',
|
||||
{
|
||||
defaultMessage: 'Create agent key',
|
||||
defaultMessage: 'Create APM agent key',
|
||||
}
|
||||
)}
|
||||
</EuiButton>
|
||||
|
|
33
x-pack/plugins/apm/public/hooks/use_current_user.ts
Normal file
33
x-pack/plugins/apm/public/hooks/use_current_user.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useKibana } from '../../../../../src/plugins/kibana_react/public';
|
||||
import { ApmPluginStartDeps } from '../plugin';
|
||||
import { AuthenticatedUser } from '../../../security/common/model';
|
||||
|
||||
export function useCurrentUser() {
|
||||
const {
|
||||
services: { security },
|
||||
} = useKibana<ApmPluginStartDeps>();
|
||||
|
||||
const [user, setUser] = useState<AuthenticatedUser>();
|
||||
|
||||
useEffect(() => {
|
||||
const getCurrentUser = async () => {
|
||||
try {
|
||||
const authenticatedUser = await security?.authc.getCurrentUser();
|
||||
setUser(authenticatedUser);
|
||||
} catch {
|
||||
setUser(undefined);
|
||||
}
|
||||
};
|
||||
getCurrentUser();
|
||||
}, [security?.authc]);
|
||||
|
||||
return user;
|
||||
}
|
|
@ -8,17 +8,14 @@
|
|||
import Boom from '@hapi/boom';
|
||||
import { ApmPluginRequestHandlerContext } from '../typings';
|
||||
import { CreateApiKeyResponse } from '../../../common/agent_key_types';
|
||||
import { PrivilegeType } from '../../../common/privilege_type';
|
||||
|
||||
const enum PrivilegeType {
|
||||
SOURCEMAP = 'sourcemap:write',
|
||||
EVENT = 'event:write',
|
||||
AGENT_CONFIG = 'config_agent:read',
|
||||
}
|
||||
const resource = '*';
|
||||
|
||||
interface SecurityHasPrivilegesResponse {
|
||||
application: {
|
||||
apm: {
|
||||
'-': {
|
||||
[resource]: {
|
||||
[PrivilegeType.SOURCEMAP]: boolean;
|
||||
[PrivilegeType.EVENT]: boolean;
|
||||
[PrivilegeType.AGENT_CONFIG]: boolean;
|
||||
|
@ -36,75 +33,56 @@ export async function createAgentKey({
|
|||
context: ApmPluginRequestHandlerContext;
|
||||
requestBody: {
|
||||
name: string;
|
||||
sourcemap?: boolean;
|
||||
event?: boolean;
|
||||
agentConfig?: boolean;
|
||||
privileges: string[];
|
||||
};
|
||||
}) {
|
||||
const { name, privileges } = requestBody;
|
||||
const application = {
|
||||
application: 'apm',
|
||||
privileges,
|
||||
resources: [resource],
|
||||
};
|
||||
|
||||
// Elasticsearch will allow a user without the right apm privileges to create API keys, but the keys won't validate
|
||||
// check first whether the user has the right privileges, and bail out early if not
|
||||
const {
|
||||
body: { application, username, has_all_requested: hasRequiredPrivileges },
|
||||
body: {
|
||||
application: userApplicationPrivileges,
|
||||
username,
|
||||
has_all_requested: hasRequiredPrivileges,
|
||||
},
|
||||
} = await context.core.elasticsearch.client.asCurrentUser.security.hasPrivileges<SecurityHasPrivilegesResponse>(
|
||||
{
|
||||
body: {
|
||||
application: [
|
||||
{
|
||||
application: 'apm',
|
||||
privileges: [
|
||||
PrivilegeType.SOURCEMAP,
|
||||
PrivilegeType.EVENT,
|
||||
PrivilegeType.AGENT_CONFIG,
|
||||
],
|
||||
resources: ['-'],
|
||||
},
|
||||
],
|
||||
application: [application],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!hasRequiredPrivileges) {
|
||||
const missingPrivileges = Object.entries(application.apm['-'])
|
||||
const missingPrivileges = Object.entries(
|
||||
userApplicationPrivileges.apm[resource]
|
||||
)
|
||||
.filter((x) => !x[1])
|
||||
.map((x) => x[0])
|
||||
.join(', ');
|
||||
const error = `${username} is missing the following requested privilege(s): ${missingPrivileges}.\
|
||||
You might try with the superuser, or add the APM application privileges to the role of the authenticated user, eg.:
|
||||
PUT /_security/role/my_role {
|
||||
.map((x) => x[0]);
|
||||
|
||||
const error = `${username} is missing the following requested privilege(s): ${missingPrivileges.join(
|
||||
', '
|
||||
)}.\
|
||||
You might try with the superuser, or add the missing APM application privileges to the role of the authenticated user, eg.:
|
||||
PUT /_security/role/my_role
|
||||
{
|
||||
...
|
||||
"applications": [{
|
||||
"application": "apm",
|
||||
"privileges": ["sourcemap:write", "event:write", "config_agent:read"],
|
||||
"resources": ["*"]
|
||||
"privileges": ${JSON.stringify(missingPrivileges)},
|
||||
"resources": [${resource}]
|
||||
}],
|
||||
...
|
||||
}`;
|
||||
throw Boom.internal(error);
|
||||
}
|
||||
|
||||
const { name = 'apm-key', sourcemap, event, agentConfig } = requestBody;
|
||||
|
||||
const privileges: PrivilegeType[] = [];
|
||||
if (!sourcemap && !event && !agentConfig) {
|
||||
privileges.push(
|
||||
PrivilegeType.SOURCEMAP,
|
||||
PrivilegeType.EVENT,
|
||||
PrivilegeType.AGENT_CONFIG
|
||||
);
|
||||
}
|
||||
|
||||
if (sourcemap) {
|
||||
privileges.push(PrivilegeType.SOURCEMAP);
|
||||
}
|
||||
|
||||
if (event) {
|
||||
privileges.push(PrivilegeType.EVENT);
|
||||
}
|
||||
|
||||
if (agentConfig) {
|
||||
privileges.push(PrivilegeType.AGENT_CONFIG);
|
||||
}
|
||||
|
||||
const body = {
|
||||
name,
|
||||
metadata: {
|
||||
|
@ -114,13 +92,7 @@ export async function createAgentKey({
|
|||
apm: {
|
||||
cluster: [],
|
||||
index: [],
|
||||
applications: [
|
||||
{
|
||||
application: 'apm',
|
||||
privileges,
|
||||
resources: ['*'],
|
||||
},
|
||||
],
|
||||
applications: [application],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -19,6 +19,7 @@ export async function invalidateAgentKey({
|
|||
{
|
||||
body: {
|
||||
ids: [id],
|
||||
owner: true,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
import Boom from '@hapi/boom';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import * as t from 'io-ts';
|
||||
import { toBooleanRt } from '@kbn/io-ts-utils/to_boolean_rt';
|
||||
import { createApmServerRoute } from '../apm_routes/create_apm_server_route';
|
||||
import { createApmServerRouteRepository } from '../apm_routes/create_apm_server_route_repository';
|
||||
import { getAgentKeys } from './get_agent_keys';
|
||||
import { getAgentKeysPrivileges } from './get_agent_keys_privileges';
|
||||
import { invalidateAgentKey } from './invalidate_agent_key';
|
||||
import { createAgentKey } from './create_agent_key';
|
||||
import { privilegesTypeRt } from '../../../common/privilege_type';
|
||||
|
||||
const agentKeysRoute = createApmServerRoute({
|
||||
endpoint: 'GET /internal/apm/agent_keys',
|
||||
|
@ -77,19 +77,13 @@ const invalidateAgentKeyRoute = createApmServerRoute({
|
|||
});
|
||||
|
||||
const createAgentKeyRoute = createApmServerRoute({
|
||||
endpoint: 'POST /apm/agent_keys',
|
||||
endpoint: 'POST /api/apm/agent_keys',
|
||||
options: { tags: ['access:apm', 'access:apm_write'] },
|
||||
params: t.type({
|
||||
body: t.intersection([
|
||||
t.partial({
|
||||
sourcemap: toBooleanRt,
|
||||
event: toBooleanRt,
|
||||
agentConfig: toBooleanRt,
|
||||
}),
|
||||
t.type({
|
||||
name: t.string,
|
||||
}),
|
||||
]),
|
||||
body: t.type({
|
||||
name: t.string,
|
||||
privileges: privilegesTypeRt,
|
||||
}),
|
||||
}),
|
||||
handler: async (resources) => {
|
||||
const { context, params } = resources;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue