mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[Authz] Migrated routes with access tags to security config (#209756)](https://github.com/elastic/kibana/pull/209756) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Elena Shostak","email":"165678770+elena-shostak@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-02-11T14:36:38Z","message":"[Authz] Migrated routes with access tags to security config (#209756)\n\n## Summary\r\n\r\nThis PR migrates the last routes with `access:<privilege>` tags used in\r\nroute definitions to new security configuration.\r\nPlease refer to the documentation for more information: [Authorization\r\nAPI](https://docs.elastic.dev/kibana-dev-docs/key-concepts/security-api-authorization)\r\n\r\n### **Before Migration:**\r\nAccess control tags were defined in the `options` object of the route:\r\n\r\n```ts\r\nrouter.get({\r\n path: '/api/path',\r\n options: {\r\n tags: ['access:<privilege_1>', 'access:<privilege_2>'],\r\n },\r\n ...\r\n}, handler);\r\n```\r\n\r\n### **After Migration:**\r\nTags have been replaced with the more robust\r\n`security.authz.requiredPrivileges` field under `security`:\r\n\r\n```ts\r\nrouter.get({\r\n path: '/api/path',\r\n security: {\r\n authz: {\r\n requiredPrivileges: ['<privilege_1>', '<privilege_2>'],\r\n },\r\n },\r\n ...\r\n}, handler);\r\n```\r\n\r\n### Checklist\r\n\r\n- [x]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"ad0e1d9d9d5ffba3c0bd7839affe0e885c3f2f03","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Security","release_note:skip","Feature:Security/Authorization","backport:prev-minor","backport:version","Authz: API migration","v9.1.0","v8.19.0"],"title":"[Authz] Migrated routes with access tags to security config","number":209756,"url":"https://github.com/elastic/kibana/pull/209756","mergeCommit":{"message":"[Authz] Migrated routes with access tags to security config (#209756)\n\n## Summary\r\n\r\nThis PR migrates the last routes with `access:<privilege>` tags used in\r\nroute definitions to new security configuration.\r\nPlease refer to the documentation for more information: [Authorization\r\nAPI](https://docs.elastic.dev/kibana-dev-docs/key-concepts/security-api-authorization)\r\n\r\n### **Before Migration:**\r\nAccess control tags were defined in the `options` object of the route:\r\n\r\n```ts\r\nrouter.get({\r\n path: '/api/path',\r\n options: {\r\n tags: ['access:<privilege_1>', 'access:<privilege_2>'],\r\n },\r\n ...\r\n}, handler);\r\n```\r\n\r\n### **After Migration:**\r\nTags have been replaced with the more robust\r\n`security.authz.requiredPrivileges` field under `security`:\r\n\r\n```ts\r\nrouter.get({\r\n path: '/api/path',\r\n security: {\r\n authz: {\r\n requiredPrivileges: ['<privilege_1>', '<privilege_2>'],\r\n },\r\n },\r\n ...\r\n}, handler);\r\n```\r\n\r\n### Checklist\r\n\r\n- [x]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"ad0e1d9d9d5ffba3c0bd7839affe0e885c3f2f03"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/209756","number":209756,"mergeCommit":{"message":"[Authz] Migrated routes with access tags to security config (#209756)\n\n## Summary\r\n\r\nThis PR migrates the last routes with `access:<privilege>` tags used in\r\nroute definitions to new security configuration.\r\nPlease refer to the documentation for more information: [Authorization\r\nAPI](https://docs.elastic.dev/kibana-dev-docs/key-concepts/security-api-authorization)\r\n\r\n### **Before Migration:**\r\nAccess control tags were defined in the `options` object of the route:\r\n\r\n```ts\r\nrouter.get({\r\n path: '/api/path',\r\n options: {\r\n tags: ['access:<privilege_1>', 'access:<privilege_2>'],\r\n },\r\n ...\r\n}, handler);\r\n```\r\n\r\n### **After Migration:**\r\nTags have been replaced with the more robust\r\n`security.authz.requiredPrivileges` field under `security`:\r\n\r\n```ts\r\nrouter.get({\r\n path: '/api/path',\r\n security: {\r\n authz: {\r\n requiredPrivileges: ['<privilege_1>', '<privilege_2>'],\r\n },\r\n },\r\n ...\r\n}, handler);\r\n```\r\n\r\n### Checklist\r\n\r\n- [x]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"ad0e1d9d9d5ffba3c0bd7839affe0e885c3f2f03"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Elena Shostak <165678770+elena-shostak@users.noreply.github.com>
This commit is contained in:
parent
1e03fc0166
commit
5d11caa37b
16 changed files with 67 additions and 40 deletions
|
@ -69,8 +69,10 @@ export class FeatureControlsPluginExample
|
|||
{
|
||||
path: '/internal/my_plugin/sensitive_action',
|
||||
validate: false,
|
||||
options: {
|
||||
tags: ['access:my_closed_example_api'],
|
||||
security: {
|
||||
authz: {
|
||||
requiredPrivileges: ['my_closed_example_api'],
|
||||
},
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
|
|
|
@ -40,7 +40,11 @@ export class UserProfilesPlugin implements Plugin<void, void, SetupDeps, StartDe
|
|||
/**
|
||||
* Important: You must restrict access to this endpoint using access `tags`.
|
||||
*/
|
||||
options: { tags: ['access:suggestUserProfiles'] },
|
||||
security: {
|
||||
authz: {
|
||||
requiredPrivileges: ['suggestUserProfiles'],
|
||||
},
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const [, pluginDeps] = await core.getStartServices();
|
||||
|
|
|
@ -268,9 +268,11 @@ export const createEntityRoute = (router: Router): void => {
|
|||
.post({
|
||||
access: 'public',
|
||||
path: '/api/my/data/{id}',
|
||||
options: {
|
||||
tags: ['access:securitySolution'],
|
||||
},
|
||||
security: {
|
||||
authz: {
|
||||
requiredPrivileges: ['securitySolution']
|
||||
}
|
||||
}
|
||||
})
|
||||
.addVersion(
|
||||
{
|
||||
|
|
|
@ -93,8 +93,10 @@ describe('CoreApp', () => {
|
|||
expect(routerMock.versioned.put).toHaveBeenCalledWith({
|
||||
path: '/internal/core/_settings',
|
||||
access: 'internal',
|
||||
options: {
|
||||
tags: ['access:updateDynamicConfig'],
|
||||
security: {
|
||||
authz: {
|
||||
requiredPrivileges: ['updateDynamicConfig'],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
@ -278,8 +278,10 @@ export class CoreAppsService {
|
|||
.put({
|
||||
path: '/internal/core/_settings',
|
||||
access: 'internal',
|
||||
options: {
|
||||
tags: ['access:updateDynamicConfig'],
|
||||
security: {
|
||||
authz: {
|
||||
requiredPrivileges: ['updateDynamicConfig'],
|
||||
},
|
||||
},
|
||||
})
|
||||
.addVersion(
|
||||
|
|
|
@ -87,13 +87,9 @@ export const registerAutocompleteEntitiesRoute = (deps: RouteDependencies) => {
|
|||
deps.router.get(
|
||||
{
|
||||
path: '/api/console/autocomplete_entities',
|
||||
options: {
|
||||
tags: ['access:console'],
|
||||
},
|
||||
security: {
|
||||
authz: {
|
||||
enabled: false,
|
||||
reason: 'Relies on es client for authorization',
|
||||
requiredPrivileges: ['console'],
|
||||
},
|
||||
},
|
||||
validate: autoCompleteEntitiesValidationConfig,
|
||||
|
|
|
@ -46,7 +46,7 @@ export function registerTelemetryUsageStatsRoutes(
|
|||
const security = getSecurity();
|
||||
// We need to check useRbacForRequest to figure out if ES has security enabled before making the privileges check
|
||||
if (security && unencrypted && security.authz.mode.useRbacForRequest(req)) {
|
||||
// Normally we would use `options: { tags: ['access:decryptedTelemetry'] }` in the route definition to check authorization for an
|
||||
// Normally we would use `security: { authz: { requiredPrivileges: ['decryptedTelemetry'] } } }` in the route definition to check authorization for an
|
||||
// API action, however, we want to check this conditionally based on the `unencrypted` parameter. In this case we need to use the
|
||||
// security API directly to check privileges for this action. Note that the 'decryptedTelemetry' API privilege string is only
|
||||
// granted to users that have "Global All" or "Global Read" privileges in Kibana.
|
||||
|
|
|
@ -122,8 +122,10 @@ export function routes(coreSetup: CoreSetup<StartDeps, unknown>, logger: Logger)
|
|||
.post({
|
||||
path: '/internal/data_visualizer/inference/{inferenceId}',
|
||||
access: 'internal',
|
||||
options: {
|
||||
tags: ['access:fileUpload:analyzeFile'],
|
||||
security: {
|
||||
authz: {
|
||||
requiredPrivileges: ['fileUpload:analyzeFile'],
|
||||
},
|
||||
},
|
||||
})
|
||||
.addVersion(
|
||||
|
|
|
@ -54,25 +54,27 @@ export interface FeatureKibanaPrivileges {
|
|||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Configure your routes with a tag starting with the 'access:' prefix
|
||||
* // Configure your routes with requiredPrivileges
|
||||
* server.route({
|
||||
* path: '/api/my-route',
|
||||
* method: 'GET',
|
||||
* handler: () => { ...},
|
||||
* options: {
|
||||
* tags: ['access:my_feature-admin']
|
||||
* }
|
||||
* security: {
|
||||
* authz: {
|
||||
* requiredPrivileges: ['my_feature_admin']
|
||||
* },
|
||||
* },
|
||||
* });
|
||||
*
|
||||
* Then, specify the tags here (without the 'access:' prefix) which should be secured:
|
||||
* Then, specify requiredPrivileges which should be secured:
|
||||
*
|
||||
* {
|
||||
* api: ['my_feature-admin']
|
||||
* api: ['my_feature_admin']
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* NOTE: It is important to name your tags in a way that will not collide with other platform/plugins/shared/features.
|
||||
* A generic tag name like "access:read" could be used elsewhere, and access to that API endpoint would also
|
||||
* NOTE: It is important to name your privileges in a way that will not collide with other platform/plugins/shared/features.
|
||||
* A generic tag name like "read" could be used elsewhere, and access to that API endpoint would also
|
||||
* extend to any routes you have also tagged with that name.
|
||||
*/
|
||||
api?: readonly string[];
|
||||
|
|
|
@ -119,7 +119,11 @@ export function backgroundTaskUtilizationRoute(
|
|||
},
|
||||
},
|
||||
// Uncomment when we determine that we can restrict API usage to Global admins based on telemetry
|
||||
// options: { tags: ['access:taskManager'] },
|
||||
// security: {
|
||||
// authz: {
|
||||
// requiredPrivileges: ['taskManager'],
|
||||
// },
|
||||
// },
|
||||
validate: false,
|
||||
options: {
|
||||
access: 'public', // access must be public to allow "system" users, like metrics collectors, to access these routes
|
||||
|
|
|
@ -148,7 +148,11 @@ export function healthRoute(params: HealthRouteParams): {
|
|||
},
|
||||
},
|
||||
// Uncomment when we determine that we can restrict API usage to Global admins based on telemetry
|
||||
// options: { tags: ['access:taskManager'] },
|
||||
// security: {
|
||||
// authz: {
|
||||
// requiredPrivileges: ['taskManager'],
|
||||
// },
|
||||
// },
|
||||
validate: false,
|
||||
options: {
|
||||
access: 'public',
|
||||
|
|
|
@ -62,7 +62,11 @@ export function metricsRoute(params: MetricsRouteParams) {
|
|||
tags: ['security:acceptJWT'],
|
||||
},
|
||||
// Uncomment when we determine that we can restrict API usage to Global admins based on telemetry
|
||||
// options: { tags: ['access:taskManager'] },
|
||||
// security: {
|
||||
// authz: {
|
||||
// requiredPrivileges: ['taskManager'],
|
||||
// },
|
||||
// },
|
||||
validate: {
|
||||
query: QuerySchema,
|
||||
},
|
||||
|
|
|
@ -9,8 +9,10 @@ import { extractEntityIndexPatternsFromDefinitions } from './extract_entity_inde
|
|||
|
||||
export const getEntityDefinitionSourceIndexPatternsByType = createInventoryServerRoute({
|
||||
endpoint: 'GET /internal/inventory/entity/definitions/sources',
|
||||
options: {
|
||||
tags: ['access:inventory'],
|
||||
security: {
|
||||
authz: {
|
||||
requiredPrivileges: ['inventory'],
|
||||
},
|
||||
},
|
||||
async handler({ context, request, plugins }) {
|
||||
const [_coreContext, entityManagerStart] = await Promise.all([
|
||||
|
|
|
@ -44,15 +44,12 @@ export class KibanaFramework {
|
|||
config: InfraRouteConfig<Params, Query, Body, Method>,
|
||||
handler: RequestHandler<Params, Query, Body, RequestHandlerContext>
|
||||
) {
|
||||
const defaultOptions = {
|
||||
tags: ['access:infra'],
|
||||
};
|
||||
const routeConfig = {
|
||||
path: config.path,
|
||||
validate: config.validate,
|
||||
// Currently we have no use of custom options beyond tags, this can be extended
|
||||
// beyond defaultOptions if it's needed.
|
||||
options: defaultOptions,
|
||||
security: {
|
||||
authz: { requiredPrivileges: ['infra'] },
|
||||
},
|
||||
};
|
||||
switch (config.method) {
|
||||
case 'get':
|
||||
|
|
|
@ -122,11 +122,13 @@ export const bulkDeleteRulesRoute = (
|
|||
access: 'public',
|
||||
path: DETECTION_ENGINE_RULES_BULK_DELETE,
|
||||
options: {
|
||||
tags: ['access:securitySolution'],
|
||||
timeout: {
|
||||
idleSocket: RULE_MANAGEMENT_BULK_ACTION_SOCKET_TIMEOUT_MS,
|
||||
},
|
||||
},
|
||||
security: {
|
||||
authz: { requiredPrivileges: ['securitySolution'] },
|
||||
},
|
||||
};
|
||||
router.versioned.delete(routeConfig).addVersion(
|
||||
{
|
||||
|
|
|
@ -25,8 +25,10 @@ export const entityStoreInternalPrivilegesRoute = (
|
|||
.get({
|
||||
access: 'internal',
|
||||
path: ENTITY_STORE_INTERNAL_PRIVILEGES_URL,
|
||||
options: {
|
||||
tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`],
|
||||
security: {
|
||||
authz: {
|
||||
requiredPrivileges: ['securitySolution', `${APP_ID}-entity-analytics`],
|
||||
},
|
||||
},
|
||||
})
|
||||
.addVersion(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue