From 0f46bdc5dc144df2e105b36cd09312f1ede437d5 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 18 Oct 2021 11:40:47 -0400 Subject: [PATCH] [7.x] Improve upgrade assistance for the legacy audit logger (#114995) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/config_deprecations.test.ts | 259 +++++++++++++----- .../security/server/config_deprecations.ts | 62 ++++- 2 files changed, 238 insertions(+), 83 deletions(-) diff --git a/x-pack/plugins/security/server/config_deprecations.test.ts b/x-pack/plugins/security/server/config_deprecations.test.ts index d4b18a2e1b296..028200d40164c 100644 --- a/x-pack/plugins/security/server/config_deprecations.test.ts +++ b/x-pack/plugins/security/server/config_deprecations.test.ts @@ -16,7 +16,7 @@ const deprecationContext = configDeprecationsMock.createContext(); const applyConfigDeprecations = (settings: Record = {}) => { const deprecations = securityConfigDeprecationProvider(configDeprecationFactory); - const deprecationMessages: string[] = []; + const generatedDeprecations: Array<{ message: string; level?: 'warning' | 'critical' }> = []; const configPaths: string[] = []; const { config: migrated } = applyDeprecations( settings, @@ -26,14 +26,14 @@ const applyConfigDeprecations = (settings: Record = {}) => { context: deprecationContext, })), () => - ({ message, configPath }) => { - deprecationMessages.push(message); + ({ message, level, configPath }) => { + generatedDeprecations.push({ message, level }); configPaths.push(configPath); } ); return { + deprecations: generatedDeprecations, configPaths, - messages: deprecationMessages, migrated, }; }; @@ -41,41 +41,53 @@ const applyConfigDeprecations = (settings: Record = {}) => { describe('Config Deprecations', () => { it('does not report any deprecations if session timeouts are specified', () => { const defaultConfig = { xpack: { security: { session: { idleTimeout: 123, lifespan: 345 } } } }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(defaultConfig)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(defaultConfig)); expect(migrated).toEqual(defaultConfig); - expect(messages).toHaveLength(0); + expect(deprecations).toHaveLength(0); }); it('reports that session idleTimeout and lifespan will have default values if none of them is specified', () => { const defaultConfig = { xpack: { security: {} } }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(defaultConfig)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(defaultConfig)); expect(migrated).toEqual(defaultConfig); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "The session idle timeout will default to 1 hour in 8.0.", - "The session lifespan will default to 30 days in 8.0.", + Object { + "level": "warning", + "message": "The session idle timeout will default to 1 hour in 8.0.", + }, + Object { + "level": "warning", + "message": "The session lifespan will default to 30 days in 8.0.", + }, ] `); }); it('reports that session idleTimeout will have a default value if it is not specified', () => { const defaultConfig = { xpack: { security: { session: { lifespan: 345 } } } }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(defaultConfig)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(defaultConfig)); expect(migrated).toEqual(defaultConfig); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "The session idle timeout will default to 1 hour in 8.0.", + Object { + "level": "warning", + "message": "The session idle timeout will default to 1 hour in 8.0.", + }, ] `); }); it('reports that session lifespan will have a default value if it is not specified', () => { const defaultConfig = { xpack: { security: { session: { idleTimeout: 123 } } } }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(defaultConfig)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(defaultConfig)); expect(migrated).toEqual(defaultConfig); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "The session lifespan will default to 30 days in 8.0.", + Object { + "level": "warning", + "message": "The session lifespan will default to 30 days in 8.0.", + }, ] `); }); @@ -88,13 +100,19 @@ describe('Config Deprecations', () => { }, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated.xpack.security.sessionTimeout).not.toBeDefined(); expect(migrated.xpack.security.session.idleTimeout).toEqual(123); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "Setting \\"xpack.security.sessionTimeout\\" has been replaced by \\"xpack.security.session.idleTimeout\\"", - "The session lifespan will default to 30 days in 8.0.", + Object { + "level": undefined, + "message": "Setting \\"xpack.security.sessionTimeout\\" has been replaced by \\"xpack.security.session.idleTimeout\\"", + }, + Object { + "level": "warning", + "message": "The session lifespan will default to 30 days in 8.0.", + }, ] `); }); @@ -112,12 +130,15 @@ describe('Config Deprecations', () => { }, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated.xpack.security.audit.appender.kind).not.toBeDefined(); expect(migrated.xpack.security.audit.appender.type).toEqual('console'); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "Setting \\"xpack.security.audit.appender.kind\\" has been replaced by \\"xpack.security.audit.appender.type\\"", + Object { + "level": undefined, + "message": "Setting \\"xpack.security.audit.appender.kind\\" has been replaced by \\"xpack.security.audit.appender.type\\"", + }, ] `); }); @@ -135,12 +156,15 @@ describe('Config Deprecations', () => { }, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated.xpack.security.audit.appender.layout.kind).not.toBeDefined(); expect(migrated.xpack.security.audit.appender.layout.type).toEqual('pattern'); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "Setting \\"xpack.security.audit.appender.layout.kind\\" has been replaced by \\"xpack.security.audit.appender.layout.type\\"", + Object { + "level": undefined, + "message": "Setting \\"xpack.security.audit.appender.layout.kind\\" has been replaced by \\"xpack.security.audit.appender.layout.type\\"", + }, ] `); }); @@ -158,12 +182,15 @@ describe('Config Deprecations', () => { }, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated.xpack.security.audit.appender.policy.kind).not.toBeDefined(); expect(migrated.xpack.security.audit.appender.policy.type).toEqual('time-interval'); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "Setting \\"xpack.security.audit.appender.policy.kind\\" has been replaced by \\"xpack.security.audit.appender.policy.type\\"", + Object { + "level": undefined, + "message": "Setting \\"xpack.security.audit.appender.policy.kind\\" has been replaced by \\"xpack.security.audit.appender.policy.type\\"", + }, ] `); }); @@ -181,12 +208,15 @@ describe('Config Deprecations', () => { }, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated.xpack.security.audit.appender.strategy.kind).not.toBeDefined(); expect(migrated.xpack.security.audit.appender.strategy.type).toEqual('numeric'); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "Setting \\"xpack.security.audit.appender.strategy.kind\\" has been replaced by \\"xpack.security.audit.appender.strategy.type\\"", + Object { + "level": undefined, + "message": "Setting \\"xpack.security.audit.appender.strategy.kind\\" has been replaced by \\"xpack.security.audit.appender.strategy.type\\"", + }, ] `); }); @@ -205,12 +235,15 @@ describe('Config Deprecations', () => { }, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated.xpack.security.audit.appender.path).not.toBeDefined(); expect(migrated.xpack.security.audit.appender.fileName).toEqual('./audit.log'); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "Setting \\"xpack.security.audit.appender.path\\" has been replaced by \\"xpack.security.audit.appender.fileName\\"", + Object { + "level": undefined, + "message": "Setting \\"xpack.security.audit.appender.path\\" has been replaced by \\"xpack.security.audit.appender.fileName\\"", + }, ] `); }); @@ -226,39 +259,94 @@ describe('Config Deprecations', () => { showInsecureClusterWarning: false, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated.security.showInsecureClusterWarning).not.toBeDefined(); expect(migrated.xpack.security.showInsecureClusterWarning).toEqual(false); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "Setting \\"security.showInsecureClusterWarning\\" has been replaced by \\"xpack.security.showInsecureClusterWarning\\"", + Object { + "level": undefined, + "message": "Setting \\"security.showInsecureClusterWarning\\" has been replaced by \\"xpack.security.showInsecureClusterWarning\\"", + }, + ] + `); + }); + + it('warns when using the legacy audit logger on-prem', () => { + const config = { + xpack: { + security: { + session: { idleTimeout: 123, lifespan: 345 }, + audit: { + enabled: true, + }, + }, + }, + }; + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); + expect(migrated.xpack.security.audit.appender).not.toBeDefined(); + expect(deprecations).toMatchInlineSnapshot(` + Array [ + Object { + "level": "warning", + "message": "Use the new ECS-compliant audit logger.", + }, ] `); }); - it('warns when using the legacy audit logger', () => { + it('does not warn when using the ECS audit logger on-prem', () => { const config = { xpack: { security: { session: { idleTimeout: 123, lifespan: 345 }, audit: { enabled: true, + appender: { + type: 'file', + fileName: './audit.log', + }, }, }, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); + expect(migrated).toEqual(config); + expect(deprecations).toHaveLength(0); + }); + + it('warns when using the legacy audit logger on cloud', () => { + const config = { + xpack: { + cloud: { + id: 'abc123', + }, + security: { + session: { idleTimeout: 123, lifespan: 345 }, + audit: { + enabled: true, + }, + }, + }, + }; + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated.xpack.security.audit.appender).not.toBeDefined(); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "The legacy audit logger is deprecated in favor of the new ECS-compliant audit logger.", + Object { + "level": "warning", + "message": "Use the new ECS-compliant audit logger.", + }, ] `); }); - it('does not warn when using the ECS audit logger', () => { + it('does not warn when using the ECS audit logger on cloud', () => { const config = { xpack: { + cloud: { + id: 'abc123', + }, security: { session: { idleTimeout: 123, lifespan: 345 }, audit: { @@ -271,9 +359,9 @@ describe('Config Deprecations', () => { }, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated).toEqual(config); - expect(messages).toHaveLength(0); + expect(deprecations).toHaveLength(0); }); it('does not warn about using the legacy logger when using the ECS audit logger, even when using the deprecated ECS appender config', () => { @@ -291,12 +379,15 @@ describe('Config Deprecations', () => { }, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated.xpack.security.audit.appender.path).not.toBeDefined(); expect(migrated.xpack.security.audit.appender.fileName).toEqual('./audit.log'); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "Setting \\"xpack.security.audit.appender.path\\" has been replaced by \\"xpack.security.audit.appender.fileName\\"", + Object { + "level": undefined, + "message": "Setting \\"xpack.security.audit.appender.path\\" has been replaced by \\"xpack.security.audit.appender.fileName\\"", + }, ] `); }); @@ -314,10 +405,13 @@ describe('Config Deprecations', () => { }, }, }; - const { messages } = applyConfigDeprecations(cloneDeep(config)); - expect(messages).toMatchInlineSnapshot(` + const { deprecations } = applyConfigDeprecations(cloneDeep(config)); + expect(deprecations).toMatchInlineSnapshot(` Array [ - "You no longer need to configure \\"xpack.security.authorization.legacyFallback.enabled\\".", + Object { + "level": undefined, + "message": "You no longer need to configure \\"xpack.security.authorization.legacyFallback.enabled\\".", + }, ] `); }); @@ -335,10 +429,13 @@ describe('Config Deprecations', () => { }, }, }; - const { messages } = applyConfigDeprecations(cloneDeep(config)); - expect(messages).toMatchInlineSnapshot(` + const { deprecations } = applyConfigDeprecations(cloneDeep(config)); + expect(deprecations).toMatchInlineSnapshot(` Array [ - "You no longer need to configure \\"xpack.security.authc.saml.maxRedirectURLSize\\".", + Object { + "level": undefined, + "message": "You no longer need to configure \\"xpack.security.authc.saml.maxRedirectURLSize\\".", + }, ] `); }); @@ -360,10 +457,13 @@ describe('Config Deprecations', () => { }, }, }; - const { messages, configPaths } = applyConfigDeprecations(cloneDeep(config)); - expect(messages).toMatchInlineSnapshot(` + const { deprecations, configPaths } = applyConfigDeprecations(cloneDeep(config)); + expect(deprecations).toMatchInlineSnapshot(` Array [ - "\\"xpack.security.authc.providers.saml..maxRedirectURLSize\\" is no longer used.", + Object { + "level": undefined, + "message": "\\"xpack.security.authc.providers.saml..maxRedirectURLSize\\" is no longer used.", + }, ] `); @@ -381,11 +481,14 @@ describe('Config Deprecations', () => { }, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated).toEqual(config); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "\\"xpack.security.authc.providers\\" accepts an extended \\"object\\" format instead of an array of provider types.", + Object { + "level": undefined, + "message": "\\"xpack.security.authc.providers\\" accepts an extended \\"object\\" format instead of an array of provider types.", + }, ] `); }); @@ -401,12 +504,18 @@ describe('Config Deprecations', () => { }, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated).toEqual(config); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "\\"xpack.security.authc.providers\\" accepts an extended \\"object\\" format instead of an array of provider types.", - "Enabling both \\"basic\\" and \\"token\\" authentication providers in \\"xpack.security.authc.providers\\" is deprecated. Login page will only use \\"token\\" provider.", + Object { + "level": undefined, + "message": "\\"xpack.security.authc.providers\\" accepts an extended \\"object\\" format instead of an array of provider types.", + }, + Object { + "level": undefined, + "message": "Enabling both \\"basic\\" and \\"token\\" authentication providers in \\"xpack.security.authc.providers\\" is deprecated. Login page will only use \\"token\\" provider.", + }, ] `); }); @@ -420,11 +529,14 @@ describe('Config Deprecations', () => { }, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated).toEqual(config); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "Enabling or disabling the Security plugin in Kibana is deprecated. Configure security in Elasticsearch instead.", + Object { + "level": undefined, + "message": "Enabling or disabling the Security plugin in Kibana is deprecated. Configure security in Elasticsearch instead.", + }, ] `); }); @@ -438,11 +550,14 @@ describe('Config Deprecations', () => { }, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated).toEqual(config); - expect(messages).toMatchInlineSnapshot(` + expect(deprecations).toMatchInlineSnapshot(` Array [ - "Enabling or disabling the Security plugin in Kibana is deprecated. Configure security in Elasticsearch instead.", + Object { + "level": undefined, + "message": "Enabling or disabling the Security plugin in Kibana is deprecated. Configure security in Elasticsearch instead.", + }, ] `); }); @@ -455,8 +570,8 @@ describe('Config Deprecations', () => { }, }, }; - const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + const { deprecations, migrated } = applyConfigDeprecations(cloneDeep(config)); expect(migrated).toEqual(config); - expect(messages).toHaveLength(0); + expect(deprecations).toHaveLength(0); }); }); diff --git a/x-pack/plugins/security/server/config_deprecations.ts b/x-pack/plugins/security/server/config_deprecations.ts index c8c8e64648c4b..e080fc1217e94 100644 --- a/x-pack/plugins/security/server/config_deprecations.ts +++ b/x-pack/plugins/security/server/config_deprecations.ts @@ -33,22 +33,62 @@ export const securityConfigDeprecationProvider: ConfigDeprecationProvider = ({ (settings, fromPath, addDeprecation, { branch }) => { const auditLoggingEnabled = settings?.xpack?.security?.audit?.enabled ?? false; const legacyAuditLoggerEnabled = !settings?.xpack?.security?.audit?.appender; - if (auditLoggingEnabled && legacyAuditLoggerEnabled) { + + // Gross, but the cloud plugin depends on the security plugin already, + // so we can't add a dependency in the other direction to check this in a more conventional manner. + const isCloudInstance = typeof settings?.xpack?.cloud?.id === 'string'; + + const isUsingLegacyAuditLogger = auditLoggingEnabled && legacyAuditLoggerEnabled; + + if (!isUsingLegacyAuditLogger) { + return; + } + + const title = i18n.translate('xpack.security.deprecations.auditLoggerTitle', { + defaultMessage: 'The legacy audit logger is deprecated', + }); + + const message = i18n.translate('xpack.security.deprecations.auditLoggerMessage', { + defaultMessage: 'Use the new ECS-compliant audit logger.', + }); + + const documentationUrl = `https://www.elastic.co/guide/en/kibana/${branch}/security-settings-kb.html#audit-logging-settings`; + + const configPath = 'xpack.security.audit.appender'; + if (isCloudInstance) { addDeprecation({ - configPath: 'xpack.security.audit.appender', - title: i18n.translate('xpack.security.deprecations.auditLoggerTitle', { - defaultMessage: 'The legacy audit logger is deprecated', - }), - message: i18n.translate('xpack.security.deprecations.auditLoggerMessage', { - defaultMessage: - 'The legacy audit logger is deprecated in favor of the new ECS-compliant audit logger.', - }), - documentationUrl: `https://www.elastic.co/guide/en/kibana/${branch}/security-settings-kb.html#audit-logging-settings`, + title, + message, + configPath, + level: 'warning', + documentationUrl, + correctiveActions: { + manualSteps: [ + i18n.translate('xpack.security.deprecations.auditLogger.manualStepOneMessageCloud', { + defaultMessage: + 'To enable the ECS audit logger now, add the "xpack.security.audit.appender.type: rolling-file" setting.', + }), + i18n.translate('xpack.security.deprecations.auditLogger.manualStepTwoMessageCloud', { + defaultMessage: `If you don't make any changes, the ECS audit logger will be enabled when you upgrade to 8.0.`, + }), + ], + }, + }); + } else { + addDeprecation({ + title, + message, + configPath, + level: 'warning', + documentationUrl, correctiveActions: { manualSteps: [ i18n.translate('xpack.security.deprecations.auditLogger.manualStepOneMessage', { defaultMessage: - 'Declare an audit logger "appender" via "xpack.security.audit.appender" to enable the ECS audit logger.', + 'To enable the ECS audit logger now, configure an appender with "xpack.security.audit.appender".', + }), + i18n.translate('xpack.security.deprecations.auditLogger.manualStepTwoMessage', { + defaultMessage: `If you don't make any changes, the ECS audit logger will be enabled when you upgrade to 8.0.`, }), ], },