Skip to content

Commit

Permalink
[8.x] Unauthorized route migration for routes owned by kibana-security (
Browse files Browse the repository at this point in the history
#198334) (#199382)

# Backport

This will backport the following commits from `main` to `8.x`:
- [Unauthorized route migration for routes owned by kibana-security
(#198334)](#198334)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Kibana
Machine","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-11-07T21:04:16Z","message":"Unauthorized
route migration for routes owned by kibana-security (#198334)\n\n###
Authz API migration for unauthorized routes\r\n\r\nThis PR migrates
unauthorized routes owned by your team to a new\r\nsecurity
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\n```ts\r\nrouter.get({\r\n path:
'/api/path',\r\n ...\r\n}, handler);\r\n```\r\n\r\n### **After
migration:**\r\n```ts\r\nrouter.get({\r\n path: '/api/path',\r\n
security: {\r\n authz: {\r\n enabled: false,\r\n reason: 'This route is
opted out from authorization because ...',\r\n },\r\n },\r\n ...\r\n},
handler);\r\n```\r\n\r\n### What to do next?\r\n1. Review the changes in
this PR.\r\n2. Elaborate on the reasoning to opt-out of
authorization.\r\n3. Routes without a compelling reason to opt-out of
authorization should\r\nplan to introduce them as soon as
possible.\r\n2. You might need to update your tests to reflect the new
security\r\nconfiguration:\r\n - If you have snapshot tests that include
the route definition.\r\n\r\n## Any questions?\r\nIf you have any
questions or need help with API authorization, please\r\nreach out to
the `@elastic/kibana-security`
team.\r\n\r\n---------\r\n\r\nCo-authored-by: “jeramysoucy”
<[email protected]>\r\nCo-authored-by: Larry Gregory
<[email protected]>\r\nCo-authored-by: Elena Shostak
<[email protected]>\r\nCo-authored-by:
Elena Shostak
<[email protected]>","sha":"c994b488053efc3f8cfb1f8785561bbdb5b54eec","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Security","enhancement","release_note:skip","Feature:Security/Authorization","v9.0.0","backport:prev-minor","Authz:
API migration"],"title":"Unauthorized route migration for routes owned
by
kibana-security","number":198334,"url":"https://github.com/elastic/kibana/pull/198334","mergeCommit":{"message":"Unauthorized
route migration for routes owned by kibana-security (#198334)\n\n###
Authz API migration for unauthorized routes\r\n\r\nThis PR migrates
unauthorized routes owned by your team to a new\r\nsecurity
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\n```ts\r\nrouter.get({\r\n path:
'/api/path',\r\n ...\r\n}, handler);\r\n```\r\n\r\n### **After
migration:**\r\n```ts\r\nrouter.get({\r\n path: '/api/path',\r\n
security: {\r\n authz: {\r\n enabled: false,\r\n reason: 'This route is
opted out from authorization because ...',\r\n },\r\n },\r\n ...\r\n},
handler);\r\n```\r\n\r\n### What to do next?\r\n1. Review the changes in
this PR.\r\n2. Elaborate on the reasoning to opt-out of
authorization.\r\n3. Routes without a compelling reason to opt-out of
authorization should\r\nplan to introduce them as soon as
possible.\r\n2. You might need to update your tests to reflect the new
security\r\nconfiguration:\r\n - If you have snapshot tests that include
the route definition.\r\n\r\n## Any questions?\r\nIf you have any
questions or need help with API authorization, please\r\nreach out to
the `@elastic/kibana-security`
team.\r\n\r\n---------\r\n\r\nCo-authored-by: “jeramysoucy”
<[email protected]>\r\nCo-authored-by: Larry Gregory
<[email protected]>\r\nCo-authored-by: Elena Shostak
<[email protected]>\r\nCo-authored-by:
Elena Shostak
<[email protected]>","sha":"c994b488053efc3f8cfb1f8785561bbdb5b54eec"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/198334","number":198334,"mergeCommit":{"message":"Unauthorized
route migration for routes owned by kibana-security (#198334)\n\n###
Authz API migration for unauthorized routes\r\n\r\nThis PR migrates
unauthorized routes owned by your team to a new\r\nsecurity
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\n```ts\r\nrouter.get({\r\n path:
'/api/path',\r\n ...\r\n}, handler);\r\n```\r\n\r\n### **After
migration:**\r\n```ts\r\nrouter.get({\r\n path: '/api/path',\r\n
security: {\r\n authz: {\r\n enabled: false,\r\n reason: 'This route is
opted out from authorization because ...',\r\n },\r\n },\r\n ...\r\n},
handler);\r\n```\r\n\r\n### What to do next?\r\n1. Review the changes in
this PR.\r\n2. Elaborate on the reasoning to opt-out of
authorization.\r\n3. Routes without a compelling reason to opt-out of
authorization should\r\nplan to introduce them as soon as
possible.\r\n2. You might need to update your tests to reflect the new
security\r\nconfiguration:\r\n - If you have snapshot tests that include
the route definition.\r\n\r\n## Any questions?\r\nIf you have any
questions or need help with API authorization, please\r\nreach out to
the `@elastic/kibana-security`
team.\r\n\r\n---------\r\n\r\nCo-authored-by: “jeramysoucy”
<[email protected]>\r\nCo-authored-by: Larry Gregory
<[email protected]>\r\nCo-authored-by: Elena Shostak
<[email protected]>\r\nCo-authored-by:
Elena Shostak
<[email protected]>","sha":"c994b488053efc3f8cfb1f8785561bbdb5b54eec"}}]}]
BACKPORT-->
  • Loading branch information
kibanamachine authored Nov 7, 2024
1 parent de032ca commit f3bb8ce
Show file tree
Hide file tree
Showing 58 changed files with 483 additions and 16 deletions.
7 changes: 7 additions & 0 deletions src/plugins/interactive_setup/server/routes/configure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ export function defineConfigureRoute({
router.post(
{
path: '/internal/interactive_setup/configure',
security: {
authz: {
enabled: false,
reason:
'Interactive setup is strictly a "pre-boot" feature which cannot leverage conventional authorization.',
},
},
validate: {
body: schema.object({
host: schema.uri({ scheme: ['http', 'https'] }),
Expand Down
7 changes: 7 additions & 0 deletions src/plugins/interactive_setup/server/routes/enroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ export function defineEnrollRoutes({
router.post(
{
path: '/internal/interactive_setup/enroll',
security: {
authz: {
enabled: false,
reason:
'Interactive setup is strictly a "pre-boot" feature which cannot leverage conventional authorization.',
},
},
validate: {
body: schema.object({
hosts: schema.arrayOf(schema.uri({ scheme: 'https' }), {
Expand Down
7 changes: 7 additions & 0 deletions src/plugins/interactive_setup/server/routes/ping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ export function definePingRoute({ router, logger, elasticsearch, preboot }: Rout
router.post(
{
path: '/internal/interactive_setup/ping',
security: {
authz: {
enabled: false,
reason:
'Interactive setup is strictly a "pre-boot" feature which cannot leverage conventional authorization.',
},
},
validate: {
body: schema.object({
host: schema.uri({ scheme: ['http', 'https'] }),
Expand Down
7 changes: 7 additions & 0 deletions src/plugins/interactive_setup/server/routes/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ export function defineStatusRoute({ router, elasticsearch, preboot }: RouteDefin
router.get(
{
path: '/internal/interactive_setup/status',
security: {
authz: {
enabled: false,
reason:
'Interactive setup is strictly a "pre-boot" feature which cannot leverage conventional authorization.',
},
},
validate: false,
options: { authRequired: false },
},
Expand Down
7 changes: 7 additions & 0 deletions src/plugins/interactive_setup/server/routes/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ export function defineVerifyRoute({ router, verificationCode }: RouteDefinitionP
router.post(
{
path: '/internal/interactive_setup/verify',
security: {
authz: {
enabled: false,
reason:
'Interactive setup is strictly a "pre-boot" feature which cannot leverage conventional authorization.',
},
},
validate: {
body: schema.object({
code: schema.string(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ export function defineRecordAnalyticsOnAuthTypeRoutes({
router.post(
{
path: '/internal/security/analytics/_record_auth_type',
security: {
authz: {
enabled: false,
reason:
'This route delegates authorization to the scoped ES cluster client of the internal authentication service',
},
},
validate: {
body: schema.nullable(
schema.object({ signature: schema.string(), timestamp: schema.number() })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,13 @@ export function defineRecordViolations({ router, analyticsService }: RouteDefini
router.post(
{
path: '/internal/security/analytics/_record_violations',
security: {
authz: {
enabled: false,
reason:
'This route is used by browsers to report CSP and Permission Policy violations. These requests are sent without authentication per the browser spec.',
},
},
validate: {
/**
* Chrome supports CSP3 spec and sends an array of reports. Safari only sends a single
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,17 @@ export function defineAnonymousAccessGetCapabilitiesRoutes({
getAnonymousAccessService,
}: RouteDefinitionParams) {
router.get(
{ path: '/internal/security/anonymous_access/capabilities', validate: false },
{
path: '/internal/security/anonymous_access/capabilities',
security: {
authz: {
enabled: false,
reason:
'This route delegates authorization to the scoped ES cluster client of the anonymous access service',
},
},
validate: false,
},
async (_context, request, response) => {
const anonymousAccessService = getAnonymousAccessService();
return response.ok({ body: await anonymousAccessService.getCapabilities(request) });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,16 @@ export function defineAnonymousAccessGetStateRoutes({
getAnonymousAccessService,
}: RouteDefinitionParams) {
router.get(
{ path: '/internal/security/anonymous_access/state', validate: false },
{
path: '/internal/security/anonymous_access/state',
security: {
authz: {
enabled: false,
reason: 'This route is used for anonymous access',
},
},
validate: false,
},
async (_context, _request, response) => {
const anonymousAccessService = getAnonymousAccessService();
const accessURLParameters = anonymousAccessService.accessURLParameters
Expand Down
7 changes: 7 additions & 0 deletions x-pack/plugins/security/server/routes/api_keys/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ export function defineCreateApiKeyRoutes({
router.post(
{
path: '/internal/security/api_key',
security: {
authz: {
enabled: false,
reason:
'This route delegates authorization to the scoped ES cluster client of the internal authentication service',
},
},
validate: {
body: schema.oneOf([
restApiKeySchema,
Expand Down
7 changes: 7 additions & 0 deletions x-pack/plugins/security/server/routes/api_keys/enabled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ export function defineEnabledApiKeysRoutes({
router.get(
{
path: '/internal/security/api_key/_enabled',
security: {
authz: {
enabled: false,
reason:
'This route delegates authorization to the scoped ES cluster client of the internal authentication service',
},
},
validate: false,
},
createLicensedRouteHandler(async (context, request, response) => {
Expand Down
6 changes: 6 additions & 0 deletions x-pack/plugins/security/server/routes/api_keys/has_active.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ export function defineHasApiKeysRoutes({
router.get(
{
path: '/internal/security/api_key/_has_active',
security: {
authz: {
enabled: false,
reason: `This route delegates authorization to the scoped ES cluster client of the internal authentication service, and to Core's ES client`,
},
},
validate: false,
options: {
access: 'internal',
Expand Down
6 changes: 6 additions & 0 deletions x-pack/plugins/security/server/routes/api_keys/invalidate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ export function defineInvalidateApiKeysRoutes({ router }: RouteDefinitionParams)
router.post(
{
path: '/internal/security/api_key/invalidate',
security: {
authz: {
enabled: false,
reason: `This route delegates authorization to Core's ES client`,
},
},
validate: {
body: schema.object({
apiKeys: schema.arrayOf(schema.object({ id: schema.string(), name: schema.string() })),
Expand Down
6 changes: 6 additions & 0 deletions x-pack/plugins/security/server/routes/api_keys/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ export function defineQueryApiKeysAndAggregationsRoute({
// on behalf of the user making the request and governed by the user's own cluster privileges.
{
path: '/internal/security/api_key/_query',
security: {
authz: {
enabled: false,
reason: `This route delegates authorization to the scoped ES cluster client of the internal authentication service, and to Core's ES client`,
},
},
validate: {
body: schema.object({
query: schema.maybe(schema.object({}, { unknowns: 'allow' })),
Expand Down
6 changes: 6 additions & 0 deletions x-pack/plugins/security/server/routes/api_keys/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ export function defineUpdateApiKeyRoutes({
router.put(
{
path: '/internal/security/api_key',
security: {
authz: {
enabled: false,
reason: `This route delegates authorization to the scoped ES cluster client of the internal authentication service`,
},
},
validate: {
body: schema.oneOf([
updateRestApiKeySchema,
Expand Down
37 changes: 34 additions & 3 deletions x-pack/plugins/security/server/routes/authentication/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ export function defineCommonRoutes({
router.get(
{
path,
security: {
authz: {
enabled: false,
reason: 'This route must remain accessible to 3rd-party IdPs',
},
},
// Allow unknown query parameters as this endpoint can be hit by the 3rd-party with any
// set of query string parameters (e.g. SAML/OIDC logout request/response parameters).
validate: { query: schema.object({}, { unknowns: 'allow' }) },
Expand Down Expand Up @@ -92,7 +98,17 @@ export function defineCommonRoutes({
]) {
const deprecated = path === '/api/security/v1/me';
router.get(
{ path, validate: false, options: { access: deprecated ? 'public' : 'internal' } },
{
path,
security: {
authz: {
enabled: false,
reason: `This route delegates authorization to Core's security service; there must be an authenticated user for this route to return information`,
},
},
validate: false,
options: { access: deprecated ? 'public' : 'internal' },
},
createLicensedRouteHandler(async (context, request, response) => {
if (deprecated) {
logger.warn(
Expand Down Expand Up @@ -135,10 +151,16 @@ export function defineCommonRoutes({
}

// Register the login route for serverless for the time being. Note: This route will move into the buildFlavor !== 'serverless' block below. See next line.
// ToDo: In the serverless environment, we do not support API login - the only valid authentication methodology (or maybe just method or mechanism?) is SAML
// ToDo: In the serverless environment, we do not support API login - the only valid authentication type is SAML
router.post(
{
path: '/internal/security/login',
security: {
authz: {
enabled: false,
reason: `This route provides basic and token login capbility, which is delegated to the internal authentication service`,
},
},
validate: {
body: schema.object({
providerType: schema.string(),
Expand Down Expand Up @@ -183,7 +205,16 @@ export function defineCommonRoutes({
if (buildFlavor !== 'serverless') {
// In the serverless offering, the access agreement functionality isn't available.
router.post(
{ path: '/internal/security/access_agreement/acknowledge', validate: false },
{
path: '/internal/security/access_agreement/acknowledge',
security: {
authz: {
enabled: false,
reason: `This route delegates authorization to the internal authentication service; there must be an authenticated user for this route to function`,
},
},
validate: false,
},
createLicensedRouteHandler(async (context, request, response) => {
// If license doesn't allow access agreement we shouldn't handle request.
if (!license.getFeatures().allowAccessAgreement) {
Expand Down
18 changes: 18 additions & 0 deletions x-pack/plugins/security/server/routes/authentication/oidc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ export function defineOIDCRoutes({
router.get(
{
path,
security: {
authz: {
enabled: false,
reason: 'This route must remain accessible to 3rd-party OIDC providers',
},
},
validate: {
query: schema.object(
{
Expand Down Expand Up @@ -176,6 +182,12 @@ export function defineOIDCRoutes({
router.post(
{
path,
security: {
authz: {
enabled: false,
reason: 'This route must remain accessible to 3rd-party OIDC providers',
},
},
validate: {
body: schema.object(
{
Expand Down Expand Up @@ -221,6 +233,12 @@ export function defineOIDCRoutes({
router.get(
{
path: '/api/security/oidc/initiate_login',
security: {
authz: {
enabled: false,
reason: 'This route must remain accessible to 3rd-party OIDC providers',
},
},
validate: {
query: schema.object(
{
Expand Down
6 changes: 6 additions & 0 deletions x-pack/plugins/security/server/routes/authentication/saml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ export function defineSAMLRoutes({
router.post(
{
path,
security: {
authz: {
enabled: false,
reason: 'This route must remain accessible to 3rd-party SAML providers',
},
},
validate: {
body: schema.object(
{ SAMLResponse: schema.string(), RelayState: schema.maybe(schema.string()) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ export function defineGetPrivilegesRoutes({ router, authz }: RouteDefinitionPara
router.get(
{
path: '/api/security/privileges',
security: {
authz: {
enabled: false,
reason:
'This route is opted out from authorization because it returns only the global list of Kibana privileges',
},
},
validate: {
query: schema.object({
// We don't use `schema.boolean` here, because all query string parameters are treated as
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@ import type { RouteDefinitionParams } from '../..';

export function defineGetBuiltinPrivilegesRoutes({ router }: RouteDefinitionParams) {
router.get(
{ path: '/internal/security/esPrivileges/builtin', validate: false },
{
path: '/internal/security/esPrivileges/builtin',
security: {
authz: {
enabled: false,
reason: `This route delegates authorization to Core's scoped ES cluster client`,
},
},
validate: false,
},
async (context, request, response) => {
const esClient = (await context.core).elasticsearch.client;
const privileges = await esClient.asCurrentUser.security.getBuiltinPrivileges();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ export function defineDeleteRolesRoutes({ router }: RouteDefinitionParams) {
.addVersion(
{
version: API_VERSIONS.roles.public.v1,
security: {
authz: {
enabled: false,
reason: `This route delegates authorization to Core's scoped ES cluster client`,
},
},
validate: {
request: {
params: schema.object({ name: schema.string({ minLength: 1 }) }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ export function defineGetRolesRoutes({
.addVersion(
{
version: API_VERSIONS.roles.public.v1,
security: {
authz: {
enabled: false,
reason: `This route delegates authorization to Core's scoped ES cluster client`,
},
},
validate: {
request: {
params: schema.object({
Expand Down
Loading

0 comments on commit f3bb8ce

Please sign in to comment.