diff --git a/packages/core/security/core-security-server-internal/src/fips/fips.test.ts b/packages/core/security/core-security-server-internal/src/fips/fips.test.ts index 80874c112619d..65f95aa7da691 100644 --- a/packages/core/security/core-security-server-internal/src/fips/fips.test.ts +++ b/packages/core/security/core-security-server-internal/src/fips/fips.test.ts @@ -6,13 +6,22 @@ * Side Public License, v 1. */ +const mockGetFipsFn = jest.fn(); +jest.mock('crypto', () => ({ + randomBytes: jest.fn(), + constants: jest.requireActual('crypto').constants, + get getFips() { + return mockGetFipsFn; + }, +})); + import { SecurityServiceConfigType } from '../utils'; -import { isFipsEnabled } from './fips'; +import { isFipsEnabled, checkFipsConfig } from './fips'; +import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; describe('fips', () => { + let config: SecurityServiceConfigType; describe('#isFipsEnabled', () => { - let config: SecurityServiceConfigType; - it('should return `true` if config.experimental.fipsMode.enabled is `true`', () => { config = { experimental: { fipsMode: { enabled: true } } }; @@ -29,4 +38,82 @@ describe('fips', () => { expect(isFipsEnabled(config)).toBe(false); }); }); + + describe('checkFipsConfig', () => { + let mockExit: jest.SpyInstance; + + beforeAll(() => { + mockExit = jest.spyOn(process, 'exit').mockImplementation((exitCode) => { + throw new Error(`Fake Exit: ${exitCode}`); + }); + }); + + afterAll(() => { + mockExit.mockRestore(); + }); + + it('should log an error message if FIPS mode is misconfigured - xpack.security.experimental.fipsMode.enabled true, Nodejs FIPS mode false', async () => { + config = { experimental: { fipsMode: { enabled: true } } }; + const logger = loggingSystemMock.create().get(); + try { + checkFipsConfig(config, logger); + } catch (e) { + expect(mockExit).toHaveBeenNthCalledWith(1, 78); + } + + expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` + Array [ + Array [ + "Configuration mismatch error. xpack.security.experimental.fipsMode.enabled is set to true and the configured Node.js environment has FIPS disabled", + ], + ] + `); + }); + + it('should log an error message if FIPS mode is misconfigured - xpack.security.experimental.fipsMode.enabled false, Nodejs FIPS mode true', async () => { + mockGetFipsFn.mockImplementationOnce(() => { + return 1; + }); + + config = { experimental: { fipsMode: { enabled: false } } }; + const logger = loggingSystemMock.create().get(); + + try { + checkFipsConfig(config, logger); + } catch (e) { + expect(mockExit).toHaveBeenNthCalledWith(1, 78); + } + + expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` + Array [ + Array [ + "Configuration mismatch error. xpack.security.experimental.fipsMode.enabled is set to false and the configured Node.js environment has FIPS enabled", + ], + ] + `); + }); + + it('should log an info message if FIPS mode is properly configured - xpack.security.experimental.fipsMode.enabled true, Nodejs FIPS mode true', async () => { + mockGetFipsFn.mockImplementationOnce(() => { + return 1; + }); + + config = { experimental: { fipsMode: { enabled: true } } }; + const logger = loggingSystemMock.create().get(); + + try { + checkFipsConfig(config, logger); + } catch (e) { + logger.error('Should not throw error!'); + } + + expect(loggingSystemMock.collect(logger).info).toMatchInlineSnapshot(` + Array [ + Array [ + "Kibana is running in FIPS mode.", + ], + ] + `); + }); + }); }); diff --git a/packages/core/security/core-security-server-internal/src/fips/fips.ts b/packages/core/security/core-security-server-internal/src/fips/fips.ts index 3e6ba2e99c706..2b48fb68ff607 100644 --- a/packages/core/security/core-security-server-internal/src/fips/fips.ts +++ b/packages/core/security/core-security-server-internal/src/fips/fips.ts @@ -6,8 +6,30 @@ * Side Public License, v 1. */ +import type { Logger } from '@kbn/logging'; +import { getFips } from 'crypto'; import { SecurityServiceConfigType } from '../utils'; export function isFipsEnabled(config: SecurityServiceConfigType): boolean { return config?.experimental?.fipsMode?.enabled ?? false; } + +export function checkFipsConfig(config: SecurityServiceConfigType, logger: Logger) { + const isFipsConfigEnabled = isFipsEnabled(config); + const isNodeRunningWithFipsEnabled = getFips() === 1; + + // Check if FIPS is enabled in either setting + if (isFipsConfigEnabled || isNodeRunningWithFipsEnabled) { + // FIPS must be enabled on both or log and error an exit Kibana + if (isFipsConfigEnabled !== isNodeRunningWithFipsEnabled) { + logger.error( + `Configuration mismatch error. xpack.security.experimental.fipsMode.enabled is set to ${isFipsConfigEnabled} and the configured Node.js environment has FIPS ${ + isNodeRunningWithFipsEnabled ? 'enabled' : 'disabled' + }` + ); + process.exit(78); + } else { + logger.info('Kibana is running in FIPS mode.'); + } + } +} diff --git a/packages/core/security/core-security-server-internal/src/security_service.ts b/packages/core/security/core-security-server-internal/src/security_service.ts index 509774ab6a5fb..215e7ef376285 100644 --- a/packages/core/security/core-security-server-internal/src/security_service.ts +++ b/packages/core/security/core-security-server-internal/src/security_service.ts @@ -11,7 +11,7 @@ import type { CoreContext, CoreService } from '@kbn/core-base-server-internal'; import type { CoreSecurityDelegateContract } from '@kbn/core-security-server'; import { Observable, Subscription } from 'rxjs'; import { Config } from '@kbn/config'; -import { isFipsEnabled } from './fips/fips'; +import { isFipsEnabled, checkFipsConfig } from './fips/fips'; import type { InternalSecurityServiceSetup, InternalSecurityServiceStart, @@ -50,6 +50,8 @@ export class SecurityService const config = this.getConfig(); const securityConfig: SecurityServiceConfigType = config.get(['xpack', 'security']); + checkFipsConfig(securityConfig, this.log); + return { registerSecurityDelegate: (api) => { if (this.securityApi) { diff --git a/x-pack/plugins/security/server/config.test.ts b/x-pack/plugins/security/server/config.test.ts index fe7a7fbf22ac1..5e6c59aee4668 100644 --- a/x-pack/plugins/security/server/config.test.ts +++ b/x-pack/plugins/security/server/config.test.ts @@ -5,13 +5,9 @@ * 2.0. */ -const mockGetFipsFn = jest.fn(); jest.mock('crypto', () => ({ randomBytes: jest.fn(), constants: jest.requireActual('crypto').constants, - get getFips() { - return mockGetFipsFn; - }, })); jest.mock('@kbn/utils', () => ({ @@ -2521,96 +2517,3 @@ describe('createConfig()', () => { }); }); }); - -describe('checkFipsConfig', () => { - let mockExit: jest.SpyInstance; - beforeAll(() => { - mockExit = jest.spyOn(process, 'exit').mockImplementation((exitCode) => { - throw new Error(`Fake Exit: ${exitCode}`); - }); - }); - - afterAll(() => { - mockExit.mockRestore(); - }); - - it('should log an error message if FIPS mode is misconfigured - xpack.security.experimental.fipsMode.enabled true, Nodejs FIPS mode false', async () => { - const logger = loggingSystemMock.create().get(); - - try { - createConfig( - ConfigSchema.validate({ experimental: { fipsMode: { enabled: true } } }), - logger, - { - isTLSEnabled: true, - } - ); - } catch (e) { - expect(mockExit).toHaveBeenNthCalledWith(1, 78); - } - - expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` - Array [ - Array [ - "Configuration mismatch error. xpack.security.experimental.fipsMode.enabled is set to true and the configured Node.js environment has FIPS disabled", - ], - ] - `); - }); - - it('should log an error message if FIPS mode is misconfigured - xpack.security.experimental.fipsMode.enabled false, Nodejs FIPS mode true', async () => { - mockGetFipsFn.mockImplementationOnce(() => { - return 1; - }); - - const logger = loggingSystemMock.create().get(); - - try { - createConfig( - ConfigSchema.validate({ experimental: { fipsMode: { enabled: false } } }), - logger, - { - isTLSEnabled: true, - } - ); - } catch (e) { - expect(mockExit).toHaveBeenNthCalledWith(1, 78); - } - - expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` - Array [ - Array [ - "Configuration mismatch error. xpack.security.experimental.fipsMode.enabled is set to false and the configured Node.js environment has FIPS enabled", - ], - ] - `); - }); - - it('should log an info message if FIPS mode is properly configured - xpack.security.experimental.fipsMode.enabled true, Nodejs FIPS mode true', async () => { - mockGetFipsFn.mockImplementationOnce(() => { - return 1; - }); - - const logger = loggingSystemMock.create().get(); - - try { - createConfig( - ConfigSchema.validate({ experimental: { fipsMode: { enabled: true } } }), - logger, - { - isTLSEnabled: true, - } - ); - } catch (e) { - logger.error('Should not throw error!'); - } - - expect(loggingSystemMock.collect(logger).info).toMatchInlineSnapshot(` - Array [ - Array [ - "Kibana is running in FIPS mode.", - ], - ] - `); - }); -}); diff --git a/x-pack/plugins/security/server/config.ts b/x-pack/plugins/security/server/config.ts index 4e28de37c853f..e12f1462b39b4 100644 --- a/x-pack/plugins/security/server/config.ts +++ b/x-pack/plugins/security/server/config.ts @@ -5,7 +5,7 @@ * 2.0. */ -import crypto, { getFips } from 'crypto'; +import crypto from 'crypto'; import type { Duration } from 'moment'; import path from 'path'; @@ -321,33 +321,11 @@ export const ConfigSchema = schema.object({ }), }); -function checkFipsConfig(config: RawConfigType, logger: Logger) { - const isFipsEnabled = config.experimental.fipsMode.enabled; - const isNodeRunningWithFipsEnabled = getFips() === 1; - - // Check if FIPS is enabled in either setting - if (isFipsEnabled || isNodeRunningWithFipsEnabled) { - // FIPS must be enabled on both or log and error an exit Kibana - if (isFipsEnabled !== isNodeRunningWithFipsEnabled) { - logger.error( - `Configuration mismatch error. xpack.security.experimental.fipsMode.enabled is set to ${isFipsEnabled} and the configured Node.js environment has FIPS ${ - isNodeRunningWithFipsEnabled ? 'enabled' : 'disabled' - }` - ); - process.exit(78); - } else { - logger.info('Kibana is running in FIPS mode.'); - } - } -} - export function createConfig( config: RawConfigType, logger: Logger, { isTLSEnabled }: { isTLSEnabled: boolean } ) { - checkFipsConfig(config, logger); - let encryptionKey = config.encryptionKey; if (encryptionKey === undefined) { logger.warn(