Add authz definitions to Onboarding API endpoints (#206557)

Closes https://github.com/elastic/kibana/issues/206394

This adds `authz` definitions to all Onboarding routes. In all cases
authorization is either done using saved objects or ES clients, with a
couple of exceptions for endpoints that are ment to be accessed from a
terminal and using an API key with a specific privileges which do not
include access to saved objects. In that case we're using internal user
client.
This commit is contained in:
Mykola Harmash 2025-01-16 14:35:10 +01:00 committed by GitHub
parent 9a439b7549
commit aaf7b9efea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 88 additions and 17 deletions

View file

@ -18,7 +18,12 @@ const generateConfig = createObservabilityOnboardingServerRoute({
params: t.type({
query: t.type({ onboardingId: t.string }),
}),
options: { tags: [] },
security: {
authz: {
enabled: false,
reason: 'Authorization is checked by the Saved Object client',
},
},
async handler(resources): Promise<string> {
const {
params: {
@ -32,7 +37,7 @@ const generateConfig = createObservabilityOnboardingServerRoute({
const authApiKey = getAuthenticationAPIKey(request);
const coreStart = await core.start();
const savedObjectsClient = coreStart.savedObjects.createInternalRepository();
const savedObjectsClient = coreStart.savedObjects.getScopedClient(request);
const elasticsearchUrl = plugins.cloud?.setup?.elasticsearchUrl
? [plugins.cloud?.setup?.elasticsearchUrl]

View file

@ -36,7 +36,12 @@ interface DocumentCountPerIndexBucket {
const createFirehoseOnboardingFlowRoute = createObservabilityOnboardingServerRoute({
endpoint: 'POST /internal/observability_onboarding/firehose/flow',
options: { tags: [] },
security: {
authz: {
enabled: false,
reason: 'This route has custom authorization logic using Elasticsearch client',
},
},
async handler({
context,
request,
@ -95,7 +100,12 @@ const hasFirehoseDataRoute = createObservabilityOnboardingServerRoute({
stackName: t.string,
}),
}),
options: { tags: [] },
security: {
authz: {
enabled: false,
reason: 'Authorization is checked by Elasticsearch client',
},
},
async handler(resources): Promise<HasFirehoseDataRouteResponse> {
const { streamName, stackName } = resources.params.query;
const { elasticsearch } = await resources.context.core;

View file

@ -30,7 +30,12 @@ import { makeTar, type Entry } from './make_tar';
const updateOnboardingFlowRoute = createObservabilityOnboardingServerRoute({
endpoint: 'PUT /internal/observability_onboarding/flow/{onboardingId}',
options: { tags: [] },
security: {
authz: {
enabled: false,
reason: 'Authorization is checked by the Saved Object client',
},
},
params: t.type({
path: t.type({
onboardingId: t.string,
@ -65,7 +70,13 @@ const updateOnboardingFlowRoute = createObservabilityOnboardingServerRoute({
const stepProgressUpdateRoute = createObservabilityOnboardingServerRoute({
endpoint: 'POST /internal/observability_onboarding/flow/{id}/step/{name}',
options: { tags: [] },
security: {
authz: {
enabled: false,
reason:
"This endpoint is meant to be called from user's terminal and authenticated using API key with a limited privileges. For this reason there is no authorization and saved object is accessed using an internal Kibana user (the API key used by the user should not have those privileges)",
},
},
params: t.type({
path: t.type({
id: t.string,
@ -129,7 +140,12 @@ const stepProgressUpdateRoute = createObservabilityOnboardingServerRoute({
const getProgressRoute = createObservabilityOnboardingServerRoute({
endpoint: 'GET /internal/observability_onboarding/flow/{onboardingId}/progress',
options: { tags: [] },
security: {
authz: {
enabled: false,
reason: 'Authorization is checked by the Saved Object client',
},
},
params: t.type({
path: t.type({
onboardingId: t.string,
@ -190,7 +206,12 @@ const getProgressRoute = createObservabilityOnboardingServerRoute({
*/
const createFlowRoute = createObservabilityOnboardingServerRoute({
endpoint: 'POST /internal/observability_onboarding/flow',
options: { tags: [] },
security: {
authz: {
enabled: false,
reason: 'Authorization is checked by the Saved Object client',
},
},
params: t.type({
body: t.type({
name: t.string,
@ -308,7 +329,13 @@ const createFlowRoute = createObservabilityOnboardingServerRoute({
*/
const integrationsInstallRoute = createObservabilityOnboardingServerRoute({
endpoint: 'POST /internal/observability_onboarding/flow/{onboardingId}/integrations/install',
options: { tags: [] },
security: {
authz: {
enabled: false,
reason:
"This endpoint is meant to be called from user's terminal. Authorization is partially checked by the Package Service client, and saved object is accessed using internal Kibana user because the API key used for installing integrations should not have those privileges.",
},
},
params: t.type({
path: t.type({
onboardingId: t.string,

View file

@ -33,7 +33,13 @@ const createKubernetesOnboardingFlowRoute = createObservabilityOnboardingServerR
params: t.type({
body: t.type({ pkgName: t.union([t.literal('kubernetes'), t.literal('kubernetes_otel')]) }),
}),
options: { tags: [] },
security: {
authz: {
enabled: false,
reason:
'Authorization is checked by custom logic using Elasticsearch client and by the Package Service client',
},
},
async handler({
context,
request,
@ -90,7 +96,12 @@ const hasKubernetesDataRoute = createObservabilityOnboardingServerRoute({
onboardingId: t.string,
}),
}),
options: { tags: [] },
security: {
authz: {
enabled: false,
reason: 'Authorization is checked by Elasticsearch',
},
},
async handler(resources): Promise<HasKubernetesDataRouteResponse> {
const { onboardingId } = resources.params.path;
const { elasticsearch } = await resources.context.core;

View file

@ -19,8 +19,12 @@ import { hasLogMonitoringPrivileges } from '../../lib/api_key/has_log_monitoring
const logMonitoringPrivilegesRoute = createObservabilityOnboardingServerRoute({
endpoint: 'GET /internal/observability_onboarding/logs/setup/privileges',
options: { tags: [] },
security: {
authz: {
enabled: false,
reason: 'This route has custom authorization logic using Elasticsearch client',
},
},
handler: async (resources): Promise<{ hasPrivileges: boolean }> => {
const { context } = resources;
@ -36,7 +40,12 @@ const logMonitoringPrivilegesRoute = createObservabilityOnboardingServerRoute({
const installShipperSetupRoute = createObservabilityOnboardingServerRoute({
endpoint: 'GET /internal/observability_onboarding/logs/setup/environment',
options: { tags: [] },
security: {
authz: {
enabled: false,
reason: "This route only reads cluster's metadata and does not require authorization",
},
},
async handler(resources): Promise<{
apiEndpoint: string;
scriptDownloadUrl: string;
@ -75,7 +84,12 @@ const installShipperSetupRoute = createObservabilityOnboardingServerRoute({
const createAPIKeyRoute = createObservabilityOnboardingServerRoute({
endpoint: 'POST /internal/observability_onboarding/otel/api_key',
options: { tags: [] },
security: {
authz: {
enabled: false,
reason: 'This route has custom authorization logic using Elasticsearch client',
},
},
params: t.type({}),
async handler(resources): Promise<{ apiKeyEncoded: string }> {
const { context } = resources;
@ -96,7 +110,12 @@ const createAPIKeyRoute = createObservabilityOnboardingServerRoute({
const createFlowRoute = createObservabilityOnboardingServerRoute({
endpoint: 'POST /internal/observability_onboarding/logs/flow',
options: { tags: [] },
security: {
authz: {
enabled: false,
reason: 'Authorization is checked by the Saved Object client and Elasticsearch client',
},
},
params: t.type({
body: t.intersection([
t.type({

View file

@ -46,7 +46,6 @@ export interface ObservabilityOnboardingRouteHandlerResources {
}
export interface ObservabilityOnboardingRouteCreateOptions {
tags: string[];
xsrfRequired?: boolean;
}