Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fleet] Output Secrets Backend #169221

Merged
merged 30 commits into from Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6609527
Create validation working
hop-dev Sep 27, 2023
4642f64
secrets being created correctly
hop-dev Sep 27, 2023
27bfcf9
password secret working
hop-dev Sep 27, 2023
3b4e09c
output secrets added to agent policy
hop-dev Sep 27, 2023
f5f5176
update working
hop-dev Sep 28, 2023
de7358b
delete secrets
hop-dev Sep 28, 2023
a16accf
put create behind feature flah
hop-dev Sep 28, 2023
61ba7dc
API docs
hop-dev Sep 28, 2023
1224f2d
fix types
hop-dev Sep 29, 2023
975f39e
add mock
hop-dev Oct 1, 2023
0c183de
update SO snapshot
hop-dev Oct 11, 2023
8d9a3de
fix deleted secrets test
hop-dev Oct 11, 2023
d78b5ab
remove console.log
hop-dev Oct 11, 2023
8a12369
do not throw if no settings object
hop-dev Oct 11, 2023
5aac2fb
add mock logger
hop-dev Oct 11, 2023
21abb0b
renove assertion
hop-dev Oct 12, 2023
47296cc
fix docs
hop-dev Oct 12, 2023
f3f275d
[CI] Auto-commit changed files from 'node scripts/check_mappings_upda…
kibanamachine Oct 12, 2023
68c8085
fix types
hop-dev Oct 12, 2023
8cf944b
remove unused res
hop-dev Oct 12, 2023
3d64063
fix agent list resturn statement
hop-dev Oct 12, 2023
ae2f2a9
Merge branch 'main' into output-secrets
kibanamachine Oct 12, 2023
512c863
Merge branch 'main' into output-secrets
hop-dev Oct 17, 2023
e9c96f1
Merge branch 'main' into output-secrets
kibanamachine Oct 17, 2023
73afbd1
add feature flag
hop-dev Oct 18, 2023
3f933f9
delete secrets after saved object
hop-dev Oct 18, 2023
239cf45
Merge branch 'main' into output-secrets
hop-dev Oct 18, 2023
ae37a99
only use feature flag for checking if output secrets are enabled
hop-dev Oct 19, 2023
32ea487
fix kibana not starting
hop-dev Oct 24, 2023
279fcea
Merge branch 'main' into output-secrets
kibanamachine Oct 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 26 additions & 0 deletions packages/kbn-check-mappings-update-cli/current_mappings.json
Expand Up @@ -1816,6 +1816,32 @@
},
"channel_buffer_size": {
"type": "integer"
},
"secrets": {
"dynamic": false,
"properties": {
"password": {
"dynamic": false,
"properties": {
"id": {
"type": "keyword"
}
}
},
"ssl": {
"dynamic": false,
"properties": {
"key": {
"dynamic": false,
"properties": {
"id": {
"type": "keyword"
}
}
}
}
}
}
}
}
},
Expand Down
Expand Up @@ -106,7 +106,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
"infrastructure-ui-source": "113182d6895764378dfe7fa9fa027244f3a457c4",
"ingest-agent-policies": "7633e578f60c074f8267bc50ec4763845e431437",
"ingest-download-sources": "279a68147e62e4d8858c09ad1cf03bd5551ce58d",
"ingest-outputs": "b4e636b13a5d0f89f0400fb67811d4cca4736eb0",
"ingest-outputs": "3982d6296373111467e839a0768d3e1c4d0ebc61",
"ingest-package-policies": "a0c9fb48e04dcd638e593db55f1c6451523f90ea",
"ingest_manager_settings": "64955ef1b7a9ffa894d4bb9cf863b5602bfa6885",
"inventory-view": "b8683c8e352a286b4aca1ab21003115a4800af83",
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/common/experimental_features.ts
Expand Up @@ -23,6 +23,7 @@ export const allowedExperimentalValues = Object.freeze<Record<string, boolean>>(
agentTamperProtectionEnabled: true,
secretsStorage: true,
kafkaOutput: true,
outputSecretsStorage: false,
});

