mirror of
https://github.com/Infisical/infisical.git
synced 2026-01-09 15:38:03 -05:00
feat(fips): fips inside
This commit is contained in:
@@ -46,3 +46,4 @@ cli/detect/config/gitleaks.toml:gcp-api-key:582
|
|||||||
.github/workflows/helm-release-infisical-core.yml:generic-api-key:47
|
.github/workflows/helm-release-infisical-core.yml:generic-api-key:47
|
||||||
backend/src/services/smtp/smtp-service.ts:generic-api-key:79
|
backend/src/services/smtp/smtp-service.ts:generic-api-key:79
|
||||||
frontend/src/components/secret-syncs/forms/SecretSyncDestinationFields/CloudflarePagesSyncFields.tsx:cloudflare-api-key:7
|
frontend/src/components/secret-syncs/forms/SecretSyncDestinationFields/CloudflarePagesSyncFields.tsx:cloudflare-api-key:7
|
||||||
|
docs/integrations/app-connections/zabbix.mdx:generic-api-key:91
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import jwt from "jsonwebtoken";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
import { seedData1 } from "@app/db/seed-data";
|
import { seedData1 } from "@app/db/seed-data";
|
||||||
import { initEnvConfig } from "@app/lib/config/env";
|
import { getDatabaseCredentials, initEnvConfig } from "@app/lib/config/env";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
import { main } from "@app/server/app";
|
import { main } from "@app/server/app";
|
||||||
import { AuthMethod, AuthTokenType } from "@app/services/auth/auth-type";
|
import { AuthMethod, AuthTokenType } from "@app/services/auth/auth-type";
|
||||||
@@ -26,16 +26,15 @@ export default {
|
|||||||
transformMode: "ssr",
|
transformMode: "ssr",
|
||||||
async setup() {
|
async setup() {
|
||||||
const logger = initLogger();
|
const logger = initLogger();
|
||||||
const { envCfg, updateRootEncryptionKey } = initEnvConfig(logger);
|
const databaseCredentials = getDatabaseCredentials(logger);
|
||||||
|
|
||||||
const db = initDbConnection({
|
const db = initDbConnection({
|
||||||
dbConnectionUri: envCfg.DB_CONNECTION_URI,
|
dbConnectionUri: databaseCredentials.dbConnectionUri,
|
||||||
dbRootCert: envCfg.DB_ROOT_CERT
|
dbRootCert: databaseCredentials.dbRootCert
|
||||||
});
|
});
|
||||||
|
|
||||||
const superAdminDAL = superAdminDALFactory(db);
|
const superAdminDAL = superAdminDALFactory(db);
|
||||||
const fipsEnabled = await crypto.initialize(superAdminDAL);
|
const envCfg = await initEnvConfig(superAdminDAL, logger);
|
||||||
if (fipsEnabled) {
|
|
||||||
updateRootEncryptionKey(envCfg.ENCRYPTION_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
const redis = buildRedisFromConfig(envCfg);
|
const redis = buildRedisFromConfig(envCfg);
|
||||||
await redis.flushdb("SYNC");
|
await redis.flushdb("SYNC");
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { inMemoryKeyStore } from "@app/keystore/memory";
|
|||||||
import { crypto } from "@app/lib/crypto/cryptography";
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { SecretKeyEncoding, TableName } from "../schemas";
|
import { SecretKeyEncoding, TableName } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig } from "./utils/env-config";
|
||||||
@@ -26,9 +27,12 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
const envConfig = getMigrationEnvConfig();
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
||||||
|
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
|
|
||||||
const projectEncryptionRingBuffer =
|
const projectEncryptionRingBuffer =
|
||||||
createCircularCache<Awaited<ReturnType<(typeof kmsService)["createCipherPairWithDataKey"]>>>(25);
|
createCircularCache<Awaited<ReturnType<(typeof kmsService)["createCipherPairWithDataKey"]>>>(25);
|
||||||
const webhooks = await knex(TableName.Webhook)
|
const webhooks = await knex(TableName.Webhook)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { crypto } from "@app/lib/crypto/cryptography";
|
|||||||
import { selectAllTableCols } from "@app/lib/knex";
|
import { selectAllTableCols } from "@app/lib/knex";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { SecretKeyEncoding, TableName } from "../schemas";
|
import { SecretKeyEncoding, TableName } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig } from "./utils/env-config";
|
||||||
@@ -29,7 +30,9 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
const envConfig = getMigrationEnvConfig();
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
||||||
|
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
const projectEncryptionRingBuffer =
|
const projectEncryptionRingBuffer =
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { crypto } from "@app/lib/crypto/cryptography";
|
|||||||
import { selectAllTableCols } from "@app/lib/knex";
|
import { selectAllTableCols } from "@app/lib/knex";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { SecretKeyEncoding, TableName } from "../schemas";
|
import { SecretKeyEncoding, TableName } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig } from "./utils/env-config";
|
||||||
@@ -23,7 +24,9 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
const envConfig = getMigrationEnvConfig();
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
||||||
|
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
const projectEncryptionRingBuffer =
|
const projectEncryptionRingBuffer =
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
|
|||||||
import { selectAllTableCols } from "@app/lib/knex";
|
import { selectAllTableCols } from "@app/lib/knex";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { SecretKeyEncoding, TableName, TOrgBots } from "../schemas";
|
import { SecretKeyEncoding, TableName, TOrgBots } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig } from "./utils/env-config";
|
||||||
@@ -54,7 +55,9 @@ const reencryptIdentityK8sAuth = async (knex: Knex) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
const envConfig = getMigrationEnvConfig();
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
||||||
|
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
const orgEncryptionRingBuffer =
|
const orgEncryptionRingBuffer =
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
|
|||||||
import { selectAllTableCols } from "@app/lib/knex";
|
import { selectAllTableCols } from "@app/lib/knex";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { SecretKeyEncoding, TableName, TOrgBots } from "../schemas";
|
import { SecretKeyEncoding, TableName, TOrgBots } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig } from "./utils/env-config";
|
||||||
@@ -34,7 +35,9 @@ const reencryptIdentityOidcAuth = async (knex: Knex) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
const envConfig = getMigrationEnvConfig();
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
||||||
|
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
const orgEncryptionRingBuffer =
|
const orgEncryptionRingBuffer =
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { SecretKeyEncoding, TableName } from "../schemas";
|
|||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig } from "./utils/env-config";
|
||||||
import { createCircularCache } from "./utils/ring-buffer";
|
import { createCircularCache } from "./utils/ring-buffer";
|
||||||
import { getMigrationEncryptionServices } from "./utils/services";
|
import { getMigrationEncryptionServices } from "./utils/services";
|
||||||
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
const BATCH_SIZE = 500;
|
const BATCH_SIZE = 500;
|
||||||
const reencryptSamlConfig = async (knex: Knex) => {
|
const reencryptSamlConfig = async (knex: Knex) => {
|
||||||
@@ -27,7 +28,8 @@ const reencryptSamlConfig = async (knex: Knex) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
const envConfig = getMigrationEnvConfig();
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
const orgEncryptionRingBuffer =
|
const orgEncryptionRingBuffer =
|
||||||
@@ -189,7 +191,8 @@ const reencryptLdapConfig = async (knex: Knex) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
const envConfig = getMigrationEnvConfig();
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
const orgEncryptionRingBuffer =
|
const orgEncryptionRingBuffer =
|
||||||
@@ -345,7 +348,8 @@ const reencryptOidcConfig = async (knex: Knex) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
const envConfig = getMigrationEnvConfig();
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
const orgEncryptionRingBuffer =
|
const orgEncryptionRingBuffer =
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { inMemoryKeyStore } from "@app/keystore/memory";
|
|||||||
import { selectAllTableCols } from "@app/lib/knex";
|
import { selectAllTableCols } from "@app/lib/knex";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { TableName } from "../schemas";
|
import { TableName } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig } from "./utils/env-config";
|
||||||
@@ -39,7 +40,8 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
const envConfig = getMigrationEnvConfig();
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { zpStr } from "@app/lib/zod";
|
import { zpStr } from "@app/lib/zod";
|
||||||
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
|
import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
const envSchema = z
|
const envSchema = z
|
||||||
.object({
|
.object({
|
||||||
@@ -35,7 +37,7 @@ const envSchema = z
|
|||||||
|
|
||||||
export type TMigrationEnvConfig = z.infer<typeof envSchema>;
|
export type TMigrationEnvConfig = z.infer<typeof envSchema>;
|
||||||
|
|
||||||
export const getMigrationEnvConfig = () => {
|
export const getMigrationEnvConfig = async (superAdminDAL: TSuperAdminDALFactory) => {
|
||||||
const parsedEnv = envSchema.safeParse(process.env);
|
const parsedEnv = envSchema.safeParse(process.env);
|
||||||
if (!parsedEnv.success) {
|
if (!parsedEnv.success) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
@@ -49,5 +51,19 @@ export const getMigrationEnvConfig = () => {
|
|||||||
process.exit(-1);
|
process.exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.freeze(parsedEnv.data);
|
let envCfg = Object.freeze(parsedEnv.data);
|
||||||
|
|
||||||
|
const fipsEnabled = await crypto.initialize(superAdminDAL);
|
||||||
|
|
||||||
|
if (fipsEnabled) {
|
||||||
|
const newEnvCfg = {
|
||||||
|
...envCfg,
|
||||||
|
ROOT_ENCRYPTION_KEY: envCfg.ENCRYPTION_KEY
|
||||||
|
};
|
||||||
|
delete newEnvCfg.ENCRYPTION_KEY;
|
||||||
|
|
||||||
|
envCfg = Object.freeze(newEnvCfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return envCfg;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -58,7 +58,8 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
|
|||||||
sshHostGroups: false,
|
sshHostGroups: false,
|
||||||
secretScanning: false,
|
secretScanning: false,
|
||||||
enterpriseSecretSyncs: false,
|
enterpriseSecretSyncs: false,
|
||||||
enterpriseAppConnections: false
|
enterpriseAppConnections: false,
|
||||||
|
fips: true
|
||||||
});
|
});
|
||||||
|
|
||||||
export const setupLicenseRequestWithStore = (
|
export const setupLicenseRequestWithStore = (
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ export type TFeatureSet = {
|
|||||||
secretScanning: false;
|
secretScanning: false;
|
||||||
enterpriseSecretSyncs: false;
|
enterpriseSecretSyncs: false;
|
||||||
enterpriseAppConnections: false;
|
enterpriseAppConnections: false;
|
||||||
|
fips: false;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TOrgPlansTableDTO = {
|
export type TOrgPlansTableDTO = {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
import { QueueWorkerProfile } from "@app/lib/types";
|
import { QueueWorkerProfile } from "@app/lib/types";
|
||||||
|
import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { BadRequestError } from "../errors";
|
import { BadRequestError } from "../errors";
|
||||||
import { removeTrailingSlash } from "../fn";
|
import { removeTrailingSlash } from "../fn";
|
||||||
@@ -349,7 +351,7 @@ export const getConfig = () => envCfg;
|
|||||||
export const getOriginalConfig = () => originalEnvConfig;
|
export const getOriginalConfig = () => originalEnvConfig;
|
||||||
|
|
||||||
// cannot import singleton logger directly as it needs config to load various transport
|
// cannot import singleton logger directly as it needs config to load various transport
|
||||||
export const initEnvConfig = (logger?: CustomLogger) => {
|
export const initEnvConfig = async (superAdminDAL?: TSuperAdminDALFactory, logger?: CustomLogger) => {
|
||||||
const parsedEnv = envSchema.safeParse(process.env);
|
const parsedEnv = envSchema.safeParse(process.env);
|
||||||
if (!parsedEnv.success) {
|
if (!parsedEnv.success) {
|
||||||
(logger ?? console).error("Invalid environment variables. Check the error below");
|
(logger ?? console).error("Invalid environment variables. Check the error below");
|
||||||
@@ -357,16 +359,50 @@ export const initEnvConfig = (logger?: CustomLogger) => {
|
|||||||
process.exit(-1);
|
process.exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = Object.freeze(parsedEnv.data);
|
if (superAdminDAL) {
|
||||||
envCfg = config;
|
const fipsEnabled = await crypto.initialize(superAdminDAL);
|
||||||
|
|
||||||
if (!originalEnvConfig) {
|
if (fipsEnabled) {
|
||||||
originalEnvConfig = config;
|
const newEnvCfg = {
|
||||||
|
...envCfg,
|
||||||
|
ROOT_ENCRYPTION_KEY: envCfg.ENCRYPTION_KEY
|
||||||
|
};
|
||||||
|
delete newEnvCfg.ENCRYPTION_KEY;
|
||||||
|
|
||||||
|
envCfg = Object.freeze(newEnvCfg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!envCfg) {
|
||||||
|
const config = Object.freeze(parsedEnv.data);
|
||||||
|
envCfg = config;
|
||||||
|
|
||||||
|
if (!originalEnvConfig) {
|
||||||
|
originalEnvConfig = config;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return envCfg;
|
return envCfg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getDatabaseCredentials = (logger?: CustomLogger) => {
|
||||||
|
const parsedEnv = envSchema.safeParse(process.env);
|
||||||
|
if (!parsedEnv.success) {
|
||||||
|
(logger ?? console).error("Invalid environment variables. Check the error below");
|
||||||
|
(logger ?? console).error(parsedEnv.error.issues);
|
||||||
|
process.exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
dbConnectionUri: envCfg.DB_CONNECTION_URI,
|
||||||
|
dbRootCert: envCfg.DB_ROOT_CERT,
|
||||||
|
readReplicas: envCfg.DB_READ_REPLICAS?.map((el) => ({
|
||||||
|
dbRootCert: el.DB_ROOT_CERT,
|
||||||
|
dbConnectionUri: el.DB_CONNECTION_URI
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// A list of environment variables that can be overwritten
|
// A list of environment variables that can be overwritten
|
||||||
export const overwriteSchema: {
|
export const overwriteSchema: {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
@@ -462,7 +498,11 @@ export const overrideEnvConfig = (config: Record<string, string>) => {
|
|||||||
const parsedResult = envSchema.safeParse(tempEnv);
|
const parsedResult = envSchema.safeParse(tempEnv);
|
||||||
|
|
||||||
if (parsedResult.success) {
|
if (parsedResult.success) {
|
||||||
envCfg = Object.freeze(parsedResult.data);
|
envCfg = Object.freeze({
|
||||||
|
...parsedResult.data,
|
||||||
|
ENCRYPTION_KEY: envCfg.ENCRYPTION_KEY,
|
||||||
|
ROOT_ENCRYPTION_KEY: envCfg.ROOT_ENCRYPTION_KEY
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import nacl from "tweetnacl";
|
|||||||
import naclUtils from "tweetnacl-util";
|
import naclUtils from "tweetnacl-util";
|
||||||
|
|
||||||
import { SecretEncryptionAlgo, SecretKeyEncoding } from "@app/db/schemas";
|
import { SecretEncryptionAlgo, SecretKeyEncoding } from "@app/db/schemas";
|
||||||
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
import { ADMIN_CONFIG_DB_UUID } from "@app/services/super-admin/super-admin-service";
|
import { ADMIN_CONFIG_DB_UUID } from "@app/services/super-admin/super-admin-service";
|
||||||
|
|
||||||
@@ -67,40 +68,101 @@ const IV_BYTES_SIZE = 12;
|
|||||||
const BLOCK_SIZE_BYTES_16 = 16;
|
const BLOCK_SIZE_BYTES_16 = 16;
|
||||||
|
|
||||||
const hasherFipsValidated = () => {
|
const hasherFipsValidated = () => {
|
||||||
const $hashPassword = (password: string, salt: string, iterations: number, keyLength: number) => {
|
const keySize = 32;
|
||||||
return new Promise<string>((resolve, reject) => {
|
|
||||||
|
// For the salt when using pkdf2, we do salt rounds^6. If the salt rounds are 10, this will result in 10^6 = 1.000.000 iterations.
|
||||||
|
// The reason for this is because pbkdf2 is not as compute intense as bcrypt, making it faster to brute-force.
|
||||||
|
// From my testing, doing salt rounds^6 brings the computational power required to a little more than bcrypt.
|
||||||
|
// OWASP recommends a minimum of 600.000 iterations for pbkdf2, so 1.000.000 is more than enough.
|
||||||
|
// Ref: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2
|
||||||
|
const MIN_COST_FACTOR = 10;
|
||||||
|
const MAX_COST_FACTOR = 20; // Iterations scales polynomial (costFactor^6), so we need an upper bound
|
||||||
|
|
||||||
|
const $calculateIterations = (costFactor: number) => {
|
||||||
|
return Math.round(costFactor ** 6);
|
||||||
|
};
|
||||||
|
|
||||||
|
const $hashPassword = (password: Buffer, salt: Buffer, iterations: number, keyLength: number) => {
|
||||||
|
return new Promise<Buffer>((resolve, reject) => {
|
||||||
crypto.pbkdf2(password, salt, iterations, keyLength, "sha256", (err, derivedKey) => {
|
crypto.pbkdf2(password, salt, iterations, keyLength, "sha256", (err, derivedKey) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return reject(err);
|
return reject(err);
|
||||||
}
|
}
|
||||||
resolve(derivedKey.toString("hex"));
|
resolve(derivedKey);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const $validatePassword = (
|
const $validatePassword = async (
|
||||||
inputPassword: string,
|
inputPassword: Buffer,
|
||||||
storedHash: string,
|
storedHash: Buffer,
|
||||||
salt: string,
|
salt: Buffer,
|
||||||
iterations: number,
|
iterations: number,
|
||||||
keyLength: number
|
keyLength: number
|
||||||
) => {
|
) => {
|
||||||
return $hashPassword(inputPassword, salt, iterations, keyLength).then((hash) => hash === storedHash);
|
const computedHash = await $hashPassword(inputPassword, salt, iterations, keyLength);
|
||||||
|
|
||||||
|
return crypto.timingSafeEqual(computedHash, storedHash);
|
||||||
};
|
};
|
||||||
|
|
||||||
const hash = async (password: string, saltRounds: number) => {
|
const hash = async (password: string, costFactor: number) => {
|
||||||
const salt = crypto.randomBytes(16).toString("hex");
|
// Strict input validation
|
||||||
const derivedKey = await $hashPassword(password, salt, saltRounds, 32);
|
if (typeof password !== "string" || password.length === 0) {
|
||||||
return `$infisical$${saltRounds}$${salt}$${derivedKey}`;
|
throw new CryptographyError({
|
||||||
|
message: "Invalid input, password must be a non-empty string"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Number.isInteger(costFactor)) {
|
||||||
|
throw new CryptographyError({
|
||||||
|
message: "Invalid cost factor, must be an integer"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (costFactor < MIN_COST_FACTOR || costFactor > MAX_COST_FACTOR) {
|
||||||
|
throw new CryptographyError({
|
||||||
|
message: `Invalid cost factor, must be between ${MIN_COST_FACTOR} and ${MAX_COST_FACTOR}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const iterations = $calculateIterations(costFactor);
|
||||||
|
|
||||||
|
const salt = crypto.randomBytes(16);
|
||||||
|
const derivedKey = await $hashPassword(Buffer.from(password), salt, iterations, keySize);
|
||||||
|
|
||||||
|
const combined = Buffer.concat([salt, derivedKey]);
|
||||||
|
return `$v1$${costFactor}$${combined.toString("base64")}`; // Store original costFactor!
|
||||||
};
|
};
|
||||||
|
|
||||||
const compare = async (password: string, hashedPassword: string) => {
|
const compare = async (password: string, hashedPassword: string) => {
|
||||||
if (!hashedPassword.startsWith("$infisical$")) {
|
try {
|
||||||
throw new Error("Invalid hash format");
|
if (!hashedPassword?.startsWith("$v1$")) return false;
|
||||||
}
|
|
||||||
|
|
||||||
const [, , iterations, salt, storedHash] = hashedPassword.split("$");
|
const parts = hashedPassword.split("$");
|
||||||
return $validatePassword(password, storedHash, salt, Number(iterations), 32);
|
if (parts.length !== 4) return false;
|
||||||
|
|
||||||
|
const [, , storedCostFactor, combined] = parts;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!Number.isInteger(Number(storedCostFactor)) ||
|
||||||
|
Number(storedCostFactor) < MIN_COST_FACTOR ||
|
||||||
|
Number(storedCostFactor) > MAX_COST_FACTOR
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const combinedBuffer = Buffer.from(combined, "base64");
|
||||||
|
const salt = combinedBuffer.subarray(0, 16);
|
||||||
|
const storedHash = combinedBuffer.subarray(16);
|
||||||
|
|
||||||
|
const iterations = $calculateIterations(Number(storedCostFactor));
|
||||||
|
|
||||||
|
const isMatch = await $validatePassword(Buffer.from(password), storedHash, salt, iterations, keySize);
|
||||||
|
|
||||||
|
return isMatch;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -216,7 +278,9 @@ const decryptAsymmetricFipsValidated = ({
|
|||||||
const final = decipher.final();
|
const final = decipher.final();
|
||||||
return Buffer.concat([plaintext, final]).toString("utf8");
|
return Buffer.concat([plaintext, final]).toString("utf8");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error("Invalid ciphertext or keys");
|
throw new CryptographyError({
|
||||||
|
message: "Invalid ciphertext or keys"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -276,7 +340,9 @@ export const computeMd5 = (message: string, digest: DigestType = DigestType.Hex)
|
|||||||
encoder = cryptoJs.enc.Base64;
|
encoder = cryptoJs.enc.Base64;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Invalid digest type: ${digest as string}`);
|
throw new CryptographyError({
|
||||||
|
message: `Invalid digest type: ${digest as string}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return cryptoJs.MD5(message).toString(encoder);
|
return cryptoJs.MD5(message).toString(encoder);
|
||||||
@@ -289,7 +355,9 @@ const cryptographyFactory = () => {
|
|||||||
|
|
||||||
const $checkIsInitialized = () => {
|
const $checkIsInitialized = () => {
|
||||||
if (!$isInitialized) {
|
if (!$isInitialized) {
|
||||||
throw new Error("Internal cryptography module is not initialized");
|
throw new CryptographyError({
|
||||||
|
message: "Internal cryptography module is not initialized"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -297,6 +365,15 @@ const cryptographyFactory = () => {
|
|||||||
$checkIsInitialized();
|
$checkIsInitialized();
|
||||||
return $fipsEnabled;
|
return $fipsEnabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const verifyFipsLicense = (licenseService: Pick<TLicenseServiceFactory, "onPremFeatures">) => {
|
||||||
|
if (isFipsModeEnabled() && !licenseService.onPremFeatures?.fips) {
|
||||||
|
throw new CryptographyError({
|
||||||
|
message: "FIPS mode is enabled but your license does not include FIPS support. Please contact support."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const $setFipsModeEnabled = (enabled: boolean) => {
|
const $setFipsModeEnabled = (enabled: boolean) => {
|
||||||
// If FIPS is enabled, we need to validate that the ENCRYPTION_KEY is in a base64 format, and is a 256-bit key.
|
// If FIPS is enabled, we need to validate that the ENCRYPTION_KEY is in a base64 format, and is a 256-bit key.
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
@@ -305,6 +382,7 @@ const cryptographyFactory = () => {
|
|||||||
if (appCfg.ENCRYPTION_KEY) {
|
if (appCfg.ENCRYPTION_KEY) {
|
||||||
// we need to validate that the ENCRYPTION_KEY is a base64 encoded 256-bit key
|
// we need to validate that the ENCRYPTION_KEY is a base64 encoded 256-bit key
|
||||||
|
|
||||||
|
// note(daniel): for some reason this resolves as true for some hex-encoded strings.
|
||||||
if (!isBase64(appCfg.ENCRYPTION_KEY)) {
|
if (!isBase64(appCfg.ENCRYPTION_KEY)) {
|
||||||
throw new CryptographyError({
|
throw new CryptographyError({
|
||||||
message:
|
message:
|
||||||
@@ -398,15 +476,8 @@ const cryptographyFactory = () => {
|
|||||||
let decipher;
|
let decipher;
|
||||||
|
|
||||||
if (keySize === SymmetricKeySize.Bits128) {
|
if (keySize === SymmetricKeySize.Bits128) {
|
||||||
if (isFipsModeEnabled()) {
|
|
||||||
throw new CryptographyError({
|
|
||||||
message: "128-bit symmetric key is not supported in FIPS mode of operation."
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not ideal: 128-bit hex key (32 chars) gets interpreted as 32 UTF-8 bytes (256 bits)
|
// Not ideal: 128-bit hex key (32 chars) gets interpreted as 32 UTF-8 bytes (256 bits)
|
||||||
// This works but reduces effective key entropy from 256 to 128 bits
|
// This works but reduces effective key entropy from 256 to 128 bits
|
||||||
// Note: Never use this for FIPS mode of operation.
|
|
||||||
decipher = crypto.createDecipheriv(SecretEncryptionAlgo.AES_256_GCM, key, Buffer.from(iv, "base64"));
|
decipher = crypto.createDecipheriv(SecretEncryptionAlgo.AES_256_GCM, key, Buffer.from(iv, "base64"));
|
||||||
} else {
|
} else {
|
||||||
const secretKey = crypto.createSecretKey(key, "base64");
|
const secretKey = crypto.createSecretKey(key, "base64");
|
||||||
@@ -425,12 +496,6 @@ const cryptographyFactory = () => {
|
|||||||
let cipher;
|
let cipher;
|
||||||
|
|
||||||
if (keySize === SymmetricKeySize.Bits128) {
|
if (keySize === SymmetricKeySize.Bits128) {
|
||||||
if (isFipsModeEnabled()) {
|
|
||||||
throw new CryptographyError({
|
|
||||||
message: "128-bit symmetric key is not supported in FIPS mode of operation."
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
iv = crypto.randomBytes(BLOCK_SIZE_BYTES_16);
|
iv = crypto.randomBytes(BLOCK_SIZE_BYTES_16);
|
||||||
cipher = crypto.createCipheriv(SecretEncryptionAlgo.AES_256_GCM, key, iv);
|
cipher = crypto.createCipheriv(SecretEncryptionAlgo.AES_256_GCM, key, iv);
|
||||||
} else {
|
} else {
|
||||||
@@ -452,6 +517,7 @@ const cryptographyFactory = () => {
|
|||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const rootEncryptionKey = appCfg.ROOT_ENCRYPTION_KEY;
|
const rootEncryptionKey = appCfg.ROOT_ENCRYPTION_KEY;
|
||||||
const encryptionKey = appCfg.ENCRYPTION_KEY;
|
const encryptionKey = appCfg.ENCRYPTION_KEY;
|
||||||
|
|
||||||
if (rootEncryptionKey) {
|
if (rootEncryptionKey) {
|
||||||
const { iv, tag, ciphertext } = encryptSymmetric({
|
const { iv, tag, ciphertext } = encryptSymmetric({
|
||||||
plaintext: data,
|
plaintext: data,
|
||||||
@@ -480,7 +546,9 @@ const cryptographyFactory = () => {
|
|||||||
encoding: SecretKeyEncoding.UTF8
|
encoding: SecretKeyEncoding.UTF8
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
throw new Error("Missing both encryption keys");
|
throw new CryptographyError({
|
||||||
|
message: "Missing both encryption keys"
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const decryptWithRootEncryptionKey = <T = string>({
|
const decryptWithRootEncryptionKey = <T = string>({
|
||||||
@@ -509,7 +577,9 @@ const cryptographyFactory = () => {
|
|||||||
const data = decryptSymmetric({ key: encryptionKey, iv, tag, ciphertext, keySize: SymmetricKeySize.Bits128 });
|
const data = decryptSymmetric({ key: encryptionKey, iv, tag, ciphertext, keySize: SymmetricKeySize.Bits128 });
|
||||||
return data as T;
|
return data as T;
|
||||||
}
|
}
|
||||||
throw new Error("Missing both encryption keys");
|
throw new CryptographyError({
|
||||||
|
message: "Missing both encryption keys"
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -540,12 +610,7 @@ const cryptographyFactory = () => {
|
|||||||
if (isFipsModeEnabled()) {
|
if (isFipsModeEnabled()) {
|
||||||
const hasher = hasherFipsValidated();
|
const hasher = hasherFipsValidated();
|
||||||
|
|
||||||
// For the salt when using pkdf2, we do salt rounds * 100.000.
|
const hash = await hasher.hash(password, saltRounds);
|
||||||
// The reason for this is because pbkdf2 is not as compute intense as bcrypt, making it faster to brute-force.
|
|
||||||
// From my testing, doing salt rounds * 100.000 brings the computational power required to roughly the same as bcrypt.
|
|
||||||
// OWASP recommends a minimum of 600.000 iterations for pbkdf2.
|
|
||||||
// Ref: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2
|
|
||||||
const hash = await hasher.hash(password, saltRounds * 100_000);
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
const hash = await bcrypt.hash(password, saltRounds);
|
const hash = await bcrypt.hash(password, saltRounds);
|
||||||
@@ -572,6 +637,7 @@ const cryptographyFactory = () => {
|
|||||||
initialize,
|
initialize,
|
||||||
isFipsModeEnabled,
|
isFipsModeEnabled,
|
||||||
hashing,
|
hashing,
|
||||||
|
verifyFipsLicense,
|
||||||
encryption,
|
encryption,
|
||||||
randomBytes: crypto.randomBytes,
|
randomBytes: crypto.randomBytes,
|
||||||
randomInt: crypto.randomInt,
|
randomInt: crypto.randomInt,
|
||||||
|
|||||||
@@ -74,10 +74,8 @@ const initTelemetryInstrumentation = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const setupTelemetry = () => {
|
const setupTelemetry = async () => {
|
||||||
const { envCfg } = initEnvConfig();
|
const envCfg = await initEnvConfig();
|
||||||
|
|
||||||
console.log("envCfg", envCfg);
|
|
||||||
|
|
||||||
if (envCfg.OTEL_TELEMETRY_COLLECTION_ENABLED) {
|
if (envCfg.OTEL_TELEMETRY_COLLECTION_ENABLED) {
|
||||||
console.log("Initializing telemetry instrumentation");
|
console.log("Initializing telemetry instrumentation");
|
||||||
|
|||||||
@@ -7,9 +7,8 @@ import { initializeHsmModule } from "@app/ee/services/hsm/hsm-fns";
|
|||||||
import { runMigrations } from "./auto-start-migrations";
|
import { runMigrations } from "./auto-start-migrations";
|
||||||
import { initAuditLogDbConnection, initDbConnection } from "./db";
|
import { initAuditLogDbConnection, initDbConnection } from "./db";
|
||||||
import { keyStoreFactory } from "./keystore/keystore";
|
import { keyStoreFactory } from "./keystore/keystore";
|
||||||
import { formatSmtpConfig, initEnvConfig } from "./lib/config/env";
|
import { formatSmtpConfig, getDatabaseCredentials, initEnvConfig } from "./lib/config/env";
|
||||||
import { buildRedisFromConfig } from "./lib/config/redis";
|
import { buildRedisFromConfig } from "./lib/config/redis";
|
||||||
import { crypto } from "./lib/crypto/cryptography";
|
|
||||||
import { removeTemporaryBaseDirectory } from "./lib/files";
|
import { removeTemporaryBaseDirectory } from "./lib/files";
|
||||||
import { initLogger } from "./lib/logger";
|
import { initLogger } from "./lib/logger";
|
||||||
import { queueServiceFactory } from "./queue";
|
import { queueServiceFactory } from "./queue";
|
||||||
@@ -22,29 +21,23 @@ dotenv.config();
|
|||||||
|
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
const logger = initLogger();
|
const logger = initLogger();
|
||||||
const { envCfg, updateRootEncryptionKey } = initEnvConfig(logger);
|
|
||||||
|
|
||||||
await removeTemporaryBaseDirectory();
|
await removeTemporaryBaseDirectory();
|
||||||
|
|
||||||
|
const databaseCredentials = getDatabaseCredentials(logger);
|
||||||
|
|
||||||
const db = initDbConnection({
|
const db = initDbConnection({
|
||||||
dbConnectionUri: envCfg.DB_CONNECTION_URI,
|
dbConnectionUri: databaseCredentials.dbConnectionUri,
|
||||||
dbRootCert: envCfg.DB_ROOT_CERT,
|
dbRootCert: databaseCredentials.dbRootCert,
|
||||||
readReplicas: envCfg.DB_READ_REPLICAS?.map((el) => ({
|
readReplicas: databaseCredentials.readReplicas
|
||||||
dbRootCert: el.DB_ROOT_CERT,
|
|
||||||
dbConnectionUri: el.DB_CONNECTION_URI
|
|
||||||
}))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const superAdminDAL = superAdminDALFactory(db);
|
const superAdminDAL = superAdminDALFactory(db);
|
||||||
const fipsEnabled = await crypto.initialize(superAdminDAL);
|
const envConfig = await initEnvConfig(superAdminDAL, logger);
|
||||||
if (fipsEnabled) {
|
|
||||||
updateRootEncryptionKey(envCfg.ENCRYPTION_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auditLogDb = envCfg.AUDIT_LOGS_DB_CONNECTION_URI
|
const auditLogDb = envConfig.AUDIT_LOGS_DB_CONNECTION_URI
|
||||||
? initAuditLogDbConnection({
|
? initAuditLogDbConnection({
|
||||||
dbConnectionUri: envCfg.AUDIT_LOGS_DB_CONNECTION_URI,
|
dbConnectionUri: envConfig.AUDIT_LOGS_DB_CONNECTION_URI,
|
||||||
dbRootCert: envCfg.AUDIT_LOGS_DB_ROOT_CERT
|
dbRootCert: envConfig.AUDIT_LOGS_DB_ROOT_CERT
|
||||||
})
|
})
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
@@ -52,17 +45,17 @@ const run = async () => {
|
|||||||
|
|
||||||
const smtp = smtpServiceFactory(formatSmtpConfig());
|
const smtp = smtpServiceFactory(formatSmtpConfig());
|
||||||
|
|
||||||
const queue = queueServiceFactory(envCfg, {
|
const queue = queueServiceFactory(envConfig, {
|
||||||
dbConnectionUrl: envCfg.DB_CONNECTION_URI,
|
dbConnectionUrl: envConfig.DB_CONNECTION_URI,
|
||||||
dbRootCert: envCfg.DB_ROOT_CERT
|
dbRootCert: envConfig.DB_ROOT_CERT
|
||||||
});
|
});
|
||||||
|
|
||||||
await queue.initialize();
|
await queue.initialize();
|
||||||
|
|
||||||
const keyStore = keyStoreFactory(envCfg);
|
const keyStore = keyStoreFactory(envConfig);
|
||||||
const redis = buildRedisFromConfig(envCfg);
|
const redis = buildRedisFromConfig(envConfig);
|
||||||
|
|
||||||
const hsmModule = initializeHsmModule(envCfg);
|
const hsmModule = initializeHsmModule(envConfig);
|
||||||
hsmModule.initialize();
|
hsmModule.initialize();
|
||||||
|
|
||||||
const server = await main({
|
const server = await main({
|
||||||
@@ -75,7 +68,7 @@ const run = async () => {
|
|||||||
queue,
|
queue,
|
||||||
keyStore,
|
keyStore,
|
||||||
redis,
|
redis,
|
||||||
envConfig: envCfg
|
envConfig
|
||||||
});
|
});
|
||||||
const bootstrap = await bootstrapCheck({ db });
|
const bootstrap = await bootstrapCheck({ db });
|
||||||
|
|
||||||
@@ -99,7 +92,7 @@ const run = async () => {
|
|||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!envCfg.isDevelopmentMode) {
|
if (!envConfig.isDevelopmentMode) {
|
||||||
process.on("uncaughtException", (error) => {
|
process.on("uncaughtException", (error) => {
|
||||||
logger.error(error, "CRITICAL ERROR: Uncaught Exception");
|
logger.error(error, "CRITICAL ERROR: Uncaught Exception");
|
||||||
});
|
});
|
||||||
@@ -110,8 +103,8 @@ const run = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await server.listen({
|
await server.listen({
|
||||||
port: envCfg.PORT,
|
port: envConfig.PORT,
|
||||||
host: envCfg.HOST,
|
host: envConfig.HOST,
|
||||||
listenTextResolver: (address) => {
|
listenTextResolver: (address) => {
|
||||||
void bootstrap();
|
void bootstrap();
|
||||||
return address;
|
return address;
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ import { trustedIpDALFactory } from "@app/ee/services/trusted-ip/trusted-ip-dal"
|
|||||||
import { trustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-service";
|
import { trustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-service";
|
||||||
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
||||||
import { getConfig, TEnvConfig } from "@app/lib/config/env";
|
import { getConfig, TEnvConfig } from "@app/lib/config/env";
|
||||||
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
import { TQueueServiceFactory } from "@app/queue";
|
import { TQueueServiceFactory } from "@app/queue";
|
||||||
import { readLimit } from "@app/server/config/rateLimiter";
|
import { readLimit } from "@app/server/config/rateLimiter";
|
||||||
@@ -1903,11 +1904,14 @@ export const registerRoutes = async (
|
|||||||
kmsService
|
kmsService
|
||||||
});
|
});
|
||||||
|
|
||||||
await superAdminService.initServerCfg();
|
|
||||||
|
|
||||||
// setup the communication with license key server
|
// setup the communication with license key server
|
||||||
await licenseService.init();
|
await licenseService.init();
|
||||||
|
|
||||||
|
// If FIPS is enabled, we check to ensure that the users license includes FIPS mode.
|
||||||
|
crypto.verifyFipsLicense(licenseService);
|
||||||
|
|
||||||
|
await superAdminService.initServerCfg();
|
||||||
|
|
||||||
// Start HSM service if it's configured/enabled.
|
// Start HSM service if it's configured/enabled.
|
||||||
await hsmService.startService();
|
await hsmService.startService();
|
||||||
|
|
||||||
|
|||||||
@@ -830,6 +830,7 @@ export const kmsServiceFactory = ({
|
|||||||
|
|
||||||
const $getBasicEncryptionKey = () => {
|
const $getBasicEncryptionKey = () => {
|
||||||
const encryptionKey = envConfig.ENCRYPTION_KEY || envConfig.ROOT_ENCRYPTION_KEY;
|
const encryptionKey = envConfig.ENCRYPTION_KEY || envConfig.ROOT_ENCRYPTION_KEY;
|
||||||
|
|
||||||
const isBase64 = !envConfig.ENCRYPTION_KEY;
|
const isBase64 = !envConfig.ENCRYPTION_KEY;
|
||||||
if (!encryptionKey)
|
if (!encryptionKey)
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
@@ -277,6 +277,7 @@ export const superAdminServiceFactory = ({
|
|||||||
|
|
||||||
const $syncEnvConfig = async () => {
|
const $syncEnvConfig = async () => {
|
||||||
const config = await getEnvOverrides();
|
const config = await getEnvOverrides();
|
||||||
|
|
||||||
overrideEnvConfig(config);
|
overrideEnvConfig(config);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -483,6 +484,7 @@ export const superAdminServiceFactory = ({
|
|||||||
userAgent
|
userAgent
|
||||||
}: TAdminSignUpDTO) => {
|
}: TAdminSignUpDTO) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
const sanitizedEmail = email.trim().toLowerCase();
|
const sanitizedEmail = email.trim().toLowerCase();
|
||||||
const existingUser = await userDAL.findOne({ username: sanitizedEmail });
|
const existingUser = await userDAL.findOne({ username: sanitizedEmail });
|
||||||
if (existingUser) throw new BadRequestError({ name: "Admin sign up", message: "User already exists" });
|
if (existingUser) throw new BadRequestError({ name: "Admin sign up", message: "User already exists" });
|
||||||
|
|||||||
Reference in New Issue
Block a user