From f22a5580a653d35cd3c86ea61b44494c5c297031 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 12 Nov 2024 02:27:38 +0400 Subject: [PATCH] requested changes --- Dockerfile.fips.standalone-infisical | 12 ++-- backend/src/ee/services/hsm/hsm-service.ts | 57 +++++++++---------- backend/src/server/app.ts | 3 +- backend/src/server/routes/v1/admin-router.ts | 1 - .../super-admin/super-admin-service.ts | 4 +- frontend/src/hooks/api/admin/types.ts | 1 - .../admin/DashboardPage/DashboardPage.tsx | 10 ++-- .../admin/DashboardPage/EncryptionPanel.tsx | 53 ++++++++++------- 8 files changed, 73 insertions(+), 68 deletions(-) diff --git a/Dockerfile.fips.standalone-infisical b/Dockerfile.fips.standalone-infisical index 53c24db5d..dfcb87deb 100644 --- a/Dockerfile.fips.standalone-infisical +++ b/Dockerfile.fips.standalone-infisical @@ -3,7 +3,7 @@ ARG POSTHOG_API_KEY=posthog-api-key ARG INTERCOM_ID=intercom-id ARG CAPTCHA_SITE_KEY=captcha-site-key -FROM --platform=linux/amd64 node:20-slim AS base +FROM node:20-slim AS base FROM base AS frontend-dependencies WORKDIR /app @@ -14,7 +14,7 @@ COPY frontend/package.json frontend/package-lock.json frontend/next.config.js ./ RUN npm ci --only-production --ignore-scripts # Rebuild the source code only when needed -FROM --platform=linux/amd64 base AS frontend-builder +FROM base AS frontend-builder WORKDIR /app # Copy dependencies @@ -39,7 +39,7 @@ ENV NEXT_PUBLIC_CAPTCHA_SITE_KEY $CAPTCHA_SITE_KEY RUN npm run build # Production image -FROM --platform=linux/amd64 base AS frontend-runner +FROM base AS frontend-runner WORKDIR /app RUN groupadd -r -g 1001 nodejs && useradd -r -u 1001 -g nodejs non-root-user @@ -61,7 +61,7 @@ ENV NEXT_TELEMETRY_DISABLED 1 ## ## BACKEND ## -FROM --platform=linux/amd64 base AS backend-build +FROM base AS backend-build ENV ChrystokiConfigurationPath=/usr/safenet/lunaclient/ @@ -85,7 +85,7 @@ RUN npm i -D tsconfig-paths RUN npm run build # Production stage -FROM --platform=linux/amd64 base AS backend-runner +FROM base AS backend-runner ENV ChrystokiConfigurationPath=/usr/safenet/lunaclient/ @@ -106,7 +106,7 @@ COPY --from=backend-build /app . RUN mkdir frontend-build # Production stage -FROM --platform=linux/amd64 base AS production +FROM base AS production # Install necessary packages RUN apt-get update && apt-get install -y \ diff --git a/backend/src/ee/services/hsm/hsm-service.ts b/backend/src/ee/services/hsm/hsm-service.ts index 6ff5665e1..a1a0773fc 100644 --- a/backend/src/ee/services/hsm/hsm-service.ts +++ b/backend/src/ee/services/hsm/hsm-service.ts @@ -27,8 +27,8 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm const HMAC_KEY_SIZE = 256; const $withSession = async (callbackWithSession: SessionCallback): Promise => { - const RETRY_INTERVAL = 300; // 300ms between attempts - const MAX_TIMEOUT = 30_000; // 30 seconds maximum total time + const RETRY_INTERVAL = 200; // 200ms between attempts + const MAX_TIMEOUT = 90_000; // 90 seconds maximum total time let sessionHandle: pkcs11js.Handle | null = null; @@ -39,7 +39,7 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm pkcs11.C_CloseSession(sessionHandle); logger.info("HSM: Terminated session successfully"); } catch (error) { - logger.error("Error during session cleanup:", error); + logger.error(error, "HSM: Failed to terminate session"); } finally { sessionHandle = null; } @@ -82,15 +82,15 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm logger.info("HSM: Successfully authenticated"); break; } catch (error) { + // Handle specific error cases if (error instanceof pkcs11js.Pkcs11Error) { - // Handle specific error cases if (error.code === pkcs11js.CKR_PIN_INCORRECT) { - logger.error(error, `Incorrect PIN detected for HSM slot ${appCfg.HSM_SLOT}`); - throw new Error("Incorrect HSM Pin detected. Please check the HSM configuration."); + // We throw instantly here to prevent further attempts, because if too many attempts are made, the HSM will potentially wipe all key material + logger.error(error, `HSM: Incorrect PIN detected for HSM slot ${appCfg.HSM_SLOT}`); + throw new Error("HSM: Incorrect HSM Pin detected. Please check the HSM configuration."); } - if (error.code === pkcs11js.CKR_USER_ALREADY_LOGGED_IN) { - logger.warn("HSM session already logged in"); + logger.warn("HSM: Session already logged in"); } } throw error; // Re-throw other errors @@ -102,7 +102,7 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm try { pkcs11.C_CloseSession(sessionHandle); } catch (closeError) { - logger.error("Error closing failed session:", closeError); + logger.error(closeError, "HSM: Failed to close session"); } sessionHandle = null; } @@ -116,7 +116,7 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm } if (sessionHandle === null) { - throw new Error("Failed to open session after maximum retries"); + throw new Error("HSM: Failed to open session after maximum retries"); } // Execute callback with session handle @@ -124,7 +124,7 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm removeSession(); return result; } catch (error) { - logger.error("Error in HSM session handling:", error); + logger.error(error, "HSM: Failed to open session"); throw error; } finally { // Ensure cleanup @@ -160,7 +160,6 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm pkcs11.C_FindObjectsFinal(sessionHandle); } } catch (error) { - logger.error("Error finding master key:", error); return null; } }; @@ -174,7 +173,7 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm } catch (error) { // If items(0) throws, it means no key was found // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-call - logger.error(error, "Error checking for HSM key presence"); + logger.error(error, "HSM: Failed while checking for HSM key presence"); if (error instanceof pkcs11js.Pkcs11Error) { if (error.code === pkcs11js.CKR_OBJECT_HANDLE_INVALID) { @@ -198,12 +197,12 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm try { const aesKey = $findKey(sessionHandle, HsmKeyType.AES); if (!aesKey) { - throw new Error("AES key not found"); + throw new Error("HSM: Encryption failed, AES key not found"); } const hmacKey = $findKey(sessionHandle, HsmKeyType.HMAC); if (!hmacKey) { - throw new Error("HMAC key not found"); + throw new Error("HSM: Encryption failed, HMAC key not found"); } const iv = Buffer.alloc(IV_LENGTH); @@ -244,8 +243,8 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm return Buffer.concat([iv, finalBuffer]); } catch (error) { - logger.error("Encryption error:", error); - throw new Error(`Encryption failed: ${(error as Error)?.message}`); + logger.error(error, "HSM: Failed to perform encryption"); + throw new Error(`HSM: Encryption failed: ${(error as Error)?.message}`); } }; @@ -261,8 +260,8 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm (encryptedBlob: Buffer, providedSession: pkcs11js.Handle): Promise; (encryptedBlob: Buffer): Promise; } = async (encryptedBlob: Buffer, providedSession?: pkcs11js.Handle) => { - if (!isInitialized) { - throw new Error("HSM service not initialized"); + if (!pkcs11 || !isInitialized) { + throw new Error("PKCS#11 module is not initialized"); } const $performDecryption = (sessionHandle: pkcs11js.Handle) => { @@ -279,12 +278,12 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm // Find the keys const aesKey = $findKey(sessionHandle, HsmKeyType.AES); if (!aesKey) { - throw new Error("AES key not found"); + throw new Error("HSM: Decryption failed, AES key not found"); } const hmacKey = $findKey(sessionHandle, HsmKeyType.HMAC); if (!hmacKey) { - throw new Error("HMAC key not found"); + throw new Error("HSM: Decryption failed, HMAC key not found"); } // Verify HMAC first @@ -333,12 +332,12 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm // We test the core functionality of the PKCS#11 module that we are using throughout Infisical. This is to ensure that the user doesn't configure a faulty or unsupported HSM device. const $testPkcs11Module = async (session: pkcs11js.Handle) => { try { - if (!isInitialized) { - throw new Error("HSM service not initialized"); + if (!pkcs11 || !isInitialized) { + throw new Error("PKCS#11 module is not initialized"); } if (!session) { - throw new Error("Session not initialized"); + throw new Error("HSM: Attempted to run test without a valid session"); } const randomData = pkcs11.C_GenerateRandom(session, Buffer.alloc(500)); @@ -350,12 +349,12 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm const decryptedDataHex = decryptedData.toString("hex"); if (randomDataHex !== decryptedDataHex && Buffer.compare(randomData, decryptedData)) { - throw new Error("Decrypted data does not match original data"); + throw new Error("HSM: Startup test failed. Decrypted data does not match original data"); } return true; } catch (error) { - logger.error(error, "Error testing PKCS#11 module"); + logger.error(error, "HSM: Error testing PKCS#11 module"); return false; } }; @@ -411,7 +410,7 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm keyTemplate ); - logger.info(`Master key created successfully with label: ${appCfg.HSM_KEY_LABEL}`); + logger.info(`HSM: Master key created successfully with label: ${appCfg.HSM_KEY_LABEL}`); } // Check if HMAC key exists, create if not @@ -435,7 +434,7 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm hmacKeyTemplate ); - logger.info(`HMAC key created successfully with label: ${appCfg.HSM_KEY_LABEL}_HMAC`); + logger.info(`HSM: HMAC key created successfully with label: ${appCfg.HSM_KEY_LABEL}_HMAC`); } // Get slot info to check supported mechanisms @@ -457,7 +456,7 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 } }: THsm } }); } catch (error) { - logger.error("Error initializing HSM service:", error); + logger.error(error, "HSM: Error initializing HSM service:"); throw error; } }; diff --git a/backend/src/server/app.ts b/backend/src/server/app.ts index 3a22aafba..6484860ea 100644 --- a/backend/src/server/app.ts +++ b/backend/src/server/app.ts @@ -43,10 +43,11 @@ type TMain = { // Run the server! export const main = async ({ db, hsmModule, auditLogDb, smtp, logger, queue, keyStore }: TMain) => { const appCfg = getConfig(); + const server = fastify({ logger: appCfg.NODE_ENV === "test" ? false : logger, trustProxy: true, - connectionTimeout: 30 * 1000, + connectionTimeout: appCfg.isHsmConfigured ? 90_000 : 30_000, ignoreTrailingSlash: true, pluginTimeout: 40_000 }).withTypeProvider(); diff --git a/backend/src/server/routes/v1/admin-router.ts b/backend/src/server/routes/v1/admin-router.ts index 9891f58e5..6ecebb274 100644 --- a/backend/src/server/routes/v1/admin-router.ts +++ b/backend/src/server/routes/v1/admin-router.ts @@ -208,7 +208,6 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => { strategies: z .object({ strategy: z.nativeEnum(RootKeyEncryptionStrategy), - name: z.string(), enabled: z.boolean() }) .array() diff --git a/backend/src/services/super-admin/super-admin-service.ts b/backend/src/services/super-admin/super-admin-service.ts index 370890a09..8ef998ac3 100644 --- a/backend/src/services/super-admin/super-admin-service.ts +++ b/backend/src/services/super-admin/super-admin-service.ts @@ -303,13 +303,12 @@ export const superAdminServiceFactory = ({ } const selectedStrategy = kmsRootCfg.encryptionStrategy; - const enabledStrategies: { enabled: boolean; strategy: RootKeyEncryptionStrategy; name: string }[] = []; + const enabledStrategies: { enabled: boolean; strategy: RootKeyEncryptionStrategy }[] = []; if (appCfg.ROOT_ENCRYPTION_KEY || appCfg.ENCRYPTION_KEY) { const basicStrategy = RootKeyEncryptionStrategy.Software; enabledStrategies.push({ - name: "Software-based Encryption", enabled: selectedStrategy === basicStrategy, strategy: basicStrategy }); @@ -318,7 +317,6 @@ export const superAdminServiceFactory = ({ const hsmStrategy = RootKeyEncryptionStrategy.HSM; enabledStrategies.push({ - name: "Hardware Security Module (HSM)", enabled: selectedStrategy === hsmStrategy, strategy: hsmStrategy }); diff --git a/frontend/src/hooks/api/admin/types.ts b/frontend/src/hooks/api/admin/types.ts index 7d35f70be..60fa3ab98 100644 --- a/frontend/src/hooks/api/admin/types.ts +++ b/frontend/src/hooks/api/admin/types.ts @@ -59,7 +59,6 @@ export type TGetServerRootKmsEncryptionDetails = { strategies: { strategy: RootKeyEncryptionStrategy; enabled: boolean; - name: string; }[]; }; diff --git a/frontend/src/views/admin/DashboardPage/DashboardPage.tsx b/frontend/src/views/admin/DashboardPage/DashboardPage.tsx index 67c2a84ca..ac87596ae 100644 --- a/frontend/src/views/admin/DashboardPage/DashboardPage.tsx +++ b/frontend/src/views/admin/DashboardPage/DashboardPage.tsx @@ -144,7 +144,7 @@ export const AdminDashboardPage = () => {
General - {!!serverRootKmsDetails && Encryption} + Encryption Authentication Rate Limit Integrations @@ -329,11 +329,9 @@ export const AdminDashboardPage = () => { - {!!serverRootKmsDetails && ( - - - - )} + + + diff --git a/frontend/src/views/admin/DashboardPage/EncryptionPanel.tsx b/frontend/src/views/admin/DashboardPage/EncryptionPanel.tsx index 8be1982d8..0383423f8 100644 --- a/frontend/src/views/admin/DashboardPage/EncryptionPanel.tsx +++ b/frontend/src/views/admin/DashboardPage/EncryptionPanel.tsx @@ -17,10 +17,15 @@ const formSchema = z.object({ encryptionStrategy: z.nativeEnum(RootKeyEncryptionStrategy) }); +const strategies: Record = { + [RootKeyEncryptionStrategy.Software]: "Software-based Encryption", + [RootKeyEncryptionStrategy.HSM]: "Hardware Security Module (HSM)" +}; + type TForm = z.infer; type Props = { - rootKmsDetails: TGetServerRootKmsEncryptionDetails; + rootKmsDetails?: TGetServerRootKmsEncryptionDetails; }; export const EncryptionPanel = ({ rootKmsDetails }: Props) => { @@ -84,27 +89,33 @@ export const EncryptionPanel = ({ rootKmsDetails }: Props) => { supported on Enterprise plans.
- ( - - - - )} - /> + + + )} + /> + )}