[Fleet] Remove kibana_api_key from secrets and use encrypted field instead (#217472)

Part I of https://github.com/elastic/kibana/issues/217025

## Summary
`kibana_api_key` and `kibana_url` fields are part of remote ES outputs
and where added in https://github.com/elastic/kibana/pull/208516.

Because of a change in the architecture of remote synced integrations
the secret field is not needed anymore: kibana can't read secrets
directly and fleet server (that can read them) won't be used.

- Remove the `secrets.kibana_api_key` field from remote outputs and
keeps only the `kibana_api_key`, registering it as an encrypted object.
- Remove these fields from full agent policy as they don't need to be
sent to fleet server/agents
- Replace the text field in the output flyout with a password field

<img width="793" alt="Screenshot 2025-04-08 at 15 18 26"
src="https://github.com/user-attachments/assets/4086b769-0a65-49d8-b93d-c51b38509497"
/>

 The `secrets.kibana_api_key` secret field was added in
9.1.0 and the whole feature is under a feature flag so it should be safe
to remove it.


### Checklist

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Cristina Amico 2025-04-09 14:54:39 +02:00 committed by GitHub
parent 47eab38887
commit a6308f3b66
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 80 additions and 504 deletions

View file

@ -29826,25 +29826,6 @@
"secrets": {
"additionalProperties": true,
"properties": {
"kibana_api_key": {
"anyOf": [
{
"additionalProperties": true,
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
{
"type": "string"
}
]
},
"service_token": {
"anyOf": [
{
@ -31007,25 +30988,6 @@
"secrets": {
"additionalProperties": false,
"properties": {
"kibana_api_key": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
{
"type": "string"
}
]
},
"service_token": {
"anyOf": [
{
@ -32121,25 +32083,6 @@
"secrets": {
"additionalProperties": true,
"properties": {
"kibana_api_key": {
"anyOf": [
{
"additionalProperties": true,
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
{
"type": "string"
}
]
},
"service_token": {
"anyOf": [
{
@ -33400,25 +33343,6 @@
"secrets": {
"additionalProperties": true,
"properties": {
"kibana_api_key": {
"anyOf": [
{
"additionalProperties": true,
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
{
"type": "string"
}
]
},
"service_token": {
"anyOf": [
{
@ -34566,25 +34490,6 @@
"secrets": {
"additionalProperties": false,
"properties": {
"kibana_api_key": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
{
"type": "string"
}
]
},
"service_token": {
"anyOf": [
{
@ -35665,25 +35570,6 @@
"secrets": {
"additionalProperties": true,
"properties": {
"kibana_api_key": {
"anyOf": [
{
"additionalProperties": true,
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
{
"type": "string"
}
]
},
"service_token": {
"anyOf": [
{

View file

@ -29826,25 +29826,6 @@
"secrets": {
"additionalProperties": true,
"properties": {
"kibana_api_key": {
"anyOf": [
{
"additionalProperties": true,
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
{
"type": "string"
}
]
},
"service_token": {
"anyOf": [
{
@ -31007,25 +30988,6 @@
"secrets": {
"additionalProperties": false,
"properties": {
"kibana_api_key": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
{
"type": "string"
}
]
},
"service_token": {
"anyOf": [
{
@ -32121,25 +32083,6 @@
"secrets": {
"additionalProperties": true,
"properties": {
"kibana_api_key": {
"anyOf": [
{
"additionalProperties": true,
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
{
"type": "string"
}
]
},
"service_token": {
"anyOf": [
{
@ -33400,25 +33343,6 @@
"secrets": {
"additionalProperties": true,
"properties": {
"kibana_api_key": {
"anyOf": [
{
"additionalProperties": true,
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
{
"type": "string"
}
]
},
"service_token": {
"anyOf": [
{
@ -34566,25 +34490,6 @@
"secrets": {
"additionalProperties": false,
"properties": {
"kibana_api_key": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
{
"type": "string"
}
]
},
"service_token": {
"anyOf": [
{
@ -35665,25 +35570,6 @@
"secrets": {
"additionalProperties": true,
"properties": {
"kibana_api_key": {
"anyOf": [
{
"additionalProperties": true,
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
{
"type": "string"
}
]
},
"service_token": {
"anyOf": [
{

View file

@ -28614,16 +28614,6 @@ paths:
additionalProperties: true
type: object
properties:
kibana_api_key:
anyOf:
- additionalProperties: true
type: object
properties:
id:
type: string
required:
- id
- type: string
service_token:
anyOf:
- additionalProperties: true
@ -29394,16 +29384,6 @@ paths:
additionalProperties: false
type: object
properties:
kibana_api_key:
anyOf:
- additionalProperties: false
type: object
properties:
id:
type: string
required:
- id
- type: string
service_token:
anyOf:
- additionalProperties: false
@ -30133,16 +30113,6 @@ paths:
additionalProperties: true
type: object
properties:
kibana_api_key:
anyOf:
- additionalProperties: true
type: object
properties:
id:
type: string
required:
- id
- type: string
service_token:
anyOf:
- additionalProperties: true
@ -30978,16 +30948,6 @@ paths:
additionalProperties: true
type: object
properties:
kibana_api_key:
anyOf:
- additionalProperties: true
type: object
properties:
id:
type: string
required:
- id
- type: string
service_token:
anyOf:
- additionalProperties: true
@ -31745,16 +31705,6 @@ paths:
additionalProperties: false
type: object
properties:
kibana_api_key:
anyOf:
- additionalProperties: false
type: object
properties:
id:
type: string
required:
- id
- type: string
service_token:
anyOf:
- additionalProperties: false
@ -32471,16 +32421,6 @@ paths:
additionalProperties: true
type: object
properties:
kibana_api_key:
anyOf:
- additionalProperties: true
type: object
properties:
id:
type: string
required:
- id
- type: string
service_token:
anyOf:
- additionalProperties: true

View file

@ -30851,16 +30851,6 @@ paths:
additionalProperties: true
type: object
properties:
kibana_api_key:
anyOf:
- additionalProperties: true
type: object
properties:
id:
type: string
required:
- id
- type: string
service_token:
anyOf:
- additionalProperties: true
@ -31631,16 +31621,6 @@ paths:
additionalProperties: false
type: object
properties:
kibana_api_key:
anyOf:
- additionalProperties: false
type: object
properties:
id:
type: string
required:
- id
- type: string
service_token:
anyOf:
- additionalProperties: false
@ -32370,16 +32350,6 @@ paths:
additionalProperties: true
type: object
properties:
kibana_api_key:
anyOf:
- additionalProperties: true
type: object
properties:
id:
type: string
required:
- id
- type: string
service_token:
anyOf:
- additionalProperties: true
@ -33215,16 +33185,6 @@ paths:
additionalProperties: true
type: object
properties:
kibana_api_key:
anyOf:
- additionalProperties: true
type: object
properties:
id:
type: string
required:
- id
- type: string
service_token:
anyOf:
- additionalProperties: true
@ -33982,16 +33942,6 @@ paths:
additionalProperties: false
type: object
properties:
kibana_api_key:
anyOf:
- additionalProperties: false
type: object
properties:
id:
type: string
required:
- id
- type: string
service_token:
anyOf:
- additionalProperties: false
@ -34708,16 +34658,6 @@ paths:
additionalProperties: true
type: object
properties:
kibana_api_key:
anyOf:
- additionalProperties: true
type: object
properties:
id:
type: string
required:
- id
- type: string
service_token:
anyOf:
- additionalProperties: true

View file

@ -133,5 +133,4 @@ interface KafkaOutputSecrets extends BaseSSLSecrets {
}
interface RemoteESOutputSecrets extends BaseSSLSecrets {
service_token?: SOSecret;
kibana_api_key?: SOSecret;
}

View file

@ -359,7 +359,6 @@ describe('EditOutputFlyout', () => {
expect(
(utils.getByTestId('settingsOutputsFlyout.kibanaURLInput') as HTMLInputElement).value
).toEqual('http://localhost');
expect(utils.queryByTestId('kibanaAPIKeySecretInput')).not.toBeNull();
expect(utils.queryByTestId('advancedSSLOptionsButton')).not.toBeNull();
fireEvent.click(utils.getByTestId('advancedSSLOptionsButton'));
@ -409,13 +408,11 @@ describe('EditOutputFlyout', () => {
);
expect(utils.queryByTestId('settingsOutputsFlyout.kibanaURLInput')).toBeNull();
expect(utils.queryByTestId('kibanaAPIKeySecretInput')).toBeNull();
fireEvent.click(utils.getByTestId('syncIntegrationsSwitch'));
expect(
(utils.getByTestId('settingsOutputsFlyout.kibanaURLInput') as HTMLInputElement).value
).toEqual('http://localhost:5601');
expect((utils.getByTestId('kibanaAPIKeySecretInput') as HTMLInputElement).value).toEqual('key');
fireEvent.click(utils.getByText('Save and apply settings'));
@ -424,9 +421,9 @@ describe('EditOutputFlyout', () => {
'outputR',
expect.objectContaining({
sync_integrations: true,
secrets: { service_token: '1234', kibana_api_key: 'key' },
secrets: { service_token: '1234' },
service_token: undefined,
kibana_api_key: undefined,
kibana_api_key: 'key',
kibana_url: 'http://localhost:5601',
})
);

View file

@ -16,6 +16,7 @@ import {
EuiButton,
EuiLink,
EuiCode,
EuiFieldPassword,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
@ -67,12 +68,6 @@ export const OutputFormRemoteEsSection: React.FunctionComponent<Props> = (props)
inputs.serviceTokenInput.clear();
isServiceTokenSecret = true;
}
let isKibanaAPIKeySecret = false;
if (inputs.kibanaAPIKeyInput.value && !inputs.kibanaAPIKeySecretInput.value) {
inputs.kibanaAPIKeySecretInput.setValue(inputs.kibanaAPIKeyInput.value);
inputs.kibanaAPIKeyInput.clear();
isKibanaAPIKeySecret = true;
}
let isSslKeySecretInput = false;
if (enableSSLSecrets) {
if (inputs.sslKeyInput.value && !inputs.sslKeySecretInput.value) {
@ -84,7 +79,6 @@ export const OutputFormRemoteEsSection: React.FunctionComponent<Props> = (props)
setIsConvertedToSecret({
...isConvertedToSecret,
serviceToken: isServiceTokenSecret,
kibanaAPIKey: isKibanaAPIKeySecret,
sslKey: isSslKeySecretInput,
});
}
@ -93,7 +87,6 @@ export const OutputFormRemoteEsSection: React.FunctionComponent<Props> = (props)
inputs.serviceTokenInput,
inputs.serviceTokenSecretInput,
inputs.kibanaAPIKeyInput,
inputs.kibanaAPIKeySecretInput,
isFirstLoad,
setIsFirstLoad,
isConvertedToSecret,
@ -109,7 +102,6 @@ export const OutputFormRemoteEsSection: React.FunctionComponent<Props> = (props)
if (enableSSLSecrets) inputs.sslKeyInput.clear();
} else {
inputs.serviceTokenSecretInput.setValue('');
inputs.kibanaAPIKeySecretInput.setValue('');
if (enableSSLSecrets) inputs.sslKeyInput.setValue('');
}
setIsConvertedToSecret({
@ -359,56 +351,31 @@ export const OutputFormRemoteEsSection: React.FunctionComponent<Props> = (props)
/>
</EuiFormRow>
<EuiSpacer size="m" />
{!useSecretsStorage ? (
<SecretFormRow
fullWidth
label={
<FormattedMessage
id="xpack.fleet.settings.editOutputFlyout.kibanaAPIKeyLabel"
defaultMessage="Remote Kibana API Key"
/>
}
{...inputs.kibanaAPIKeyInput.formRowProps}
useSecretsStorage={useSecretsStorage}
onToggleSecretStorage={onToggleSecretAndClearValue}
>
<EuiFieldText
fullWidth
data-test-subj="kibanaAPIKeySecretInput"
{...inputs.kibanaAPIKeyInput.props}
placeholder={i18n.translate(
'xpack.fleet.settings.editOutputFlyout.kibanaAPIKeyPlaceholder',
{
defaultMessage: 'Specify Kibana API Key',
}
)}
<EuiFormRow
fullWidth
label={
<FormattedMessage
id="xpack.fleet.settings.editOutputFlyout.kibanaAPIKeyLabel"
defaultMessage="Remote Kibana API Key"
/>
</SecretFormRow>
) : (
<SecretFormRow
}
{...inputs.kibanaAPIKeyInput.formRowProps}
>
<EuiFieldPassword
fullWidth
title={i18n.translate('xpack.fleet.settings.editOutputFlyout.kibanaAPIKeyLabel', {
defaultMessage: 'Remote Kibana API Key',
})}
{...inputs.kibanaAPIKeySecretInput.formRowProps}
cancelEdit={inputs.kibanaAPIKeySecretInput.cancelEdit}
useSecretsStorage={useSecretsStorage}
isConvertedToSecret={isConvertedToSecret.kibanaAPIKey}
onToggleSecretStorage={onToggleSecretAndClearValue}
>
<EuiFieldText
data-test-subj="kibanaAPIKeySecretInput"
fullWidth
{...inputs.kibanaAPIKeySecretInput.props}
placeholder={i18n.translate(
'xpack.fleet.settings.editOutputFlyout.kibanaAPIKeyPlaceholder',
{
defaultMessage: 'Specify Kibana API Key',
}
)}
/>
</SecretFormRow>
)}
type="dual"
data-test-subj="kibanaAPIKeySecretInput"
{...inputs.kibanaAPIKeyInput.props}
placeholder={i18n.translate(
'xpack.fleet.settings.editOutputFlyout.kibanaAPIKeyPlaceholder',
{
defaultMessage: 'Specify Kibana API Key',
}
)}
/>
</EuiFormRow>
<EuiSpacer size="m" />
<EuiCallOut
title={

View file

@ -76,7 +76,6 @@ import {
validateDynamicKafkaTopics,
validateKibanaURL,
validateKibanaAPIKey,
validateKibanaAPIKeySecret,
} from './output_form_validators';
import { confirmUpdate } from './confirm_update';
@ -104,7 +103,6 @@ export interface OutputFormInputsType {
syncIntegrationsInput: ReturnType<typeof useSwitchInput>;
kibanaURLInput: ReturnType<typeof useInput>;
kibanaAPIKeyInput: ReturnType<typeof useInput>;
kibanaAPIKeySecretInput: ReturnType<typeof useSecretInput>;
sslCertificateInput: ReturnType<typeof useInput>;
sslKeyInput: ReturnType<typeof useInput>;
sslKeySecretInput: ReturnType<typeof useSecretInput>;
@ -294,12 +292,6 @@ export function useOutputForm(onSucess: () => void, output?: Output, defaultOupu
isDisabled('kibana_api_key')
);
const kibanaAPIKeySecretInput = useSecretInput(
(output as NewRemoteElasticsearchOutput)?.secrets?.kibana_api_key ?? '',
syncIntegrationsInput.value ? validateKibanaAPIKeySecret : undefined,
isDisabled('kibana_api_key')
);
const kibanaURLInput = useInput(
(output as NewRemoteElasticsearchOutput)?.kibana_url ?? '',
(val) => validateKibanaURL(val, syncIntegrationsInput.value),
@ -600,7 +592,6 @@ export function useOutputForm(onSucess: () => void, output?: Output, defaultOupu
serviceTokenInput,
serviceTokenSecretInput,
kibanaAPIKeyInput,
kibanaAPIKeySecretInput,
syncIntegrationsInput,
kibanaURLInput,
sslCertificateInput,
@ -663,7 +654,6 @@ export function useOutputForm(onSucess: () => void, output?: Output, defaultOupu
const serviceTokenValid = serviceTokenInput.validate();
const serviceTokenSecretValid = serviceTokenSecretInput.validate();
const kibanaAPIKeyValid = kibanaAPIKeyInput.validate();
const kibanaAPIKeySecretValid = kibanaAPIKeySecretInput.validate();
const kibanaURLInputValid = kibanaURLInput.validate();
const sslCertificateValid = sslCertificateInput.validate();
const sslKeyValid = sslKeyInput.validate();
@ -719,8 +709,8 @@ export function useOutputForm(onSucess: () => void, output?: Output, defaultOupu
(serviceTokenSecretInput.value && serviceTokenSecretValid)) &&
((!syncIntegrationsInput.value && kibanaURLInputValid) ||
(syncIntegrationsInput.value &&
((kibanaAPIKeyInput.value && kibanaAPIKeyValid) ||
(kibanaAPIKeySecretInput.value && kibanaAPIKeySecretValid)) &&
kibanaAPIKeyInput.value &&
kibanaAPIKeyValid &&
kibanaURLInputValid))
);
} else {
@ -751,7 +741,6 @@ export function useOutputForm(onSucess: () => void, output?: Output, defaultOupu
serviceTokenInput,
serviceTokenSecretInput,
kibanaAPIKeyInput,
kibanaAPIKeySecretInput,
syncIntegrationsInput,
kibanaURLInput,
sslCertificateInput,
@ -981,12 +970,7 @@ export function useOutputForm(onSucess: () => void, output?: Output, defaultOupu
service_token: serviceTokenSecretInput.value,
};
}
if (!kibanaAPIKeyInput.value && kibanaAPIKeySecretInput.value) {
secrets = {
...(secrets ?? {}),
kibana_api_key: kibanaAPIKeySecretInput.value,
};
}
if (!sslKeyInput.value && sslKeySecretInput.value) {
secrets = {
...(secrets ?? {}),
@ -1140,7 +1124,6 @@ export function useOutputForm(onSucess: () => void, output?: Output, defaultOupu
serviceTokenInput.value,
serviceTokenSecretInput.value,
kibanaAPIKeyInput.value,
kibanaAPIKeySecretInput.value,
syncIntegrationsInput.value,
kibanaURLInput.value,
caTrustedFingerprintInput.value,

View file

@ -14,7 +14,7 @@ import { postOutputHandler, putOutputHandler } from './handler';
const putOutputHandlerWithErrorHandler = withDefaultErrorHandler(putOutputHandler);
const postOutputHandlerWithErrorHandler = withDefaultErrorHandler(postOutputHandler);
describe('output handler', () => {
describe('Outputs handler', () => {
const mockContext = {
core: Promise.resolve({
savedObjects: {},
@ -259,37 +259,14 @@ describe('output handler', () => {
expect(res).toEqual({ body: { item: { id: 'output1' } } });
});
it('should return error if both kibana_api_key and secrets.kibana_api_key is provided for remote_elasticsearch output', async () => {
it('should return ok if one of kibana_api_key is provided for remote_elasticsearch output', async () => {
jest
.spyOn(appContextService, 'getCloud')
.mockReturnValue({ isServerlessEnabled: false } as any);
const res = await postOutputHandlerWithErrorHandler(
mockContext,
{
body: {
type: 'remote_elasticsearch',
kibana_api_key: 'value1',
secrets: { kibana_api_key: 'value2' },
},
} as any,
mockResponse as any
);
expect(res).toEqual({
body: { message: 'Cannot specify both kibana_api_key and secrets.kibana_api_key' },
statusCode: 400,
});
});
it('should return ok if one of kibana_api_key and secrets.kibana_api_key is provided for remote_elasticsearch output', async () => {
jest
.spyOn(appContextService, 'getCloud')
.mockReturnValue({ isServerlessEnabled: false } as any);
const res = await postOutputHandlerWithErrorHandler(
mockContext,
{ body: { type: 'remote_elasticsearch', secrets: { kibana_api_key: 'value2' } } } as any,
{ body: { type: 'remote_elasticsearch', kibana_api_key: 'value2' } } as any,
mockResponse as any
);

View file

@ -44,9 +44,6 @@ function ensureNoDuplicateSecrets(output: Partial<Output>) {
if (output.service_token && output.secrets?.service_token) {
throw Boom.badRequest('Cannot specify both service_token and secrets.service_token');
}
if (output.kibana_api_key && output.secrets?.kibana_api_key) {
throw Boom.badRequest('Cannot specify both kibana_api_key and secrets.kibana_api_key');
}
}
}

View file

@ -1277,6 +1277,7 @@ export const OUTPUT_INCLUDE_AAD_FIELDS = new Set([
export const OUTPUT_ENCRYPTED_FIELDS = new Set([
{ key: 'ssl', dangerouslyExposeValue: true },
{ key: 'password', dangerouslyExposeValue: true },
{ key: 'kibana_api_key', dangerouslyExposeValue: true },
]);
export const FLEET_SERVER_HOST_ENCRYPTED_FIELDS = new Set([

View file

@ -309,8 +309,6 @@ Object {
"hosts": Array [
"http://127.0.0.1:9201",
],
"kibana_api_key": undefined,
"kibana_url": undefined,
"preset": "balanced",
"service_token": undefined,
"sync_integrations": undefined,

View file

@ -616,8 +616,6 @@ export function transformOutputToFullPolicyOutput(
if (output.type === outputType.RemoteElasticsearch) {
newOutput.service_token = output.service_token;
newOutput.kibana_api_key = output.kibana_api_key;
newOutput.kibana_url = output.kibana_url;
newOutput.sync_integrations = output.sync_integrations;
}

View file

@ -706,9 +706,6 @@ class OutputService {
if (!output.service_token && output.secrets?.service_token) {
data.service_token = output.secrets?.service_token as string;
}
if (!output.kibana_api_key && output.secrets?.kibana_api_key) {
data.kibana_api_key = output.secrets?.kibana_api_key as string;
}
}
}
@ -1133,9 +1130,6 @@ class OutputService {
if (!data.service_token && data.secrets?.service_token) {
updateData.service_token = data.secrets?.service_token as string;
}
if (!data.kibana_api_key && data.secrets?.kibana_api_key) {
updateData.kibana_api_key = data.secrets?.kibana_api_key as string;
}
}
}

View file

@ -18,6 +18,7 @@ describe(`_getFieldsToIncludeEncryptedSO`, () => {
Array [
"ssl",
"password",
"kibana_api_key",
"service_token",
"shipper",
"allow_edit",

View file

@ -53,7 +53,7 @@ const spyAgentPolicyServicBumpAllAgentPoliciesForOutput = jest.spyOn(
'bumpAllAgentPoliciesForOutput'
);
describe('output preconfiguration', () => {
describe('Outputs preconfiguration', () => {
let logstashSecretHash: string;
beforeEach(async () => {
@ -79,7 +79,7 @@ describe('output preconfiguration', () => {
const keyHash = (await hashSecret('secretKey')) as string;
const passwordHash = (await hashSecret('secretPassword')) as string;
const serviceTokenHash = (await hashSecret('secretServiceToken')) as string;
const serviceKibanaAPIKeyHash = (await hashSecret('secretKibanaAPIKey')) as string;
mockedOutputService.bulkGet.mockImplementation(async (soClient, id): Promise<Output[]> => {
return [
{
@ -255,10 +255,6 @@ describe('output preconfiguration', () => {
id: '101112',
hash: serviceTokenHash,
},
kibana_api_key: {
id: '131415',
hash: serviceKibanaAPIKeyHash,
},
ssl: {
key: {
id: '789',
@ -277,7 +273,6 @@ describe('output preconfiguration', () => {
is_preconfigured: true,
secrets: {
service_token: 'secretServiceToken',
kibana_api_key: 'secretKibanaAPIKey',
},
},
];
@ -900,7 +895,6 @@ describe('output preconfiguration', () => {
is_preconfigured: true,
secrets: {
service_token: 'secretServiceToken', // no change
kibana_api_key: 'secretKibanaAPIKey',
},
},
]);
@ -1060,7 +1054,6 @@ describe('output preconfiguration', () => {
is_preconfigured: true,
secrets: {
service_token: 'secretServiceToken',
kibana_api_key: 'secretKibanaAPIKey',
ssl: { key: 'secretKey' },
},
},

View file

@ -188,13 +188,6 @@ async function hashSecrets(output: PreconfiguredOutput) {
service_token: serviceToken,
};
}
if (typeof remoteESOutput.secrets?.kibana_api_key === 'string') {
const kibanaAPIKey = await hashSecret(remoteESOutput.secrets?.kibana_api_key);
secrets = {
...(secrets ? secrets : {}),
kibana_api_key: kibanaAPIKey,
};
}
}
// common to all types
if (typeof output.secrets?.ssl?.key === 'string') {
@ -348,10 +341,6 @@ async function isPreconfiguredOutputDifferentFromCurrent(
preconfiguredOutput.secrets?.service_token,
existingOutput.secrets?.service_token
)) ||
(await isSecretDifferent(
preconfiguredOutput.secrets?.kibana_api_key,
existingOutput.secrets?.kibana_api_key
)) ||
isDifferent(existingOutput.kibana_url, preconfiguredOutput.kibana_url) ||
isDifferent(existingOutput.sync_integrations, preconfiguredOutput.sync_integrations);

View file

@ -934,12 +934,6 @@ function getOutputSecretPaths(
value: remoteESOutput.secrets.service_token,
});
}
if (remoteESOutput.secrets?.kibana_api_key) {
outputSecretPaths.push({
path: 'secrets.kibana_api_key',
value: remoteESOutput.secrets.kibana_api_key,
});
}
}
// common to all outputs
@ -986,11 +980,6 @@ export function getOutputSecretReferences(output: Output): PolicySecretReference
id: output.secrets.service_token.id,
});
}
if (typeof output?.secrets?.kibana_api_key === 'object') {
outputSecretPaths.push({
id: output.secrets.kibana_api_key.id,
});
}
}
return outputSecretPaths;

View file

@ -157,7 +157,6 @@ export const RemoteElasticSearchSchema = {
secrets: schema.maybe(
schema.object({
service_token: schema.maybe(secretRefSchema),
kibana_api_key: schema.maybe(secretRefSchema),
ssl: schema.maybe(schema.object({ key: schema.maybe(secretRefSchema) })),
})
),
@ -173,7 +172,6 @@ const RemoteElasticSearchUpdateSchema = {
secrets: schema.maybe(
schema.object({
service_token: schema.maybe(secretRefSchema),
kibana_api_key: schema.maybe(secretRefSchema),
ssl: schema.maybe(schema.object({ key: schema.maybe(secretRefSchema) })),
})
),

View file

@ -183,7 +183,6 @@ export interface OutputSoRemoteElasticsearchAttributes extends OutputSoBaseAttri
service_token?: string;
secrets?: {
service_token?: { id: string };
kibana_api_key?: { id: string };
ssl?: {
key?: { id: string };
};

View file

@ -792,6 +792,35 @@ export default function (providerContext: FtrProviderContext) {
}
});
it('should allow to update kibana_api_key on an existing remote_elasticsearch output', async function () {
const res = await supertest
.post(`/api/fleet/outputs`)
.set('kbn-xsrf', 'xxxx')
.send({
name: 'Remote Output With kibana_api_key',
type: 'remote_elasticsearch',
hosts: ['https://test.fr:443'],
sync_integrations: true,
kibana_url: 'https://testhost',
kibana_api_key: 'aaaa',
})
.expect(200);
const outputId = res.body.item.id;
const updatedRes = await supertest
.put(`/api/fleet/outputs/${outputId}`)
.set('kbn-xsrf', 'xxxx')
.send({
name: 'Remote Output With kibana_api_key',
type: 'remote_elasticsearch',
hosts: ['https://test.fr:443'],
sync_integrations: true,
kibana_url: 'https://testhost',
kibana_api_key: 'bbbb',
})
.expect(200);
expect(updatedRes.body.item.kibana_api_key).to.equal('bbbb');
});
it('should bump all policies in all spaces if updating the default output', async () => {
const { body: nonDefaultOutput } = await supertest
.post(`/api/fleet/outputs`)
@ -1794,6 +1823,21 @@ export default function (providerContext: FtrProviderContext) {
})
.expect(200);
});
it('should allow to create a new remote_elasticsearch output with kibana_api_key field', async function () {
await supertest
.post(`/api/fleet/outputs`)
.set('kbn-xsrf', 'xxxx')
.send({
name: 'My remote ES Output',
type: 'remote_elasticsearch',
hosts: ['https://test.fr:443'],
sync_integrations: true,
kibana_url: 'https://testhost',
kibana_api_key: 'aaaa',
})
.expect(200);
});
});
describe('DELETE /outputs/{outputId}', () => {