-
Notifications
You must be signed in to change notification settings - Fork 8.5k
[APM][9.0] Adding kibana upgrade deprecation warning apm_user removed #200163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
cauemarcondes
merged 16 commits into
elastic:main
from
cauemarcondes:apm-remove-apm-user
Nov 20, 2024
Merged
Changes from 13 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
9574f10
[APM] Adding kibana upgrade deprecation warning apm_user removed
cauemarcondes 34f99da
moving to apm folder
cauemarcondes 1807b33
reverting
cauemarcondes a052756
tests
cauemarcondes 306da87
test
cauemarcondes dc241ac
i18n
cauemarcondes 2470e7e
PR comments
cauemarcondes 807a49f
removing old test
cauemarcondes 851842e
Merge branch 'main' into apm-remove-apm-user
cauemarcondes 4743d7f
i18n
cauemarcondes cb47a46
Merge branch 'apm-remove-apm-user' of github.com:cauemarcondes/kibana…
cauemarcondes 8d2322f
i18n
cauemarcondes 22a8250
updating test
cauemarcondes 0a3f843
pr comments
cauemarcondes 5ee6fc3
addressing pr comments
cauemarcondes 38439ef
Merge branch 'main' into apm-remove-apm-user
cauemarcondes File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
37 changes: 37 additions & 0 deletions
37
...s/observability_solution/apm/server/deprecations/__snapshots__/apm_user_role.test.ts.snap
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
102 changes: 102 additions & 0 deletions
102
x-pack/plugins/observability_solution/apm/server/deprecations/apm_user_role.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| /* | ||
| * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
| * or more contributor license agreements. Licensed under the Elastic License | ||
| * 2.0; you may not use this file except in compliance with the Elastic License | ||
| * 2.0. | ||
| */ | ||
|
|
||
| import type { GetDeprecationsContext, IScopedClusterClient, CoreSetup } from '@kbn/core/server'; | ||
| import { elasticsearchServiceMock, loggingSystemMock } from '@kbn/core/server/mocks'; | ||
| import { getDeprecationsInfo } from './apm_user_role'; | ||
| import { SecurityPluginSetup } from '@kbn/security-plugin/server'; | ||
|
|
||
| let context: GetDeprecationsContext; | ||
| let esClient: jest.Mocked<IScopedClusterClient>; | ||
| const core = { docLinks: { version: 'main' } } as unknown as CoreSetup; | ||
| const logger = loggingSystemMock.createLogger(); | ||
| const security = { license: { isEnabled: () => true } } as unknown as SecurityPluginSetup; | ||
|
|
||
| describe('apm_user deprecation', () => { | ||
| beforeEach(async () => { | ||
| esClient = elasticsearchServiceMock.createScopedClusterClient(); | ||
| esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({ | ||
| xyz: { username: 'normal_user', roles: ['data_analyst'] }, | ||
| }); | ||
| esClient.asCurrentUser.security.getRoleMapping = jest.fn().mockResolvedValue({}); | ||
|
|
||
| context = { esClient } as unknown as GetDeprecationsContext; | ||
| }); | ||
|
|
||
| test('logs no deprecations when setup has no issues', async () => { | ||
| expect(await getDeprecationsInfo(context, core, { logger, security })).toMatchInlineSnapshot( | ||
| `Array []` | ||
| ); | ||
| }); | ||
|
|
||
| describe('users assigned to a removed role', () => { | ||
| test('logs a deprecation when a user was found with a removed apm_user role', async () => { | ||
| esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({ | ||
| foo: { | ||
| username: 'foo', | ||
| roles: ['kibana_admin', 'apm_user'], | ||
| }, | ||
| }); | ||
|
|
||
| expect(await getDeprecationsInfo(context, core, { logger, security })).toMatchSnapshot(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('roles mapped to a removed role', () => { | ||
| test('logs a deprecation when a role was found that maps to the removed apm_user role', async () => { | ||
| esClient.asCurrentUser.security.getRoleMapping = jest | ||
| .fn() | ||
| .mockResolvedValue({ dungeon_master: { roles: ['apm_user'] } }); | ||
|
|
||
| expect(await getDeprecationsInfo(context, core, { logger, security })).toMatchSnapshot(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('check deprecations when security is disabled', () => { | ||
| test('logs no deprecations', async () => { | ||
| expect( | ||
| await getDeprecationsInfo(context, core, { logger, security: undefined }) | ||
| ).toMatchInlineSnapshot(`Array []`); | ||
| }); | ||
| }); | ||
|
|
||
| it('insufficient permissions', async () => { | ||
| const permissionsError = new Error('you shall not pass'); | ||
| (permissionsError as unknown as { statusCode: number }).statusCode = 403; | ||
| esClient.asCurrentUser.security.getUser = jest.fn().mockRejectedValue(permissionsError); | ||
| esClient.asCurrentUser.security.getRoleMapping = jest.fn().mockRejectedValue(permissionsError); | ||
|
|
||
| expect(await getDeprecationsInfo(context, core, { logger, security })).toMatchInlineSnapshot(` | ||
| Array [ | ||
| Object { | ||
| "correctiveActions": Object { | ||
| "manualSteps": Array [ | ||
| "Make sure you have a \\"manage_security\\" cluster privilege assigned.", | ||
| ], | ||
| }, | ||
| "deprecationType": "feature", | ||
| "documentationUrl": "https://www.elastic.co/guide/en/kibana/main/xpack-security.html#_required_permissions_7", | ||
| "level": "fetch_error", | ||
| "message": "You do not have enough permissions to fix this deprecation.", | ||
| "title": "Check for users assigned the deprecated \\"apm_user\\" role", | ||
| }, | ||
| Object { | ||
| "correctiveActions": Object { | ||
| "manualSteps": Array [ | ||
| "Make sure you have a \\"manage_security\\" cluster privilege assigned.", | ||
| ], | ||
| }, | ||
| "deprecationType": "feature", | ||
| "documentationUrl": "https://www.elastic.co/guide/en/kibana/main/xpack-security.html#_required_permissions_7", | ||
| "level": "fetch_error", | ||
| "message": "You do not have enough permissions to fix this deprecation.", | ||
| "title": "Check for role mappings using the deprecated \\"apm_user\\" role", | ||
| }, | ||
| ] | ||
| `); | ||
| }); | ||
| }); |
179 changes: 179 additions & 0 deletions
179
x-pack/plugins/observability_solution/apm/server/deprecations/apm_user_role.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,179 @@ | ||
| /* | ||
| * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
| * or more contributor license agreements. Licensed under the Elastic License | ||
| * 2.0; you may not use this file except in compliance with the Elastic License | ||
| * 2.0. | ||
| */ | ||
|
|
||
| import { | ||
| SecurityGetRoleMappingResponse, | ||
| SecurityGetUserResponse, | ||
| } from '@elastic/elasticsearch/lib/api/types'; | ||
| import type { | ||
| CoreSetup, | ||
| DeprecationsDetails, | ||
| DocLinksServiceSetup, | ||
| ElasticsearchClient, | ||
| GetDeprecationsContext, | ||
| } from '@kbn/core/server'; | ||
| import { i18n } from '@kbn/i18n'; | ||
| import type { DeprecationApmDeps } from '.'; | ||
| import { deprecations } from '../lib/deprecations'; | ||
|
|
||
| const APM_USER_ROLE_NAME = 'apm_user'; | ||
| const getKibanaPrivilegesDocumentationUrl = (branch: string) => { | ||
| return `https://www.elastic.co/guide/en/kibana/${branch}/kibana-privileges.html`; | ||
| }; | ||
|
|
||
| export async function getDeprecationsInfo( | ||
| { esClient }: GetDeprecationsContext, | ||
| core: CoreSetup, | ||
| apmDeps: DeprecationApmDeps | ||
| ) { | ||
| const client = esClient.asCurrentUser; | ||
| const { docLinks } = core; | ||
| const { security } = apmDeps; | ||
|
|
||
| // Nothing to do if security is disabled | ||
| if (!security?.license.isEnabled()) { | ||
| return []; | ||
| } | ||
|
|
||
| return [ | ||
| ...(await getUsersDeprecations(client, apmDeps, docLinks)), | ||
| ...(await getRoleMappingsDeprecations(client, apmDeps, docLinks)), | ||
| ]; | ||
| } | ||
|
|
||
| async function getUsersDeprecations( | ||
cauemarcondes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| client: ElasticsearchClient, | ||
| apmDeps: DeprecationApmDeps, | ||
| docLinks: DocLinksServiceSetup | ||
| ): Promise<DeprecationsDetails[]> { | ||
| const title = i18n.translate('xpack.apm.deprecations.apmUser.title', { | ||
| defaultMessage: `Check for users assigned the deprecated "{apmUserRoleName}" role`, | ||
| values: { apmUserRoleName: APM_USER_ROLE_NAME }, | ||
| }); | ||
|
|
||
| let users: SecurityGetUserResponse; | ||
| try { | ||
| users = await client.security.getUser(); | ||
| } catch (err) { | ||
| const { logger } = apmDeps; | ||
| if (deprecations.getErrorStatusCode(err) === 403) { | ||
| logger.warn( | ||
| `Failed to retrieve users when checking for deprecations:` + | ||
| ` the "manage_security" cluster privilege is required.` | ||
cauemarcondes marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ); | ||
| } else { | ||
| logger.error( | ||
| `Failed to retrieve users when checking for deprecations,` + | ||
| ` unexpected error: ${deprecations.getDetailedErrorMessage(err)}.` | ||
cauemarcondes marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ); | ||
| } | ||
| return deprecations.deprecationError(title, err, docLinks); | ||
| } | ||
|
|
||
| const reportingUsers = Object.entries(users) | ||
| .filter(([_, user]) => user.roles.find(hasApmUserRole)) | ||
| .map(([userName]) => userName); | ||
|
|
||
| if (reportingUsers.length === 0) { | ||
cauemarcondes marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return []; | ||
| } | ||
|
|
||
| return [ | ||
| { | ||
| title, | ||
| message: i18n.translate('xpack.apm.deprecations.apmUser.description', { | ||
| defaultMessage: `The "{apmUserRoleName}" role has been deprecated. Remove the "{apmUserRoleName}" role from affected users in this cluster including: {users}`, | ||
| values: { apmUserRoleName: APM_USER_ROLE_NAME, users: reportingUsers.join(', ') }, | ||
cauemarcondes marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| }), | ||
| correctiveActions: { | ||
| manualSteps: [ | ||
| i18n.translate('xpack.apm.deprecations.apmUser.manualStepOne', { | ||
| defaultMessage: `Go to Management > Security > Users to find users with the "{apmUserRoleName}" role.`, | ||
| values: { apmUserRoleName: APM_USER_ROLE_NAME }, | ||
| }), | ||
| i18n.translate('xpack.apm.deprecations.apmUser.manualStepTwo', { | ||
| defaultMessage: | ||
| 'Remove the "{apmUserRoleName}" role from all users and add the built-in "viewer" role.', | ||
| values: { apmUserRoleName: APM_USER_ROLE_NAME }, | ||
| }), | ||
| ], | ||
| }, | ||
| level: 'critical', | ||
| deprecationType: 'feature', | ||
| documentationUrl: getKibanaPrivilegesDocumentationUrl(docLinks.version), | ||
| }, | ||
| ]; | ||
| } | ||
|
|
||
| async function getRoleMappingsDeprecations( | ||
| client: ElasticsearchClient, | ||
| apmDeps: DeprecationApmDeps, | ||
| docLinks: DocLinksServiceSetup | ||
| ): Promise<DeprecationsDetails[]> { | ||
| const title = i18n.translate('xpack.apm.deprecations.apmUserRoleMappings.title', { | ||
| defaultMessage: `Check for role mappings using the deprecated "{apmUserRoleName}" role`, | ||
| values: { apmUserRoleName: APM_USER_ROLE_NAME }, | ||
| }); | ||
|
|
||
| let roleMappings: SecurityGetRoleMappingResponse; | ||
| try { | ||
| roleMappings = await client.security.getRoleMapping(); | ||
| } catch (err) { | ||
| const { logger } = apmDeps; | ||
| if (deprecations.getErrorStatusCode(err) === 403) { | ||
| logger.warn( | ||
| `Failed to retrieve role mappings when checking for deprecations:` + | ||
| ` the "manage_security" cluster privilege is required.` | ||
cauemarcondes marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ); | ||
| } else { | ||
| logger.error( | ||
| `Failed to retrieve role mappings when checking for deprecations,` + | ||
| ` unexpected error: ${deprecations.getDetailedErrorMessage(err)}.` | ||
cauemarcondes marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ); | ||
| } | ||
| return deprecations.deprecationError(title, err, docLinks); | ||
| } | ||
|
|
||
| const roleMappingsWithReportingRole: string[] = Object.entries(roleMappings) | ||
cauemarcondes marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| .filter(([_, role]) => role.roles?.find(hasApmUserRole)) | ||
| ?.map(([roleName]) => roleName); | ||
cauemarcondes marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| if (roleMappingsWithReportingRole.length === 0) { | ||
| return []; | ||
| } | ||
|
|
||
| return [ | ||
| { | ||
| title, | ||
| message: i18n.translate('xpack.apm.deprecations.apmUserRoleMappings.description', { | ||
| defaultMessage: `The "{apmUserRoleName}" role has been deprecated. Remove the "{apmUserRoleName}" role from affected role mappings in this cluster including: {roles}`, | ||
| values: { | ||
| apmUserRoleName: APM_USER_ROLE_NAME, | ||
| roles: roleMappingsWithReportingRole.join(', '), | ||
cauemarcondes marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| }, | ||
| }), | ||
| correctiveActions: { | ||
| manualSteps: [ | ||
| i18n.translate('xpack.apm.deprecations.apmUserRoleMappings.manualStepOne', { | ||
| defaultMessage: `Go to Management > Security > Roles to find roles with the "{apmUserRoleName}" role.`, | ||
cauemarcondes marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| values: { apmUserRoleName: APM_USER_ROLE_NAME }, | ||
| }), | ||
| i18n.translate('xpack.apm.deprecations.apmUserRoleMappings.manualStepTwo', { | ||
| defaultMessage: | ||
| 'Remove the "{apmUserRoleName}" role from all role mappings and add the built-in "viewer" role', | ||
| values: { apmUserRoleName: APM_USER_ROLE_NAME }, | ||
| }), | ||
| ], | ||
| }, | ||
| level: 'critical', | ||
| deprecationType: 'feature', | ||
| documentationUrl: getKibanaPrivilegesDocumentationUrl(docLinks.version), | ||
| }, | ||
| ]; | ||
| } | ||
|
|
||
| const hasApmUserRole = (role: string) => role === APM_USER_ROLE_NAME; | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.