mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Surface Kibana security route deprecations in Upgrade Assistant (#199656)
Closes #197389 ## Summary Uses the `deprecated` route configuration option on all Kibana Security "v1" endpoints. This will surface deprecation information in the Upgrade Assistant. ## Related PRs - https://github.com/elastic/kibana/pull/50695 - `7.6.0`, deprecated - `/api/security/v1/me` - `/api/security/v1/logout` - `/api/security/v1/oidc/implicit` - `/api/security/v1/oidc` (POST) - https://github.com/elastic/kibana/pull/53886 - `7.6.0`, deprecated `/api/security/v1/oidc` (GET) - https://github.com/elastic/kibana/pull/47929 - `8.0.0`, dropped `/api/security/v1/saml` (`breaking` release note) - https://github.com/elastic/kibana/pull/106665 - restored `/api/security/v1/saml` but warned as deprecated (no release note) ## Testing 1. Start ES & Kibana in trial license mode 2. Make several calls to one or more of the deprecated endpoints 3. Navigate to `Stack Management`->`Upgrade Assistant` 4. Click on Kibana warnings <img width="1003" alt="Screenshot 2024-11-18 at 10 01 10 AM" src="https://github.com/user-attachments/assets/da44af13-57eb-4ffd-a507-e423eb767a11"> 5. Confirm the called endpoints are displayed as warnings in the Upgrade Assistant <img width="1274" alt="Screenshot 2024-11-18 at 9 59 34 AM" src="https://github.com/user-attachments/assets/4c054fbe-6838-48cf-8b1b-8c161252db0f"> ## Previous release notes ### v7.6.0 https://www.elastic.co/guide/en/kibana/7.6/release-notes-7.6.0.html#deprecation-7.6.0 https://www.elastic.co/guide/en/kibana/7.6/breaking-changes-7.6.html The deprecations are not listed in the release notes or breaking changes notes. ### v8.0.0 https://www.elastic.co/guide/en/kibana/current/release-notes-8.0.0-alpha1.html#rest-api-changes SAML endpoint deprecation only appears in the 8.0.0-alpha1 release notes, and was reverted in 8.0.0-alpha2 # Release note See `docs/upgrade-notes.asciidoc` in file changes # Follow-up A follow-up PR must be created to create and backfill the docLinks. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
b8e6bbd461
commit
742ae9fd2a
10 changed files with 157 additions and 28 deletions
|
@ -49,6 +49,32 @@ For Elastic Security release information, refer to {security-guide}/release-note
|
|||
[float]
|
||||
==== Kibana APIs
|
||||
|
||||
[discrete]
|
||||
[[breaking-199656]]
|
||||
.Removed all security v1 endpoints (9.0.0)
|
||||
[%collapsible]
|
||||
====
|
||||
*Details* +
|
||||
All `v1` Kibana security HTTP endpoints have been removed.
|
||||
|
||||
`GET /api/security/v1/logout` has been replaced by `GET /api/security/logout`
|
||||
`GET /api/security/v1/oidc/implicit` has been replaced by `GET /api/security/oidc/implicit`
|
||||
`GET /api/security/v1/oidc` has been replaced by GET `/api/security/oidc/callback`
|
||||
`POST /api/security/v1/oidc` has been replaced by POST `/api/security/oidc/initiate_login`
|
||||
`POST /api/security/v1/saml` has been replaced by POST `/api/security/saml/callback`
|
||||
`GET /api/security/v1/me` has been removed with no replacement.
|
||||
|
||||
For more information, refer to {kibana-pull}199656[#199656].
|
||||
|
||||
*Impact* +
|
||||
Any HTTP API calls to the `v1` Kibana security endpoints will fail with a 404 status code starting from version 9.0.0.
|
||||
Third party OIDC and SAML identity providers configured with `v1` endpoints will no longer work.
|
||||
|
||||
*Action* +
|
||||
Update any OIDC and SAML identity providers to reference the corresponding replacement endpoint listed above.
|
||||
Remove references to the `/api/security/v1/me` endpoint from any automations, applications, tooling, and scripts.
|
||||
====
|
||||
|
||||
[discrete]
|
||||
[[breaking-193792]]
|
||||
.Access to all internal APIs is blocked (9.0.0)
|
||||
|
@ -814,18 +840,6 @@ The legacy audit logger has been removed. For more information, refer to {kibana
|
|||
Audit logs will be written to the default location in the new ECS format. To change the output file, filter events, and more, use the <<audit-logging-settings, audit logging settings>>.
|
||||
====
|
||||
|
||||
[discrete]
|
||||
[[breaking-47929]]
|
||||
.[Security] Removed `/api/security/v1/saml` route. (8.0)
|
||||
[%collapsible]
|
||||
====
|
||||
*Details* +
|
||||
The `/api/security/v1/saml` route has been removed and is reflected in the kibana.yml `server.xsrf.whitelist` setting, {es}, and the Identity Provider SAML settings. For more information, refer to {kibana-pull}47929[#47929]
|
||||
|
||||
*Impact* +
|
||||
Use the `/api/security/saml/callback` route, or wait to upgrade to 8.0.0-alpha2 when the `/api/security/saml/callback` route breaking change is reverted.
|
||||
====
|
||||
|
||||
[discrete]
|
||||
[[breaking-41700]]
|
||||
.[Security] Legacy browsers rejected by default. (8.0)
|
||||
|
|
|
@ -717,6 +717,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D
|
|||
mappingRoles: `${ELASTICSEARCH_DOCS}mapping-roles.html`,
|
||||
mappingRolesFieldRules: `${ELASTICSEARCH_DOCS}role-mapping-resources.html#mapping-roles-rule-field`,
|
||||
runAsPrivilege: `${ELASTICSEARCH_DOCS}security-privileges.html#_run_as_privilege`,
|
||||
deprecatedV1Endpoints: `${KIBANA_DOCS}breaking-changes-summary.html#breaking-199656`,
|
||||
},
|
||||
spaces: {
|
||||
kibanaLegacyUrlAliases: `${KIBANA_DOCS}legacy-url-aliases.html`,
|
||||
|
|
|
@ -505,6 +505,7 @@ export interface DocLinks {
|
|||
mappingRoles: string;
|
||||
mappingRolesFieldRules: string;
|
||||
runAsPrivilege: string;
|
||||
deprecatedV1Endpoints: string;
|
||||
}>;
|
||||
readonly spaces: Readonly<{
|
||||
kibanaLegacyUrlAliases: string;
|
||||
|
|
|
@ -338,6 +338,7 @@ export class SecurityPlugin
|
|||
getUserProfileService: this.getUserProfileService,
|
||||
analyticsService: this.analyticsService.setup({ analytics: core.analytics }),
|
||||
buildFlavor: this.initializerContext.env.packageInfo.buildFlavor,
|
||||
docLinks: core.docLinks,
|
||||
});
|
||||
|
||||
return Object.freeze<SecurityPluginSetup>({
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import type { TypeOf } from '@kbn/config-schema';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { parseNextURL } from '@kbn/std';
|
||||
|
||||
import type { RouteDefinitionParams } from '..';
|
||||
|
@ -33,6 +34,7 @@ export function defineCommonRoutes({
|
|||
license,
|
||||
logger,
|
||||
buildFlavor,
|
||||
docLinks,
|
||||
}: RouteDefinitionParams) {
|
||||
// Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used.
|
||||
// For a serverless build, do not register deprecated versioned routes
|
||||
|
@ -40,6 +42,7 @@ export function defineCommonRoutes({
|
|||
'/api/security/logout',
|
||||
...(buildFlavor !== 'serverless' ? ['/api/security/v1/logout'] : []),
|
||||
]) {
|
||||
const isDeprecated = path === '/api/security/v1/logout';
|
||||
router.get(
|
||||
{
|
||||
path,
|
||||
|
@ -57,13 +60,29 @@ export function defineCommonRoutes({
|
|||
excludeFromOAS: true,
|
||||
authRequired: false,
|
||||
tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW],
|
||||
...(isDeprecated && {
|
||||
deprecated: {
|
||||
documentationUrl: docLinks.links.security.deprecatedV1Endpoints,
|
||||
severity: 'warning',
|
||||
message: i18n.translate('xpack.security.deprecations.logoutRouteMessage', {
|
||||
defaultMessage:
|
||||
'The "{path}" URL is deprecated and will be removed in the next major version. Use "/api/security/logout" instead.',
|
||||
values: { path },
|
||||
}),
|
||||
reason: {
|
||||
type: 'migrate',
|
||||
newApiMethod: 'GET',
|
||||
newApiPath: '/api/security/logout',
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const serverBasePath = basePath.serverBasePath;
|
||||
if (path === '/api/security/v1/logout') {
|
||||
if (isDeprecated) {
|
||||
logger.warn(
|
||||
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/logout" URL instead.`,
|
||||
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version. Use "${serverBasePath}/api/security/logout" URL instead.`,
|
||||
{ tags: ['deprecation'] }
|
||||
);
|
||||
}
|
||||
|
@ -96,7 +115,7 @@ export function defineCommonRoutes({
|
|||
'/internal/security/me',
|
||||
...(buildFlavor !== 'serverless' ? ['/api/security/v1/me'] : []),
|
||||
]) {
|
||||
const deprecated = path === '/api/security/v1/me';
|
||||
const isDeprecated = path === '/api/security/v1/me';
|
||||
router.get(
|
||||
{
|
||||
path,
|
||||
|
@ -107,10 +126,24 @@ export function defineCommonRoutes({
|
|||
},
|
||||
},
|
||||
validate: false,
|
||||
options: { access: deprecated ? 'public' : 'internal' },
|
||||
options: {
|
||||
access: isDeprecated ? 'public' : 'internal',
|
||||
...(isDeprecated && {
|
||||
deprecated: {
|
||||
documentationUrl: docLinks.links.security.deprecatedV1Endpoints,
|
||||
severity: 'warning',
|
||||
message: i18n.translate('xpack.security.deprecations.meRouteMessage', {
|
||||
defaultMessage:
|
||||
'The "{path}" endpoint is deprecated and will be removed in the next major version.',
|
||||
values: { path },
|
||||
}),
|
||||
reason: { type: 'remove' },
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
createLicensedRouteHandler(async (context, request, response) => {
|
||||
if (deprecated) {
|
||||
if (isDeprecated) {
|
||||
logger.warn(
|
||||
`The "${basePath.serverBasePath}${path}" endpoint is deprecated and will be removed in the next major version.`,
|
||||
{ tags: ['deprecation'] }
|
||||
|
|
|
@ -25,9 +25,11 @@ export function defineOIDCRoutes({
|
|||
logger,
|
||||
getAuthenticationService,
|
||||
basePath,
|
||||
docLinks,
|
||||
}: RouteDefinitionParams) {
|
||||
// Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used.
|
||||
for (const path of ['/api/security/oidc/implicit', '/api/security/v1/oidc/implicit']) {
|
||||
const isDeprecated = path === '/api/security/v1/oidc/implicit';
|
||||
/**
|
||||
* The route should be configured as a redirect URI in OP when OpenID Connect implicit flow
|
||||
* is used, so that we can extract authentication response from URL fragment and send it to
|
||||
|
@ -37,13 +39,32 @@ export function defineOIDCRoutes({
|
|||
{
|
||||
path,
|
||||
validate: false,
|
||||
options: { authRequired: false, excludeFromOAS: true },
|
||||
options: {
|
||||
authRequired: false,
|
||||
excludeFromOAS: true,
|
||||
...(isDeprecated && {
|
||||
deprecated: {
|
||||
documentationUrl: docLinks.links.security.deprecatedV1Endpoints,
|
||||
severity: 'warning',
|
||||
message: i18n.translate('xpack.security.deprecations.oidcImplicitRouteMessage', {
|
||||
defaultMessage:
|
||||
'The "{path}" URL is deprecated and will be removed in the next major version. Use "/api/security/oidc/implicit" instead.',
|
||||
values: { path },
|
||||
}),
|
||||
reason: {
|
||||
type: 'migrate',
|
||||
newApiMethod: 'GET',
|
||||
newApiPath: '/api/security/oidc/implicit',
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
(context, request, response) => {
|
||||
const serverBasePath = basePath.serverBasePath;
|
||||
if (path === '/api/security/v1/oidc/implicit') {
|
||||
if (isDeprecated) {
|
||||
logger.warn(
|
||||
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/oidc/implicit" URL instead.`,
|
||||
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version. Use "${serverBasePath}/api/security/oidc/implicit" URL instead.`,
|
||||
{ tags: ['deprecation'] }
|
||||
);
|
||||
}
|
||||
|
@ -84,6 +105,7 @@ export function defineOIDCRoutes({
|
|||
|
||||
// Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used.
|
||||
for (const path of ['/api/security/oidc/callback', '/api/security/v1/oidc']) {
|
||||
const isDeprecated = path === '/api/security/v1/oidc';
|
||||
router.get(
|
||||
{
|
||||
path,
|
||||
|
@ -117,6 +139,22 @@ export function defineOIDCRoutes({
|
|||
excludeFromOAS: true,
|
||||
authRequired: false,
|
||||
tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW],
|
||||
...(isDeprecated && {
|
||||
deprecated: {
|
||||
documentationUrl: docLinks.links.security.deprecatedV1Endpoints,
|
||||
severity: 'warning',
|
||||
message: i18n.translate('xpack.security.deprecations.oidcCallbackRouteMessage', {
|
||||
defaultMessage:
|
||||
'The "{path}" URL is deprecated and will be removed in the next major version. Use "/api/security/oidc/callback" instead.',
|
||||
values: { path },
|
||||
}),
|
||||
reason: {
|
||||
type: 'migrate',
|
||||
newApiMethod: 'GET',
|
||||
newApiPath: '/api/security/oidc/callback',
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
createLicensedRouteHandler(async (context, request, response) => {
|
||||
|
@ -133,9 +171,9 @@ export function defineOIDCRoutes({
|
|||
authenticationResponseURI: request.query.authenticationResponseURI,
|
||||
};
|
||||
} else if (request.query.code || request.query.error) {
|
||||
if (path === '/api/security/v1/oidc') {
|
||||
if (isDeprecated) {
|
||||
logger.warn(
|
||||
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/oidc/callback" URL instead.`,
|
||||
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version. Use "${serverBasePath}/api/security/oidc/callback" URL instead.`,
|
||||
{ tags: ['deprecation'] }
|
||||
);
|
||||
}
|
||||
|
@ -150,7 +188,7 @@ export function defineOIDCRoutes({
|
|||
};
|
||||
} else if (request.query.iss) {
|
||||
logger.warn(
|
||||
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/oidc/initiate_login" URL for Third-Party Initiated login instead.`,
|
||||
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version. Use "${serverBasePath}/api/security/oidc/initiate_login" URL for Third-Party Initiated login instead.`,
|
||||
{ tags: ['deprecation'] }
|
||||
);
|
||||
// An HTTP GET request with a query parameter named `iss` as part of a 3rd party initiated authentication.
|
||||
|
@ -175,6 +213,7 @@ export function defineOIDCRoutes({
|
|||
|
||||
// Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used.
|
||||
for (const path of ['/api/security/oidc/initiate_login', '/api/security/v1/oidc']) {
|
||||
const isDeprecated = path === '/api/security/v1/oidc';
|
||||
/**
|
||||
* An HTTP POST request with the payload parameter named `iss` as part of a 3rd party initiated authentication.
|
||||
* See more details at https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin
|
||||
|
@ -206,13 +245,29 @@ export function defineOIDCRoutes({
|
|||
authRequired: false,
|
||||
xsrfRequired: false,
|
||||
tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW],
|
||||
...(isDeprecated && {
|
||||
deprecated: {
|
||||
documentationUrl: docLinks.links.security.deprecatedV1Endpoints,
|
||||
severity: 'warning',
|
||||
message: i18n.translate('xpack.security.deprecations.oidcInitiateRouteMessage', {
|
||||
defaultMessage:
|
||||
'The "{path}" URL is deprecated and will be removed in the next major version. Use "/api/security/oidc/initiate_login" instead.',
|
||||
values: { path },
|
||||
}),
|
||||
reason: {
|
||||
type: 'migrate',
|
||||
newApiMethod: 'POST',
|
||||
newApiPath: '/api/security/oidc/initiate_login',
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
createLicensedRouteHandler(async (context, request, response) => {
|
||||
const serverBasePath = basePath.serverBasePath;
|
||||
if (path === '/api/security/v1/oidc') {
|
||||
if (isDeprecated) {
|
||||
logger.warn(
|
||||
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/oidc/initiate_login" URL for Third-Party Initiated login instead.`,
|
||||
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version. Use "${serverBasePath}/api/security/oidc/initiate_login" URL for Third-Party Initiated login instead.`,
|
||||
{ tags: ['deprecation'] }
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import type { RouteDefinitionParams } from '..';
|
||||
import { SAMLAuthenticationProvider, SAMLLogin } from '../../authentication';
|
||||
|
@ -20,6 +21,7 @@ export function defineSAMLRoutes({
|
|||
basePath,
|
||||
logger,
|
||||
buildFlavor,
|
||||
docLinks,
|
||||
}: RouteDefinitionParams) {
|
||||
// Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used.
|
||||
// For a serverless build, do not register deprecated versioned routes
|
||||
|
@ -27,6 +29,7 @@ export function defineSAMLRoutes({
|
|||
'/api/security/saml/callback',
|
||||
...(buildFlavor !== 'serverless' ? ['/api/security/v1/saml'] : []),
|
||||
]) {
|
||||
const isDeprecated = path === '/api/security/v1/saml';
|
||||
router.post(
|
||||
{
|
||||
path,
|
||||
|
@ -48,14 +51,30 @@ export function defineSAMLRoutes({
|
|||
authRequired: false,
|
||||
xsrfRequired: false,
|
||||
tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW],
|
||||
...(isDeprecated && {
|
||||
deprecated: {
|
||||
documentationUrl: docLinks.links.security.deprecatedV1Endpoints,
|
||||
severity: 'warning',
|
||||
message: i18n.translate('xpack.security.deprecations.samlPostRouteMessage', {
|
||||
defaultMessage:
|
||||
'The "{path}" URL is deprecated and will be removed in the next major version. Use "/api/security/saml/callback" instead.',
|
||||
values: { path },
|
||||
}),
|
||||
reason: {
|
||||
type: 'migrate',
|
||||
newApiMethod: 'POST',
|
||||
newApiPath: '/api/security/saml/callback',
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
if (path === '/api/security/v1/saml') {
|
||||
if (isDeprecated) {
|
||||
const serverBasePath = basePath.serverBasePath;
|
||||
logger.warn(
|
||||
// When authenticating using SAML we _expect_ to redirect to the SAML Identity provider.
|
||||
`The "${serverBasePath}${path}" URL is deprecated and might stop working in a future release. Please use "${serverBasePath}/api/security/saml/callback" URL instead.`
|
||||
`The "${serverBasePath}${path}" URL is deprecated and might stop working in a future release. Use "${serverBasePath}/api/security/saml/callback" URL instead.`
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
httpServiceMock,
|
||||
loggingSystemMock,
|
||||
} from '@kbn/core/server/mocks';
|
||||
import { getDocLinks } from '@kbn/doc-links';
|
||||
import { licensingMock } from '@kbn/licensing-plugin/server/mocks';
|
||||
import type { DeeplyMockedKeys } from '@kbn/utility-types-jest';
|
||||
|
||||
|
@ -50,6 +51,8 @@ export const routeDefinitionParamsMock = {
|
|||
getAnonymousAccessService: jest.fn(),
|
||||
getUserProfileService: jest.fn().mockReturnValue(userProfileServiceMock.createStart()),
|
||||
analyticsService: analyticsServiceMock.createSetup(),
|
||||
buildFlavor: 'traditional',
|
||||
docLinks: { links: getDocLinks({ kibanaBranch: 'main', buildFlavor: 'traditional' }) },
|
||||
} as unknown as DeeplyMockedKeys<RouteDefinitionParams>;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import type { Observable } from 'rxjs';
|
||||
|
||||
import type { BuildFlavor } from '@kbn/config/src/types';
|
||||
import type { HttpResources, IBasePath, Logger } from '@kbn/core/server';
|
||||
import type { DocLinksServiceSetup, HttpResources, IBasePath, Logger } from '@kbn/core/server';
|
||||
import type { KibanaFeature } from '@kbn/features-plugin/server';
|
||||
import type { SubFeaturePrivilegeIterator } from '@kbn/features-plugin/server/feature_privilege_iterator';
|
||||
import type { PublicMethodsOf } from '@kbn/utility-types';
|
||||
|
@ -59,6 +59,7 @@ export interface RouteDefinitionParams {
|
|||
getAnonymousAccessService: () => AnonymousAccessServiceStart;
|
||||
analyticsService: AnalyticsServiceSetup;
|
||||
buildFlavor: BuildFlavor;
|
||||
docLinks: DocLinksServiceSetup;
|
||||
}
|
||||
|
||||
export function defineRoutes(params: RouteDefinitionParams) {
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
"@kbn/security-ui-components",
|
||||
"@kbn/core-http-router-server-mocks",
|
||||
"@kbn/security-authorization-core-common",
|
||||
"@kbn/doc-links",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue