diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts index 0849a7523..fe7b24783 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts @@ -68,18 +68,15 @@ const awsRegionFromHeader = (authorizationHeader: string): string | null => { return null; }; - - -function isValidAwsRegion(region: (string | null)): boolean { - const validRegionPattern = new RE2('^[a-z0-9-]+$'); - if (typeof region !== 'string' || region.length === 0 || region.length > 20) { +function isValidAwsRegion(region: string | null): boolean { + const validRegionPattern = new RE2("^[a-z0-9-]+$"); + if (typeof region !== "string" || region.length === 0 || region.length > 20) { return false; } - + return validRegionPattern.test(region); } - export const identityAwsAuthServiceFactory = ({ identityAccessTokenDAL, identityAwsAuthDAL, @@ -100,7 +97,7 @@ export const identityAwsAuthServiceFactory = ({ const region = headers.Authorization ? awsRegionFromHeader(headers.Authorization) : null; if (!isValidAwsRegion(region)) { - throw new BadRequestError({message: "Invalid AWS region"}); + throw new BadRequestError({ message: "Invalid AWS region" }); } const url = region ? `https://sts.${region}.amazonaws.com` : identityAwsAuth.stsEndpoint; diff --git a/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts b/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts index 2d8283f7b..05fc7cd35 100644 --- a/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts +++ b/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts @@ -1,3 +1,4 @@ +import { MongoAbility } from "@casl/ability"; import { Knex } from "knex"; import { validate as uuidValidate } from "uuid"; @@ -21,22 +22,21 @@ import type { TFindSecretsByFolderIdsFilter, TGetSecretsDTO } from "@app/services/secret-v2-bridge/secret-v2-bridge-types"; -import { MongoAbility } from "@casl/ability"; -export const SecretDalCacheKeys = { +export const SecretServiceCacheKeys = { get productKey() { const { INFISICAL_PLATFORM_VERSION } = getConfig(); return `${ProjectType.SecretManager}:${INFISICAL_PLATFORM_VERSION || 0}`; }, getSecretDalVersion: (projectId: string) => { - return `${SecretDalCacheKeys.productKey}:${projectId}:${TableName.SecretV2}-dal-version`; + return `${SecretServiceCacheKeys.productKey}:${projectId}:${TableName.SecretV2}-dal-version`; }, getSecretsOfServiceLayer: ( projectId: string, version: number, dto: TGetSecretsDTO & { permissionRules: MongoAbility["rules"] } ) => { - return `${SecretDalCacheKeys.productKey}:${projectId}:${ + return `${SecretServiceCacheKeys.productKey}:${projectId}:${ TableName.SecretV2 }-dal:v${version}:get-secrets-service-layer:${dto.actorId}-${generateCacheKeyFromData(dto)}`; } @@ -55,7 +55,7 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { const secretOrm = ormify(db, TableName.SecretV2); const invalidateSecretCacheByProjectId = async (projectId: string) => { - const secretDalVersionKey = SecretDalCacheKeys.getSecretDalVersion(projectId); + const secretDalVersionKey = SecretServiceCacheKeys.getSecretDalVersion(projectId); await keyStore.incrementBy(secretDalVersionKey, 1); await keyStore.setExpiry(secretDalVersionKey, SECRET_DAL_VERSION_TTL); }; @@ -287,7 +287,7 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { } }; - const findByFolderId = async (dto: { folderId: string; userId?: string; tx?: Knex; useCache?: boolean }) => { + const findByFolderId = async (dto: { folderId: string; userId?: string; tx?: Knex }) => { try { const { folderId, tx } = dto; let { userId } = dto; diff --git a/backend/src/services/secret-v2-bridge/secret-v2-bridge-service.ts b/backend/src/services/secret-v2-bridge/secret-v2-bridge-service.ts index 7c8171c31..ca815c6e1 100644 --- a/backend/src/services/secret-v2-bridge/secret-v2-bridge-service.ts +++ b/backend/src/services/secret-v2-bridge/secret-v2-bridge-service.ts @@ -25,6 +25,7 @@ import { TSecretApprovalPolicyServiceFactory } from "@app/ee/services/secret-app import { TSecretApprovalRequestDALFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-dal"; import { TSecretApprovalRequestSecretDALFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-secret-dal"; import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service"; +import { TKeyStoreFactory } from "@app/keystore/keystore"; import { DatabaseErrorCode } from "@app/lib/error-codes"; import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors"; import { diff, groupBy } from "@app/lib/fn"; @@ -46,7 +47,7 @@ import { TSecretTagDALFactory } from "../secret-tag/secret-tag-dal"; import { MAX_SECRET_CACHE_BYTES, SECRET_DAL_TTL, - SecretDalCacheKeys, + SecretServiceCacheKeys, TSecretV2BridgeDALFactory } from "./secret-v2-bridge-dal"; import { @@ -81,7 +82,6 @@ import { } from "./secret-v2-bridge-types"; import { TSecretVersionV2DALFactory } from "./secret-version-dal"; import { TSecretVersionV2TagDALFactory } from "./secret-version-tag-dal"; -import { TKeyStoreFactory } from "@app/keystore/keystore"; type TSecretV2BridgeServiceFactoryDep = { secretDAL: TSecretV2BridgeDALFactory; @@ -111,7 +111,7 @@ type TSecretV2BridgeServiceFactoryDep = { >; snapshotService: Pick; resourceMetadataDAL: Pick; - keyStore: Pick; + keyStore: Pick; }; export type TSecretV2BridgeServiceFactory = ReturnType; @@ -941,9 +941,9 @@ export const secretV2BridgeServiceFactory = ({ }); throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret); - const cachedSecretDalVersion = await keyStore.getItem(SecretDalCacheKeys.getSecretDalVersion(projectId)); + const cachedSecretDalVersion = await keyStore.getItem(SecretServiceCacheKeys.getSecretDalVersion(projectId)); const secretDalVersion = Number(cachedSecretDalVersion || 0); - const cacheKey = SecretDalCacheKeys.getSecretsOfServiceLayer(projectId, secretDalVersion, { + const cacheKey = SecretServiceCacheKeys.getSecretsOfServiceLayer(projectId, secretDalVersion, { ...dto, permissionRules: permission.rules }); @@ -953,18 +953,28 @@ export const secretV2BridgeServiceFactory = ({ type: KmsDataKey.SecretManager, projectId }); + const encryptedCachedSecrets = await keyStore.getItem(cacheKey); if (encryptedCachedSecrets) { - await keyStore.setExpiry(cacheKey, SECRET_DAL_TTL); - const cachedSecrets = secretManagerDecryptor({ cipherTextBlob: Buffer.from(encryptedCachedSecrets, "base64") }); - const { secrets, imports = [] } = JSON.parse(cachedSecrets.toString("utf8")) as { - secrets: typeof decryptedSecrets; - imports: typeof importedSecrets; - }; - return { - secrets: secrets.map((el) => ({ ...el, createdAt: new Date(el.createdAt), updatedAt: new Date(el.updatedAt) })), - imports - }; + try { + await keyStore.setExpiry(cacheKey, SECRET_DAL_TTL); + const cachedSecrets = secretManagerDecryptor({ cipherTextBlob: Buffer.from(encryptedCachedSecrets, "base64") }); + const { secrets, imports = [] } = JSON.parse(cachedSecrets.toString("utf8")) as { + secrets: typeof decryptedSecrets; + imports: typeof importedSecrets; + }; + return { + secrets: secrets.map((el) => ({ + ...el, + createdAt: new Date(el.createdAt), + updatedAt: new Date(el.updatedAt) + })), + imports + }; + } catch (err) { + logger.error(err, "Secret service layer cache miss"); + await keyStore.deleteItem(cacheKey); + } } let paths: { folderId: string; path: string }[] = [];