From 763b5deafd0eec37e960e499299f1205e6a3e999 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 12 Nov 2024 23:21:58 +1100 Subject: [PATCH] Unauthorized route migration for routes owned by kibana-core (#198333) ### Authz API migration for unauthorized routes This PR migrates unauthorized routes owned by your team to a new security configuration. Please refer to the documentation for more information: [Authorization API](https://docs.elastic.dev/kibana-dev-docs/key-concepts/security-api-authorization) ### **Before migration:** ```ts router.get({ path: '/api/path', ... }, handler); ``` ### **After migration:** ```ts router.get({ path: '/api/path', security: { authz: { enabled: false, reason: 'This route is opted out from authorization because ...', }, }, ... }, handler); ``` ### What to do next? 1. Review the changes in this PR. 2. Elaborate on the reasoning to opt-out of authorization. 3. Routes without a compelling reason to opt-out of authorization should plan to introduce them as soon as possible. 2. You might need to update your tests to reflect the new security configuration: - If you have snapshot tests that include the route definition. ## Any questions? If you have any questions or need help with API authorization, please reach out to the `@elastic/kibana-security` team. Co-authored-by: Jean-Louis Leysens --- .../server/routes/fetch_es_hits_status.ts | 6 ++ .../server/routes/bulk_delete.ts | 6 ++ .../server/routes/bulk_get.ts | 6 ++ .../server/routes/find.ts | 6 ++ .../server/routes/get_allowed_types.ts | 6 ++ .../server/routes/relationships.ts | 6 ++ .../server/routes/scroll_count.ts | 6 ++ .../server/routes/telemetry_config.ts | 44 +++++++++++++-- .../server/routes/telemetry_last_reported.ts | 56 +++++++++++++++++-- .../server/routes/telemetry_opt_in.ts | 28 +++++++++- .../server/routes/telemetry_opt_in_stats.ts | 6 ++ .../server/routes/telemetry_usage_stats.ts | 28 +++++++++- .../routes/telemetry_user_has_seen_notice.ts | 28 +++++++++- .../server/routes/stats/stats.ts | 6 ++ .../server/routes/ui_counters.ts | 6 ++ .../server/routes/elasticsearch_routes.ts | 28 +++++++--- .../licensing/server/routes/feature_usage.ts | 11 +++- .../plugins/licensing/server/routes/info.ts | 11 +++- .../routes/internal/notify_feature_usage.ts | 6 ++ .../routes/internal/register_feature.ts | 6 ++ 20 files changed, 281 insertions(+), 25 deletions(-) diff --git a/src/plugins/home/server/routes/fetch_es_hits_status.ts b/src/plugins/home/server/routes/fetch_es_hits_status.ts index f01660876210a..aa4c1286ce67e 100644 --- a/src/plugins/home/server/routes/fetch_es_hits_status.ts +++ b/src/plugins/home/server/routes/fetch_es_hits_status.ts @@ -14,6 +14,12 @@ export const registerHitsStatusRoute = (router: IRouter) => { router.post( { path: '/api/home/hits_status', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { body: schema.object({ index: schema.string(), diff --git a/src/plugins/saved_objects_management/server/routes/bulk_delete.ts b/src/plugins/saved_objects_management/server/routes/bulk_delete.ts index ed82726ade0da..da082cc85a1b4 100644 --- a/src/plugins/saved_objects_management/server/routes/bulk_delete.ts +++ b/src/plugins/saved_objects_management/server/routes/bulk_delete.ts @@ -15,6 +15,12 @@ export const registerBulkDeleteRoute = (router: IRouter) => { router.post( { path: '/internal/kibana/management/saved_objects/_bulk_delete', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { body: schema.arrayOf( schema.object({ diff --git a/src/plugins/saved_objects_management/server/routes/bulk_get.ts b/src/plugins/saved_objects_management/server/routes/bulk_get.ts index 9b7c1505cc699..59efd552196c8 100644 --- a/src/plugins/saved_objects_management/server/routes/bulk_get.ts +++ b/src/plugins/saved_objects_management/server/routes/bulk_get.ts @@ -20,6 +20,12 @@ export const registerBulkGetRoute = ( router.post( { path: '/api/kibana/management/saved_objects/_bulk_get', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { body: schema.arrayOf( schema.object({ diff --git a/src/plugins/saved_objects_management/server/routes/find.ts b/src/plugins/saved_objects_management/server/routes/find.ts index 8b37c3550f7da..e1c028a4fab2c 100644 --- a/src/plugins/saved_objects_management/server/routes/find.ts +++ b/src/plugins/saved_objects_management/server/routes/find.ts @@ -34,6 +34,12 @@ export const registerFindRoute = ( router.get( { path: '/api/kibana/management/saved_objects/_find', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { query: schema.object({ perPage: schema.number({ min: 0, defaultValue: 20 }), diff --git a/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts b/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts index c484f5643d8cc..6b89643e8142e 100644 --- a/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts +++ b/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts @@ -23,6 +23,12 @@ export const registerGetAllowedTypesRoute = (router: IRouter) => { router.get( { path: '/api/kibana/management/saved_objects/_allowed_types', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: false, }, async (context, req, res) => { diff --git a/src/plugins/saved_objects_management/server/routes/relationships.ts b/src/plugins/saved_objects_management/server/routes/relationships.ts index 7f06e6a5dabc8..d39f001f2f2a1 100644 --- a/src/plugins/saved_objects_management/server/routes/relationships.ts +++ b/src/plugins/saved_objects_management/server/routes/relationships.ts @@ -21,6 +21,12 @@ export const registerRelationshipsRoute = ( router.get( { path: '/api/kibana/management/saved_objects/relationships/{type}/{id}', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { params: schema.object({ type: schema.string(), diff --git a/src/plugins/saved_objects_management/server/routes/scroll_count.ts b/src/plugins/saved_objects_management/server/routes/scroll_count.ts index 31c01536d6003..3116ca3a22fb1 100644 --- a/src/plugins/saved_objects_management/server/routes/scroll_count.ts +++ b/src/plugins/saved_objects_management/server/routes/scroll_count.ts @@ -17,6 +17,12 @@ export const registerScrollForCountRoute = (router: IRouter) => { router.post( { path: '/api/kibana/management/saved_objects/scroll/counts', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { body: schema.object({ typesToInclude: schema.arrayOf(schema.string()), diff --git a/src/plugins/telemetry/server/routes/telemetry_config.ts b/src/plugins/telemetry/server/routes/telemetry_config.ts index ebc5ca53985e9..700e778ceea27 100644 --- a/src/plugins/telemetry/server/routes/telemetry_config.ts +++ b/src/plugins/telemetry/server/routes/telemetry_config.ts @@ -102,12 +102,46 @@ export function registerTelemetryConfigRoutes({ options: { authRequired: 'optional' }, }) // Just because it used to be /v2/, we are creating identical v1 and v2. - .addVersion({ version: '1', validate: v2Validations }, v2Handler) - .addVersion({ version: '2', validate: v2Validations }, v2Handler); + .addVersion( + { + version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2Validations, + }, + v2Handler + ) + .addVersion( + { + version: '2', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2Validations, + }, + v2Handler + ); // Register the deprecated public and path-based for BWC // as we know this one is used by other Elastic products to fetch the opt-in status. - router.versioned - .get({ access: 'public', path: FetchTelemetryConfigRoutePathBasedV2 }) - .addVersion({ version: '2023-10-31', validate: v2Validations }, v2Handler); + router.versioned.get({ access: 'public', path: FetchTelemetryConfigRoutePathBasedV2 }).addVersion( + { + version: '2023-10-31', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2Validations, + }, + v2Handler + ); } diff --git a/src/plugins/telemetry/server/routes/telemetry_last_reported.ts b/src/plugins/telemetry/server/routes/telemetry_last_reported.ts index 299d457e080b6..932b7ab8db9cc 100644 --- a/src/plugins/telemetry/server/routes/telemetry_last_reported.ts +++ b/src/plugins/telemetry/server/routes/telemetry_last_reported.ts @@ -40,8 +40,32 @@ export function registerTelemetryLastReported( router.versioned .get({ access: 'internal', path: LastReportedRoute }) // Just because it used to be /v2/, we are creating identical v1 and v2. - .addVersion({ version: '1', validate: v2GetValidations }, v2GetHandler) - .addVersion({ version: '2', validate: v2GetValidations }, v2GetHandler); + .addVersion( + { + version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2GetValidations, + }, + v2GetHandler + ) + .addVersion( + { + version: '2', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2GetValidations, + }, + v2GetHandler + ); // PUT to update const v2PutHandler: RequestHandler = async (context, req, res) => { @@ -55,6 +79,30 @@ export function registerTelemetryLastReported( router.versioned .put({ access: 'internal', path: LastReportedRoute }) // Just because it used to be /v2/, we are creating identical v1 and v2. - .addVersion({ version: '1', validate: false }, v2PutHandler) - .addVersion({ version: '2', validate: false }, v2PutHandler); + .addVersion( + { + version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, + v2PutHandler + ) + .addVersion( + { + version: '2', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, + v2PutHandler + ); } diff --git a/src/plugins/telemetry/server/routes/telemetry_opt_in.ts b/src/plugins/telemetry/server/routes/telemetry_opt_in.ts index 21b674c3dc45d..de13162ff0619 100644 --- a/src/plugins/telemetry/server/routes/telemetry_opt_in.ts +++ b/src/plugins/telemetry/server/routes/telemetry_opt_in.ts @@ -128,6 +128,30 @@ export function registerTelemetryOptInRoutes({ router.versioned .post({ access: 'internal', path: OptInRoute }) // Just because it used to be /v2/, we are creating identical v1 and v2. - .addVersion({ version: '1', validate: v2Validations }, v2Handler) - .addVersion({ version: '2', validate: v2Validations }, v2Handler); + .addVersion( + { + version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2Validations, + }, + v2Handler + ) + .addVersion( + { + version: '2', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2Validations, + }, + v2Handler + ); } diff --git a/src/plugins/telemetry/server/routes/telemetry_opt_in_stats.ts b/src/plugins/telemetry/server/routes/telemetry_opt_in_stats.ts index dcd7790b67e68..0c38b59818500 100644 --- a/src/plugins/telemetry/server/routes/telemetry_opt_in_stats.ts +++ b/src/plugins/telemetry/server/routes/telemetry_opt_in_stats.ts @@ -72,6 +72,12 @@ export function registerTelemetryOptInStatsRoutes( .addVersion( { version: '2023-10-31', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { request: { body: schema.object({ diff --git a/src/plugins/telemetry/server/routes/telemetry_usage_stats.ts b/src/plugins/telemetry/server/routes/telemetry_usage_stats.ts index f19ec804ac6e9..28198c853e4b5 100644 --- a/src/plugins/telemetry/server/routes/telemetry_usage_stats.ts +++ b/src/plugins/telemetry/server/routes/telemetry_usage_stats.ts @@ -97,6 +97,30 @@ export function registerTelemetryUsageStatsRoutes( enableQueryVersion: true, // Allow specifying the version through querystring so that we can use it in Dev Console }) // Just because it used to be /v2/, we are creating identical v1 and v2. - .addVersion({ version: '1', validate: v2Validations }, v2Handler) - .addVersion({ version: '2', validate: v2Validations }, v2Handler); + .addVersion( + { + version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2Validations, + }, + v2Handler + ) + .addVersion( + { + version: '2', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2Validations, + }, + v2Handler + ); } diff --git a/src/plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts b/src/plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts index 54eaae80648ef..dff8a8f2d5bd4 100644 --- a/src/plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts +++ b/src/plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts @@ -56,6 +56,30 @@ export function registerTelemetryUserHasSeenNotice(router: IRouter, currentKiban router.versioned .put({ access: 'internal', path: UserHasSeenNoticeRoute }) // Just because it used to be /v2/, we are creating identical v1 and v2. - .addVersion({ version: '1', validate: false }, v2Handler) - .addVersion({ version: '2', validate: false }, v2Handler); + .addVersion( + { + version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, + v2Handler + ) + .addVersion( + { + version: '2', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, + v2Handler + ); } diff --git a/src/plugins/usage_collection/server/routes/stats/stats.ts b/src/plugins/usage_collection/server/routes/stats/stats.ts index 95a82abbbf150..3a7683bb1c46d 100644 --- a/src/plugins/usage_collection/server/routes/stats/stats.ts +++ b/src/plugins/usage_collection/server/routes/stats/stats.ts @@ -54,6 +54,12 @@ export function registerStatsRoute({ router.get( { path: '/api/stats', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, options: { authRequired: !config.allowAnonymous, // The `api` tag ensures that unauthenticated calls receive a 401 rather than a 302 redirect to login page. diff --git a/src/plugins/usage_collection/server/routes/ui_counters.ts b/src/plugins/usage_collection/server/routes/ui_counters.ts index 2545afb7f90fc..fbeba04ac1901 100644 --- a/src/plugins/usage_collection/server/routes/ui_counters.ts +++ b/src/plugins/usage_collection/server/routes/ui_counters.ts @@ -21,6 +21,12 @@ export function registerUiCountersRoute( router.post( { path: '/api/ui_counters/_report', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { body: schema.object({ report: reportSchema, diff --git a/x-pack/plugins/cloud/server/routes/elasticsearch_routes.ts b/x-pack/plugins/cloud/server/routes/elasticsearch_routes.ts index 5cdc2f90559cc..d3a5c4bebf305 100644 --- a/x-pack/plugins/cloud/server/routes/elasticsearch_routes.ts +++ b/x-pack/plugins/cloud/server/routes/elasticsearch_routes.ts @@ -24,12 +24,24 @@ export function defineRoutes({ path: ELASTICSEARCH_CONFIG_ROUTE, access: 'internal', }) - .addVersion({ version: '1', validate: {} }, async (context, request, response) => { - const body: ElasticsearchConfigType = { - elasticsearch_url: elasticsearchUrl, - }; - return response.ok({ - body, - }); - }); + .addVersion( + { + version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: {}, + }, + async (context, request, response) => { + const body: ElasticsearchConfigType = { + elasticsearch_url: elasticsearchUrl, + }; + return response.ok({ + body, + }); + } + ); } diff --git a/x-pack/plugins/licensing/server/routes/feature_usage.ts b/x-pack/plugins/licensing/server/routes/feature_usage.ts index 33317ab09cb9d..acb3303834de3 100644 --- a/x-pack/plugins/licensing/server/routes/feature_usage.ts +++ b/x-pack/plugins/licensing/server/routes/feature_usage.ts @@ -14,7 +14,16 @@ export function registerFeatureUsageRoute( getStartServices: StartServicesAccessor<{}, LicensingPluginStart> ) { router.get( - { path: '/api/licensing/feature_usage', validate: false }, + { + path: '/api/licensing/feature_usage', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, async (context, request, response) => { const [, , { featureUsage }] = await getStartServices(); return response.ok({ diff --git a/x-pack/plugins/licensing/server/routes/info.ts b/x-pack/plugins/licensing/server/routes/info.ts index 1cbc7b6398966..c73508fac8236 100644 --- a/x-pack/plugins/licensing/server/routes/info.ts +++ b/x-pack/plugins/licensing/server/routes/info.ts @@ -9,7 +9,16 @@ import { LicensingRouter } from '../types'; export function registerInfoRoute(router: LicensingRouter) { router.get( - { path: '/api/licensing/info', validate: false }, + { + path: '/api/licensing/info', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, async (context, request, response) => { return response.ok({ body: (await context.licensing).license, diff --git a/x-pack/plugins/licensing/server/routes/internal/notify_feature_usage.ts b/x-pack/plugins/licensing/server/routes/internal/notify_feature_usage.ts index a33cf4284245d..c3c70243005e2 100644 --- a/x-pack/plugins/licensing/server/routes/internal/notify_feature_usage.ts +++ b/x-pack/plugins/licensing/server/routes/internal/notify_feature_usage.ts @@ -12,6 +12,12 @@ export function registerNotifyFeatureUsageRoute(router: LicensingRouter) { router.post( { path: '/internal/licensing/feature_usage/notify', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { body: schema.object({ featureName: schema.string(), diff --git a/x-pack/plugins/licensing/server/routes/internal/register_feature.ts b/x-pack/plugins/licensing/server/routes/internal/register_feature.ts index 0c043c7c127a9..6b35c32a266d3 100644 --- a/x-pack/plugins/licensing/server/routes/internal/register_feature.ts +++ b/x-pack/plugins/licensing/server/routes/internal/register_feature.ts @@ -17,6 +17,12 @@ export function registerRegisterFeatureRoute( router.post( { path: '/internal/licensing/feature_usage/register', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { body: schema.arrayOf( schema.object({