mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat: added external kms router but not connected with the server yet
This commit is contained in:
1062
backend/package-lock.json
generated
1062
backend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -106,6 +106,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-iam": "^3.525.0",
|
||||
"@aws-sdk/client-kms": "^3.609.0",
|
||||
"@aws-sdk/client-secrets-manager": "^3.504.0",
|
||||
"@aws-sdk/client-sts": "^3.600.0",
|
||||
"@casl/ability": "^6.5.0",
|
||||
@@ -125,8 +126,8 @@
|
||||
"@peculiar/asn1-schema": "^2.3.8",
|
||||
"@peculiar/x509": "^1.10.0",
|
||||
"@serdnam/pino-cloudwatch-transport": "^1.0.4",
|
||||
"@team-plain/typescript-sdk": "^4.6.1",
|
||||
"@sindresorhus/slugify": "1.1.0",
|
||||
"@team-plain/typescript-sdk": "^4.6.1",
|
||||
"@ucast/mongo2js": "^1.3.4",
|
||||
"ajv": "^8.12.0",
|
||||
"argon2": "^0.31.2",
|
||||
|
||||
47
backend/src/ee/services/external-kms/external-kms-dal.ts
Normal file
47
backend/src/ee/services/external-kms/external-kms-dal.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TDbClient } from "@app/db";
|
||||
import { TableName, TKmsKeys } from "@app/db/schemas";
|
||||
import { DatabaseError } from "@app/lib/errors";
|
||||
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
||||
|
||||
export type TExternalKmsDALFactory = ReturnType<typeof externalKmsDALFactory>;
|
||||
|
||||
export const externalKmsDALFactory = (db: TDbClient) => {
|
||||
const externalKmsOrm = ormify(db, TableName.ExternalKms);
|
||||
|
||||
const find = async (filter: Partial<TKmsKeys>, tx?: Knex) => {
|
||||
try {
|
||||
const result = await (tx || db.replicaNode())(TableName.ExternalKms)
|
||||
.join(TableName.KmsKey, `${TableName.KmsKey}.id`, `${TableName.ExternalKms}.kmsKeyId`)
|
||||
.where(filter)
|
||||
.select(selectAllTableCols(TableName.KmsKey))
|
||||
.select(
|
||||
db.ref("id").withSchema(TableName.ExternalKms).as("externalKmsId"),
|
||||
db.ref("provider").withSchema(TableName.ExternalKms).as("externalKmsProvider"),
|
||||
db.ref("encryptedProviderInputs").withSchema(TableName.ExternalKms).as("externalKmsEncryptedProviderInput"),
|
||||
db.ref("status").withSchema(TableName.ExternalKms).as("externalKmsStatus"),
|
||||
db.ref("statusDetails").withSchema(TableName.ExternalKms).as("externalKmsStatusDetails")
|
||||
);
|
||||
|
||||
return result.map((el) => ({
|
||||
id: el.id,
|
||||
description: el.description,
|
||||
isDisabled: el.isDisabled,
|
||||
isReserved: el.isReserved,
|
||||
orgId: el.orgId,
|
||||
slug: el.slug,
|
||||
externalKms: {
|
||||
id: el.externalKmsId,
|
||||
provider: el.externalKmsProvider,
|
||||
status: el.externalKmsStatus,
|
||||
statusDetails: el.externalKmsStatusDetails
|
||||
}
|
||||
}));
|
||||
} catch (error) {
|
||||
throw new DatabaseError({ error, name: "Find" });
|
||||
}
|
||||
};
|
||||
|
||||
return { ...externalKmsOrm, find };
|
||||
};
|
||||
298
backend/src/ee/services/external-kms/external-kms-service.ts
Normal file
298
backend/src/ee/services/external-kms/external-kms-service.ts
Normal file
@@ -0,0 +1,298 @@
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
import slugify from "@sindresorhus/slugify";
|
||||
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
|
||||
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
||||
import { TExternalKmsDALFactory } from "./external-kms-dal";
|
||||
import {
|
||||
TCreateExternalKmsDTO,
|
||||
TDeleteExternalKmsDTO,
|
||||
TGetExternalKmsByIdDTO,
|
||||
TGetExternalKmsBySlugDTO,
|
||||
TListExternalKmsDTO,
|
||||
TUpdateExternalKmsDTO
|
||||
} from "./external-kms-types";
|
||||
import { AwsKmsProviderFactory } from "./providers/aws-kms";
|
||||
import { ExternalKmsAwsSchema, KmsProviders } from "./providers/model";
|
||||
|
||||
type TExternalKmsServiceFactoryDep = {
|
||||
externalKmsDAL: TExternalKmsDALFactory;
|
||||
kmsService: Pick<TKmsServiceFactory, "getOrgKmsKeyId" | "encrypt" | "decrypt">;
|
||||
kmsDAL: Pick<TKmsKeyDALFactory, "create" | "updateById" | "findById" | "deleteById" | "findOne">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||
};
|
||||
|
||||
export type TExternalKmsServiceFactory = ReturnType<typeof externalKmsServiceFactory>;
|
||||
|
||||
export const externalKmsServiceFactory = ({
|
||||
externalKmsDAL,
|
||||
permissionService,
|
||||
kmsService,
|
||||
kmsDAL
|
||||
}: TExternalKmsServiceFactoryDep) => {
|
||||
const create = async ({
|
||||
provider,
|
||||
description,
|
||||
actor,
|
||||
slug,
|
||||
actorId,
|
||||
actorOrgId,
|
||||
actorAuthMethod
|
||||
}: TCreateExternalKmsDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
actor,
|
||||
actorId,
|
||||
actorOrgId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
|
||||
const kmsSlug = slug ? slugify(slug) : slugify(alphaNumericNanoId(32));
|
||||
|
||||
let sanitizedProviderInput = "";
|
||||
switch (provider.type) {
|
||||
case KmsProviders.Aws:
|
||||
{
|
||||
const externalKms = await AwsKmsProviderFactory({ inputs: provider.inputs });
|
||||
await externalKms.validateConnection();
|
||||
// if missing kms key this generate a new kms key id and returns new provider input
|
||||
const newProviderInput = await externalKms.generateInputKmsKey();
|
||||
sanitizedProviderInput = JSON.stringify(newProviderInput);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new BadRequestError({ message: "external kms provided is invalid" });
|
||||
}
|
||||
|
||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(actorOrgId);
|
||||
const { cipherTextBlob: encryptedProviderInputs } = await kmsService.encrypt({
|
||||
kmsId: orgKmsKeyId,
|
||||
plainText: Buffer.from(sanitizedProviderInput, "utf8")
|
||||
});
|
||||
|
||||
const externalKms = await externalKmsDAL.transaction(async (tx) => {
|
||||
const kms = await kmsDAL.create(
|
||||
{
|
||||
isReserved: false,
|
||||
description,
|
||||
slug: kmsSlug,
|
||||
orgId: actorOrgId
|
||||
},
|
||||
tx
|
||||
);
|
||||
const externalKmsCfg = await externalKmsDAL.create(
|
||||
{
|
||||
provider: provider.type,
|
||||
encryptedProviderInputs,
|
||||
kmsKeyId: kms.id
|
||||
},
|
||||
tx
|
||||
);
|
||||
return { ...kms, external: externalKmsCfg };
|
||||
});
|
||||
|
||||
return externalKms;
|
||||
};
|
||||
|
||||
const updateById = async ({
|
||||
provider,
|
||||
description,
|
||||
actor,
|
||||
id: kmsId,
|
||||
slug,
|
||||
actorId,
|
||||
actorOrgId,
|
||||
actorAuthMethod
|
||||
}: TUpdateExternalKmsDTO) => {
|
||||
const kmsDoc = await kmsDAL.findById(kmsId);
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
actor,
|
||||
actorId,
|
||||
kmsDoc.orgId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
|
||||
const kmsSlug = slug ? slugify(slug) : undefined;
|
||||
|
||||
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
||||
if (!externalKmsDoc) throw new BadRequestError({ message: "External kms not found" });
|
||||
|
||||
const orgDefaultKmsId = await kmsService.getOrgKmsKeyId(kmsDoc.orgId);
|
||||
let sanitizedProviderInput = "";
|
||||
if (provider) {
|
||||
const decryptedProviderInputBlob = await kmsService.decrypt({
|
||||
kmsId: orgDefaultKmsId,
|
||||
cipherTextBlob: externalKmsDoc.encryptedProviderInputs
|
||||
});
|
||||
|
||||
switch (provider.type) {
|
||||
case KmsProviders.Aws:
|
||||
{
|
||||
const decryptedProviderInput = await ExternalKmsAwsSchema.parseAsync(
|
||||
JSON.parse(decryptedProviderInputBlob.toString("utf8"))
|
||||
);
|
||||
const updatedProviderInput = { ...decryptedProviderInput, ...provider.inputs };
|
||||
const externalKms = await AwsKmsProviderFactory({ inputs: updatedProviderInput });
|
||||
await externalKms.validateConnection();
|
||||
sanitizedProviderInput = JSON.stringify(updatedProviderInput);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new BadRequestError({ message: "external kms provided is invalid" });
|
||||
}
|
||||
}
|
||||
|
||||
let encryptedProviderInputs: Buffer | undefined;
|
||||
if (sanitizedProviderInput) {
|
||||
const { cipherTextBlob } = await kmsService.encrypt({
|
||||
kmsId: orgDefaultKmsId,
|
||||
plainText: Buffer.from(sanitizedProviderInput, "utf8")
|
||||
});
|
||||
encryptedProviderInputs = cipherTextBlob;
|
||||
}
|
||||
|
||||
const externalKms = await externalKmsDAL.transaction(async (tx) => {
|
||||
const kms = await kmsDAL.updateById(
|
||||
kmsDoc.id,
|
||||
{
|
||||
description,
|
||||
slug: kmsSlug
|
||||
},
|
||||
tx
|
||||
);
|
||||
if (encryptedProviderInputs) {
|
||||
const externalKmsCfg = await externalKmsDAL.updateById(
|
||||
externalKmsDoc.id,
|
||||
{
|
||||
encryptedProviderInputs
|
||||
},
|
||||
tx
|
||||
);
|
||||
return { ...kms, external: externalKmsCfg };
|
||||
}
|
||||
return { ...kms, external: externalKmsDoc };
|
||||
});
|
||||
|
||||
return externalKms;
|
||||
};
|
||||
|
||||
const deleteById = async ({ actor, id: kmsId, actorId, actorOrgId, actorAuthMethod }: TDeleteExternalKmsDTO) => {
|
||||
const kmsDoc = await kmsDAL.findById(kmsId);
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
actor,
|
||||
actorId,
|
||||
kmsDoc.orgId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
|
||||
|
||||
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
||||
if (!externalKmsDoc) throw new BadRequestError({ message: "External kms not found" });
|
||||
|
||||
const externalKms = await externalKmsDAL.transaction(async (tx) => {
|
||||
const kms = await kmsDAL.deleteById(kmsDoc.id, tx);
|
||||
return { ...kms, external: externalKmsDoc };
|
||||
});
|
||||
|
||||
return externalKms;
|
||||
};
|
||||
|
||||
const list = async ({ actor, actorId, actorOrgId, actorAuthMethod }: TListExternalKmsDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
actor,
|
||||
actorId,
|
||||
actorOrgId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
|
||||
|
||||
const externalKmsDocs = await externalKmsDAL.find({ orgId: actorOrgId });
|
||||
|
||||
return externalKmsDocs;
|
||||
};
|
||||
|
||||
const findById = async ({ actor, actorId, actorOrgId, actorAuthMethod, id: kmsId }: TGetExternalKmsByIdDTO) => {
|
||||
const kmsDoc = await kmsDAL.findById(kmsId);
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
actor,
|
||||
actorId,
|
||||
kmsDoc.orgId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
|
||||
|
||||
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
||||
if (!externalKmsDoc) throw new BadRequestError({ message: "External kms not found" });
|
||||
|
||||
const orgDefaultKmsId = await kmsService.getOrgKmsKeyId(kmsDoc.orgId);
|
||||
const decryptedProviderInputBlob = await kmsService.decrypt({
|
||||
kmsId: orgDefaultKmsId,
|
||||
cipherTextBlob: externalKmsDoc.encryptedProviderInputs
|
||||
});
|
||||
switch (externalKmsDoc.provider) {
|
||||
case KmsProviders.Aws: {
|
||||
const decryptedProviderInput = await ExternalKmsAwsSchema.parseAsync(
|
||||
JSON.parse(decryptedProviderInputBlob.toString("utf8"))
|
||||
);
|
||||
return { ...kmsDoc, external: { ...externalKmsDoc, providerInput: decryptedProviderInput } };
|
||||
}
|
||||
default:
|
||||
throw new BadRequestError({ message: "external kms provided is invalid" });
|
||||
}
|
||||
};
|
||||
|
||||
const findBySlug = async ({
|
||||
actor,
|
||||
actorId,
|
||||
actorOrgId,
|
||||
actorAuthMethod,
|
||||
slug: kmsSlug
|
||||
}: TGetExternalKmsBySlugDTO) => {
|
||||
const kmsDoc = await kmsDAL.findOne({ slug: kmsSlug, orgId: actorOrgId });
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
actor,
|
||||
actorId,
|
||||
kmsDoc.orgId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
|
||||
|
||||
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
||||
if (!externalKmsDoc) throw new BadRequestError({ message: "External kms not found" });
|
||||
|
||||
const orgDefaultKmsId = await kmsService.getOrgKmsKeyId(kmsDoc.orgId);
|
||||
const decryptedProviderInputBlob = await kmsService.decrypt({
|
||||
kmsId: orgDefaultKmsId,
|
||||
cipherTextBlob: externalKmsDoc.encryptedProviderInputs
|
||||
});
|
||||
switch (externalKmsDoc.provider) {
|
||||
case KmsProviders.Aws: {
|
||||
const decryptedProviderInput = await ExternalKmsAwsSchema.parseAsync(
|
||||
JSON.parse(decryptedProviderInputBlob.toString("utf8"))
|
||||
);
|
||||
return { ...kmsDoc, external: { ...externalKmsDoc, providerInput: decryptedProviderInput } };
|
||||
}
|
||||
default:
|
||||
throw new BadRequestError({ message: "external kms provided is invalid" });
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
create,
|
||||
updateById,
|
||||
deleteById,
|
||||
list,
|
||||
findById,
|
||||
findBySlug
|
||||
};
|
||||
};
|
||||
30
backend/src/ee/services/external-kms/external-kms-types.ts
Normal file
30
backend/src/ee/services/external-kms/external-kms-types.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { TOrgPermission } from "@app/lib/types";
|
||||
|
||||
import { TExternalKmsInputSchema, TExternalKmsInputUpdateSchema } from "./providers/model";
|
||||
|
||||
export type TCreateExternalKmsDTO = {
|
||||
slug?: string;
|
||||
description?: string;
|
||||
provider: TExternalKmsInputSchema;
|
||||
} & Omit<TOrgPermission, "orgId">;
|
||||
|
||||
export type TUpdateExternalKmsDTO = {
|
||||
id: string;
|
||||
slug?: string;
|
||||
description?: string;
|
||||
provider?: TExternalKmsInputUpdateSchema;
|
||||
} & Omit<TOrgPermission, "orgId">;
|
||||
|
||||
export type TDeleteExternalKmsDTO = {
|
||||
id: string;
|
||||
} & Omit<TOrgPermission, "orgId">;
|
||||
|
||||
export type TListExternalKmsDTO = Omit<TOrgPermission, "orgId">;
|
||||
|
||||
export type TGetExternalKmsByIdDTO = {
|
||||
id: string;
|
||||
} & Omit<TOrgPermission, "orgId">;
|
||||
|
||||
export type TGetExternalKmsBySlugDTO = {
|
||||
slug: string;
|
||||
} & Omit<TOrgPermission, "orgId">;
|
||||
102
backend/src/ee/services/external-kms/providers/aws-kms.ts
Normal file
102
backend/src/ee/services/external-kms/providers/aws-kms.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { CreateKeyCommand, DecryptCommand, DescribeKeyCommand, EncryptCommand, KMSClient } from "@aws-sdk/client-kms";
|
||||
import { AssumeRoleCommand, STSClient } from "@aws-sdk/client-sts";
|
||||
import { randomUUID } from "crypto";
|
||||
|
||||
import { ExternalKmsAwsSchema, KmsAwsCredentialType, TExternalKmsAwsSchema, TExternalKmsProviderFns } from "./model";
|
||||
|
||||
const getAwsKmsClient = async (providerInputs: TExternalKmsAwsSchema) => {
|
||||
if (providerInputs.credential.type === KmsAwsCredentialType.AssumeRole) {
|
||||
const awsCredential = providerInputs.credential.data;
|
||||
const stsClient = new STSClient({
|
||||
region: providerInputs.awsRegion
|
||||
});
|
||||
const command = new AssumeRoleCommand({
|
||||
RoleArn: awsCredential.assumeRoleArn,
|
||||
RoleSessionName: `infisical-kms-${randomUUID()}`,
|
||||
DurationSeconds: 900, // 15mins
|
||||
ExternalId: awsCredential.externalId
|
||||
});
|
||||
const response = await stsClient.send(command);
|
||||
if (!response.Credentials?.AccessKeyId || !response.Credentials?.SecretAccessKey)
|
||||
throw new Error("Failed to assume role");
|
||||
|
||||
const kmsClient = new KMSClient({
|
||||
region: providerInputs.awsRegion,
|
||||
credentials: {
|
||||
accessKeyId: response.Credentials.AccessKeyId,
|
||||
secretAccessKey: response.Credentials.SecretAccessKey,
|
||||
sessionToken: response.Credentials.SessionToken,
|
||||
expiration: response.Credentials.Expiration
|
||||
}
|
||||
});
|
||||
return kmsClient;
|
||||
}
|
||||
const awsCredential = providerInputs.credential.data;
|
||||
const kmsClient = new KMSClient({
|
||||
region: providerInputs.awsRegion,
|
||||
credentials: {
|
||||
accessKeyId: awsCredential.accessKey,
|
||||
secretAccessKey: awsCredential.secretKey
|
||||
}
|
||||
});
|
||||
return kmsClient;
|
||||
};
|
||||
|
||||
type AwsKmsProviderArgs = {
|
||||
inputs: unknown;
|
||||
};
|
||||
type TAwsKmsProviderFactoryReturn = TExternalKmsProviderFns & {
|
||||
generateInputKmsKey: () => Promise<TExternalKmsAwsSchema>;
|
||||
};
|
||||
|
||||
export const AwsKmsProviderFactory = async ({ inputs }: AwsKmsProviderArgs): Promise<TAwsKmsProviderFactoryReturn> => {
|
||||
const providerInputs = await ExternalKmsAwsSchema.parseAsync(inputs);
|
||||
const awsClient = await getAwsKmsClient(providerInputs);
|
||||
|
||||
const generateInputKmsKey = async () => {
|
||||
if (providerInputs.kmsKeyId) return providerInputs;
|
||||
|
||||
const command = new CreateKeyCommand({ Tags: [{ TagKey: "author", TagValue: "infisical" }] });
|
||||
const kmsKey = await awsClient.send(command);
|
||||
if (!kmsKey.KeyMetadata?.KeyId) throw new Error("Failed to generate kms key");
|
||||
|
||||
return { ...providerInputs, kmsKeyId: kmsKey.KeyMetadata?.KeyId };
|
||||
};
|
||||
|
||||
const validateConnection = async () => {
|
||||
const command = new DescribeKeyCommand({
|
||||
KeyId: providerInputs.kmsKeyId
|
||||
});
|
||||
const isConnected = await awsClient.send(command).then(() => true);
|
||||
return isConnected;
|
||||
};
|
||||
|
||||
const encrypt = async (data: Buffer) => {
|
||||
const command = new EncryptCommand({
|
||||
KeyId: providerInputs.kmsKeyId,
|
||||
Plaintext: data
|
||||
});
|
||||
const encryptionCommand = await awsClient.send(command);
|
||||
if (!encryptionCommand.CiphertextBlob) throw new Error("encryption failed");
|
||||
|
||||
return { encryptedBlob: Buffer.from(encryptionCommand.CiphertextBlob) };
|
||||
};
|
||||
|
||||
const decrypt = async (encryptedBlob: Buffer) => {
|
||||
const command = new DecryptCommand({
|
||||
KeyId: providerInputs.kmsKeyId,
|
||||
CiphertextBlob: encryptedBlob
|
||||
});
|
||||
const decryptionCommand = await awsClient.send(command);
|
||||
if (!decryptionCommand.Plaintext) throw new Error("decryption failed");
|
||||
|
||||
return { data: Buffer.from(decryptionCommand.Plaintext) };
|
||||
};
|
||||
|
||||
return {
|
||||
generateInputKmsKey,
|
||||
validateConnection,
|
||||
encrypt,
|
||||
decrypt
|
||||
};
|
||||
};
|
||||
61
backend/src/ee/services/external-kms/providers/model.ts
Normal file
61
backend/src/ee/services/external-kms/providers/model.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export enum KmsProviders {
|
||||
Aws = "aws"
|
||||
}
|
||||
|
||||
export enum KmsAwsCredentialType {
|
||||
AssumeRole = "assume-role",
|
||||
AccessKey = "access-key"
|
||||
}
|
||||
|
||||
export const ExternalKmsAwsSchema = z.object({
|
||||
credential: z
|
||||
.discriminatedUnion("type", [
|
||||
z.object({
|
||||
type: z.literal(KmsAwsCredentialType.AccessKey),
|
||||
data: z.object({
|
||||
accessKey: z.string().trim().min(1).describe("AWS user account access key"),
|
||||
secretKey: z.string().trim().min(1).describe("AWS user account secret key")
|
||||
})
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal(KmsAwsCredentialType.AssumeRole),
|
||||
data: z.object({
|
||||
assumeRoleArn: z.string().trim().min(1).describe("AWS user role to be assumed by infisical"),
|
||||
externalId: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
.optional()
|
||||
.describe("AWS assume role external id for furthur security in authentication")
|
||||
})
|
||||
})
|
||||
])
|
||||
.describe("AWS credential information to connect"),
|
||||
awsRegion: z.string().min(1).trim().describe("AWS region to connect"),
|
||||
kmsKeyId: z
|
||||
.string()
|
||||
.trim()
|
||||
.optional()
|
||||
.describe("A pre existing AWS KMS key id to be used for encryption. If not provided a kms key will be generated.")
|
||||
});
|
||||
export type TExternalKmsAwsSchema = z.infer<typeof ExternalKmsAwsSchema>;
|
||||
|
||||
// The root schema of the JSON
|
||||
export const ExternalKmsInputSchema = z.discriminatedUnion("type", [
|
||||
z.object({ type: z.literal(KmsProviders.Aws), inputs: ExternalKmsAwsSchema })
|
||||
]);
|
||||
export type TExternalKmsInputSchema = z.infer<typeof ExternalKmsInputSchema>;
|
||||
|
||||
export const ExternalKmsInputUpdateSchema = z.discriminatedUnion("type", [
|
||||
z.object({ type: z.literal(KmsProviders.Aws), inputs: ExternalKmsAwsSchema.partial() })
|
||||
]);
|
||||
export type TExternalKmsInputUpdateSchema = z.infer<typeof ExternalKmsInputUpdateSchema>;
|
||||
|
||||
// generic function shared by all provider
|
||||
export type TExternalKmsProviderFns = {
|
||||
validateConnection: () => Promise<boolean>;
|
||||
encrypt: (data: Buffer) => Promise<{ encryptedBlob: Buffer }>;
|
||||
decrypt: (encryptedBlob: Buffer) => Promise<{ data: Buffer }>;
|
||||
};
|
||||
@@ -109,6 +109,9 @@ export const permissionServiceFactory = ({
|
||||
authMethod: ActorAuthMethod,
|
||||
userOrgId?: string
|
||||
) => {
|
||||
// when token is scoped, ensure the passed org id is same as user org id
|
||||
if (userOrgId && userOrgId !== orgId)
|
||||
throw new BadRequestError({ message: "Invalid user token. Scoped to different organization." });
|
||||
const membership = await permissionDAL.getOrgPermission(userId, orgId);
|
||||
if (!membership) throw new UnauthorizedError({ name: "User not in org" });
|
||||
if (membership.role === OrgMembershipRole.Custom && !membership.permissions) {
|
||||
|
||||
Reference in New Issue
Block a user