mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 05:27:48 +00:00
requested changes
This commit is contained in:
@@ -16,7 +16,7 @@ import { initDbConnection } from "@app/db";
|
|||||||
import { queueServiceFactory } from "@app/queue";
|
import { queueServiceFactory } from "@app/queue";
|
||||||
import { keyStoreFactory } from "@app/keystore/keystore";
|
import { keyStoreFactory } from "@app/keystore/keystore";
|
||||||
import { Redis } from "ioredis";
|
import { Redis } from "ioredis";
|
||||||
import { initializePkcs11Module } from "@app/services/hsm/hsm-fns";
|
import { initializeHsmModule } from "@app/services/hsm/hsm-fns";
|
||||||
|
|
||||||
dotenv.config({ path: path.join(__dirname, "../../.env.test"), debug: true });
|
dotenv.config({ path: path.join(__dirname, "../../.env.test"), debug: true });
|
||||||
export default {
|
export default {
|
||||||
@@ -56,10 +56,10 @@ export default {
|
|||||||
const queue = queueServiceFactory(cfg.REDIS_URL);
|
const queue = queueServiceFactory(cfg.REDIS_URL);
|
||||||
const keyStore = keyStoreFactory(cfg.REDIS_URL);
|
const keyStore = keyStoreFactory(cfg.REDIS_URL);
|
||||||
|
|
||||||
const pkcs11Module = initializePkcs11Module();
|
const hsmModule = initializeHsmModule();
|
||||||
pkcs11Module.initialize();
|
hsmModule.initialize();
|
||||||
|
|
||||||
const server = await main({ db, smtp, logger, queue, keyStore, hsmModule: pkcs11Module.getModule() });
|
const server = await main({ db, smtp, logger, queue, keyStore, hsmModule: hsmModule.getModule() });
|
||||||
|
|
||||||
// @ts-expect-error type
|
// @ts-expect-error type
|
||||||
globalThis.testServer = server;
|
globalThis.testServer = server;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
const hasTimestampsCol = await knex.schema.hasColumn(TableName.KmsServerRootConfig, "createdAt");
|
const hasTimestampsCol = await knex.schema.hasColumn(TableName.KmsServerRootConfig, "createdAt");
|
||||||
|
|
||||||
await knex.schema.alterTable(TableName.KmsServerRootConfig, (t) => {
|
await knex.schema.alterTable(TableName.KmsServerRootConfig, (t) => {
|
||||||
if (!hasEncryptionStrategy) t.string("encryptionStrategy").defaultTo("BASIC");
|
if (!hasEncryptionStrategy) t.string("encryptionStrategy").defaultTo("SOFTWARE");
|
||||||
if (!hasTimestampsCol) t.timestamps(true, true, true);
|
if (!hasTimestampsCol) t.timestamps(true, true, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ const envSchema = z
|
|||||||
})
|
})
|
||||||
// To ensure that basic encryption is always possible.
|
// To ensure that basic encryption is always possible.
|
||||||
.refine(
|
.refine(
|
||||||
(data) => data.ENCRYPTION_KEY != null || data.ROOT_ENCRYPTION_KEY != null,
|
(data) => Boolean(data.ENCRYPTION_KEY) || Boolean(data.ROOT_ENCRYPTION_KEY),
|
||||||
"Either ENCRYPTION_KEY or ROOT_ENCRYPTION_KEY must be defined."
|
"Either ENCRYPTION_KEY or ROOT_ENCRYPTION_KEY must be defined."
|
||||||
)
|
)
|
||||||
.transform((data) => ({
|
.transform((data) => ({
|
||||||
|
|||||||
+6
-6
@@ -9,7 +9,7 @@ import { initLogger } from "./lib/logger";
|
|||||||
import { queueServiceFactory } from "./queue";
|
import { queueServiceFactory } from "./queue";
|
||||||
import { main } from "./server/app";
|
import { main } from "./server/app";
|
||||||
import { bootstrapCheck } from "./server/boot-strap-check";
|
import { bootstrapCheck } from "./server/boot-strap-check";
|
||||||
import { initializePkcs11Module } from "./services/hsm/hsm-fns";
|
import { initializeHsmModule } from "./services/hsm/hsm-fns";
|
||||||
import { smtpServiceFactory } from "./services/smtp/smtp-service";
|
import { smtpServiceFactory } from "./services/smtp/smtp-service";
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
@@ -54,17 +54,17 @@ const run = async () => {
|
|||||||
const queue = queueServiceFactory(appCfg.REDIS_URL);
|
const queue = queueServiceFactory(appCfg.REDIS_URL);
|
||||||
const keyStore = keyStoreFactory(appCfg.REDIS_URL);
|
const keyStore = keyStoreFactory(appCfg.REDIS_URL);
|
||||||
|
|
||||||
const pkcs11Module = initializePkcs11Module();
|
const hsmModule = initializeHsmModule();
|
||||||
pkcs11Module.initialize();
|
hsmModule.initialize();
|
||||||
|
|
||||||
const server = await main({ db, auditLogDb, hsmModule: pkcs11Module.getModule(), smtp, logger, queue, keyStore });
|
const server = await main({ db, auditLogDb, hsmModule: hsmModule.getModule(), smtp, logger, queue, keyStore });
|
||||||
const bootstrap = await bootstrapCheck({ db });
|
const bootstrap = await bootstrapCheck({ db });
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
process.on("SIGINT", async () => {
|
process.on("SIGINT", async () => {
|
||||||
await server.close();
|
await server.close();
|
||||||
await db.destroy();
|
await db.destroy();
|
||||||
pkcs11Module.finalize();
|
hsmModule.finalize();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ const run = async () => {
|
|||||||
process.on("SIGTERM", async () => {
|
process.on("SIGTERM", async () => {
|
||||||
await server.close();
|
await server.close();
|
||||||
await db.destroy();
|
await db.destroy();
|
||||||
pkcs11Module.finalize();
|
hsmModule.finalize();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { Logger } from "pino";
|
|||||||
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
||||||
import { getConfig, IS_PACKAGED } from "@app/lib/config/env";
|
import { getConfig, IS_PACKAGED } from "@app/lib/config/env";
|
||||||
import { TQueueServiceFactory } from "@app/queue";
|
import { TQueueServiceFactory } from "@app/queue";
|
||||||
import { HsmModule } from "@app/services/hsm/hsm-fns";
|
import { HsmModule } from "@app/services/hsm/hsm-types";
|
||||||
import { TSmtpService } from "@app/services/smtp/smtp-service";
|
import { TSmtpService } from "@app/services/smtp/smtp-service";
|
||||||
|
|
||||||
import { globalRateLimiterCfg } from "./config/rateLimiter";
|
import { globalRateLimiterCfg } from "./config/rateLimiter";
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ import { externalMigrationServiceFactory } from "@app/services/external-migratio
|
|||||||
import { groupProjectDALFactory } from "@app/services/group-project/group-project-dal";
|
import { groupProjectDALFactory } from "@app/services/group-project/group-project-dal";
|
||||||
import { groupProjectMembershipRoleDALFactory } from "@app/services/group-project/group-project-membership-role-dal";
|
import { groupProjectMembershipRoleDALFactory } from "@app/services/group-project/group-project-membership-role-dal";
|
||||||
import { groupProjectServiceFactory } from "@app/services/group-project/group-project-service";
|
import { groupProjectServiceFactory } from "@app/services/group-project/group-project-service";
|
||||||
import { HsmModule } from "@app/services/hsm/hsm-fns";
|
|
||||||
import { hsmServiceFactory } from "@app/services/hsm/hsm-service";
|
import { hsmServiceFactory } from "@app/services/hsm/hsm-service";
|
||||||
|
import { HsmModule } from "@app/services/hsm/hsm-types";
|
||||||
import { identityDALFactory } from "@app/services/identity/identity-dal";
|
import { identityDALFactory } from "@app/services/identity/identity-dal";
|
||||||
import { identityMetadataDALFactory } from "@app/services/identity/identity-metadata-dal";
|
import { identityMetadataDALFactory } from "@app/services/identity/identity-metadata-dal";
|
||||||
import { identityOrgDALFactory } from "@app/services/identity/identity-org-dal";
|
import { identityOrgDALFactory } from "@app/services/identity/identity-org-dal";
|
||||||
@@ -363,7 +363,7 @@ export const registerRoutes = async (
|
|||||||
const licenseService = licenseServiceFactory({ permissionService, orgDAL, licenseDAL, keyStore });
|
const licenseService = licenseServiceFactory({ permissionService, orgDAL, licenseDAL, keyStore });
|
||||||
|
|
||||||
const hsmService = hsmServiceFactory({
|
const hsmService = hsmServiceFactory({
|
||||||
pkcs11Module: hsmModule
|
hsmModule
|
||||||
});
|
});
|
||||||
|
|
||||||
const kmsService = kmsServiceFactory({
|
const kmsService = kmsServiceFactory({
|
||||||
|
|||||||
@@ -3,12 +3,9 @@ import * as grapheneLib from "graphene-pk11";
|
|||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
|
|
||||||
export type HsmModule = {
|
import { HsmModule } from "./hsm-types";
|
||||||
module: grapheneLib.Module | null;
|
|
||||||
graphene: typeof grapheneLib;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const initializePkcs11Module = () => {
|
export const initializeHsmModule = () => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
let module: grapheneLib.Module | null = null;
|
let module: grapheneLib.Module | null = null;
|
||||||
|
|||||||
@@ -3,21 +3,16 @@ import grapheneLib from "graphene-pk11";
|
|||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
|
|
||||||
import { HsmModule } from "./hsm-fns";
|
import { HsmModule, RequiredMechanisms } from "./hsm-types";
|
||||||
|
|
||||||
type THsmServiceFactoryDep = {
|
type THsmServiceFactoryDep = {
|
||||||
pkcs11Module: HsmModule;
|
hsmModule: HsmModule;
|
||||||
};
|
};
|
||||||
const SESSION_TIMEOUT = 5 * 60 * 1000; // 5 minutes
|
const SESSION_TIMEOUT = 5 * 60 * 1000; // 5 minutes
|
||||||
const USER_ALREADY_LOGGED_IN_ERROR = "CKR_USER_ALREADY_LOGGED_IN";
|
const USER_ALREADY_LOGGED_IN_ERROR = "CKR_USER_ALREADY_LOGGED_IN";
|
||||||
|
|
||||||
export type THsmServiceFactory = ReturnType<typeof hsmServiceFactory>;
|
export type THsmServiceFactory = ReturnType<typeof hsmServiceFactory>;
|
||||||
|
|
||||||
enum RequiredMechanisms {
|
|
||||||
AesGcm = "AES_GCM",
|
|
||||||
AesKeyWrap = "AES_KEY_WRAP"
|
|
||||||
}
|
|
||||||
|
|
||||||
class HsmSessionManager {
|
class HsmSessionManager {
|
||||||
private session: grapheneLib.Session | null = null;
|
private session: grapheneLib.Session | null = null;
|
||||||
|
|
||||||
@@ -114,7 +109,7 @@ class HsmSessionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-empty-pattern
|
// eslint-disable-next-line no-empty-pattern
|
||||||
export const hsmServiceFactory = ({ pkcs11Module: { module, graphene } }: THsmServiceFactoryDep) => {
|
export const hsmServiceFactory = ({ hsmModule: { module, graphene } }: THsmServiceFactoryDep) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
// Constants for buffer structure
|
// Constants for buffer structure
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import * as grapheneLib from "graphene-pk11";
|
||||||
|
|
||||||
|
export type HsmModule = {
|
||||||
|
module: grapheneLib.Module | null;
|
||||||
|
graphene: typeof grapheneLib;
|
||||||
|
};
|
||||||
|
|
||||||
|
export enum RequiredMechanisms {
|
||||||
|
AesGcm = "AES_GCM",
|
||||||
|
AesKeyWrap = "AES_KEY_WRAP"
|
||||||
|
}
|
||||||
@@ -629,7 +629,7 @@ export const kmsServiceFactory = ({
|
|||||||
|
|
||||||
const $decryptRootKey = async (kmsRootConfig: TKmsRootConfig) => {
|
const $decryptRootKey = async (kmsRootConfig: TKmsRootConfig) => {
|
||||||
// case 1: root key is encrypted with HSM
|
// case 1: root key is encrypted with HSM
|
||||||
if (kmsRootConfig.encryptionStrategy === RootKeyEncryptionStrategy.Hsm) {
|
if (kmsRootConfig.encryptionStrategy === RootKeyEncryptionStrategy.HSM) {
|
||||||
if (!hsmService.isActive()) {
|
if (!hsmService.isActive()) {
|
||||||
throw new Error("Unable to decrypt root KMS key. HSM service is inactive. Did you configure the HSM?");
|
throw new Error("Unable to decrypt root KMS key. HSM service is inactive. Did you configure the HSM?");
|
||||||
}
|
}
|
||||||
@@ -637,8 +637,8 @@ export const kmsServiceFactory = ({
|
|||||||
return hsmService.decrypt(kmsRootConfig.encryptedRootKey);
|
return hsmService.decrypt(kmsRootConfig.encryptedRootKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
// case 2: root key is encrypted with basic encryption
|
// case 2: root key is encrypted with software encryption
|
||||||
if (kmsRootConfig.encryptionStrategy === RootKeyEncryptionStrategy.Basic) {
|
if (kmsRootConfig.encryptionStrategy === RootKeyEncryptionStrategy.Software) {
|
||||||
const cipher = symmetricCipherService(SymmetricEncryption.AES_GCM_256);
|
const cipher = symmetricCipherService(SymmetricEncryption.AES_GCM_256);
|
||||||
const encryptionKeyBuffer = $getBasicEncryptionKey();
|
const encryptionKeyBuffer = $getBasicEncryptionKey();
|
||||||
|
|
||||||
@@ -649,14 +649,14 @@ export const kmsServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const $encryptRootKey = async (plainKeyBuffer: Buffer, strategy: RootKeyEncryptionStrategy) => {
|
const $encryptRootKey = async (plainKeyBuffer: Buffer, strategy: RootKeyEncryptionStrategy) => {
|
||||||
if (strategy === RootKeyEncryptionStrategy.Hsm) {
|
if (strategy === RootKeyEncryptionStrategy.HSM) {
|
||||||
if (!hsmService.isActive()) {
|
if (!hsmService.isActive()) {
|
||||||
throw new Error("Unable to encrypt root KMS key. HSM service is inactive. Did you configure the HSM?");
|
throw new Error("Unable to encrypt root KMS key. HSM service is inactive. Did you configure the HSM?");
|
||||||
}
|
}
|
||||||
return hsmService.encrypt(plainKeyBuffer);
|
return hsmService.encrypt(plainKeyBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strategy === RootKeyEncryptionStrategy.Basic) {
|
if (strategy === RootKeyEncryptionStrategy.Software) {
|
||||||
const cipher = symmetricCipherService(SymmetricEncryption.AES_GCM_256);
|
const cipher = symmetricCipherService(SymmetricEncryption.AES_GCM_256);
|
||||||
const encryptionKeyBuffer = $getBasicEncryptionKey();
|
const encryptionKeyBuffer = $getBasicEncryptionKey();
|
||||||
|
|
||||||
@@ -870,9 +870,7 @@ export const kmsServiceFactory = ({
|
|||||||
|
|
||||||
const decryptedRootKey = await $decryptRootKey(kmsRootConfig).catch((err) => {
|
const decryptedRootKey = await $decryptRootKey(kmsRootConfig).catch((err) => {
|
||||||
logger.error(err, `KMS: Failed to decrypt ROOT Key [strategy=${kmsRootConfig.encryptionStrategy}]`);
|
logger.error(err, `KMS: Failed to decrypt ROOT Key [strategy=${kmsRootConfig.encryptionStrategy}]`);
|
||||||
// We do not want to throw on startup. If the HSM has issues, this will throw an error, causing the entire API to shut down.
|
throw err;
|
||||||
// If the API shuts down, the user will have no way to do recovery by importing their backup decryption key and rolling back to basic encryption.
|
|
||||||
return Buffer.alloc(0);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// set the flag so that other instance nodes can start
|
// set the flag so that other instance nodes can start
|
||||||
@@ -885,7 +883,7 @@ export const kmsServiceFactory = ({
|
|||||||
// case 2: no config is found, so we create a new root key with basic encryption
|
// case 2: no config is found, so we create a new root key with basic encryption
|
||||||
logger.info("KMS: Generating new ROOT Key");
|
logger.info("KMS: Generating new ROOT Key");
|
||||||
const newRootKey = randomSecureBytes(32);
|
const newRootKey = randomSecureBytes(32);
|
||||||
const encryptedRootKey = await $encryptRootKey(newRootKey, RootKeyEncryptionStrategy.Basic).catch((err) => {
|
const encryptedRootKey = await $encryptRootKey(newRootKey, RootKeyEncryptionStrategy.Software).catch((err) => {
|
||||||
logger.error({ hsmEnabled: hsmService.isActive() }, "KMS: Failed to encrypt ROOT Key");
|
logger.error({ hsmEnabled: hsmService.isActive() }, "KMS: Failed to encrypt ROOT Key");
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
@@ -894,7 +892,7 @@ export const kmsServiceFactory = ({
|
|||||||
// @ts-expect-error id is kept as fixed for idempotence and to avoid race condition
|
// @ts-expect-error id is kept as fixed for idempotence and to avoid race condition
|
||||||
id: KMS_ROOT_CONFIG_UUID,
|
id: KMS_ROOT_CONFIG_UUID,
|
||||||
encryptedRootKey,
|
encryptedRootKey,
|
||||||
encryptionStrategy: RootKeyEncryptionStrategy.Basic
|
encryptionStrategy: RootKeyEncryptionStrategy.Software
|
||||||
});
|
});
|
||||||
|
|
||||||
// set the flag so that other instance nodes can start
|
// set the flag so that other instance nodes can start
|
||||||
|
|||||||
@@ -58,6 +58,6 @@ export type TUpdateProjectSecretManagerKmsKeyDTO = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export enum RootKeyEncryptionStrategy {
|
export enum RootKeyEncryptionStrategy {
|
||||||
Basic = "BASIC",
|
Software = "SOFTWARE",
|
||||||
Hsm = "HSM"
|
HSM = "HSM"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -306,16 +306,16 @@ export const superAdminServiceFactory = ({
|
|||||||
const enabledStrategies: { enabled: boolean; strategy: RootKeyEncryptionStrategy; name: string }[] = [];
|
const enabledStrategies: { enabled: boolean; strategy: RootKeyEncryptionStrategy; name: string }[] = [];
|
||||||
|
|
||||||
if (appCfg.ROOT_ENCRYPTION_KEY || appCfg.ENCRYPTION_KEY) {
|
if (appCfg.ROOT_ENCRYPTION_KEY || appCfg.ENCRYPTION_KEY) {
|
||||||
const basicStrategy = RootKeyEncryptionStrategy.Basic;
|
const basicStrategy = RootKeyEncryptionStrategy.Software;
|
||||||
|
|
||||||
enabledStrategies.push({
|
enabledStrategies.push({
|
||||||
name: "Regular Encryption",
|
name: "Software-based Encryption",
|
||||||
enabled: selectedStrategy === basicStrategy,
|
enabled: selectedStrategy === basicStrategy,
|
||||||
strategy: basicStrategy
|
strategy: basicStrategy
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (appCfg.isHsmConfigured) {
|
if (appCfg.isHsmConfigured) {
|
||||||
const hsmStrategy = RootKeyEncryptionStrategy.Hsm;
|
const hsmStrategy = RootKeyEncryptionStrategy.HSM;
|
||||||
|
|
||||||
enabledStrategies.push({
|
enabledStrategies.push({
|
||||||
name: "Hardware Security Module (HSM)",
|
name: "Hardware Security Module (HSM)",
|
||||||
|
|||||||
@@ -64,6 +64,6 @@ export type TGetServerRootKmsEncryptionDetails = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export enum RootKeyEncryptionStrategy {
|
export enum RootKeyEncryptionStrategy {
|
||||||
Basic = "BASIC",
|
Software = "SOFTWARE",
|
||||||
Hsm = "HSM"
|
HSM = "HSM"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import { useCallback } from "react";
|
|
||||||
|
|
||||||
export const useFileDownload = () => {
|
|
||||||
return useCallback((content: string, filename: string) => {
|
|
||||||
const downloadUrl = `data:text/plain;charset=utf-8,${encodeURIComponent(content)}`;
|
|
||||||
const link = document.createElement("a");
|
|
||||||
link.href = downloadUrl;
|
|
||||||
link.setAttribute("download", filename);
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
link.remove();
|
|
||||||
}, []);
|
|
||||||
};
|
|
||||||
@@ -38,7 +38,7 @@ export const EncryptionPanel = ({ rootKmsDetails }: Props) => {
|
|||||||
values: {
|
values: {
|
||||||
encryptionStrategy:
|
encryptionStrategy:
|
||||||
rootKmsDetails?.strategies?.find((s) => s.enabled)?.strategy ??
|
rootKmsDetails?.strategies?.find((s) => s.enabled)?.strategy ??
|
||||||
RootKeyEncryptionStrategy.Basic
|
RootKeyEncryptionStrategy.Software
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user