mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 11:38:55 +00:00
Move ssh back to project level
This commit is contained in:
@@ -27,10 +27,7 @@ export enum OrgPermissionSubjects {
|
||||
Kms = "kms",
|
||||
AdminConsole = "organization-admin-console",
|
||||
AuditLogs = "audit-logs",
|
||||
ProjectTemplates = "project-templates",
|
||||
SshCertificates = "ssh-certificates",
|
||||
SshCertificateAuthorities = "ssh-certificate-authorities",
|
||||
SshCertificateTemplates = "ssh-certificate-templates"
|
||||
ProjectTemplates = "project-templates"
|
||||
}
|
||||
|
||||
export type OrgPermissionSet =
|
||||
@@ -49,10 +46,7 @@ export type OrgPermissionSet =
|
||||
| [OrgPermissionActions, OrgPermissionSubjects.Kms]
|
||||
| [OrgPermissionActions, OrgPermissionSubjects.AuditLogs]
|
||||
| [OrgPermissionActions, OrgPermissionSubjects.ProjectTemplates]
|
||||
| [OrgPermissionAdminConsoleAction, OrgPermissionSubjects.AdminConsole]
|
||||
| [OrgPermissionActions, OrgPermissionSubjects.SshCertificateAuthorities]
|
||||
| [OrgPermissionActions, OrgPermissionSubjects.SshCertificates]
|
||||
| [OrgPermissionActions, OrgPermissionSubjects.SshCertificateTemplates];
|
||||
| [OrgPermissionAdminConsoleAction, OrgPermissionSubjects.AdminConsole];
|
||||
|
||||
const buildAdminPermission = () => {
|
||||
const { can, rules } = new AbilityBuilder<MongoAbility<OrgPermissionSet>>(createMongoAbility);
|
||||
@@ -129,19 +123,6 @@ const buildAdminPermission = () => {
|
||||
can(OrgPermissionActions.Edit, OrgPermissionSubjects.ProjectTemplates);
|
||||
can(OrgPermissionActions.Delete, OrgPermissionSubjects.ProjectTemplates);
|
||||
|
||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.SshCertificates);
|
||||
can(OrgPermissionActions.Create, OrgPermissionSubjects.SshCertificates);
|
||||
|
||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.SshCertificateAuthorities);
|
||||
can(OrgPermissionActions.Create, OrgPermissionSubjects.SshCertificateAuthorities);
|
||||
can(OrgPermissionActions.Edit, OrgPermissionSubjects.SshCertificateAuthorities);
|
||||
can(OrgPermissionActions.Delete, OrgPermissionSubjects.SshCertificateAuthorities);
|
||||
|
||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.SshCertificateTemplates);
|
||||
can(OrgPermissionActions.Create, OrgPermissionSubjects.SshCertificateTemplates);
|
||||
can(OrgPermissionActions.Edit, OrgPermissionSubjects.SshCertificateTemplates);
|
||||
can(OrgPermissionActions.Delete, OrgPermissionSubjects.SshCertificateTemplates);
|
||||
|
||||
can(OrgPermissionAdminConsoleAction.AccessAllProjects, OrgPermissionSubjects.AdminConsole);
|
||||
|
||||
return rules;
|
||||
@@ -172,11 +153,6 @@ const buildMemberPermission = () => {
|
||||
|
||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.AuditLogs);
|
||||
|
||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.SshCertificateAuthorities);
|
||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.SshCertificates);
|
||||
can(OrgPermissionActions.Create, OrgPermissionSubjects.SshCertificates);
|
||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.SshCertificateTemplates);
|
||||
|
||||
return rules;
|
||||
};
|
||||
|
||||
|
||||
@@ -54,6 +54,9 @@ export enum ProjectPermissionSub {
|
||||
CertificateAuthorities = "certificate-authorities",
|
||||
Certificates = "certificates",
|
||||
CertificateTemplates = "certificate-templates",
|
||||
SshCertificateAuthorities = "ssh-certificate-authorities",
|
||||
SshCertificates = "ssh-certificates",
|
||||
SshCertificateTemplates = "ssh-certificate-templates",
|
||||
PkiAlerts = "pki-alerts",
|
||||
PkiCollections = "pki-collections",
|
||||
Kms = "kms",
|
||||
@@ -125,6 +128,9 @@ export type ProjectPermissionSet =
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.CertificateAuthorities]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.Certificates]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.CertificateTemplates]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.SshCertificateAuthorities]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.SshCertificates]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.SshCertificateTemplates]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.PkiAlerts]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.PkiCollections]
|
||||
| [ProjectPermissionCmekActions, ProjectPermissionSub.Cmek]
|
||||
@@ -322,6 +328,28 @@ const GeneralPermissionSchema = [
|
||||
"Describe what action an entity can take."
|
||||
)
|
||||
}),
|
||||
z.object({
|
||||
subject: z
|
||||
.literal(ProjectPermissionSub.SshCertificateAuthorities)
|
||||
.describe("The entity this permission pertains to."),
|
||||
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||
"Describe what action an entity can take."
|
||||
)
|
||||
}),
|
||||
z.object({
|
||||
subject: z.literal(ProjectPermissionSub.SshCertificates).describe("The entity this permission pertains to."),
|
||||
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||
"Describe what action an entity can take."
|
||||
)
|
||||
}),
|
||||
z.object({
|
||||
subject: z
|
||||
.literal(ProjectPermissionSub.SshCertificateTemplates)
|
||||
.describe("The entity this permission pertains to."),
|
||||
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||
"Describe what action an entity can take."
|
||||
)
|
||||
}),
|
||||
z.object({
|
||||
subject: z.literal(ProjectPermissionSub.PkiAlerts).describe("The entity this permission pertains to."),
|
||||
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||
@@ -448,7 +476,10 @@ const buildAdminPermissionRules = () => {
|
||||
ProjectPermissionSub.Certificates,
|
||||
ProjectPermissionSub.CertificateTemplates,
|
||||
ProjectPermissionSub.PkiAlerts,
|
||||
ProjectPermissionSub.PkiCollections
|
||||
ProjectPermissionSub.PkiCollections,
|
||||
ProjectPermissionSub.SshCertificateAuthorities,
|
||||
ProjectPermissionSub.SshCertificates,
|
||||
ProjectPermissionSub.SshCertificateTemplates
|
||||
].forEach((el) => {
|
||||
can(
|
||||
[
|
||||
@@ -633,6 +664,11 @@ const buildMemberPermissionRules = () => {
|
||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.PkiAlerts);
|
||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.PkiCollections);
|
||||
|
||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificateAuthorities);
|
||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificates);
|
||||
can([ProjectPermissionActions.Create], ProjectPermissionSub.SshCertificates);
|
||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificateTemplates);
|
||||
|
||||
can(
|
||||
[
|
||||
ProjectPermissionCmekActions.Create,
|
||||
@@ -675,6 +711,9 @@ const buildViewerPermissionRules = () => {
|
||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.CertificateAuthorities);
|
||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Certificates);
|
||||
can(ProjectPermissionCmekActions.Read, ProjectPermissionSub.Cmek);
|
||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.SshCertificateAuthorities);
|
||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.SshCertificates);
|
||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.SshCertificateTemplates);
|
||||
|
||||
return rules;
|
||||
};
|
||||
|
||||
@@ -18,11 +18,11 @@ export const sshCertificateTemplateDALFactory = (db: TDbClient) => {
|
||||
`${TableName.SshCertificateAuthority}.id`,
|
||||
`${TableName.SshCertificateTemplate}.sshCaId`
|
||||
)
|
||||
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.SshCertificateAuthority}.orgId`)
|
||||
.join(TableName.Project, `${TableName.Project}.id`, `${TableName.SshCertificateAuthority}.projectId`)
|
||||
.where(`${TableName.SshCertificateTemplate}.id`, "=", id)
|
||||
.select(selectAllTableCols(TableName.SshCertificateTemplate))
|
||||
.select(
|
||||
db.ref("orgId").withSchema(TableName.SshCertificateAuthority),
|
||||
db.ref("projectId").withSchema(TableName.SshCertificateAuthority),
|
||||
db.ref("friendlyName").as("caName").withSchema(TableName.SshCertificateAuthority),
|
||||
db.ref("status").as("caStatus").withSchema(TableName.SshCertificateAuthority)
|
||||
)
|
||||
@@ -34,7 +34,10 @@ export const sshCertificateTemplateDALFactory = (db: TDbClient) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getByName = async (name: string, orgId: string, tx?: Knex) => {
|
||||
/**
|
||||
* Returns the SSH certificate template named [name] within project with id [projectId]
|
||||
*/
|
||||
const getByName = async (name: string, projectId: string, tx?: Knex) => {
|
||||
try {
|
||||
const certTemplate = await (tx || db.replicaNode())(TableName.SshCertificateTemplate)
|
||||
.join(
|
||||
@@ -42,12 +45,12 @@ export const sshCertificateTemplateDALFactory = (db: TDbClient) => {
|
||||
`${TableName.SshCertificateAuthority}.id`,
|
||||
`${TableName.SshCertificateTemplate}.sshCaId`
|
||||
)
|
||||
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.SshCertificateAuthority}.orgId`)
|
||||
.join(TableName.Project, `${TableName.Project}.id`, `${TableName.SshCertificateAuthority}.projectId`)
|
||||
.where(`${TableName.SshCertificateTemplate}.name`, "=", name)
|
||||
.where(`${TableName.Organization}.id`, "=", orgId)
|
||||
.where(`${TableName.Project}.id`, "=", projectId)
|
||||
.select(selectAllTableCols(TableName.SshCertificateTemplate))
|
||||
.select(
|
||||
db.ref("orgId").withSchema(TableName.SshCertificateAuthority),
|
||||
db.ref("projectId").withSchema(TableName.SshCertificateAuthority),
|
||||
db.ref("friendlyName").as("caName").withSchema(TableName.SshCertificateAuthority),
|
||||
db.ref("status").as("caStatus").withSchema(TableName.SshCertificateAuthority)
|
||||
)
|
||||
|
||||
+21
-21
@@ -1,8 +1,8 @@
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
import ms from "ms";
|
||||
|
||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||
|
||||
import { TSshCertificateAuthorityDALFactory } from "../ssh/ssh-certificate-authority-dal";
|
||||
@@ -21,7 +21,7 @@ type TSshCertificateTemplateServiceFactoryDep = {
|
||||
"transaction" | "getByName" | "create" | "updateById" | "deleteById" | "getById"
|
||||
>;
|
||||
sshCertificateAuthorityDAL: Pick<TSshCertificateAuthorityDALFactory, "findById">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||
};
|
||||
|
||||
export type TSshCertificateTemplateServiceFactory = ReturnType<typeof sshCertificateTemplateServiceFactory>;
|
||||
@@ -53,17 +53,17 @@ export const sshCertificateTemplateServiceFactory = ({
|
||||
});
|
||||
}
|
||||
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
ca.orgId,
|
||||
ca.projectId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
OrgPermissionActions.Create,
|
||||
OrgPermissionSubjects.SshCertificateTemplates
|
||||
ProjectPermissionActions.Create,
|
||||
ProjectPermissionSub.SshCertificateTemplates
|
||||
);
|
||||
|
||||
if (ms(ttl) > ms(maxTTL)) {
|
||||
@@ -73,7 +73,7 @@ export const sshCertificateTemplateServiceFactory = ({
|
||||
}
|
||||
|
||||
const newCertificateTemplate = await sshCertificateTemplateDAL.transaction(async (tx) => {
|
||||
const existingTemplate = await sshCertificateTemplateDAL.getByName(name, ca.orgId, tx);
|
||||
const existingTemplate = await sshCertificateTemplateDAL.getByName(name, ca.projectId, tx);
|
||||
if (existingTemplate) {
|
||||
throw new BadRequestError({
|
||||
message: `SSH certificate template with name ${name} already exists`
|
||||
@@ -125,22 +125,22 @@ export const sshCertificateTemplateServiceFactory = ({
|
||||
});
|
||||
}
|
||||
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
certTemplate.orgId,
|
||||
certTemplate.projectId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
OrgPermissionActions.Edit,
|
||||
OrgPermissionSubjects.SshCertificateTemplates
|
||||
ProjectPermissionActions.Edit,
|
||||
ProjectPermissionSub.SshCertificateTemplates
|
||||
);
|
||||
|
||||
const updatedCertificateTemplate = await sshCertificateTemplateDAL.transaction(async (tx) => {
|
||||
if (name) {
|
||||
const existingTemplate = await sshCertificateTemplateDAL.getByName(name, actorOrgId, tx);
|
||||
const existingTemplate = await sshCertificateTemplateDAL.getByName(name, certTemplate.projectId, tx);
|
||||
if (existingTemplate && existingTemplate.id !== id) {
|
||||
throw new BadRequestError({
|
||||
message: `SSH certificate template with name ${name} already exists`
|
||||
@@ -175,7 +175,7 @@ export const sshCertificateTemplateServiceFactory = ({
|
||||
|
||||
return {
|
||||
certificateTemplate: updatedCertificateTemplate,
|
||||
orgId: certTemplate.orgId
|
||||
projectId: certTemplate.projectId
|
||||
};
|
||||
};
|
||||
|
||||
@@ -193,17 +193,17 @@ export const sshCertificateTemplateServiceFactory = ({
|
||||
});
|
||||
}
|
||||
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
certificateTemplate.orgId,
|
||||
certificateTemplate.projectId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
OrgPermissionActions.Delete,
|
||||
OrgPermissionSubjects.SshCertificateTemplates
|
||||
ProjectPermissionActions.Delete,
|
||||
ProjectPermissionSub.SshCertificateTemplates
|
||||
);
|
||||
|
||||
await sshCertificateTemplateDAL.deleteById(certificateTemplate.id);
|
||||
@@ -219,17 +219,17 @@ export const sshCertificateTemplateServiceFactory = ({
|
||||
});
|
||||
}
|
||||
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
certTemplate.orgId,
|
||||
certTemplate.projectId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
OrgPermissionActions.Read,
|
||||
OrgPermissionSubjects.SshCertificateTemplates
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSub.SshCertificateTemplates
|
||||
);
|
||||
|
||||
return certTemplate;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { TDbClient } from "@app/db";
|
||||
import { TableName } from "@app/db/schemas";
|
||||
import { ormify } from "@app/lib/knex";
|
||||
|
||||
export type TSshCertificateBodyDALFactory = ReturnType<typeof sshCertificateBodyDALFactory>;
|
||||
|
||||
export const sshCertificateBodyDALFactory = (db: TDbClient) => {
|
||||
const sshCertificateBodyOrm = ormify(db, TableName.SshCertificateBody);
|
||||
return sshCertificateBodyOrm;
|
||||
};
|
||||
@@ -8,7 +8,7 @@ export type TSshCertificateDALFactory = ReturnType<typeof sshCertificateDALFacto
|
||||
export const sshCertificateDALFactory = (db: TDbClient) => {
|
||||
const sshCertificateOrm = ormify(db, TableName.SshCertificate);
|
||||
|
||||
const countSshCertificatesInOrg = async (orgId: string) => {
|
||||
const countSshCertificatesInProject = async (projectId: string) => {
|
||||
try {
|
||||
interface CountResult {
|
||||
count: string;
|
||||
@@ -21,18 +21,18 @@ export const sshCertificateDALFactory = (db: TDbClient) => {
|
||||
`${TableName.SshCertificate}.sshCaId`,
|
||||
`${TableName.SshCertificateAuthority}.id`
|
||||
)
|
||||
.join(TableName.Organization, `${TableName.SshCertificateAuthority}.orgId`, `${TableName.Organization}.id`)
|
||||
.where(`${TableName.Organization}.id`, orgId);
|
||||
.join(TableName.Project, `${TableName.SshCertificateAuthority}.projectId`, `${TableName.Project}.id`)
|
||||
.where(`${TableName.Project}.id`, projectId);
|
||||
|
||||
const count = await query.count("*").first();
|
||||
|
||||
return parseInt((count as unknown as CountResult).count || "0", 10);
|
||||
} catch (error) {
|
||||
throw new DatabaseError({ error, name: "Count all SSH certificates in organization" });
|
||||
throw new DatabaseError({ error, name: "Count all SSH certificates in project" });
|
||||
}
|
||||
};
|
||||
return {
|
||||
...sshCertificateOrm,
|
||||
countSshCertificatesInOrg
|
||||
countSshCertificatesInProject
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { SshCertificateAuthoritiesSchema } from "@app/db/schemas";
|
||||
|
||||
export const sanitizedSshCa = SshCertificateAuthoritiesSchema.pick({
|
||||
id: true,
|
||||
orgId: true,
|
||||
projectId: true,
|
||||
friendlyName: true,
|
||||
status: true,
|
||||
keyAlgorithm: true
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
|
||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||
import { TSshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal";
|
||||
import { TSshCertificateAuthoritySecretDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-secret-dal";
|
||||
import { TSshCertificateBodyDALFactory } from "@app/ee/services/ssh-certificate/ssh-certificate-body-dal";
|
||||
import { TSshCertificateDALFactory } from "@app/ee/services/ssh-certificate/ssh-certificate-dal";
|
||||
import { TSshCertificateTemplateDALFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-dal";
|
||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||
|
||||
import { SshCertTemplateStatus } from "../ssh-certificate-template/ssh-certificate-template-types";
|
||||
import {
|
||||
@@ -37,18 +39,25 @@ type TSshCertificateAuthorityServiceFactoryDep = {
|
||||
>;
|
||||
sshCertificateAuthoritySecretDAL: Pick<TSshCertificateAuthoritySecretDALFactory, "create" | "findOne">;
|
||||
sshCertificateTemplateDAL: Pick<TSshCertificateTemplateDALFactory, "find" | "getByName">;
|
||||
sshCertificateDAL: Pick<TSshCertificateDALFactory, "create">;
|
||||
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "encryptWithKmsKey" | "decryptWithKmsKey" | "getOrgKmsKeyId">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||
sshCertificateDAL: Pick<TSshCertificateDALFactory, "create" | "transaction">;
|
||||
sshCertificateBodyDAL: Pick<TSshCertificateBodyDALFactory, "create">;
|
||||
kmsService: Pick<
|
||||
TKmsServiceFactory,
|
||||
"generateKmsKey" | "encryptWithKmsKey" | "decryptWithKmsKey" | "getOrgKmsKeyId" | "createCipherPairWithDataKey"
|
||||
>;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||
};
|
||||
|
||||
export type TSshCertificateAuthorityServiceFactory = ReturnType<typeof sshCertificateAuthorityServiceFactory>;
|
||||
|
||||
// TODO: secretManagerEncryptor -> sshEncryptor (cc akhil)
|
||||
|
||||
export const sshCertificateAuthorityServiceFactory = ({
|
||||
sshCertificateAuthorityDAL,
|
||||
sshCertificateAuthoritySecretDAL,
|
||||
sshCertificateTemplateDAL,
|
||||
sshCertificateDAL,
|
||||
sshCertificateBodyDAL,
|
||||
kmsService,
|
||||
permissionService
|
||||
}: TSshCertificateAuthorityServiceFactoryDep) => {
|
||||
@@ -56,6 +65,7 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
* Generates a new SSH CA
|
||||
*/
|
||||
const createSshCa = async ({
|
||||
projectId,
|
||||
friendlyName,
|
||||
keyAlgorithm,
|
||||
actorId,
|
||||
@@ -63,23 +73,23 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
actor,
|
||||
actorOrgId
|
||||
}: TCreateSshCaDTO) => {
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
actorOrgId,
|
||||
projectId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
OrgPermissionActions.Create,
|
||||
OrgPermissionSubjects.SshCertificateAuthorities
|
||||
ProjectPermissionActions.Create,
|
||||
ProjectPermissionSub.SshCertificateAuthorities
|
||||
);
|
||||
|
||||
const newCa = await sshCertificateAuthorityDAL.transaction(async (tx) => {
|
||||
const ca = await sshCertificateAuthorityDAL.create(
|
||||
{
|
||||
orgId: actorOrgId,
|
||||
projectId,
|
||||
friendlyName,
|
||||
status: SshCaStatus.ACTIVE,
|
||||
keyAlgorithm
|
||||
@@ -89,19 +99,16 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
|
||||
const { publicKey, privateKey } = createSshKeyPair(keyAlgorithm, ca.friendlyName);
|
||||
|
||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(actorOrgId);
|
||||
const kmsEncryptor = await kmsService.encryptWithKmsKey({
|
||||
kmsId: orgKmsKeyId
|
||||
});
|
||||
|
||||
const { cipherTextBlob: encryptedPrivateKey } = await kmsEncryptor({
|
||||
plainText: Buffer.from(privateKey, "utf8")
|
||||
// TODO: update to sshEncryptor
|
||||
const { encryptor: secretManagerEncryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
|
||||
await sshCertificateAuthoritySecretDAL.create(
|
||||
{
|
||||
sshCaId: ca.id,
|
||||
encryptedPrivateKey
|
||||
encryptedPrivateKey: secretManagerEncryptor({ plainText: Buffer.from(privateKey, "utf8") }).cipherTextBlob
|
||||
},
|
||||
tx
|
||||
);
|
||||
@@ -119,28 +126,28 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
const ca = await sshCertificateAuthorityDAL.findById(caId);
|
||||
if (!ca) throw new NotFoundError({ message: `SSH CA with ID '${caId}' not found` });
|
||||
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
ca.orgId,
|
||||
ca.projectId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
OrgPermissionActions.Read,
|
||||
OrgPermissionSubjects.SshCertificateAuthorities
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSub.SshCertificateAuthorities
|
||||
);
|
||||
|
||||
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: ca.id });
|
||||
|
||||
// decrypt secret
|
||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(actorOrgId);
|
||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
||||
kmsId: orgKmsKeyId
|
||||
// TODO: update to sshDecryptor
|
||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId: ca.projectId
|
||||
});
|
||||
|
||||
const decryptedCaPrivateKey = await kmsDecryptor({
|
||||
const decryptedCaPrivateKey = secretManagerDecryptor({
|
||||
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
||||
});
|
||||
|
||||
@@ -158,13 +165,13 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
|
||||
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: ca.id });
|
||||
|
||||
// decrypt secret
|
||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(ca.orgId);
|
||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
||||
kmsId: orgKmsKeyId
|
||||
// TODO: update to sshDecryptor
|
||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId: ca.projectId
|
||||
});
|
||||
|
||||
const decryptedCaPrivateKey = await kmsDecryptor({
|
||||
const decryptedCaPrivateKey = secretManagerDecryptor({
|
||||
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
||||
});
|
||||
|
||||
@@ -189,30 +196,30 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
const ca = await sshCertificateAuthorityDAL.findById(caId);
|
||||
if (!ca) throw new NotFoundError({ message: `SSH CA with ID '${caId}' not found` });
|
||||
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
ca.orgId,
|
||||
ca.projectId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
OrgPermissionActions.Edit,
|
||||
OrgPermissionSubjects.SshCertificateAuthorities
|
||||
ProjectPermissionActions.Edit,
|
||||
ProjectPermissionSub.SshCertificateAuthorities
|
||||
);
|
||||
|
||||
const updatedCa = await sshCertificateAuthorityDAL.updateById(caId, { friendlyName, status });
|
||||
|
||||
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: ca.id });
|
||||
|
||||
// decrypt secret
|
||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(actorOrgId);
|
||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
||||
kmsId: orgKmsKeyId
|
||||
// TODO: update to sshDecryptor
|
||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId: ca.projectId
|
||||
});
|
||||
|
||||
const decryptedCaPrivateKey = await kmsDecryptor({
|
||||
const decryptedCaPrivateKey = secretManagerDecryptor({
|
||||
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
||||
});
|
||||
|
||||
@@ -228,17 +235,17 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
const ca = await sshCertificateAuthorityDAL.findById(caId);
|
||||
if (!ca) throw new NotFoundError({ message: `SSH CA with ID '${caId}' not found` });
|
||||
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
ca.orgId,
|
||||
ca.projectId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
OrgPermissionActions.Delete,
|
||||
OrgPermissionSubjects.SshCertificateAuthorities
|
||||
ProjectPermissionActions.Delete,
|
||||
ProjectPermissionSub.SshCertificateAuthorities
|
||||
);
|
||||
|
||||
const deletedCa = await sshCertificateAuthorityDAL.deleteById(caId);
|
||||
@@ -251,6 +258,7 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
* SSH public key is signed using CA behind SSH certificate with name [templateName].
|
||||
*/
|
||||
const issueSshCreds = async ({
|
||||
projectId,
|
||||
templateName,
|
||||
keyAlgorithm,
|
||||
certType,
|
||||
@@ -262,22 +270,25 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
}: TIssueSshCredsDTO) => {
|
||||
const sshCertificateTemplate = await sshCertificateTemplateDAL.getByName(templateName, actorOrgId);
|
||||
const sshCertificateTemplate = await sshCertificateTemplateDAL.getByName(templateName, projectId);
|
||||
if (!sshCertificateTemplate) {
|
||||
throw new NotFoundError({
|
||||
message: "No SSH certificate template found with specified name"
|
||||
});
|
||||
}
|
||||
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
actorOrgId,
|
||||
sshCertificateTemplate.projectId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SshCertificates);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Create,
|
||||
ProjectPermissionSub.SshCertificates
|
||||
);
|
||||
|
||||
if (sshCertificateTemplate.caStatus === SshCaStatus.DISABLED) {
|
||||
throw new BadRequestError({
|
||||
@@ -307,13 +318,13 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
|
||||
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: sshCertificateTemplate.sshCaId });
|
||||
|
||||
// decrypt secret
|
||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(actorOrgId);
|
||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
||||
kmsId: orgKmsKeyId
|
||||
// TODO: update to sshDecryptor
|
||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
|
||||
const decryptedCaPrivateKey = await kmsDecryptor({
|
||||
const decryptedCaPrivateKey = secretManagerDecryptor({
|
||||
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
||||
});
|
||||
|
||||
@@ -329,16 +340,38 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
certType
|
||||
});
|
||||
|
||||
await sshCertificateDAL.create({
|
||||
sshCaId: sshCertificateTemplate.sshCaId,
|
||||
sshCertificateTemplateId: sshCertificateTemplate.id,
|
||||
serialNumber,
|
||||
certType,
|
||||
publicKey,
|
||||
principals,
|
||||
keyId,
|
||||
notBefore: new Date(),
|
||||
notAfter: new Date(Date.now() + ttl * 1000)
|
||||
// TODO: update to sshEncryptor
|
||||
const { encryptor: secretManagerEncryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId: sshCertificateTemplate.projectId
|
||||
});
|
||||
|
||||
const encryptedCertificate = secretManagerEncryptor({
|
||||
plainText: Buffer.from(signedPublicKey, "utf8")
|
||||
}).cipherTextBlob;
|
||||
|
||||
await sshCertificateDAL.transaction(async (tx) => {
|
||||
const cert = await sshCertificateDAL.create(
|
||||
{
|
||||
sshCaId: sshCertificateTemplate.sshCaId,
|
||||
sshCertificateTemplateId: sshCertificateTemplate.id,
|
||||
serialNumber,
|
||||
certType,
|
||||
principals,
|
||||
keyId,
|
||||
notBefore: new Date(),
|
||||
notAfter: new Date(Date.now() + ttl * 1000)
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
await sshCertificateBodyDAL.create(
|
||||
{
|
||||
sshCertId: cert.id,
|
||||
encryptedCertificate
|
||||
},
|
||||
tx
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -357,6 +390,7 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
* using CA behind SSH certificate template with name [templateName]
|
||||
*/
|
||||
const signSshKey = async ({
|
||||
projectId,
|
||||
templateName,
|
||||
publicKey,
|
||||
certType,
|
||||
@@ -368,22 +402,25 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
}: TSignSshKeyDTO) => {
|
||||
const sshCertificateTemplate = await sshCertificateTemplateDAL.getByName(templateName, actorOrgId);
|
||||
const sshCertificateTemplate = await sshCertificateTemplateDAL.getByName(templateName, projectId);
|
||||
if (!sshCertificateTemplate) {
|
||||
throw new NotFoundError({
|
||||
message: "No SSH certificate template found with specified name"
|
||||
});
|
||||
}
|
||||
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
actorOrgId,
|
||||
sshCertificateTemplate.projectId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SshCertificates);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Create,
|
||||
ProjectPermissionSub.SshCertificates
|
||||
);
|
||||
|
||||
if (sshCertificateTemplate.caStatus === SshCaStatus.DISABLED) {
|
||||
throw new BadRequestError({
|
||||
@@ -413,13 +450,13 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
|
||||
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: sshCertificateTemplate.sshCaId });
|
||||
|
||||
// decrypt secret
|
||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(actorOrgId);
|
||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
||||
kmsId: orgKmsKeyId
|
||||
// TODO: update to sshDecryptor
|
||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
|
||||
const decryptedCaPrivateKey = await kmsDecryptor({
|
||||
const decryptedCaPrivateKey = secretManagerDecryptor({
|
||||
cipherTextBlob: sshCaSecret.encryptedPrivateKey
|
||||
});
|
||||
|
||||
@@ -432,16 +469,38 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
certType
|
||||
});
|
||||
|
||||
await sshCertificateDAL.create({
|
||||
sshCaId: sshCertificateTemplate.sshCaId,
|
||||
sshCertificateTemplateId: sshCertificateTemplate.id,
|
||||
serialNumber,
|
||||
certType,
|
||||
publicKey,
|
||||
principals,
|
||||
keyId,
|
||||
notBefore: new Date(),
|
||||
notAfter: new Date(Date.now() + ttl * 1000)
|
||||
// TODO: update to sshEncryptor
|
||||
const { encryptor: secretManagerEncryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId: sshCertificateTemplate.projectId
|
||||
});
|
||||
|
||||
const encryptedCertificate = secretManagerEncryptor({
|
||||
plainText: Buffer.from(signedPublicKey, "utf8")
|
||||
}).cipherTextBlob;
|
||||
|
||||
await sshCertificateDAL.transaction(async (tx) => {
|
||||
const cert = await sshCertificateDAL.create(
|
||||
{
|
||||
sshCaId: sshCertificateTemplate.sshCaId,
|
||||
sshCertificateTemplateId: sshCertificateTemplate.id,
|
||||
serialNumber,
|
||||
certType,
|
||||
principals,
|
||||
keyId,
|
||||
notBefore: new Date(),
|
||||
notAfter: new Date(Date.now() + ttl * 1000)
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
await sshCertificateBodyDAL.create(
|
||||
{
|
||||
sshCertId: cert.id,
|
||||
encryptedCertificate
|
||||
},
|
||||
tx
|
||||
);
|
||||
});
|
||||
|
||||
return { serialNumber, signedPublicKey, certificateTemplate: sshCertificateTemplate, ttl, keyId };
|
||||
@@ -457,17 +516,17 @@ export const sshCertificateAuthorityServiceFactory = ({
|
||||
const ca = await sshCertificateAuthorityDAL.findById(caId);
|
||||
if (!ca) throw new NotFoundError({ message: `SSH CA with ID '${caId}' not found` });
|
||||
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
actorOrgId,
|
||||
ca.projectId,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
OrgPermissionActions.Read,
|
||||
OrgPermissionSubjects.SshCertificateTemplates
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSub.SshCertificateTemplates
|
||||
);
|
||||
|
||||
const certificateTemplates = await sshCertificateTemplateDAL.find({ sshCaId: caId });
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TOrgPermission } from "@app/lib/types";
|
||||
import { TProjectPermission } from "@app/lib/types";
|
||||
import { CertKeyAlgorithm } from "@app/services/certificate/certificate-types";
|
||||
|
||||
export enum SshCaStatus {
|
||||
@@ -14,11 +14,11 @@ export enum SshCertType {
|
||||
export type TCreateSshCaDTO = {
|
||||
friendlyName: string;
|
||||
keyAlgorithm: CertKeyAlgorithm;
|
||||
} & Omit<TOrgPermission, "orgId">;
|
||||
} & TProjectPermission;
|
||||
|
||||
export type TGetSshCaDTO = {
|
||||
caId: string;
|
||||
} & Omit<TOrgPermission, "orgId">;
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
|
||||
export type TGetSshCaPublicKeyDTO = {
|
||||
caId: string;
|
||||
@@ -28,11 +28,11 @@ export type TUpdateSshCaDTO = {
|
||||
caId: string;
|
||||
friendlyName?: string;
|
||||
status?: SshCaStatus;
|
||||
} & Omit<TOrgPermission, "orgId">;
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
|
||||
export type TDeleteSshCaDTO = {
|
||||
caId: string;
|
||||
} & Omit<TOrgPermission, "orgId">;
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
|
||||
export type TIssueSshCredsDTO = {
|
||||
templateName: string;
|
||||
@@ -41,7 +41,7 @@ export type TIssueSshCredsDTO = {
|
||||
principals: string[];
|
||||
ttl?: string;
|
||||
keyId?: string;
|
||||
} & Omit<TOrgPermission, "orgId">;
|
||||
} & TProjectPermission;
|
||||
|
||||
export type TSignSshKeyDTO = {
|
||||
templateName: string;
|
||||
@@ -50,11 +50,11 @@ export type TSignSshKeyDTO = {
|
||||
principals: string[];
|
||||
ttl?: string;
|
||||
keyId?: string;
|
||||
} & Omit<TOrgPermission, "orgId">;
|
||||
} & TProjectPermission;
|
||||
|
||||
export type TGetSshCaCertificateTemplatesDTO = {
|
||||
caId: string;
|
||||
} & Omit<TOrgPermission, "orgId">;
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
|
||||
export type TCreateSshCertDTO = {
|
||||
caPrivateKey: string;
|
||||
|
||||
Reference in New Issue
Block a user