mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-04 19:26:19 +00:00
feat: resolved concurrent bug with kms management
This commit is contained in:
@@ -165,7 +165,8 @@ export enum SecretType {
|
|||||||
|
|
||||||
export enum ProjectVersion {
|
export enum ProjectVersion {
|
||||||
V1 = 1,
|
V1 = 1,
|
||||||
V2 = 2
|
V2 = 2,
|
||||||
|
V3 = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ProjectUpgradeStatus {
|
export enum ProjectUpgradeStatus {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export const keyStoreFactory = (redisUrl: string) => {
|
|||||||
exp: number | string,
|
exp: number | string,
|
||||||
value: string | number | Buffer,
|
value: string | number | Buffer,
|
||||||
prefix?: string
|
prefix?: string
|
||||||
) => redis.setex(prefix ? `${prefix}:${key}` : key, exp, value);
|
) => redis.set(prefix ? `${prefix}:${key}` : key, value, "EX", exp);
|
||||||
|
|
||||||
const deleteItem = async (key: string) => redis.del(key);
|
const deleteItem = async (key: string) => redis.del(key);
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ export const keyStoreFactory = (redisUrl: string) => {
|
|||||||
});
|
});
|
||||||
attempts += 1;
|
attempts += 1;
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
isReady = keyCheckCb(await getItem(key, "wait_till_ready"));
|
isReady = keyCheckCb(await getItem(key));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -620,10 +620,8 @@ export const registerRoutes = async (
|
|||||||
permissionService,
|
permissionService,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
projectQueue: projectQueueService,
|
projectQueue: projectQueueService,
|
||||||
secretBlindIndexDAL,
|
|
||||||
identityProjectDAL,
|
identityProjectDAL,
|
||||||
identityOrgMembershipDAL,
|
identityOrgMembershipDAL,
|
||||||
projectBotDAL,
|
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
userDAL,
|
userDAL,
|
||||||
projectEnvDAL,
|
projectEnvDAL,
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ export const kmsServiceFactory = ({
|
|||||||
|
|
||||||
if (!project.kmsSecretManagerKeyId) {
|
if (!project.kmsSecretManagerKeyId) {
|
||||||
const lock = await keyStore
|
const lock = await keyStore
|
||||||
.acquireLock([KeyStorePrefixes.KmsProjectKeyCreation, projectId], 3000, { retryCount: 3 })
|
.acquireLock([KeyStorePrefixes.KmsProjectKeyCreation, projectId], 3000, { retryCount: 0 })
|
||||||
.catch(() => null);
|
.catch(() => null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -399,7 +399,8 @@ export const kmsServiceFactory = ({
|
|||||||
await keyStore.waitTillReady({
|
await keyStore.waitTillReady({
|
||||||
key: `${KeyStorePrefixes.WaitUntilReadyKmsProjectKeyCreation}${projectId}`,
|
key: `${KeyStorePrefixes.WaitUntilReadyKmsProjectKeyCreation}${projectId}`,
|
||||||
keyCheckCb: (val) => val === "true",
|
keyCheckCb: (val) => val === "true",
|
||||||
waitingCb: () => logger.info("KMS. Waiting for project key to be created")
|
waitingCb: () => logger.debug("KMS. Waiting for project key to be created"),
|
||||||
|
delay: 500
|
||||||
});
|
});
|
||||||
|
|
||||||
project = await projectDAL.findById(projectId);
|
project = await projectDAL.findById(projectId);
|
||||||
@@ -460,7 +461,7 @@ export const kmsServiceFactory = ({
|
|||||||
|
|
||||||
if (!project.kmsSecretManagerEncryptedDataKey) {
|
if (!project.kmsSecretManagerEncryptedDataKey) {
|
||||||
const lock = await keyStore
|
const lock = await keyStore
|
||||||
.acquireLock([KeyStorePrefixes.KmsProjectDataKeyCreation, projectId], 3000, { retryCount: 3 })
|
.acquireLock([KeyStorePrefixes.KmsProjectDataKeyCreation, projectId], 3000, { retryCount: 0 })
|
||||||
.catch(() => null);
|
.catch(() => null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -468,7 +469,8 @@ export const kmsServiceFactory = ({
|
|||||||
await keyStore.waitTillReady({
|
await keyStore.waitTillReady({
|
||||||
key: `${KeyStorePrefixes.WaitUntilReadyKmsProjectDataKeyCreation}${projectId}`,
|
key: `${KeyStorePrefixes.WaitUntilReadyKmsProjectDataKeyCreation}${projectId}`,
|
||||||
keyCheckCb: (val) => val === "true",
|
keyCheckCb: (val) => val === "true",
|
||||||
waitingCb: () => logger.info("KMS. Waiting for project data key to be created")
|
waitingCb: () => logger.debug("KMS. Waiting for secret manager data key to be created"),
|
||||||
|
delay: 500
|
||||||
});
|
});
|
||||||
|
|
||||||
project = await projectDAL.findById(projectId);
|
project = await projectDAL.findById(projectId);
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio
|
|||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
||||||
import { isAtLeastAsPrivileged } from "@app/lib/casl";
|
import { isAtLeastAsPrivileged } from "@app/lib/casl";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
|
||||||
import { createSecretBlindIndex } from "@app/lib/crypto";
|
|
||||||
import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
|
import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
|
||||||
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
@@ -24,12 +22,10 @@ import { TIdentityProjectMembershipRoleDALFactory } from "../identity-project/id
|
|||||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||||
import { TOrgDALFactory } from "../org/org-dal";
|
import { TOrgDALFactory } from "../org/org-dal";
|
||||||
import { TOrgServiceFactory } from "../org/org-service";
|
import { TOrgServiceFactory } from "../org/org-service";
|
||||||
import { TProjectBotDALFactory } from "../project-bot/project-bot-dal";
|
|
||||||
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
|
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
|
||||||
import { TProjectKeyDALFactory } from "../project-key/project-key-dal";
|
import { TProjectKeyDALFactory } from "../project-key/project-key-dal";
|
||||||
import { TProjectMembershipDALFactory } from "../project-membership/project-membership-dal";
|
import { TProjectMembershipDALFactory } from "../project-membership/project-membership-dal";
|
||||||
import { TProjectUserMembershipRoleDALFactory } from "../project-membership/project-user-membership-role-dal";
|
import { TProjectUserMembershipRoleDALFactory } from "../project-membership/project-user-membership-role-dal";
|
||||||
import { TSecretBlindIndexDALFactory } from "../secret-blind-index/secret-blind-index-dal";
|
|
||||||
import { ROOT_FOLDER_NAME, TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
|
import { ROOT_FOLDER_NAME, TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
|
||||||
import { TUserDALFactory } from "../user/user-dal";
|
import { TUserDALFactory } from "../user/user-dal";
|
||||||
import { TProjectDALFactory } from "./project-dal";
|
import { TProjectDALFactory } from "./project-dal";
|
||||||
@@ -69,10 +65,8 @@ type TProjectServiceFactoryDep = {
|
|||||||
identityProjectDAL: TIdentityProjectDALFactory;
|
identityProjectDAL: TIdentityProjectDALFactory;
|
||||||
identityProjectMembershipRoleDAL: Pick<TIdentityProjectMembershipRoleDALFactory, "create">;
|
identityProjectMembershipRoleDAL: Pick<TIdentityProjectMembershipRoleDALFactory, "create">;
|
||||||
projectKeyDAL: Pick<TProjectKeyDALFactory, "create" | "findLatestProjectKey" | "delete" | "find" | "insertMany">;
|
projectKeyDAL: Pick<TProjectKeyDALFactory, "create" | "findLatestProjectKey" | "delete" | "find" | "insertMany">;
|
||||||
projectBotDAL: Pick<TProjectBotDALFactory, "create" | "findById" | "delete" | "findOne">;
|
|
||||||
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "create" | "findProjectGhostUser" | "findOne">;
|
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "create" | "findProjectGhostUser" | "findOne">;
|
||||||
projectUserMembershipRoleDAL: Pick<TProjectUserMembershipRoleDALFactory, "create">;
|
projectUserMembershipRoleDAL: Pick<TProjectUserMembershipRoleDALFactory, "create">;
|
||||||
secretBlindIndexDAL: Pick<TSecretBlindIndexDALFactory, "create">;
|
|
||||||
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "find">;
|
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "find">;
|
||||||
certificateDAL: Pick<TCertificateDALFactory, "find" | "countCertificatesInProject">;
|
certificateDAL: Pick<TCertificateDALFactory, "find" | "countCertificatesInProject">;
|
||||||
permissionService: TPermissionServiceFactory;
|
permissionService: TPermissionServiceFactory;
|
||||||
@@ -102,9 +96,7 @@ export const projectServiceFactory = ({
|
|||||||
folderDAL,
|
folderDAL,
|
||||||
orgService,
|
orgService,
|
||||||
identityProjectDAL,
|
identityProjectDAL,
|
||||||
projectBotDAL,
|
|
||||||
identityOrgMembershipDAL,
|
identityOrgMembershipDAL,
|
||||||
secretBlindIndexDAL,
|
|
||||||
projectMembershipDAL,
|
projectMembershipDAL,
|
||||||
projectEnvDAL,
|
projectEnvDAL,
|
||||||
licenseService,
|
licenseService,
|
||||||
@@ -138,9 +130,6 @@ export const projectServiceFactory = ({
|
|||||||
);
|
);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Workspace);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Workspace);
|
||||||
|
|
||||||
const appCfg = getConfig();
|
|
||||||
const blindIndex = createSecretBlindIndex(appCfg.ROOT_ENCRYPTION_KEY, appCfg.ENCRYPTION_KEY);
|
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(organization.id);
|
const plan = await licenseService.getPlan(organization.id);
|
||||||
if (plan.workspaceLimit !== null && plan.workspacesUsed >= plan.workspaceLimit) {
|
if (plan.workspaceLimit !== null && plan.workspacesUsed >= plan.workspaceLimit) {
|
||||||
// case: limit imposed on number of workspaces allowed
|
// case: limit imposed on number of workspaces allowed
|
||||||
@@ -168,9 +157,9 @@ export const projectServiceFactory = ({
|
|||||||
name: workspaceName,
|
name: workspaceName,
|
||||||
orgId: organization.id,
|
orgId: organization.id,
|
||||||
slug: projectSlug || slugify(`${workspaceName}-${alphaNumericNanoId(4)}`),
|
slug: projectSlug || slugify(`${workspaceName}-${alphaNumericNanoId(4)}`),
|
||||||
version: ProjectVersion.V2,
|
kmsSecretManagerKeyId: kmsKeyId,
|
||||||
pitVersionLimit: 10,
|
version: ProjectVersion.V3,
|
||||||
kmsSecretManagerKeyId: kmsKeyId
|
pitVersionLimit: 10
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -188,18 +177,6 @@ export const projectServiceFactory = ({
|
|||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
|
|
||||||
// generate the blind index for project
|
|
||||||
await secretBlindIndexDAL.create(
|
|
||||||
{
|
|
||||||
projectId: project.id,
|
|
||||||
keyEncoding: blindIndex.keyEncoding,
|
|
||||||
saltIV: blindIndex.iv,
|
|
||||||
saltTag: blindIndex.tag,
|
|
||||||
algorithm: blindIndex.algorithm,
|
|
||||||
encryptedSaltCipherText: blindIndex.ciphertext
|
|
||||||
},
|
|
||||||
tx
|
|
||||||
);
|
|
||||||
// set default environments and root folder for provided environments
|
// set default environments and root folder for provided environments
|
||||||
const envs = await projectEnvDAL.insertMany(
|
const envs = await projectEnvDAL.insertMany(
|
||||||
DEFAULT_PROJECT_ENVS.map((el, i) => ({ ...el, projectId: project.id, position: i + 1 })),
|
DEFAULT_PROJECT_ENVS.map((el, i) => ({ ...el, projectId: project.id, position: i + 1 })),
|
||||||
@@ -228,26 +205,7 @@ export const projectServiceFactory = ({
|
|||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
|
|
||||||
const { iv, tag, ciphertext, encoding, algorithm } = infisicalSymmetricEncypt(ghostUser.keys.plainPrivateKey);
|
// const { iv, tag, ciphertext, encoding, algorithm } = infisicalSymmetricEncypt(ghostUser.keys.plainPrivateKey);
|
||||||
|
|
||||||
// 5. Create & a bot for the project
|
|
||||||
await projectBotDAL.create(
|
|
||||||
{
|
|
||||||
name: "Infisical Bot (Ghost)",
|
|
||||||
projectId: project.id,
|
|
||||||
tag,
|
|
||||||
iv,
|
|
||||||
encryptedProjectKey,
|
|
||||||
encryptedProjectKeyNonce: encryptedProjectKeyIv,
|
|
||||||
encryptedPrivateKey: ciphertext,
|
|
||||||
isActive: true,
|
|
||||||
publicKey: ghostUser.keys.publicKey,
|
|
||||||
senderId: ghostUser.user.id,
|
|
||||||
algorithm,
|
|
||||||
keyEncoding: encoding
|
|
||||||
},
|
|
||||||
tx
|
|
||||||
);
|
|
||||||
|
|
||||||
// Find the ghost users latest key
|
// Find the ghost users latest key
|
||||||
const latestKey = await projectKeyDAL.findLatestProjectKey(ghostUser.user.id, project.id, tx);
|
const latestKey = await projectKeyDAL.findLatestProjectKey(ghostUser.user.id, project.id, tx);
|
||||||
|
|||||||
Reference in New Issue
Block a user