mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-18 19:39:25 +00:00
Merge branch 'main' into feature/north-flank-app-connection
This commit is contained in:
@@ -33,6 +33,7 @@ export enum ApiDocsTags {
|
||||
LdapAuth = "LDAP Auth",
|
||||
Groups = "Groups",
|
||||
Organizations = "Organizations",
|
||||
SubOrganizations = "Sub Organizations",
|
||||
Projects = "Projects",
|
||||
ProjectUsers = "Project Users",
|
||||
ProjectGroups = "Project Groups",
|
||||
@@ -717,6 +718,21 @@ export const ORGANIZATIONS = {
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const SUB_ORGANIZATIONS = {
|
||||
CREATE: {
|
||||
name: "The name of the sub organization to create."
|
||||
},
|
||||
UPDATE: {
|
||||
name: "The name of the sub organization to update.",
|
||||
subOrgId: "The id of the sub organization to update."
|
||||
},
|
||||
LIST: {
|
||||
limit: "The number of sub organizations to return.",
|
||||
offset: "The offset to start from. If you enter 10, it will start from the 10th sub organization.",
|
||||
isAccessible: "Filter to only return sub organizations that the actor has access to."
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const PROJECTS = {
|
||||
CREATE: {
|
||||
organizationSlug: "The slug of the organization to create the project in.",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { THsmServiceFactory } from "@app/ee/services/hsm/hsm-service";
|
||||
import { crypto } from "@app/lib/crypto/cryptography";
|
||||
import { QueueWorkerProfile } from "@app/lib/types";
|
||||
import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||
@@ -8,6 +9,7 @@ import { BadRequestError } from "../errors";
|
||||
import { removeTrailingSlash } from "../fn";
|
||||
import { CustomLogger } from "../logger/logger";
|
||||
import { zpStr } from "../zod";
|
||||
import { TKmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||
|
||||
export const GITLAB_URL = "https://gitlab.com";
|
||||
|
||||
@@ -363,11 +365,6 @@ const envSchema = z
|
||||
/* INTERNAL ----------------------------------------------------------------------------- */
|
||||
INTERNAL_REGION: zpStr(z.enum(["us", "eu"]).optional())
|
||||
})
|
||||
// To ensure that basic encryption is always possible.
|
||||
.refine(
|
||||
(data) => Boolean(data.ENCRYPTION_KEY) || Boolean(data.ROOT_ENCRYPTION_KEY),
|
||||
"Either ENCRYPTION_KEY or ROOT_ENCRYPTION_KEY must be defined."
|
||||
)
|
||||
.refine(
|
||||
(data) => Boolean(data.REDIS_URL) || Boolean(data.REDIS_SENTINEL_HOSTS) || Boolean(data.REDIS_CLUSTER_HOSTS),
|
||||
"Either REDIS_URL, REDIS_SENTINEL_HOSTS or REDIS_CLUSTER_HOSTS must be defined."
|
||||
@@ -453,7 +450,12 @@ export const getConfig = () => envCfg;
|
||||
export const getOriginalConfig = () => originalEnvConfig;
|
||||
|
||||
// cannot import singleton logger directly as it needs config to load various transport
|
||||
export const initEnvConfig = async (superAdminDAL?: TSuperAdminDALFactory, logger?: CustomLogger) => {
|
||||
export const initEnvConfig = async (
|
||||
hsmService: THsmServiceFactory,
|
||||
kmsRootConfigDAL: TKmsRootConfigDALFactory,
|
||||
superAdminDAL?: TSuperAdminDALFactory,
|
||||
logger?: CustomLogger
|
||||
) => {
|
||||
const parsedEnv = envSchema.safeParse(process.env);
|
||||
if (!parsedEnv.success) {
|
||||
(logger ?? console).error("Invalid environment variables. Check the error below");
|
||||
@@ -469,7 +471,7 @@ export const initEnvConfig = async (superAdminDAL?: TSuperAdminDALFactory, logge
|
||||
}
|
||||
|
||||
if (superAdminDAL) {
|
||||
const fipsEnabled = await crypto.initialize(superAdminDAL);
|
||||
const fipsEnabled = await crypto.initialize(superAdminDAL, hsmService, kmsRootConfigDAL);
|
||||
|
||||
if (fipsEnabled) {
|
||||
const newEnvCfg = {
|
||||
@@ -532,6 +534,22 @@ export const getDatabaseCredentials = (logger?: CustomLogger) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const getHsmConfig = (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 {
|
||||
isHsmConfigured: parsedEnv.data.isHsmConfigured,
|
||||
HSM_PIN: parsedEnv.data.HSM_PIN,
|
||||
HSM_SLOT: parsedEnv.data.HSM_SLOT,
|
||||
HSM_LIB_PATH: parsedEnv.data.HSM_LIB_PATH,
|
||||
HSM_KEY_LABEL: parsedEnv.data.HSM_KEY_LABEL
|
||||
};
|
||||
};
|
||||
|
||||
// A list of environment variables that can be overwritten
|
||||
export const overwriteSchema: {
|
||||
[key: string]: {
|
||||
|
||||
@@ -9,7 +9,11 @@ import nacl from "tweetnacl";
|
||||
import naclUtils from "tweetnacl-util";
|
||||
|
||||
import { SecretEncryptionAlgo, SecretKeyEncoding } from "@app/db/schemas";
|
||||
import { isHsmActiveAndEnabled } from "@app/ee/services/hsm/hsm-fns";
|
||||
import { THsmServiceFactory } from "@app/ee/services/hsm/hsm-service";
|
||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||
import { TKmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||
import { RootKeyEncryptionStrategy } from "@app/services/kms/kms-types";
|
||||
import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||
import { ADMIN_CONFIG_DB_UUID } from "@app/services/super-admin/super-admin-service";
|
||||
|
||||
@@ -106,49 +110,73 @@ const cryptographyFactory = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const $setFipsModeEnabled = (enabled: boolean, envCfg?: Pick<TEnvConfig, "ENCRYPTION_KEY">) => {
|
||||
const $setFipsModeEnabled = async (
|
||||
enabled: boolean,
|
||||
hsmService: THsmServiceFactory,
|
||||
kmsRootConfigDAL: TKmsRootConfigDALFactory,
|
||||
envCfg?: Pick<TEnvConfig, "ENCRYPTION_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) {
|
||||
crypto.setFips(true);
|
||||
|
||||
const appCfg = envCfg || getConfig();
|
||||
|
||||
if (appCfg.ENCRYPTION_KEY) {
|
||||
// we need to validate that the ENCRYPTION_KEY is a base64 encoded 256-bit key
|
||||
const hsmStatus = await isHsmActiveAndEnabled({
|
||||
hsmService,
|
||||
kmsRootConfigDAL
|
||||
});
|
||||
|
||||
// note(daniel): for some reason this resolves as true for some hex-encoded strings.
|
||||
if (!isBase64(appCfg.ENCRYPTION_KEY)) {
|
||||
// if the encryption strategy is software - user needs to provide an encryption key
|
||||
// if the encryption strategy is null AND the hsm is not configured - user needs to provide an encryption key
|
||||
const needsEncryptionKey =
|
||||
hsmStatus.rootKmsConfigEncryptionStrategy === RootKeyEncryptionStrategy.Software ||
|
||||
(hsmStatus.rootKmsConfigEncryptionStrategy === null && !hsmStatus.isHsmConfigured);
|
||||
|
||||
// only perform encryption key validation if it's actually required.
|
||||
if (needsEncryptionKey) {
|
||||
if (appCfg.ENCRYPTION_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)) {
|
||||
throw new CryptographyError({
|
||||
message:
|
||||
"FIPS mode is enabled, but the ENCRYPTION_KEY environment variable is not a base64 encoded 256-bit key.\nYou can generate a 256-bit key using the following command: `openssl rand -base64 32`"
|
||||
});
|
||||
}
|
||||
|
||||
if (bytesToBits(Buffer.from(appCfg.ENCRYPTION_KEY, "base64").length) !== 256) {
|
||||
throw new CryptographyError({
|
||||
message:
|
||||
"FIPS mode is enabled, but the ENCRYPTION_KEY environment variable is not a 256-bit key.\nYou can generate a 256-bit key using the following command: `openssl rand -base64 32`"
|
||||
});
|
||||
}
|
||||
} else {
|
||||
throw new CryptographyError({
|
||||
message:
|
||||
"FIPS mode is enabled, but the ENCRYPTION_KEY environment variable is not a base64 encoded 256-bit key.\nYou can generate a 256-bit key using the following command: `openssl rand -base64 32`"
|
||||
"FIPS mode is enabled, but the ENCRYPTION_KEY environment variable is not set.\nYou can generate a 256-bit key using the following command: `openssl rand -base64 32`"
|
||||
});
|
||||
}
|
||||
|
||||
if (bytesToBits(Buffer.from(appCfg.ENCRYPTION_KEY, "base64").length) !== 256) {
|
||||
throw new CryptographyError({
|
||||
message:
|
||||
"FIPS mode is enabled, but the ENCRYPTION_KEY environment variable is not a 256-bit key.\nYou can generate a 256-bit key using the following command: `openssl rand -base64 32`"
|
||||
});
|
||||
}
|
||||
} else {
|
||||
throw new CryptographyError({
|
||||
message:
|
||||
"FIPS mode is enabled, but the ENCRYPTION_KEY environment variable is not set.\nYou can generate a 256-bit key using the following command: `openssl rand -base64 32`"
|
||||
});
|
||||
}
|
||||
}
|
||||
$fipsEnabled = enabled;
|
||||
$isInitialized = true;
|
||||
};
|
||||
|
||||
const initialize = async (superAdminDAL: TSuperAdminDALFactory, envCfg?: Pick<TEnvConfig, "ENCRYPTION_KEY">) => {
|
||||
const initialize = async (
|
||||
superAdminDAL: TSuperAdminDALFactory,
|
||||
hsmService: THsmServiceFactory,
|
||||
kmsRootConfigDAL: TKmsRootConfigDALFactory,
|
||||
envCfg?: Pick<TEnvConfig, "ENCRYPTION_KEY">
|
||||
) => {
|
||||
if ($isInitialized) {
|
||||
return isFipsModeEnabled();
|
||||
}
|
||||
|
||||
if (process.env.FIPS_ENABLED !== "true") {
|
||||
logger.info("Cryptography module initialized in normal operation mode.");
|
||||
$setFipsModeEnabled(false, envCfg);
|
||||
await $setFipsModeEnabled(false, hsmService, kmsRootConfigDAL, envCfg);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -158,11 +186,11 @@ const cryptographyFactory = () => {
|
||||
if (serverCfg) {
|
||||
if (serverCfg.fipsEnabled) {
|
||||
logger.info("[FIPS]: Instance is configured for FIPS mode of operation. Continuing startup with FIPS enabled.");
|
||||
$setFipsModeEnabled(true, envCfg);
|
||||
await $setFipsModeEnabled(true, hsmService, kmsRootConfigDAL, envCfg);
|
||||
return true;
|
||||
}
|
||||
logger.info("[FIPS]: Instance age predates FIPS mode inception date. Continuing without FIPS.");
|
||||
$setFipsModeEnabled(false, envCfg);
|
||||
await $setFipsModeEnabled(false, hsmService, kmsRootConfigDAL, envCfg);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -171,7 +199,7 @@ const cryptographyFactory = () => {
|
||||
// TODO(daniel): check if it's an enterprise deployment
|
||||
|
||||
// if there is no server cfg, and FIPS_MODE is `true`, its a fresh FIPS deployment. We need to set the fipsEnabled to true.
|
||||
$setFipsModeEnabled(true, envCfg);
|
||||
await $setFipsModeEnabled(true, hsmService, kmsRootConfigDAL, envCfg);
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -258,6 +286,13 @@ const cryptographyFactory = () => {
|
||||
const rootEncryptionKey = appCfg.ROOT_ENCRYPTION_KEY;
|
||||
const encryptionKey = appCfg.ENCRYPTION_KEY;
|
||||
|
||||
// Sanity check
|
||||
if (!rootEncryptionKey && !encryptionKey) {
|
||||
throw new CryptographyError({
|
||||
message: "Tried to encrypt with instance root encryption key, but no root encryption key is set."
|
||||
});
|
||||
}
|
||||
|
||||
if (rootEncryptionKey) {
|
||||
const { iv, tag, ciphertext } = encrypt({
|
||||
plaintext: data,
|
||||
@@ -303,6 +338,14 @@ const cryptographyFactory = () => {
|
||||
// the or gate is used used in migration
|
||||
const rootEncryptionKey = appCfg?.ROOT_ENCRYPTION_KEY || process.env.ROOT_ENCRYPTION_KEY;
|
||||
const encryptionKey = appCfg?.ENCRYPTION_KEY || process.env.ENCRYPTION_KEY;
|
||||
|
||||
// Sanity check
|
||||
if (!rootEncryptionKey && !encryptionKey) {
|
||||
throw new CryptographyError({
|
||||
message: "Tried to decrypt with instance root encryption key, but no root encryption key is set."
|
||||
});
|
||||
}
|
||||
|
||||
if (rootEncryptionKey && keyEncoding === SecretKeyEncoding.BASE64) {
|
||||
const data = symmetric().decrypt({
|
||||
key: rootEncryptionKey,
|
||||
|
||||
@@ -5,7 +5,7 @@ export type TGenericPermission = {
|
||||
actor: ActorType;
|
||||
actorId: string;
|
||||
actorAuthMethod: ActorAuthMethod;
|
||||
actorOrgId: string | undefined;
|
||||
actorOrgId: string;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -78,6 +78,15 @@ export type OrgServiceActor = {
|
||||
id: string;
|
||||
authMethod: ActorAuthMethod;
|
||||
orgId: string;
|
||||
rootOrgId: string;
|
||||
parentOrgId: string;
|
||||
};
|
||||
|
||||
export type ProjectServiceActor = {
|
||||
type: ActorType;
|
||||
id: string;
|
||||
authMethod: ActorAuthMethod;
|
||||
orgId: string;
|
||||
};
|
||||
|
||||
export enum QueueWorkerProfile {
|
||||
|
||||
Reference in New Issue
Block a user