mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Implement acme secret reveal
This commit is contained in:
@@ -20,5 +20,3 @@ Feature: ACME Cert Profile
|
||||
Then the value response with jq .certificateProfile.caId should be equal to "{CERT_CA_ID}"
|
||||
Then the value response with jq .certificateProfile.certificateTemplateId should be equal to "{CERT_TEMPLATE_ID}"
|
||||
Then the value response with jq .certificateProfile.enrollmentType should be equal to "acme"
|
||||
Then the value response with jq .certificateProfile.eabKid should be present
|
||||
Then the value response with jq .certificateProfile.eabSecret should be present
|
||||
|
||||
@@ -106,7 +106,9 @@ const buildAdminPermissionRules = () => {
|
||||
ProjectPermissionCertificateProfileActions.Edit,
|
||||
ProjectPermissionCertificateProfileActions.Create,
|
||||
ProjectPermissionCertificateProfileActions.Delete,
|
||||
ProjectPermissionCertificateProfileActions.IssueCert
|
||||
ProjectPermissionCertificateProfileActions.IssueCert,
|
||||
ProjectPermissionCertificateProfileActions.RevealAcmeEabSecret,
|
||||
ProjectPermissionCertificateProfileActions.RotateAcmeEabSecret
|
||||
],
|
||||
ProjectPermissionSub.CertificateProfiles
|
||||
);
|
||||
|
||||
@@ -116,7 +116,9 @@ export enum ProjectPermissionCertificateProfileActions {
|
||||
Create = "create",
|
||||
Edit = "edit",
|
||||
Delete = "delete",
|
||||
IssueCert = "issue-cert"
|
||||
IssueCert = "issue-cert",
|
||||
RevealAcmeEabSecret = "reveal-acme-eab-secret",
|
||||
RotateAcmeEabSecret = "rotate-acme-eab-secret"
|
||||
}
|
||||
|
||||
export enum ProjectPermissionSecretSyncActions {
|
||||
|
||||
@@ -7,8 +7,8 @@ import { ApiDocsTags } from "@app/lib/api-docs";
|
||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||
import { AuthMode } from "@app/services/auth/auth-type";
|
||||
import { CertStatus } from "@app/services/certificate/certificate-types";
|
||||
import { EnrollmentType } from "@app/services/certificate-profile/certificate-profile-types";
|
||||
import { CertStatus } from "@app/services/certificate/certificate-types";
|
||||
|
||||
export const registerCertificateProfilesRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
@@ -491,4 +491,35 @@ export const registerCertificateProfilesRouter = async (server: FastifyZodProvid
|
||||
return { certificates };
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "GET",
|
||||
url: "/:id/acme/eab-secret/reveal",
|
||||
config: {
|
||||
rateLimit: readLimit
|
||||
},
|
||||
schema: {
|
||||
hide: false,
|
||||
tags: [ApiDocsTags.PkiCertificateProfiles],
|
||||
params: z.object({
|
||||
id: z.string().uuid()
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
eabSecret: z.string()
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req) => {
|
||||
const eabSecret = await server.services.certificateProfile.revealAcmeEabSecret({
|
||||
actor: req.permission.type,
|
||||
actorId: req.permission.id,
|
||||
actorAuthMethod: req.permission.authMethod,
|
||||
actorOrgId: req.permission.orgId,
|
||||
profileId: req.params.id
|
||||
});
|
||||
return { eabSecret };
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -782,6 +782,59 @@ export const certificateProfileServiceFactory = ({
|
||||
};
|
||||
};
|
||||
|
||||
const revealAcmeEabSecret = async ({
|
||||
actor,
|
||||
actorId,
|
||||
actorAuthMethod,
|
||||
actorOrgId,
|
||||
profileId
|
||||
}: {
|
||||
actor: ActorType;
|
||||
actorId: string;
|
||||
actorAuthMethod: ActorAuthMethod;
|
||||
actorOrgId: string;
|
||||
profileId: string;
|
||||
}) => {
|
||||
const profile = await certificateProfileDAL.findByIdWithConfigs(profileId);
|
||||
if (!profile) {
|
||||
throw new NotFoundError({ message: "Certificate profile not found" });
|
||||
}
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
actor,
|
||||
actorId,
|
||||
projectId: profile.projectId,
|
||||
actorAuthMethod,
|
||||
actorOrgId,
|
||||
actionProjectType: ActionProjectType.CertificateManager
|
||||
});
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionCertificateProfileActions.RevealAcmeEabSecret,
|
||||
ProjectPermissionSub.CertificateProfiles
|
||||
);
|
||||
|
||||
if (profile.enrollmentType !== EnrollmentType.ACME) {
|
||||
throw new ForbiddenRequestError({
|
||||
message: "Profile is not configured for ACME enrollment"
|
||||
});
|
||||
}
|
||||
if (!profile.acmeConfig) {
|
||||
throw new NotFoundError({ message: "ACME configuration not found for this profile" });
|
||||
}
|
||||
|
||||
const certificateManagerKmsId = await getProjectKmsCertificateKeyId({
|
||||
projectId: profile.projectId,
|
||||
projectDAL,
|
||||
kmsService
|
||||
});
|
||||
|
||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
||||
kmsId: certificateManagerKmsId
|
||||
});
|
||||
const eabSecret = await kmsDecryptor({ cipherTextBlob: profile.acmeConfig.encryptedEabSecret });
|
||||
return eabSecret.toString();
|
||||
};
|
||||
|
||||
return {
|
||||
createProfile,
|
||||
updateProfile,
|
||||
@@ -791,6 +844,7 @@ export const certificateProfileServiceFactory = ({
|
||||
listProfiles,
|
||||
deleteProfile,
|
||||
getProfileCertificates,
|
||||
getEstConfigurationByProfile
|
||||
getEstConfigurationByProfile,
|
||||
revealAcmeEabSecret
|
||||
};
|
||||
};
|
||||
|
||||
@@ -58,6 +58,7 @@ export type TCertificateProfileWithConfigs = TCertificateProfile & {
|
||||
};
|
||||
acmeConfig?: {
|
||||
id: string;
|
||||
encryptedEabSecret: Buffer;
|
||||
};
|
||||
metrics?: TCertificateProfileMetrics;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user