Unauthorized route migration for routes owned by kibana-visualizations,kibana-data-discovery (#198331)

### 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)

--- EDIT ---

This PR also adds two privileges related to saved query APIs:
`savedQuery:read` and `savedQuery:manage`. These are given by default to
the same roles that already have access to the `query`-type saved
objects.

### **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: Lukas Olson <lukas@elastic.co>
Co-authored-by: Matthias Wilhelm <matthias.wilhelm@elastic.co>
Co-authored-by: Marta Bondyra <4283304+mbondyra@users.noreply.github.com>
Co-authored-by: Davis McPhee <davis.mcphee@elastic.co>
This commit is contained in:
Kibana Machine 2024-12-05 09:29:15 +11:00 committed by GitHub
parent 52e021ff7f
commit 56c38bca20
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 183 additions and 24 deletions

View file

@ -24,6 +24,12 @@ export function registerKqlTelemetryRoute(
.addVersion(
{
version: KQL_TELEMETRY_ROUTE_LATEST_VERSION,
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: {
request: {
body: schema.object({

View file

@ -43,6 +43,11 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void {
router.versioned.post({ path: `${SAVED_QUERY_BASE_URL}/_is_duplicate_title`, access }).addVersion(
{
version,
security: {
authz: {
requiredPrivileges: ['savedQuery:read'],
},
},
validate: {
request: {
body: schema.object({
@ -75,6 +80,11 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void {
router.versioned.post({ path: `${SAVED_QUERY_BASE_URL}/_create`, access }).addVersion(
{
version,
security: {
authz: {
requiredPrivileges: ['savedQuery:manage'],
},
},
validate: {
request: {
body: SAVED_QUERY_ATTRS_CONFIG,
@ -101,6 +111,11 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void {
router.versioned.put({ path: `${SAVED_QUERY_BASE_URL}/{id}`, access }).addVersion(
{
version,
security: {
authz: {
requiredPrivileges: ['savedQuery:manage'],
},
},
validate: {
request: {
params: SAVED_QUERY_ID_CONFIG,
@ -129,6 +144,11 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void {
router.versioned.get({ path: `${SAVED_QUERY_BASE_URL}/{id}`, access }).addVersion(
{
version,
security: {
authz: {
requiredPrivileges: ['savedQuery:read'],
},
},
validate: {
request: {
params: SAVED_QUERY_ID_CONFIG,
@ -156,6 +176,11 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void {
router.versioned.get({ path: `${SAVED_QUERY_BASE_URL}/_count`, access }).addVersion(
{
version,
security: {
authz: {
requiredPrivileges: ['savedQuery:read'],
},
},
validate: {
request: {},
response: {
@ -180,6 +205,11 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void {
router.versioned.post({ path: `${SAVED_QUERY_BASE_URL}/_find`, access }).addVersion(
{
version,
security: {
authz: {
requiredPrivileges: ['savedQuery:read'],
},
},
validate: {
request: {
body: schema.object({
@ -214,6 +244,11 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void {
router.versioned.delete({ path: `${SAVED_QUERY_BASE_URL}/{id}`, access }).addVersion(
{
version,
security: {
authz: {
requiredPrivileges: ['savedQuery:manage'],
},
},
validate: {
request: {
params: SAVED_QUERY_ID_CONFIG,

View file

@ -20,6 +20,12 @@ export function registerScriptsRoute(router: IRouter) {
.addVersion(
{
version: SCRIPT_LANGUAGES_ROUTE_LATEST_VERSION,
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: {
response: {
'200': {

View file

@ -24,11 +24,8 @@ import {
searchSessionsUpdateSchema,
} from './response_schema';
const STORE_SEARCH_SESSIONS_ROLE_TAG = `access:store_search_session`;
const access = 'internal';
const options = {
tags: [STORE_SEARCH_SESSIONS_ROLE_TAG],
};
const requiredPrivileges = ['store_search_session'];
const pathPrefix = '/internal/session';
export const INITIAL_SEARCH_SESSION_REST_VERSION = '1';
const version = INITIAL_SEARCH_SESSION_REST_VERSION;
@ -37,9 +34,12 @@ const idAndAttrsOnly = (so?: SearchSessionRestResponse) =>
so && { id: so.id, attributes: so.attributes };
export function registerSessionRoutes(router: DataPluginRouter, logger: Logger): void {
router.versioned.post({ path: pathPrefix, access, options }).addVersion(
router.versioned.post({ path: pathPrefix, access }).addVersion(
{
version,
security: {
authz: { requiredPrivileges },
},
validate: {
request: {
body: schema.object({
@ -85,9 +85,12 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
}
);
router.versioned.get({ path: `${pathPrefix}/{id}`, access, options }).addVersion(
router.versioned.get({ path: `${pathPrefix}/{id}`, access }).addVersion(
{
version,
security: {
authz: { requiredPrivileges },
},
validate: {
request: {
params: schema.object({
@ -117,9 +120,12 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
}
);
router.versioned.get({ path: `${pathPrefix}/{id}/status`, access, options }).addVersion(
router.versioned.get({ path: `${pathPrefix}/{id}/status`, access }).addVersion(
{
version,
security: {
authz: { requiredPrivileges },
},
validate: {
request: {
params: schema.object({
@ -150,9 +156,12 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
}
);
router.versioned.post({ path: `${pathPrefix}/_find`, access, options }).addVersion(
router.versioned.post({ path: `${pathPrefix}/_find`, access }).addVersion(
{
version,
security: {
authz: { requiredPrivileges },
},
validate: {
request: {
body: schema.object({
@ -200,9 +209,12 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
}
);
router.versioned.delete({ path: `${pathPrefix}/{id}`, access, options }).addVersion(
router.versioned.delete({ path: `${pathPrefix}/{id}`, access }).addVersion(
{
version,
security: {
authz: { requiredPrivileges },
},
validate: {
request: {
params: schema.object({
@ -226,9 +238,12 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
}
);
router.versioned.post({ path: `${pathPrefix}/{id}/cancel`, access, options }).addVersion(
router.versioned.post({ path: `${pathPrefix}/{id}/cancel`, access }).addVersion(
{
version,
security: {
authz: { requiredPrivileges },
},
validate: {
request: {
params: schema.object({
@ -252,9 +267,12 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
}
);
router.versioned.put({ path: `${pathPrefix}/{id}`, access, options }).addVersion(
router.versioned.put({ path: `${pathPrefix}/{id}`, access }).addVersion(
{
version,
security: {
authz: { requiredPrivileges },
},
validate: {
request: {
params: schema.object({
@ -291,9 +309,12 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
}
);
router.versioned.post({ path: `${pathPrefix}/{id}/_extend`, access, options }).addVersion(
router.versioned.post({ path: `${pathPrefix}/{id}/_extend`, access }).addVersion(
{
version,
security: {
authz: { requiredPrivileges },
},
validate: {
request: {
params: schema.object({

View file

@ -548,6 +548,8 @@ Array [
"api": Array [
"bulkGetUserProfiles",
"dashboardUsageStats",
"savedQuery:manage",
"savedQuery:read",
"store_search_session",
],
"app": Array [
@ -607,6 +609,7 @@ Array [
"api": Array [
"bulkGetUserProfiles",
"dashboardUsageStats",
"savedQuery:read",
],
"app": Array [
"dashboards",
@ -709,6 +712,8 @@ Array [
},
"api": Array [
"fileUpload:analyzeFile",
"savedQuery:manage",
"savedQuery:read",
"store_search_session",
],
"app": Array [
@ -757,6 +762,9 @@ Array [
},
Object {
"privilege": Object {
"api": Array [
"savedQuery:read",
],
"app": Array [
"discover",
"kibana",
@ -1004,6 +1012,10 @@ exports[`buildOSSFeatures with a basic license returns the savedQueryManagement
Array [
Object {
"privilege": Object {
"api": Array [
"savedQuery:manage",
"savedQuery:read",
],
"app": Array [
"kibana",
],
@ -1022,10 +1034,14 @@ Array [
},
Object {
"privilege": Object {
"disabled": true,
"api": Array [
"savedQuery:read",
],
"savedObject": Object {
"all": Array [],
"read": Array [],
"read": Array [
"query",
],
},
"ui": Array [],
},
@ -1048,7 +1064,10 @@ Array [
"read": Array [],
},
},
"api": Array [],
"api": Array [
"savedQuery:manage",
"savedQuery:read",
],
"app": Array [
"visualize",
"lens",
@ -1094,6 +1113,9 @@ Array [
},
Object {
"privilege": Object {
"api": Array [
"savedQuery:read",
],
"app": Array [
"visualize",
"lens",
@ -1190,6 +1212,8 @@ Array [
"api": Array [
"bulkGetUserProfiles",
"dashboardUsageStats",
"savedQuery:manage",
"savedQuery:read",
"store_search_session",
],
"app": Array [
@ -1249,6 +1273,7 @@ Array [
"api": Array [
"bulkGetUserProfiles",
"dashboardUsageStats",
"savedQuery:read",
],
"app": Array [
"dashboards",
@ -1351,6 +1376,8 @@ Array [
},
"api": Array [
"fileUpload:analyzeFile",
"savedQuery:manage",
"savedQuery:read",
"store_search_session",
],
"app": Array [
@ -1399,6 +1426,9 @@ Array [
},
Object {
"privilege": Object {
"api": Array [
"savedQuery:read",
],
"app": Array [
"discover",
"kibana",
@ -1646,6 +1676,10 @@ exports[`buildOSSFeatures with a enterprise license returns the savedQueryManage
Array [
Object {
"privilege": Object {
"api": Array [
"savedQuery:manage",
"savedQuery:read",
],
"app": Array [
"kibana",
],
@ -1664,10 +1698,14 @@ Array [
},
Object {
"privilege": Object {
"disabled": true,
"api": Array [
"savedQuery:read",
],
"savedObject": Object {
"all": Array [],
"read": Array [],
"read": Array [
"query",
],
},
"ui": Array [],
},
@ -1690,7 +1728,10 @@ Array [
"read": Array [],
},
},
"api": Array [],
"api": Array [
"savedQuery:manage",
"savedQuery:read",
],
"app": Array [
"visualize",
"lens",
@ -1736,6 +1777,9 @@ Array [
},
Object {
"privilege": Object {
"api": Array [
"savedQuery:read",
],
"app": Array [
"visualize",
"lens",

View file

@ -37,7 +37,7 @@ export const buildOSSFeatures = ({
privileges: {
all: {
app: ['discover', 'kibana'],
api: ['fileUpload:analyzeFile'],
api: ['fileUpload:analyzeFile', 'savedQuery:manage', 'savedQuery:read'],
catalogue: ['discover'],
savedObject: {
all: ['search', 'query'],
@ -53,6 +53,7 @@ export const buildOSSFeatures = ({
read: ['index-pattern', 'search', 'query'],
},
ui: ['show'],
api: ['savedQuery:read'],
},
},
subFeatures: [
@ -139,6 +140,7 @@ export const buildOSSFeatures = ({
read: ['index-pattern', 'search', 'tag'],
},
ui: ['show', 'delete', 'save', 'saveQuery'],
api: ['savedQuery:manage', 'savedQuery:read'],
},
read: {
app: ['visualize', 'lens', 'kibana'],
@ -148,6 +150,7 @@ export const buildOSSFeatures = ({
read: ['index-pattern', 'search', 'visualization', 'query', 'lens', 'tag'],
},
ui: ['show'],
api: ['savedQuery:read'],
},
},
subFeatures: [
@ -213,7 +216,12 @@ export const buildOSSFeatures = ({
],
},
ui: ['createNew', 'show', 'showWriteControls', 'saveQuery'],
api: ['bulkGetUserProfiles', 'dashboardUsageStats'],
api: [
'bulkGetUserProfiles',
'dashboardUsageStats',
'savedQuery:manage',
'savedQuery:read',
],
},
read: {
app: ['dashboards', 'kibana'],
@ -234,7 +242,7 @@ export const buildOSSFeatures = ({
],
},
ui: ['show'],
api: ['bulkGetUserProfiles', 'dashboardUsageStats'],
api: ['bulkGetUserProfiles', 'dashboardUsageStats', 'savedQuery:read'],
},
},
subFeatures: [
@ -545,7 +553,7 @@ export const buildOSSFeatures = ({
catalogue: [],
privilegesTooltip: i18n.translate('xpack.features.savedQueryManagementTooltip', {
defaultMessage:
'If set to "All", saved queries can be managed across Kibana in all applications that support them. If set to "None", saved query privileges will be determined independently by each application.',
'If set to "All", saved queries can be managed across Kibana in all applications that support them. Otherwise, saved query privileges will be determined independently by each application.',
}),
privileges: {
all: {
@ -556,9 +564,16 @@ export const buildOSSFeatures = ({
read: [],
},
ui: ['saveQuery'],
api: ['savedQuery:manage', 'savedQuery:read'],
},
read: {
savedObject: {
all: [],
read: ['query'],
},
ui: [],
api: ['savedQuery:read'],
},
// No read-only mode supported
read: { disabled: true, savedObject: { all: [], read: [] }, ui: [] },
},
},
];

View file

@ -188,6 +188,7 @@ export class MapsPlugin implements Plugin {
read: ['index-pattern', 'tag'],
},
ui: ['save', 'show', 'saveQuery'],
api: ['savedQuery:manage', 'savedQuery:read'],
},
read: {
app: [APP_ID, 'kibana'],
@ -197,6 +198,7 @@ export class MapsPlugin implements Plugin {
read: [MAP_SAVED_OBJECT_TYPE, 'index-pattern', 'query', 'tag'],
},
ui: ['show'],
api: ['savedQuery:read'],
},
},
});

View file

@ -4235,6 +4235,8 @@ export default function ({ getService }: FtrProviderContext) {
"login:",
"api:bulkGetUserProfiles",
"api:dashboardUsageStats",
"api:savedQuery:manage",
"api:savedQuery:read",
"api:store_search_session",
"api:generateReport",
"api:downloadCsv",
@ -4418,6 +4420,8 @@ export default function ({ getService }: FtrProviderContext) {
"login:",
"api:bulkGetUserProfiles",
"api:dashboardUsageStats",
"api:savedQuery:manage",
"api:savedQuery:read",
"app:dashboards",
"app:kibana",
"ui:catalogue/dashboard",
@ -4570,6 +4574,7 @@ export default function ({ getService }: FtrProviderContext) {
"login:",
"api:bulkGetUserProfiles",
"api:dashboardUsageStats",
"api:savedQuery:read",
"app:dashboards",
"app:kibana",
"ui:catalogue/dashboard",
@ -4669,6 +4674,7 @@ export default function ({ getService }: FtrProviderContext) {
"login:",
"api:bulkGetUserProfiles",
"api:dashboardUsageStats",
"api:savedQuery:read",
"app:dashboards",
"app:kibana",
"ui:catalogue/dashboard",
@ -4804,6 +4810,8 @@ export default function ({ getService }: FtrProviderContext) {
"all": Array [
"login:",
"api:fileUpload:analyzeFile",
"api:savedQuery:manage",
"api:savedQuery:read",
"api:store_search_session",
"api:generateReport",
"app:discover",
@ -6032,6 +6040,8 @@ export default function ({ getService }: FtrProviderContext) {
"minimal_all": Array [
"login:",
"api:fileUpload:analyzeFile",
"api:savedQuery:manage",
"api:savedQuery:read",
"app:discover",
"app:kibana",
"ui:catalogue/discover",
@ -7227,6 +7237,7 @@ export default function ({ getService }: FtrProviderContext) {
],
"minimal_read": Array [
"login:",
"api:savedQuery:read",
"app:discover",
"app:kibana",
"ui:catalogue/discover",
@ -7718,6 +7729,7 @@ export default function ({ getService }: FtrProviderContext) {
],
"read": Array [
"login:",
"api:savedQuery:read",
"app:discover",
"app:kibana",
"ui:catalogue/discover",

View file

@ -42,6 +42,8 @@ export default function ({ getService }: FtrProviderContext) {
"login:",
"api:bulkGetUserProfiles",
"api:dashboardUsageStats",
"api:savedQuery:manage",
"api:savedQuery:read",
"api:store_search_session",
"api:generateReport",
"api:downloadCsv",
@ -225,6 +227,8 @@ export default function ({ getService }: FtrProviderContext) {
"login:",
"api:bulkGetUserProfiles",
"api:dashboardUsageStats",
"api:savedQuery:manage",
"api:savedQuery:read",
"app:dashboards",
"app:kibana",
"ui:catalogue/dashboard",
@ -377,6 +381,7 @@ export default function ({ getService }: FtrProviderContext) {
"login:",
"api:bulkGetUserProfiles",
"api:dashboardUsageStats",
"api:savedQuery:read",
"app:dashboards",
"app:kibana",
"ui:catalogue/dashboard",
@ -476,6 +481,7 @@ export default function ({ getService }: FtrProviderContext) {
"login:",
"api:bulkGetUserProfiles",
"api:dashboardUsageStats",
"api:savedQuery:read",
"app:dashboards",
"app:kibana",
"ui:catalogue/dashboard",
@ -611,6 +617,8 @@ export default function ({ getService }: FtrProviderContext) {
"all": Array [
"login:",
"api:fileUpload:analyzeFile",
"api:savedQuery:manage",
"api:savedQuery:read",
"api:store_search_session",
"api:generateReport",
"app:discover",
@ -711,6 +719,8 @@ export default function ({ getService }: FtrProviderContext) {
"minimal_all": Array [
"login:",
"api:fileUpload:analyzeFile",
"api:savedQuery:manage",
"api:savedQuery:read",
"app:discover",
"app:kibana",
"ui:catalogue/discover",
@ -778,6 +788,7 @@ export default function ({ getService }: FtrProviderContext) {
],
"minimal_read": Array [
"login:",
"api:savedQuery:read",
"app:discover",
"app:kibana",
"ui:catalogue/discover",
@ -822,6 +833,7 @@ export default function ({ getService }: FtrProviderContext) {
],
"read": Array [
"login:",
"api:savedQuery:read",
"app:discover",
"app:kibana",
"ui:catalogue/discover",

View file

@ -742,6 +742,8 @@ export default function ({ getService }: FtrProviderContext) {
"alerting:siem.newTermsRule/siem/alert/getAlertSummary",
"alerting:siem.newTermsRule/siem/alert/update",
"api:fileUpload:analyzeFile",
"api:savedQuery:manage",
"api:savedQuery:read",
"api:store_search_session",
"api:generateReport",
"app:discover",
@ -1597,6 +1599,8 @@ export default function ({ getService }: FtrProviderContext) {
"alerting:siem.newTermsRule/siem/alert/getAlertSummary",
"alerting:siem.newTermsRule/siem/alert/update",
"api:fileUpload:analyzeFile",
"api:savedQuery:manage",
"api:savedQuery:read",
"api:store_search_session",
"api:generateReport",
"app:discover",
@ -2003,6 +2007,7 @@ export default function ({ getService }: FtrProviderContext) {
"alerting:siem.newTermsRule/siem/alert/getAuthorizedAlertsIndices",
"alerting:siem.newTermsRule/siem/alert/getAlertSummary",
"alerting:siem.newTermsRule/siem/alert/update",
"api:savedQuery:read",
"app:discover",
"ui:catalogue/discover",
"ui:navLinks/discover",
@ -2370,6 +2375,7 @@ export default function ({ getService }: FtrProviderContext) {
"alerting:siem.newTermsRule/siem/alert/getAuthorizedAlertsIndices",
"alerting:siem.newTermsRule/siem/alert/getAlertSummary",
"alerting:siem.newTermsRule/siem/alert/update",
"api:savedQuery:read",
"app:discover",
"ui:catalogue/discover",
"ui:navLinks/discover",