Skip to main content

api-authz

Kibana API route authorization patterns. Use when configuring route security, working with requiredPrivileges or extendedPrivileges, using authzResult for privilege-based branching, opting out of authorization, or naming custom privileges.

소스 정보

저장소
elastic/kibana
최근 소스 활동
2026년 7월 30일 13:21
감지된 SKILL.md 언어
영어
스타
21,236
포크
8,623

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
api-authz
description
Kibana API route authorization patterns. Use when configuring route security, working with requiredPrivileges or extendedPrivileges, using authzResult for privilege-based branching, opting out of authorization, or naming custom privileges.
# API Authorization > All API routes in Kibana must have authorization checks. Authorization is not optional, even for `internal` routes. ## Route Security Configuration Routes declare authorization via the `security` option in `KibanaRouteOptions`: ```ts router.get({ path: '/api/path', security: { authz: { requiredPrivileges: ['<privilege_1>', '<privilege_2>'], // Optional: checked and surfaced in request.authzResult, but not enforced // extendedPrivileges: ['<optional_privilege>'], }, }, ... }, handler); ``` ## Privilege Naming Privilege names follow the `<operation>_<subject>` convention using underscores only. | Incorrect | Why | Correct | |-----------|-----|---------| | `read-entity-a` | Uses `-` instead of `_` | `read_entity_a` | | `delete_entity-a` | Mixes `_` and `-` | `delete_entity_a` | | `entity_manage` | Subject before operation | `manage_entity` | ## Privilege-Based Branching with `authzResult` When a route handler branches logic based on user privileges (returns different data, enables different features), it **must** use `request.authzResult`. Do not use `capabilities.resolveCapabilities()` or other authorization checks for branching — `authzResult` is the single source of truth. **Look for:** routes that conditionally expose data based on permissions, or functions that check capabilities and return booleans for branching. ### Optional privileges that extend behavior (`extendedPrivileges`) When a privilege **gates access** and another privilege only **extends** what the route returns or allows, declare the gate in `requiredPrivileges` and the optional checks in `extendedPrivileges`. Extended privileges are checked and surfaced in `authzResult` but never produce a 403. `extendedPrivileges` is a **flat list of privilege name strings** only. Privilege sets (`anyRequired` / `allRequired`) are not supported there. When authz is enabled, `requiredPrivileges` is always required by the schema — optional privileges alone cannot protect a route. **Correct — required gate + optional extension:** ```ts router.get({ path: '/api/path', security: { authz: { requiredPrivileges: ['read_entity'], extendedPrivileges: ['read_entity_details'], }, }, ... }, (context, request, response) => { const includeDetails = request.authzResult?.read_entity_details === true; return response.ok({ body: getEntity({ includeDetails }) }); }); ``` **Wrong — abusing `anyRequired` then re-enforcing in the handler:** ```ts router.get({ path: '/api/path', security: { authz: { // Under-declares the real requirement; OAS implies either privilege alone grants access requiredPrivileges: [{ anyRequired: ['read_entity', 'read_entity_details'] }], }, }, }, (context, request, response) => { if (request.authzResult?.read_entity !== true) { return response.forbidden(); // easy to forget → under-protected route } const includeDetails = request.authzResult?.read_entity_details === true; return response.ok({ body: getEntity({ includeDetails }) }); }); ``` ### Mutually exclusive privilege branches (`anyRequired`) When either of several privileges grants access and the handler picks a branch, use `anyRequired` and branch on `authzResult`: ```ts router.get({ path: '/api/path', security: { authz: { requiredPrivileges: ['privilege_3', { anyRequired: ['privilege_1', 'privilege_2'] }], }, }, ... }, (context, request, response) => { const authzResult = request.authzResult; // { "privilege_3": true, "privilege_1": true, "privilege_2": false } if (authzResult.privilege_1) { return response.ok({ body: ... }); } else if (authzResult.privilege_2) { return response.ok({ body: ... }); } return response.ok({ body: { data: ... } }); }); ``` **Wrong — using capabilities for authorization branching:** ```ts const canReadDecryptedParams = async (routeContext: RouteContext) => { const { request, server } = routeContext; const capabilities = await server.coreStart.capabilities.resolveCapabilities(request, { capabilityPath: 'my_capability.*', }); return capabilities.my_capability?.canReadParams ?? false; }; if (await canReadDecryptedParams(routeContext)) { return getDecryptedParams(routeContext, paramId); } else { return getBasicParams(routeContext, paramId); } ``` **Fix:** declare both privileges in the route config with `anyRequired` and branch on `request.authzResult`: ```ts router.get({ path: '/api/params', security: { authz: { requiredPrivileges: [{ anyRequired: ['read_params_decrypted', 'read_params'] }], }, }, }, (context, request, response) => { if (request.authzResult.read_params_decrypted) { return getDecryptedParams(routeContext, paramId); } else { return getBasicParams(routeContext, paramId); } }); ``` ## Opting Out of Authorization When a route must opt out, use the predefined `AuthzOptOutReason` enum or `AuthzDisabled` helpers from `@kbn/core-security-server`: ```ts import { AuthzDisabled, AuthzOptOutReason } from '@kbn/core-security-server'; // Predefined helper router.get({ path: '/api/path', security: { authz: AuthzDisabled.delegateToSOClient }, ... }, handler); // Predefined enum router.get({ path: '/api/path', security: { authz: { enabled: false, reason: AuthzOptOutReason.DelegateToSOClient }, }, ... }, handler); // Custom reason — only when no predefined reason applies router.get({ path: '/api/health', security: { authz: { enabled: false, reason: 'This route is a health check endpoint that returns no sensitive information', }, }, ... }, handler); ``` **Invalid opt-out reasons — flag these:** - `"Opt out from authorization"` — too generic, no context - `"This route does not need authorization"` — no explanation why - `"Authorization not required"` — no context provided - `"Authorization is delegated to SO Client"` — use `AuthzOptOutReason.DelegateToSOClient` instead ## References - [Kibana API Authorization Documentation](dev_docs/key_concepts/api_authorization.mdx) - [Kibana HTTP API Design Guidelines](dev_docs/contributing/kibana_http_api_design_guidelines.mdx)
GitHub에서 보기