diff --git a/package.json b/package.json index 2f334f54c42e2..5e43d8bb910cf 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/x-pack/plugins/fleet/common/types/models/output.ts b/x-pack/plugins/fleet/common/types/models/output.ts index 5f6a6db3315e9..3283f4d01e540 100644 --- a/x-pack/plugins/fleet/common/types/models/output.ts +++ b/x-pack/plugins/fleet/common/types/models/output.ts @@ -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; secrets?: { - password?: OutputSecret; + password?: + | string + | { + id: string; + }; ssl?: { - key?: OutputSecret; + key?: + | string + | { + id: string; + }; }; }; } diff --git a/x-pack/plugins/fleet/server/services/output.ts b/x-pack/plugins/fleet/server/services/output.ts index 016026533e3c7..0cb1099b58ebb 100644 --- a/x-pack/plugins/fleet/server/services/output.ts +++ b/x-pack/plugins/fleet/server/services/output.ts @@ -419,12 +419,7 @@ class OutputService { soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, output: NewOutput, - options?: { - id?: string; - fromPreconfiguration?: boolean; - overwrite?: boolean; - secretHashes?: Record; - } + options?: { id?: string; fromPreconfiguration?: boolean; overwrite?: boolean } ): Promise { 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, - { - fromPreconfiguration = false, - secretHashes, - }: { fromPreconfiguration: boolean; secretHashes?: Record } = { + { 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; diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.test.ts b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.test.ts index a0dd3fd5e7f5d..1023e1bdb7b56 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.test.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.test.ts @@ -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 => { 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', diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts index 07636dd1266c0..5bc7c452b481e 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts @@ -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)); - - 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); - } + existingOutput && isPreconfiguredOutputDifferentFromCurrent(existingOutput, data); + + 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 { - 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 -): Promise { - const kafkaFieldsAreDifferent = async (): Promise => { +): 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 => { - 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() ); } diff --git a/x-pack/plugins/fleet/server/services/secrets.ts b/x-pack/plugins/fleet/server/services/secrets.ts index baabdf55e793d..36a88b4a7a4c1 100644 --- a/x-pack/plugins/fleet/server/services/secrets.ts +++ b/x-pack/plugins/fleet/server/services/secrets.ts @@ -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; }): 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; esClient: ElasticsearchClient; - secretHashes?: Record; }): Promise<{ outputUpdate: Partial; 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 = [ diff --git a/yarn.lock b/yarn.lock index 584c660603157..6eba5c6fe3da0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"