mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 09:28:06 +00:00
feat: testing v2 architecture changes and corrections as needed
This commit is contained in:
@@ -128,7 +128,7 @@ export async function up(knex: Knex): Promise<void> {
|
||||
if (!hasEncryptedAccess) t.binary("encryptedAccess");
|
||||
if (!hasEncryptedAccessId) t.binary("encryptedAccessId");
|
||||
if (!hasEncryptedRefresh) t.binary("encryptedRefresh");
|
||||
if (!hasEncryptedAwsIamAssumRole) t.binary("hasEncryptedAwsIamAssumRole");
|
||||
if (!hasEncryptedAwsIamAssumRole) t.binary("encryptedAwsIamAssumRole");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -160,7 +160,7 @@ export async function down(knex: Knex): Promise<void> {
|
||||
if (hasEncryptedAccess) t.dropColumn("encryptedAccess");
|
||||
if (hasEncryptedAccessId) t.dropColumn("encryptedAccessId");
|
||||
if (hasEncryptedRefresh) t.dropColumn("encryptedRefresh");
|
||||
if (hasEncryptedAwsIamAssumRole) t.dropColumn("hasEncryptedAwsIamAssumRole");
|
||||
if (hasEncryptedAwsIamAssumRole) t.dropColumn("encryptedAwsIamAssumRole");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export const IntegrationAuthsSchema = z.object({
|
||||
encryptedAccess: zodBuffer.nullable().optional(),
|
||||
encryptedAccessId: zodBuffer.nullable().optional(),
|
||||
encryptedRefresh: zodBuffer.nullable().optional(),
|
||||
hasEncryptedAwsIamAssumRole: zodBuffer.nullable().optional()
|
||||
encryptedAwsIamAssumRole: zodBuffer.nullable().optional()
|
||||
});
|
||||
|
||||
export type TIntegrationAuths = z.infer<typeof IntegrationAuthsSchema>;
|
||||
|
||||
@@ -12,6 +12,7 @@ import { getConfig } from "@app/lib/config/env";
|
||||
import { decryptSymmetric128BitHexKeyUTF8 } from "@app/lib/crypto";
|
||||
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
||||
import { groupBy, pick, unique } from "@app/lib/fn";
|
||||
import { setKnexStringValue } from "@app/lib/knex";
|
||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||
import { EnforcementLevel } from "@app/lib/types";
|
||||
import { ActorType } from "@app/services/auth/auth-type";
|
||||
@@ -43,8 +44,7 @@ import {
|
||||
fnSecretBulkDelete as fnSecretV2BridgeBulkDelete,
|
||||
fnSecretBulkInsert as fnSecretV2BridgeBulkInsert,
|
||||
fnSecretBulkUpdate as fnSecretV2BridgeBulkUpdate,
|
||||
getAllNestedSecretReferences as getAllNestedSecretReferencesV2Bridge,
|
||||
secretEncryptionHelper
|
||||
getAllNestedSecretReferences as getAllNestedSecretReferencesV2Bridge
|
||||
} from "@app/services/secret-v2-bridge/secret-v2-bridge-fns";
|
||||
import { TSecretVersionV2DALFactory } from "@app/services/secret-v2-bridge/secret-version-dal";
|
||||
import { TSecretVersionV2TagDALFactory } from "@app/services/secret-v2-bridge/secret-version-tag-dal";
|
||||
@@ -1086,8 +1086,14 @@ export const secretApprovalRequestServiceFactory = ({
|
||||
...createdSecrets.map((createdSecret) => ({
|
||||
op: SecretOperations.Create,
|
||||
version: 1,
|
||||
encryptedComment: secretEncryptionHelper.encryptValue(secretManagerEncryptor, createdSecret.secretComment),
|
||||
encryptedValue: secretEncryptionHelper.encryptValue(secretManagerEncryptor, createdSecret.secretValue),
|
||||
encryptedComment: setKnexStringValue(
|
||||
createdSecret.secretComment,
|
||||
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||
),
|
||||
encryptedValue: setKnexStringValue(
|
||||
createdSecret.secretValue,
|
||||
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||
),
|
||||
skipMultilineEncoding: createdSecret.skipMultilineEncoding,
|
||||
key: createdSecret.secretKey,
|
||||
type: SecretType.Shared
|
||||
@@ -1152,8 +1158,14 @@ export const secretApprovalRequestServiceFactory = ({
|
||||
return {
|
||||
...latestSecretVersions[secretId],
|
||||
key: newSecretName || secretKey,
|
||||
encryptedValue: secretEncryptionHelper.encryptValue(secretManagerEncryptor, secretValue) as Buffer,
|
||||
encryptedComment: secretEncryptionHelper.encryptValue(secretManagerEncryptor, secretComment) as Buffer,
|
||||
encryptedComment: setKnexStringValue(
|
||||
secretComment,
|
||||
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||
),
|
||||
encryptedValue: setKnexStringValue(
|
||||
secretValue,
|
||||
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||
),
|
||||
reminderRepeatDays,
|
||||
reminderNote,
|
||||
metadata,
|
||||
|
||||
@@ -12,3 +12,12 @@ export const stripUndefinedInWhere = <T extends object>(val: T): Exclude<T, unde
|
||||
});
|
||||
return copy as Exclude<T, undefined>;
|
||||
};
|
||||
|
||||
// if its undefined its skipped in knex
|
||||
// if its empty string its set as null
|
||||
// else pass to the required one
|
||||
export const setKnexStringValue = <T>(value: string | null | undefined, cb: (arg: string) => T) => {
|
||||
if (typeof value === "undefined") return;
|
||||
if (value === "" || value === null) return null;
|
||||
return cb(value);
|
||||
};
|
||||
|
||||
@@ -694,7 +694,6 @@ export const registerRoutes = async (
|
||||
integrationAuthDAL,
|
||||
integrationDAL,
|
||||
permissionService,
|
||||
projectBotDAL,
|
||||
projectBotService,
|
||||
kmsService
|
||||
});
|
||||
|
||||
@@ -13,7 +13,6 @@ import { TProjectPermission } from "@app/lib/types";
|
||||
import { TIntegrationDALFactory } from "../integration/integration-dal";
|
||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||
import { KmsDataKey } from "../kms/kms-types";
|
||||
import { TProjectBotDALFactory } from "../project-bot/project-bot-dal";
|
||||
import { TProjectBotServiceFactory } from "../project-bot/project-bot-service";
|
||||
import { getApps } from "./integration-app-list";
|
||||
import { TIntegrationAuthDALFactory } from "./integration-auth-dal";
|
||||
@@ -55,7 +54,6 @@ type TIntegrationAuthServiceFactoryDep = {
|
||||
integrationAuthDAL: TIntegrationAuthDALFactory;
|
||||
integrationDAL: Pick<TIntegrationDALFactory, "delete">;
|
||||
projectBotService: Pick<TProjectBotServiceFactory, "getBotKey">;
|
||||
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
};
|
||||
@@ -66,7 +64,6 @@ export const integrationAuthServiceFactory = ({
|
||||
permissionService,
|
||||
integrationAuthDAL,
|
||||
integrationDAL,
|
||||
projectBotDAL,
|
||||
projectBotService,
|
||||
kmsService
|
||||
}: TIntegrationAuthServiceFactoryDep) => {
|
||||
@@ -126,9 +123,6 @@ export const integrationAuthServiceFactory = ({
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
|
||||
|
||||
const bot = await projectBotDAL.findOne({ isActive: true, projectId });
|
||||
if (!bot) throw new BadRequestError({ message: "Bot must be enabled for oauth2 code token exchange" });
|
||||
|
||||
const tokenExchange = await exchangeCode({ integration, code, url });
|
||||
const updateDoc: TIntegrationAuthsInsert = {
|
||||
projectId,
|
||||
@@ -217,9 +211,6 @@ export const integrationAuthServiceFactory = ({
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
|
||||
|
||||
const bot = await projectBotDAL.findOne({ isActive: true, projectId });
|
||||
if (!bot) throw new BadRequestError({ message: "Bot must be enabled for oauth2 code token exchange" });
|
||||
|
||||
const updateDoc: TIntegrationAuthsInsert = {
|
||||
projectId,
|
||||
namespace,
|
||||
@@ -278,7 +269,7 @@ export const integrationAuthServiceFactory = ({
|
||||
const awsAssumeIamRoleArnEncrypted = secretManagerEncryptor({
|
||||
plainText: Buffer.from(awsAssumeIamRoleArn)
|
||||
}).cipherTextBlob;
|
||||
updateDoc.hasEncryptedAwsIamAssumRole = awsAssumeIamRoleArnEncrypted;
|
||||
updateDoc.encryptedAwsIamAssumRole = awsAssumeIamRoleArnEncrypted;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -338,7 +329,7 @@ export const integrationAuthServiceFactory = ({
|
||||
if (
|
||||
integrationAuth.integration === Integrations.AWS_SECRET_MANAGER &&
|
||||
(shouldUseSecretV2Bridge
|
||||
? integrationAuth.hasEncryptedAwsIamAssumRole
|
||||
? integrationAuth.encryptedAwsIamAssumRole
|
||||
: integrationAuth.awsAssumeIamRoleArnCipherText)
|
||||
) {
|
||||
return { accessToken: "", accessId: "" };
|
||||
|
||||
@@ -123,7 +123,11 @@ export const integrationDALFactory = (db: TDbClient) => {
|
||||
db.ref("keyEncoding").withSchema(TableName.IntegrationAuth).as("keyEncodingAu"),
|
||||
db.ref("awsAssumeIamRoleArnCipherText").withSchema(TableName.IntegrationAuth),
|
||||
db.ref("awsAssumeIamRoleArnIV").withSchema(TableName.IntegrationAuth),
|
||||
db.ref("awsAssumeIamRoleArnTag").withSchema(TableName.IntegrationAuth)
|
||||
db.ref("awsAssumeIamRoleArnTag").withSchema(TableName.IntegrationAuth),
|
||||
db.ref("encryptedRefresh").withSchema(TableName.IntegrationAuth),
|
||||
db.ref("encryptedAccess").withSchema(TableName.IntegrationAuth),
|
||||
db.ref("encryptedAccessId").withSchema(TableName.IntegrationAuth),
|
||||
db.ref("encryptedAwsIamAssumRole").withSchema(TableName.IntegrationAuth)
|
||||
);
|
||||
return docs.map(
|
||||
({
|
||||
@@ -152,6 +156,10 @@ export const integrationDALFactory = (db: TDbClient) => {
|
||||
awsAssumeIamRoleArnIV,
|
||||
awsAssumeIamRoleArnCipherText,
|
||||
awsAssumeIamRoleArnTag,
|
||||
encryptedAccess,
|
||||
encryptedRefresh,
|
||||
encryptedAccessId,
|
||||
encryptedAwsIamAssumRole,
|
||||
...el
|
||||
}) => ({
|
||||
...el,
|
||||
@@ -183,7 +191,11 @@ export const integrationDALFactory = (db: TDbClient) => {
|
||||
accessExpiresAt,
|
||||
awsAssumeIamRoleArnIV,
|
||||
awsAssumeIamRoleArnCipherText,
|
||||
awsAssumeIamRoleArnTag
|
||||
awsAssumeIamRoleArnTag,
|
||||
encryptedAccess,
|
||||
encryptedRefresh,
|
||||
encryptedAccessId,
|
||||
encryptedAwsIamAssumRole
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
@@ -498,7 +498,7 @@ export const secretImportServiceFactory = ({
|
||||
|
||||
const { botKey, shouldUseSecretV2Bridge } = await projectBotService.getBotKey(projectId);
|
||||
if (shouldUseSecretV2Bridge) {
|
||||
const { encryptor: secretManagerEncryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
@@ -507,8 +507,7 @@ export const secretImportServiceFactory = ({
|
||||
folderDAL,
|
||||
secretDAL: secretV2BridgeDAL,
|
||||
secretImportDAL,
|
||||
decryptor: (value) =>
|
||||
value ? secretManagerEncryptor({ plainText: value }).cipherTextBlob.toString() : undefined
|
||||
decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined)
|
||||
});
|
||||
return importedSecrets;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import { TableName, TSecretFolders, TSecretsV2 } from "@app/db/schemas";
|
||||
import { groupBy } from "@app/lib/fn";
|
||||
import { logger } from "@app/lib/logger";
|
||||
|
||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
|
||||
import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
|
||||
import { TSecretV2BridgeDALFactory } from "./secret-v2-bridge-dal";
|
||||
@@ -204,7 +203,10 @@ export const fnSecretBulkUpdate = async ({
|
||||
tags !== undefined ? { tags, secretId: newSecrets[i].id } : []
|
||||
);
|
||||
if (secsUpdatedTag.length) {
|
||||
await secretTagDAL.deleteTagsToSecretV2({ $in: { id: secsUpdatedTag.map(({ secretId }) => secretId) } }, tx);
|
||||
await secretTagDAL.deleteTagsToSecretV2(
|
||||
{ $in: { secrets_v2Id: secsUpdatedTag.map(({ secretId }) => secretId) } },
|
||||
tx
|
||||
);
|
||||
const newSecretTags = secsUpdatedTag.flatMap(({ tags: secretTags = [], secretId }) =>
|
||||
secretTags.map((tag) => ({
|
||||
[`${TableName.SecretTag}Id` as const]: tag,
|
||||
@@ -552,14 +554,3 @@ export const reshapeBridgeSecret = (
|
||||
createdAt: secret.createdAt,
|
||||
updatedAt: secret.updatedAt
|
||||
});
|
||||
|
||||
export const secretEncryptionHelper = {
|
||||
encryptValue: (encryptor: Awaited<ReturnType<TKmsServiceFactory["encryptWithKmsKey"]>>, value?: string) => {
|
||||
if (typeof value === "undefined") return;
|
||||
return encryptor({ plainText: Buffer.from(value) }).cipherTextBlob;
|
||||
},
|
||||
decryptValue: (decryptor: Awaited<ReturnType<TKmsServiceFactory["decryptWithInputKey"]>>, value?: Buffer | null) => {
|
||||
if (!value) return;
|
||||
return decryptor({ cipherTextBlob: value }).toString();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@ import { TSecretApprovalRequestSecretDALFactory } from "@app/ee/services/secret-
|
||||
import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service";
|
||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||
import { groupBy } from "@app/lib/fn";
|
||||
import { setKnexStringValue } from "@app/lib/knex";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||
|
||||
@@ -160,9 +161,10 @@ export const secretV2BridgeServiceFactory = ({
|
||||
version: 1,
|
||||
type,
|
||||
reminderRepeatDays: el.secretReminderRepeatDays,
|
||||
encryptedComment: el.secretComment
|
||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretComment) }).cipherTextBlob
|
||||
: undefined,
|
||||
encryptedComment: setKnexStringValue(
|
||||
el.secretComment,
|
||||
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||
),
|
||||
encryptedValue: el.secretValue
|
||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretValue) }).cipherTextBlob
|
||||
: undefined,
|
||||
@@ -265,7 +267,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
|
||||
if (inputSecret.newSecretName) {
|
||||
const doesNewNameSecretExist = await secretDAL.findOne({
|
||||
key: inputSecret.secretName,
|
||||
key: inputSecret.newSecretName,
|
||||
type: SecretType.Shared,
|
||||
folderId
|
||||
});
|
||||
@@ -299,9 +301,10 @@ export const secretV2BridgeServiceFactory = ({
|
||||
filter: { id: secretId },
|
||||
data: {
|
||||
reminderRepeatDays: inputSecret.secretReminderRepeatDays,
|
||||
encryptedComment: inputSecret.secretComment
|
||||
? secretManagerEncryptor({ plainText: Buffer.from(inputSecret.secretComment) }).cipherTextBlob
|
||||
: undefined,
|
||||
encryptedComment: setKnexStringValue(
|
||||
inputSecret.secretComment,
|
||||
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||
),
|
||||
reminderNote: inputSecret.secretReminderNote,
|
||||
skipMultilineEncoding: inputSecret.skipMultilineEncoding,
|
||||
key: inputSecret.newSecretName || secretName,
|
||||
@@ -732,9 +735,10 @@ export const secretV2BridgeServiceFactory = ({
|
||||
fnSecretBulkInsert({
|
||||
inputSecrets: inputSecrets.map((el) => ({
|
||||
version: 1,
|
||||
encryptedComment: el.secretComment
|
||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretComment) }).cipherTextBlob
|
||||
: undefined,
|
||||
encryptedComment: setKnexStringValue(
|
||||
el.secretComment,
|
||||
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||
),
|
||||
encryptedValue: el.secretValue
|
||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretValue) }).cipherTextBlob
|
||||
: undefined,
|
||||
@@ -821,7 +825,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
const secrets = await secretDAL.findBySecretKeys(
|
||||
folderId,
|
||||
secretsWithNewName.map((el) => ({
|
||||
key: el.secretKey,
|
||||
key: el.newSecretName as string,
|
||||
type: SecretType.Shared
|
||||
}))
|
||||
);
|
||||
@@ -856,9 +860,10 @@ export const secretV2BridgeServiceFactory = ({
|
||||
filter: { id: originalSecret.id, type: SecretType.Shared },
|
||||
data: {
|
||||
reminderRepeatDays: el.secretReminderRepeatDays,
|
||||
encryptedComment: el.secretComment
|
||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretComment) }).cipherTextBlob
|
||||
: undefined,
|
||||
encryptedComment: setKnexStringValue(
|
||||
el.secretComment,
|
||||
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||
),
|
||||
reminderNote: el.secretReminderNote,
|
||||
skipMultilineEncoding: el.skipMultilineEncoding,
|
||||
key: el.newSecretName || el.secretKey,
|
||||
|
||||
@@ -635,9 +635,9 @@ export const secretQueueFactory = ({
|
||||
);
|
||||
let awsAssumeRoleArn = null;
|
||||
if (shouldUseSecretV2Bridge) {
|
||||
if (integrationAuth.awsAssumeIamRoleArnCipherText) {
|
||||
if (integrationAuth.encryptedAwsIamAssumRole) {
|
||||
awsAssumeRoleArn = secretManagerDecryptor({
|
||||
cipherTextBlob: Buffer.from(integrationAuth.awsAssumeIamRoleArnCipherText)
|
||||
cipherTextBlob: Buffer.from(integrationAuth.encryptedAwsIamAssumRole)
|
||||
}).toString();
|
||||
}
|
||||
} else if (
|
||||
|
||||
Reference in New Issue
Block a user