Revert "[Fleet] Support preconfigured output secrets (#170259)"

This reverts commit 1f7a527494.
This commit is contained in:
Tiago Costa 2023-11-23 18:08:02 +00:00
parent e7c793e0d7
commit 78f7b80e33
No known key found for this signature in database
GPG key ID: BAECC2D04A04C6EA
7 changed files with 61 additions and 511 deletions

View file

@ -865,7 +865,6 @@
"ansi-regex": "^5.0.1",
"antlr4ts": "^0.5.0-alpha.3",
"archiver": "^5.3.1",
"argon2": "0.31.1",
"async": "^3.2.3",
"aws4": "^1.12.0",
"axios": "^1.6.0",

View file

@ -23,12 +23,7 @@ export type KafkaPartitionType = typeof kafkaPartitionType;
export type KafkaTopicWhenType = typeof kafkaTopicWhenType;
export type KafkaAcknowledgeReliabilityLevel = typeof kafkaAcknowledgeReliabilityLevel;
export type KafkaVerificationMode = typeof kafkaVerificationModes;
export type OutputSecret =
| string
| {
id: string;
hash?: string;
};
interface NewBaseOutput {
is_default: boolean;
is_default_monitoring: boolean;
@ -50,7 +45,11 @@ interface NewBaseOutput {
allow_edit?: string[];
secrets?: {
ssl?: {
key?: OutputSecret;
key?:
| string
| {
id: string;
};
};
};
}
@ -132,9 +131,17 @@ export interface KafkaOutput extends NewBaseOutput {
broker_timeout?: number;
required_acks?: ValueOf<KafkaAcknowledgeReliabilityLevel>;
secrets?: {
password?: OutputSecret;
password?:
| string
| {
id: string;
};
ssl?: {
key?: OutputSecret;
key?:
| string
| {
id: string;
};
};
};
}

View file

@ -419,12 +419,7 @@ class OutputService {
soClient: SavedObjectsClientContract,
esClient: ElasticsearchClient,
output: NewOutput,
options?: {
id?: string;
fromPreconfiguration?: boolean;
overwrite?: boolean;
secretHashes?: Record<string, any>;
}
options?: { id?: string; fromPreconfiguration?: boolean; overwrite?: boolean }
): Promise<Output> {
const data: OutputSOAttributes = { ...omit(output, ['ssl', 'secrets']) };
if (output.type === outputType.RemoteElasticsearch) {
@ -560,7 +555,6 @@ class OutputService {
const { output: outputWithSecrets } = await extractAndWriteOutputSecrets({
output,
esClient,
secretHashes: output.is_preconfigured ? options?.secretHashes : undefined,
});
if (outputWithSecrets.secrets) data.secrets = outputWithSecrets.secrets;
@ -722,10 +716,7 @@ class OutputService {
esClient: ElasticsearchClient,
id: string,
data: Partial<Output>,
{
fromPreconfiguration = false,
secretHashes,
}: { fromPreconfiguration: boolean; secretHashes?: Record<string, any> } = {
{ fromPreconfiguration = false }: { fromPreconfiguration: boolean } = {
fromPreconfiguration: false,
}
) {
@ -756,7 +747,6 @@ class OutputService {
oldOutput: originalOutput,
outputUpdate: data,
esClient,
secretHashes: data.is_preconfigured ? secretHashes : undefined,
});
updateData.secrets = secretsRes.outputUpdate.secrets;

View file

@ -17,7 +17,6 @@ import {
createOrUpdatePreconfiguredOutputs,
cleanPreconfiguredOutputs,
getPreconfiguredOutputFromConfig,
hash,
} from './outputs';
jest.mock('../agent_policy_update');
@ -47,18 +46,16 @@ const spyAgentPolicyServicBumpAllAgentPoliciesForOutput = jest.spyOn(
);
describe('output preconfiguration', () => {
beforeEach(async () => {
beforeEach(() => {
mockedOutputService.create.mockReset();
mockedOutputService.update.mockReset();
mockedOutputService.delete.mockReset();
mockedOutputService.getDefaultDataOutputId.mockReset();
mockedOutputService.getDefaultESHosts.mockReturnValue(['http://default-es:9200']);
const keyHash = await hash('secretKey');
const passwordHash = await hash('secretPassword');
mockedOutputService.bulkGet.mockImplementation(async (soClient, id): Promise<Output[]> => {
return [
{
id: 'existing-es-output-1',
id: 'existing-output-1',
is_default: false,
is_default_monitoring: false,
name: 'Output 1',
@ -77,76 +74,8 @@ describe('output preconfiguration', () => {
hosts: ['kafka.co:80'],
is_preconfigured: true,
},
{
id: 'existing-logstash-output-with-secrets-1',
is_default: false,
is_default_monitoring: false,
name: 'Logstash Output With Secrets 1',
type: 'logstash',
hosts: ['test:4343'],
is_preconfigured: true,
secrets: {
ssl: {
key: {
id: '123',
hash: keyHash,
},
},
},
},
{
id: 'existing-logstash-output-with-secrets-2',
is_default: false,
is_default_monitoring: false,
name: 'Logstash Output With Secrets 2',
type: 'logstash',
hosts: ['test:4343'],
is_preconfigured: true,
secrets: {
ssl: {
key: 'secretKey',
},
},
},
{
id: 'existing-kafka-output-with-secrets-1',
is_default: false,
is_default_monitoring: false,
name: 'Kafka Output With Secrets 1',
type: 'kafka',
hosts: ['kafka.co:80'],
is_preconfigured: true,
secrets: {
password: {
id: '456',
hash: passwordHash,
},
ssl: {
key: {
id: '789',
hash: keyHash,
},
},
},
},
{
id: 'existing-kafka-output-with-secrets-2',
is_default: false,
is_default_monitoring: false,
name: 'Kafka Output With Secrets 2',
type: 'kafka',
hosts: ['kafka.co:80'],
is_preconfigured: true,
secrets: {
password: 'secretPassword',
ssl: {
key: 'secretKey',
},
},
},
];
});
spyAgentPolicyServicBumpAllAgentPoliciesForOutput.mockClear();
});
it('should generate a preconfigured output if elasticsearch.hosts is set in the config', async () => {
@ -175,7 +104,7 @@ describe('output preconfiguration', () => {
`);
});
it('should create preconfigured output that does not exist', async () => {
it('should create preconfigured output that does not exists', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
@ -194,7 +123,7 @@ describe('output preconfiguration', () => {
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled();
});
it('should create preconfigured kafka output that does not exist', async () => {
it('should create preconfigured kafka output that does not exists', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
@ -213,7 +142,7 @@ describe('output preconfiguration', () => {
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled();
});
it('should create a preconfigured output with ca_trusted_fingerprint that does not exist', async () => {
it('should create a preconfigured output with ca_trusted_fingerprint that does not exists', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
@ -241,7 +170,7 @@ describe('output preconfiguration', () => {
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled();
});
it('should create a preconfigured logstash output that does not exist', async () => {
it('should create preconfigured logstash output that does not exist', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
@ -261,66 +190,7 @@ describe('output preconfiguration', () => {
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled();
});
it('should create a preconfigured logstash output with secrets that does not exist', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
{
id: 'non-existing-logstash-output-with-secrets-1',
name: 'Logstash Output With Secrets 2',
type: 'logstash',
is_default: false,
is_default_monitoring: false,
secrets: {
ssl: {
key: 'secretKey',
},
},
},
]);
expect(mockedOutputService.create).toBeCalled();
expect(mockedOutputService.create).toBeCalledWith(
expect.anything(),
expect.anything(),
expect.objectContaining({
secrets: {
ssl: {
key: 'secretKey',
},
},
}),
expect.anything()
);
expect(mockedOutputService.update).not.toBeCalled();
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled();
});
it('should create a preconfigured kafka output with secrets that does not exist', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
{
id: 'non-existing-kafka-output-with-secrets-1',
name: 'Kafka Output With Secrets 2',
type: 'kafka',
is_default: false,
is_default_monitoring: false,
secrets: {
password: 'secretPassword',
ssl: {
key: 'secretKey',
},
},
},
]);
expect(mockedOutputService.create).toBeCalled();
expect(mockedOutputService.update).not.toBeCalled();
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled();
});
it('should set default hosts if hosts is not set output that does not exist', async () => {
it('should set default hosts if hosts is not set output that does not exists', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
@ -343,7 +213,7 @@ describe('output preconfiguration', () => {
soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 });
mockedOutputService.bulkGet.mockResolvedValue([
{
id: 'existing-es-output-1',
id: 'existing-output-1',
is_default: false,
is_default_monitoring: false,
name: 'Output 1',
@ -355,7 +225,7 @@ describe('output preconfiguration', () => {
]);
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
{
id: 'existing-es-output-1',
id: 'existing-output-1',
is_default: false,
is_default_monitoring: false,
name: 'Output 1',
@ -369,7 +239,7 @@ describe('output preconfiguration', () => {
expect(mockedOutputService.update).toBeCalledWith(
expect.anything(),
expect.anything(),
'existing-es-output-1',
'existing-output-1',
expect.objectContaining({
is_preconfigured: true,
}),
@ -384,7 +254,7 @@ describe('output preconfiguration', () => {
soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 });
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
{
id: 'existing-es-output-1',
id: 'existing-output-1',
is_default: false,
is_default_monitoring: false,
name: 'Output 1',
@ -398,30 +268,6 @@ describe('output preconfiguration', () => {
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled();
});
it('should update output if a preconfigured logstash ouput with secrets exists and has changed', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 });
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
{
id: 'existing-logstash-output-with-secrets-1',
is_default: false,
is_default_monitoring: false,
name: 'Logstash Output With Secrets 1',
type: 'logstash',
secrets: {
ssl: {
key: 'secretKey2', // field that changed
},
},
},
]);
expect(mockedOutputService.create).not.toBeCalled();
expect(mockedOutputService.update).toBeCalled();
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled();
});
it('should update output if preconfigured kafka output exists and changed', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
@ -433,7 +279,7 @@ describe('output preconfiguration', () => {
is_default_monitoring: false,
name: 'Kafka Output 1',
type: 'kafka',
hosts: ['kafka.co:8080'], // field that changed
hosts: ['kafka.co:8080'],
},
]);
@ -442,49 +288,24 @@ describe('output preconfiguration', () => {
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled();
});
it('should update ouput if a preconfigured kafka with secrets exists and has changed', async () => {
it('should not update output if preconfigured output exists and did not changed', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 });
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
{
id: 'existing-kafka-output-with-secrets-1',
is_default: false,
is_default_monitoring: false,
name: 'Kafka Output With Secrets 1',
type: 'kafka',
secrets: {
password: 'secretPassword2', // field that changed
ssl: {
key: 'secretKey2',
},
},
},
]);
expect(mockedOutputService.create).not.toBeCalled();
expect(mockedOutputService.update).toBeCalled();
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled();
});
it('should not update output if preconfigured output exists and did not change', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 });
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
{
id: 'existing-es-output-1',
id: 'existing-output-1',
is_default: false,
is_default_monitoring: false,
name: 'Output 1',
type: 'elasticsearch',
hosts: ['http://es.co:80'],
hosts: ['http://newhostichanged.co:9201'], // field that changed
},
]);
expect(mockedOutputService.create).not.toBeCalled();
expect(mockedOutputService.update).not.toBeCalled();
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled();
expect(mockedOutputService.update).toBeCalled();
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled();
});
it('should not update output if preconfigured kafka output exists and did not change', async () => {
@ -498,109 +319,7 @@ describe('output preconfiguration', () => {
is_default_monitoring: false,
name: 'Kafka Output 1',
type: 'kafka',
hosts: ['kafka.co:80'],
},
]);
expect(mockedOutputService.create).not.toBeCalled();
expect(mockedOutputService.update).not.toBeCalled();
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled();
});
it('should not update output if a preconfigured logstash output with secrets exists and did not change', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 });
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
{
id: 'existing-logstash-output-with-secrets-1',
is_default: false,
is_default_monitoring: false,
name: 'Logstash Output With Secrets 1',
type: 'logstash',
hosts: ['test:4343'],
secrets: {
ssl: {
key: 'secretKey',
},
},
},
]);
expect(mockedOutputService.create).not.toBeCalled();
expect(mockedOutputService.update).not.toBeCalled();
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled();
});
it('should not update output if a preconfigured kafka output with secrets exists and did not change', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 });
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
{
id: 'existing-kafka-output-with-secrets-1',
is_default: false,
is_default_monitoring: false,
name: 'Kafka Output With Secrets 1',
type: 'kafka',
hosts: ['kafka.co:80'],
secrets: {
password: 'secretPassword',
ssl: {
key: 'secretKey',
},
},
},
]);
expect(mockedOutputService.create).not.toBeCalled();
expect(mockedOutputService.update).not.toBeCalled();
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled();
});
it('should update output if a preconfigured logstash output with plain value secrets exists and did not change', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 });
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
{
id: 'existing-logstash-output-with-secrets-2',
is_default: false,
is_default_monitoring: false,
name: 'Logstash Output With Secrets 2',
type: 'logstash',
hosts: ['test:4343'],
secrets: {
ssl: {
key: 'secretKey', // no change
},
},
},
]);
expect(mockedOutputService.create).not.toBeCalled();
expect(mockedOutputService.update).toBeCalled();
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled();
});
it('should update output if a preconfigured kafka output with plain value secrets exists and did not change', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 });
await createOrUpdatePreconfiguredOutputs(soClient, esClient, [
{
id: 'existing-kafka-output-with-secrets-2',
is_default: false,
is_default_monitoring: false,
name: 'Kafka Output With Secrets 2',
type: 'kafka',
hosts: ['kafka.co:80'],
secrets: {
password: 'secretPassword', // no change
ssl: {
key: 'secretKey', // no change
},
},
hosts: ['kafka.co:8080'],
},
]);
@ -613,7 +332,7 @@ describe('output preconfiguration', () => {
{
name: 'no changes',
data: {
id: 'existing-es-output-1',
id: 'existing-output-1',
is_default: false,
is_default_monitoring: false,
name: 'Output 1',
@ -624,7 +343,7 @@ describe('output preconfiguration', () => {
{
name: 'hosts without port',
data: {
id: 'existing-es-output-1',
id: 'existing-output-1',
is_default: false,
is_default_monitoring: false,
name: 'Output 1',

View file

@ -8,16 +8,8 @@
import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server';
import { isEqual } from 'lodash';
import { safeDump } from 'js-yaml';
import argon2 from 'argon2';
import type {
PreconfiguredOutput,
Output,
NewOutput,
OutputSecret,
KafkaOutput,
NewLogstashOutput,
} from '../../../common/types';
import type { PreconfiguredOutput, Output, NewOutput } from '../../../common/types';
import { normalizeHostsForAgents } from '../../../common/services';
import type { FleetConfigType } from '../../config';
import { DEFAULT_OUTPUT_ID, DEFAULT_OUTPUT } from '../../constants';
@ -107,79 +99,25 @@ export async function createOrUpdatePreconfiguredOutputs(
}
const isUpdateWithNewData =
existingOutput && (await isPreconfiguredOutputDifferentFromCurrent(existingOutput, data));
existingOutput && isPreconfiguredOutputDifferentFromCurrent(existingOutput, data);
if (isCreate || isUpdateWithNewData) {
const secretHashes = await hashSecrets(output);
if (isCreate) {
logger.debug(`Creating preconfigured output ${output.id}`);
await outputService.create(soClient, esClient, data, {
id,
fromPreconfiguration: true,
secretHashes,
});
} else if (isUpdateWithNewData) {
logger.debug(`Updating preconfigured output ${output.id}`);
await outputService.update(soClient, esClient, id, data, {
fromPreconfiguration: true,
secretHashes,
});
// Bump revision of all policies using that output
if (outputData.is_default || outputData.is_default_monitoring) {
await agentPolicyService.bumpAllAgentPolicies(soClient, esClient);
} else {
await agentPolicyService.bumpAllAgentPoliciesForOutput(soClient, esClient, id);
}
if (isCreate) {
logger.debug(`Creating output ${output.id}`);
await outputService.create(soClient, esClient, data, { id, fromPreconfiguration: true });
} else if (isUpdateWithNewData) {
logger.debug(`Updating output ${output.id}`);
await outputService.update(soClient, esClient, id, data, { fromPreconfiguration: true });
// Bump revision of all policies using that output
if (outputData.is_default || outputData.is_default_monitoring) {
await agentPolicyService.bumpAllAgentPolicies(soClient, esClient);
} else {
await agentPolicyService.bumpAllAgentPoliciesForOutput(soClient, esClient, id);
}
}
})
);
}
export async function hash(str: string) {
return argon2.hash(str, {
type: argon2.argon2id,
memoryCost: 19456,
timeCost: 2,
parallelism: 1,
});
}
async function hashSecrets(output: PreconfiguredOutput) {
if (output.type === 'kafka') {
const kafkaOutput = output as KafkaOutput;
if (typeof kafkaOutput.secrets?.password === 'string') {
const password = await hash(kafkaOutput.secrets?.password);
return {
password,
};
}
if (typeof kafkaOutput.secrets?.ssl?.key === 'string') {
const key = await hash(kafkaOutput.secrets?.ssl?.key);
return {
ssl: {
key,
},
};
}
}
if (output.type === 'logstash') {
const logstashOutput = output as NewLogstashOutput;
if (typeof logstashOutput.secrets?.ssl?.key === 'string') {
const key = await hash(logstashOutput.secrets?.ssl?.key);
return {
ssl: {
key,
},
};
}
}
return undefined;
}
export async function cleanPreconfiguredOutputs(
soClient: SavedObjectsClientContract,
esClient: ElasticsearchClient,
@ -227,56 +165,15 @@ export async function cleanPreconfiguredOutputs(
}
}
const hasHash = (secret?: OutputSecret): secret is { id: string; hash: string } => {
return !!secret && typeof secret !== 'string' && !!secret.hash;
};
async function isSecretDifferent(
preconfiguredValue: OutputSecret | undefined,
existingSecret: OutputSecret | undefined
): Promise<boolean> {
if (!existingSecret && preconfiguredValue) {
return true;
}
if (!preconfiguredValue && existingSecret) {
return true;
}
if (!preconfiguredValue && !existingSecret) {
return false;
}
if (hasHash(existingSecret) && typeof preconfiguredValue === 'string') {
// verifying the has tells us if the value has changed
const hashIsVerified = await argon2.verify(existingSecret.hash, preconfiguredValue!);
return !hashIsVerified;
} else {
// if there is no hash then the safest thing to do is assume the value has changed
return true;
}
}
async function isPreconfiguredOutputDifferentFromCurrent(
function isPreconfiguredOutputDifferentFromCurrent(
existingOutput: Output,
preconfiguredOutput: Partial<Output>
): Promise<boolean> {
const kafkaFieldsAreDifferent = async (): Promise<boolean> => {
): boolean {
const kafkaFieldsAreDifferent = (): boolean => {
if (existingOutput.type !== 'kafka' || preconfiguredOutput.type !== 'kafka') {
return false;
}
const passwordHashIsDifferent = await isSecretDifferent(
preconfiguredOutput.secrets?.password,
existingOutput.secrets?.password
);
const sslKeyHashIsDifferent = await isSecretDifferent(
preconfiguredOutput.secrets?.ssl?.key,
existingOutput.secrets?.ssl?.key
);
return (
isDifferent(existingOutput.client_id, preconfiguredOutput.client_id) ||
isDifferent(existingOutput.version, preconfiguredOutput.version) ||
@ -296,24 +193,10 @@ async function isPreconfiguredOutputDifferentFromCurrent(
isDifferent(existingOutput.headers, preconfiguredOutput.headers) ||
isDifferent(existingOutput.timeout, preconfiguredOutput.timeout) ||
isDifferent(existingOutput.broker_timeout, preconfiguredOutput.broker_timeout) ||
isDifferent(existingOutput.required_acks, preconfiguredOutput.required_acks) ||
passwordHashIsDifferent ||
sslKeyHashIsDifferent
isDifferent(existingOutput.required_acks, preconfiguredOutput.required_acks)
);
};
const logstashFieldsAreDifferent = async (): Promise<boolean> => {
if (existingOutput.type !== 'logstash' || preconfiguredOutput.type !== 'logstash') {
return false;
}
const sslKeyHashIsDifferent = await isSecretDifferent(
preconfiguredOutput.secrets?.ssl?.key,
existingOutput.secrets?.ssl?.key
);
return sslKeyHashIsDifferent;
};
return (
!existingOutput.is_preconfigured ||
isDifferent(existingOutput.is_default, preconfiguredOutput.is_default) ||
@ -338,7 +221,6 @@ async function isPreconfiguredOutputDifferentFromCurrent(
isDifferent(existingOutput.config_yaml, preconfiguredOutput.config_yaml) ||
isDifferent(existingOutput.proxy_id, preconfiguredOutput.proxy_id) ||
isDifferent(existingOutput.allow_edit ?? [], preconfiguredOutput.allow_edit ?? []) ||
(await kafkaFieldsAreDifferent()) ||
(await logstashFieldsAreDifferent())
kafkaFieldsAreDifferent()
);
}

View file

@ -7,7 +7,7 @@
import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server';
import { get, keyBy } from 'lodash';
import { keyBy } from 'lodash';
import { set } from '@kbn/safer-lodash-set';
import type { KafkaOutput, Output, OutputSecretPath } from '../../common/types';
@ -247,9 +247,8 @@ export async function extractAndWriteSecrets(opts: {
export async function extractAndWriteOutputSecrets(opts: {
output: NewOutput;
esClient: ElasticsearchClient;
secretHashes?: Record<string, any>;
}): Promise<{ output: NewOutput; secretReferences: PolicySecretReference[] }> {
const { output, esClient, secretHashes = {} } = opts;
const { output, esClient } = opts;
const secretPaths = getOutputSecretPaths(output.type, output).filter(
(path) => typeof path.value === 'string'
@ -266,12 +265,7 @@ export async function extractAndWriteOutputSecrets(opts: {
const outputWithSecretRefs = JSON.parse(JSON.stringify(output));
secretPaths.forEach((secretPath, i) => {
const pathWithoutPrefix = secretPath.path.replace('secrets.', '');
const maybeHash = get(secretHashes, pathWithoutPrefix);
set(outputWithSecretRefs, secretPath.path, {
id: secrets[i].id,
...(typeof maybeHash === 'string' && { hash: maybeHash }),
});
set(outputWithSecretRefs, secretPath.path, { id: secrets[i].id });
});
return {
@ -405,13 +399,12 @@ export async function extractAndUpdateOutputSecrets(opts: {
oldOutput: Output;
outputUpdate: Partial<Output>;
esClient: ElasticsearchClient;
secretHashes?: Record<string, any>;
}): Promise<{
outputUpdate: Partial<Output>;
secretReferences: PolicySecretReference[];
secretsToDelete: PolicySecretReference[];
}> {
const { oldOutput, outputUpdate, esClient, secretHashes } = opts;
const { oldOutput, outputUpdate, esClient } = opts;
const outputType = outputUpdate.type || oldOutput.type;
const oldSecretPaths = getOutputSecretPaths(outputType, oldOutput);
const updatedSecretPaths = getOutputSecretPaths(outputType, outputUpdate);
@ -432,13 +425,7 @@ export async function extractAndUpdateOutputSecrets(opts: {
const outputWithSecretRefs = JSON.parse(JSON.stringify(outputUpdate));
toCreate.forEach((secretPath, i) => {
const pathWithoutPrefix = secretPath.path.replace('secrets.', '');
const maybeHash = get(secretHashes, pathWithoutPrefix);
set(outputWithSecretRefs, secretPath.path, {
id: createdSecrets[i].id,
...(typeof maybeHash === 'string' && { hash: maybeHash }),
});
set(outputWithSecretRefs, secretPath.path, { id: createdSecrets[i].id });
});
const secretReferences = [

View file

@ -6477,21 +6477,6 @@
resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-2.0.1.tgz#c15367178d8bfe4765e6b47b542fe821ce259c7b"
integrity sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ==
"@mapbox/node-pre-gyp@^1.0.11":
version "1.0.11"
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa"
integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==
dependencies:
detect-libc "^2.0.0"
https-proxy-agent "^5.0.0"
make-dir "^3.1.0"
node-fetch "^2.6.7"
nopt "^5.0.0"
npmlog "^5.0.1"
rimraf "^3.0.2"
semver "^7.3.5"
tar "^6.1.11"
"@mapbox/point-geometry@0.1.0", "@mapbox/point-geometry@^0.1.0", "@mapbox/point-geometry@~0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz#8a83f9335c7860effa2eeeca254332aa0aeed8f2"
@ -7140,11 +7125,6 @@
node-addon-api "^3.2.1"
node-gyp-build "^4.3.0"
"@phc/format@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@phc/format/-/format-1.0.0.tgz#b5627003b3216dc4362125b13f48a4daa76680e4"
integrity sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==
"@pkgjs/parseargs@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
@ -11169,15 +11149,6 @@ arg@^5.0.1, arg@^5.0.2:
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
argon2@0.31.1:
version "0.31.1"
resolved "https://registry.yarnpkg.com/argon2/-/argon2-0.31.1.tgz#c8560bc76b12681afea13e28f3417aaa4b84c466"
integrity sha512-ik2xnJrLXazya7m4Nz1XfBSRjXj8Koq8qF9PsQC8059p20ifWc9zx/hgU3ItZh/3TnwXkv0RbhvjodPkmFf0bg==
dependencies:
"@mapbox/node-pre-gyp" "^1.0.11"
"@phc/format" "^1.0.0"
node-addon-api "^7.0.0"
argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@ -22796,11 +22767,6 @@ node-addon-api@^6.1.0:
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-6.1.0.tgz#ac8470034e58e67d0c6f1204a18ae6995d9c0d76"
integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==
node-addon-api@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.0.0.tgz#8136add2f510997b3b94814f4af1cce0b0e3962e"
integrity sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==
node-cache@^5.1.0:
version "5.1.2"
resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-5.1.2.tgz#f264dc2ccad0a780e76253a694e9fd0ed19c398d"