type ExperimentalConfigKeys = Array<keyof ExperimentalFeatures>;
Expand Down
29 changes: 29 additions & 0 deletions x-pack/plugins/fleet/common/openapi/bundled.json
Expand Up @@ -8121,6 +8121,22 @@
},
"required_acks": {
"type": "number"
},
"secrets": {
"type": "object",
"properties": {
"password": {
"type": "string"
},
"ssl": {
"type": "object",
"properties": {
"key": {
"type": "string"
}
}
}
}
}
},
"required": [
Expand Down Expand Up @@ -8216,6 +8232,19 @@
"type": "boolean"
}
}
},
"secrets": {
"type": "object",
"properties": {
"ssl": {
"type": "object",
"properties": {
"key": {
"type": "string"
}
}
}
}
}
},
"required": [
Expand Down
18 changes: 18 additions & 0 deletions x-pack/plugins/fleet/common/openapi/bundled.yaml
Expand Up @@ -5240,6 +5240,16 @@ components:
type: number
required_acks:
type: number
secrets:
type: object
properties:
password:
type: string
ssl:
type: object
properties:
key:
type: string
required:
- name
- type
Expand Down Expand Up @@ -5304,6 +5314,14 @@ components:
type: number
loadbalance:
type: boolean
secrets:
type: object
properties:
ssl:
type: object
properties:
key:
type: string
required:
- name
- hosts
Expand Down
Expand Up @@ -122,6 +122,17 @@ properties:
type: number
required_acks:
type: number
secrets:
type: object
properties:
password:
type: string
ssl:
type: object
properties:
key:
type: string

required:
- name
- type
Expand Down
Expand Up @@ -54,6 +54,14 @@ properties:
type: number
loadbalance:
type: boolean
secrets:
type: object
properties:
ssl:
type: object
properties:
key:
type: string
required:
- name
- hosts
Expand Down
23 changes: 23 additions & 0 deletions x-pack/plugins/fleet/common/types/models/output.ts
Expand Up @@ -43,6 +43,15 @@ interface NewBaseOutput {
proxy_id?: string | null;
shipper?: ShipperOutput | null;
allow_edit?: string[];
secrets?: {
ssl?: {
key?:
| string
| {
id: string;
};
};
};
}

export interface NewElasticsearchOutput extends NewBaseOutput {
Expand Down Expand Up @@ -112,4 +121,18 @@ export interface KafkaOutput extends NewBaseOutput {
timeout?: number;
broker_timeout?: number;
required_acks?: ValueOf<KafkaAcknowledgeReliabilityLevel>;
secrets?: {
password?:
| string
| {
id: string;
};
ssl?: {
key?:
| string
| {
id: string;
};
};
};
}
4 changes: 4 additions & 0 deletions x-pack/plugins/fleet/common/types/models/secret.ts
Expand Up @@ -21,6 +21,10 @@ export interface SecretPath {
path: string;
value: PackagePolicyConfigRecordEntry;
}
export interface OutputSecretPath {
path: string;
value: string | { id: string };
}
// this is used in the top level secret_refs array on package and agent policies
export interface PolicySecretReference {
id: string;
Expand Down
23 changes: 20 additions & 3 deletions x-pack/plugins/fleet/server/routes/output/handler.ts
Expand Up @@ -8,6 +8,10 @@
import type { RequestHandler } from '@kbn/core/server';
import type { TypeOf } from '@kbn/config-schema';

import Boom from '@hapi/boom';

import { outputType } from '../../../common/constants';

import type {
DeleteOutputRequestSchema,
GetOneOutputRequestSchema,
Expand All @@ -18,13 +22,23 @@ import type {
DeleteOutputResponse,
GetOneOutputResponse,
GetOutputsResponse,
Output,
PostLogstashApiKeyResponse,
} from '../../../common/types';
import { outputService } from '../../services/output';
import { defaultFleetErrorHandler, FleetUnauthorizedError } from '../../errors';
import { agentPolicyService } from '../../services';
import { generateLogstashApiKey, canCreateLogstashApiKey } from '../../services/api_keys';

function ensureNoDuplicateSecrets(output: Partial<Output>) {
if (output.type === outputType.Kafka && output?.password && output?.secrets?.password) {
throw Boom.badRequest('Cannot specify both password and secrets.password');
}
if (output.ssl?.key && output.secrets?.ssl?.key) {
throw Boom.badRequest('Cannot specify both ssl.key and secrets.ssl.key');
}
}

export const getOutputsHandler: RequestHandler = async (context, request, response) => {
const soClient = (await context.core).savedObjects.client;
try {
Expand Down Expand Up @@ -74,8 +88,10 @@ export const putOutputHandler: RequestHandler<
const coreContext = await context.core;
const soClient = coreContext.savedObjects.client;
const esClient = coreContext.elasticsearch.client.asInternalUser;
const outputUpdate = request.body;
ensureNoDuplicateSecrets(outputUpdate);
try {
await outputService.update(soClient, esClient, request.params.outputId, request.body);
await outputService.update(soClient, esClient, request.params.outputId, outputUpdate);
const output = await outputService.get(soClient, request.params.outputId);
if (output.is_default || output.is_default_monitoring) {
await agentPolicyService.bumpAllAgentPolicies(soClient, esClient);
Expand Down Expand Up @@ -108,8 +124,9 @@ export const postOutputHandler: RequestHandler<
const soClient = coreContext.savedObjects.client;
const esClient = coreContext.elasticsearch.client.asInternalUser;
try {
const { id, ...data } = request.body;
const output = await outputService.create(soClient, esClient, data, { id });
const { id, ...newOutput } = request.body;
ensureNoDuplicateSecrets(newOutput);
const output = await outputService.create(soClient, esClient, newOutput, { id });
if (output.is_default || output.is_default_monitoring) {
await agentPolicyService.bumpAllAgentPolicies(soClient, esClient);
}
Expand Down
22 changes: 22 additions & 0 deletions x-pack/plugins/fleet/server/saved_objects/index.ts
Expand Up @@ -247,6 +247,28 @@ const getSavedObjectTypes = (): { [key: string]: SavedObjectsType } => ({
broker_buffer_size: { type: 'integer' },
required_acks: { type: 'integer' },
channel_buffer_size: { type: 'integer' },
secrets: {
dynamic: false,
properties: {
password: {
dynamic: false,
properties: {
id: { type: 'keyword' },
},
},
ssl: {
dynamic: false,
properties: {
key: {
dynamic: false,
properties: {
id: { type: 'keyword' },
},
},
},
},
},
},
},
},
modelVersions: {
Expand Down
Expand Up @@ -31,6 +31,8 @@ import { getPackageInfo } from '../epm/packages';
import { pkgToPkgKey, splitPkgKey } from '../epm/registry';
import { appContextService } from '../app_context';

import { getOutputSecretReferences } from '../secrets';

import { getMonitoringPermissions } from './monitoring_permissions';
import { storedPackagePoliciesToAgentInputs } from '.';
import {
Expand Down Expand Up @@ -110,6 +112,10 @@ export async function getFullAgentPolicy(
return acc;
}, {} as NonNullable<FullAgentPolicy['agent']>['features']);

const outputSecretReferences = outputs.flatMap((output) => getOutputSecretReferences(output));
const packagePolicySecretReferences = (agentPolicy?.package_policies || []).flatMap(
(policy) => policy.secret_references || []
);
const defaultMonitoringConfig: FullAgentPolicyMonitoring = {
enabled: false,
logs: false,
Expand Down Expand Up @@ -152,9 +158,7 @@ export async function getFullAgentPolicy(
}, {}),
},
inputs,
secret_references: (agentPolicy?.package_policies || []).flatMap(
(policy) => policy.secret_references || []
),
secret_references: [...outputSecretReferences, ...packagePolicySecretReferences],
revision: agentPolicy.revision,
agent: {
download: {
Expand Down Expand Up @@ -305,7 +309,8 @@ export function transformOutputToFullPolicyOutput(
standalone = false
): FullAgentPolicyOutput {
// eslint-disable-next-line @typescript-eslint/naming-convention
const { config_yaml, type, hosts, ca_sha256, ca_trusted_fingerprint, ssl, shipper } = output;
const { config_yaml, type, hosts, ca_sha256, ca_trusted_fingerprint, ssl, shipper, secrets } =
output;

const configJs = config_yaml ? safeLoad(config_yaml) : {};

Expand Down Expand Up @@ -432,6 +437,7 @@ export function transformOutputToFullPolicyOutput(
...(!isShipperDisabled ? generalShipperData : {}),
...(ca_sha256 ? { ca_sha256 } : {}),
...(ssl ? { ssl } : {}),
...(secrets ? { secrets } : {}),
...(ca_trusted_fingerprint ? { 'ssl.ca_trusted_fingerprint': ca_trusted_fingerprint } : {}),
};

Expand Down
5 changes: 2 additions & 3 deletions x-pack/plugins/fleet/server/services/agents/versions.ts
Expand Up @@ -75,9 +75,8 @@ export const getAvailableVersions = async ({

return availableVersions;
} catch (e) {
if (e.code === 'ENOENT' && !config?.internal?.onlyAllowAgentUpgradeToKnownVersions) {
// If the file does not exist, return the current version
return [kibanaVersion];
if (e.code === 'ENOENT') {
return config?.internal?.onlyAllowAgentUpgradeToKnownVersions ? [] : [kibanaVersion];
}
throw e;
}
Expand Down
14 changes: 13 additions & 1 deletion x-pack/plugins/fleet/server/services/output.test.ts
Expand Up @@ -9,8 +9,9 @@ import { savedObjectsClientMock, elasticsearchServiceMock } from '@kbn/core/serv

import { securityMock } from '@kbn/security-plugin/server/mocks';

import type { OutputSOAttributes } from '../types';
import type { Logger } from '@kbn/logging';

import type { OutputSOAttributes } from '../types';
import { OUTPUT_SAVED_OBJECT_TYPE } from '../constants';

import { outputService, outputIdToUuid } from './output';
Expand All @@ -28,6 +29,17 @@ mockedAppContextService.getSecuritySetup.mockImplementation(() => ({
...securityMock.createSetup(),
}));

mockedAppContextService.getLogger.mockImplementation(() => {
return {
debug: jest.fn(),
info: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
} as unknown as Logger;
});

mockedAppContextService.getExperimentalFeatures.mockReturnValue({});

const mockedAgentPolicyService = agentPolicyService as jest.Mocked<typeof agentPolicyService>;

const CLOUD_ID =
Expand Down