mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 19:28:16 +00:00
review fixes
This commit is contained in:
@@ -21,7 +21,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function down(knex: Knex): Promise<void> {
|
export async function down(knex: Knex): Promise<void> {
|
||||||
if (await knex.schema.hasTable(TableName.Certificate)) {
|
if (await knex.schema.hasTable(TableName.CertificateSecret)) {
|
||||||
await knex.schema.dropTable(TableName.CertificateSecret);
|
await knex.schema.dropTable(TableName.CertificateSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-floating-promises */
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { CertificatesSchema } from "@app/db/schemas";
|
import { CertificatesSchema } from "@app/db/schemas";
|
||||||
@@ -83,7 +84,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
|
|||||||
200: z.string().trim()
|
200: z.string().trim()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req, reply) => {
|
||||||
const { ca, cert, certPrivateKey } = await server.services.certificate.getCertPrivateKey({
|
const { ca, cert, certPrivateKey } = await server.services.certificate.getCertPrivateKey({
|
||||||
serialNumber: req.params.serialNumber,
|
serialNumber: req.params.serialNumber,
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
@@ -105,6 +106,12 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Prevent proxies from caching sensitive data (private key)
|
||||||
|
reply.header("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate");
|
||||||
|
reply.header("Pragma", "no-cache");
|
||||||
|
reply.header("Expires", "0");
|
||||||
|
reply.header("Surrogate-Control", "no-store");
|
||||||
|
|
||||||
return certPrivateKey;
|
return certPrivateKey;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -128,12 +135,12 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
|
|||||||
200: z.object({
|
200: z.object({
|
||||||
certificate: z.string().trim().describe(CERTIFICATES.GET_CERT.certificate),
|
certificate: z.string().trim().describe(CERTIFICATES.GET_CERT.certificate),
|
||||||
certificateChain: z.string().trim().describe(CERTIFICATES.GET_CERT.certificateChain),
|
certificateChain: z.string().trim().describe(CERTIFICATES.GET_CERT.certificateChain),
|
||||||
privateKey: z.string().trim().describe(CERTIFICATES.GET_CERT.certificateChain),
|
privateKey: z.string().trim().describe(CERTIFICATES.GET_CERT.privateKey),
|
||||||
serialNumber: z.string().trim().describe(CERTIFICATES.GET_CERT.serialNumberRes)
|
serialNumber: z.string().trim().describe(CERTIFICATES.GET_CERT.serialNumberRes)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req, reply) => {
|
||||||
const { certificate, certificateChain, serialNumber, cert, ca, privateKey } =
|
const { certificate, certificateChain, serialNumber, cert, ca, privateKey } =
|
||||||
await server.services.certificate.getCertBundle({
|
await server.services.certificate.getCertBundle({
|
||||||
serialNumber: req.params.serialNumber,
|
serialNumber: req.params.serialNumber,
|
||||||
@@ -156,6 +163,12 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Prevent proxies from caching sensitive data (private key)
|
||||||
|
reply.header("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate");
|
||||||
|
reply.header("Pragma", "no-cache");
|
||||||
|
reply.header("Expires", "0");
|
||||||
|
reply.header("Surrogate-Control", "no-store");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
certificate,
|
certificate,
|
||||||
certificateChain,
|
certificateChain,
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import crypto from "node:crypto";
|
|||||||
|
|
||||||
import * as x509 from "@peculiar/x509";
|
import * as x509 from "@peculiar/x509";
|
||||||
|
|
||||||
import { NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
|
|
||||||
import { getProjectKmsCertificateKeyId } from "../project/project-fns";
|
import { getProjectKmsCertificateKeyId } from "../project/project-fns";
|
||||||
import { CrlReason, TGetCertificateCredentialsDTO } from "./certificate-types";
|
import { CrlReason, TBuildCertificateChainDTO, TGetCertificateCredentialsDTO } from "./certificate-types";
|
||||||
|
|
||||||
export const revocationReasonToCrlCode = (crlReason: CrlReason) => {
|
export const revocationReasonToCrlCode = (crlReason: CrlReason) => {
|
||||||
switch (crlReason) {
|
switch (crlReason) {
|
||||||
@@ -79,15 +79,42 @@ export const getCertificateCredentials = async ({
|
|||||||
cipherTextBlob: certificateSecret.encryptedPrivateKey
|
cipherTextBlob: certificateSecret.encryptedPrivateKey
|
||||||
});
|
});
|
||||||
|
|
||||||
const skObj = crypto.createPrivateKey({ key: decryptedPrivateKey, format: "pem", type: "pkcs8" });
|
try {
|
||||||
const certPrivateKey = skObj.export({ format: "pem", type: "pkcs8" }).toString();
|
const skObj = crypto.createPrivateKey({ key: decryptedPrivateKey, format: "pem", type: "pkcs8" });
|
||||||
|
const certPrivateKey = skObj.export({ format: "pem", type: "pkcs8" }).toString();
|
||||||
|
|
||||||
const pkObj = crypto.createPublicKey(skObj);
|
const pkObj = crypto.createPublicKey(skObj);
|
||||||
const certPublicKey = pkObj.export({ format: "pem", type: "spki" }).toString();
|
const certPublicKey = pkObj.export({ format: "pem", type: "spki" }).toString();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
certificateSecret,
|
certificateSecret,
|
||||||
certPrivateKey,
|
certPrivateKey,
|
||||||
certPublicKey
|
certPublicKey
|
||||||
};
|
};
|
||||||
|
} catch (error) {
|
||||||
|
throw new BadRequestError({ message: `Failed to process private key for certificate with ID '${certId}'` });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// If the certificate was generated after ~05/01/25 it will have a encryptedCertificateChain attached to it's body
|
||||||
|
// Otherwise we'll fallback to manually building the chain
|
||||||
|
export const buildCertificateChain = async ({
|
||||||
|
caCert,
|
||||||
|
caCertChain,
|
||||||
|
encryptedCertificateChain,
|
||||||
|
kmsService,
|
||||||
|
kmsId
|
||||||
|
}: TBuildCertificateChainDTO) => {
|
||||||
|
let certificateChain = `${caCert}\n${caCertChain}`.trim();
|
||||||
|
|
||||||
|
// If the certificate was generated after ~05/01/25 it will have a encryptedCertificateChain attached to it's body
|
||||||
|
if (encryptedCertificateChain) {
|
||||||
|
const kmsDecryptor = await kmsService.decryptWithKmsKey({ kmsId });
|
||||||
|
const decryptedCertChain = await kmsDecryptor({
|
||||||
|
cipherTextBlob: encryptedCertificateChain
|
||||||
|
});
|
||||||
|
certificateChain = decryptedCertChain.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return certificateChain;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { TProjectDALFactory } from "@app/services/project/project-dal";
|
|||||||
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
|
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
|
||||||
|
|
||||||
import { getCaCertChain, rebuildCaCrl } from "../certificate-authority/certificate-authority-fns";
|
import { getCaCertChain, rebuildCaCrl } from "../certificate-authority/certificate-authority-fns";
|
||||||
import { getCertificateCredentials, revocationReasonToCrlCode } from "./certificate-fns";
|
import { buildCertificateChain, getCertificateCredentials, revocationReasonToCrlCode } from "./certificate-fns";
|
||||||
import { TCertificateSecretDALFactory } from "./certificate-secret-dal";
|
import { TCertificateSecretDALFactory } from "./certificate-secret-dal";
|
||||||
import {
|
import {
|
||||||
CertStatus,
|
CertStatus,
|
||||||
@@ -245,16 +245,13 @@ export const certificateServiceFactory = ({
|
|||||||
kmsService
|
kmsService
|
||||||
});
|
});
|
||||||
|
|
||||||
let certificateChain = `${caCert}\n${caCertChain}`.trim();
|
const certificateChain = await buildCertificateChain({
|
||||||
|
caCert,
|
||||||
// If the certificate was generated after ~05/01/25 it will have a encryptedCertificateChain attached to it's body
|
caCertChain,
|
||||||
if (certBody.encryptedCertificateChain) {
|
kmsId: certificateManagerKeyId,
|
||||||
const decryptedCertChain = await kmsDecryptor({
|
kmsService,
|
||||||
cipherTextBlob: certBody.encryptedCertificateChain
|
encryptedCertificateChain: certBody.encryptedCertificateChain || undefined
|
||||||
});
|
});
|
||||||
const certChainObj = new x509.X509Certificate(decryptedCertChain);
|
|
||||||
certificateChain = certChainObj.toString("pem");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
certificate: certObj.toString("pem"),
|
certificate: certObj.toString("pem"),
|
||||||
@@ -314,16 +311,13 @@ export const certificateServiceFactory = ({
|
|||||||
kmsService
|
kmsService
|
||||||
});
|
});
|
||||||
|
|
||||||
let certificateChain = `${caCert}\n${caCertChain}`.trim();
|
const certificateChain = await buildCertificateChain({
|
||||||
|
caCert,
|
||||||
// If the certificate was generated after ~05/01/25 it will have a encryptedCertificateChain attached to it's body
|
caCertChain,
|
||||||
if (certBody.encryptedCertificateChain) {
|
kmsId: certificateManagerKeyId,
|
||||||
const decryptedCertChain = await kmsDecryptor({
|
kmsService,
|
||||||
cipherTextBlob: certBody.encryptedCertificateChain
|
encryptedCertificateChain: certBody.encryptedCertificateChain || undefined
|
||||||
});
|
});
|
||||||
const certChainObj = new x509.X509Certificate(decryptedCertChain);
|
|
||||||
certificateChain = certChainObj.toString("pem");
|
|
||||||
}
|
|
||||||
|
|
||||||
const { certPrivateKey } = await getCertificateCredentials({
|
const { certPrivateKey } = await getCertificateCredentials({
|
||||||
certId: cert.id,
|
certId: cert.id,
|
||||||
|
|||||||
@@ -93,3 +93,11 @@ export type TGetCertificateCredentialsDTO = {
|
|||||||
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;
|
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;
|
||||||
kmsService: Pick<TKmsServiceFactory, "decryptWithKmsKey" | "generateKmsKey">;
|
kmsService: Pick<TKmsServiceFactory, "decryptWithKmsKey" | "generateKmsKey">;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TBuildCertificateChainDTO = {
|
||||||
|
caCert: string;
|
||||||
|
caCertChain: string;
|
||||||
|
encryptedCertificateChain?: Buffer;
|
||||||
|
kmsService: Pick<TKmsServiceFactory, "decryptWithKmsKey">;
|
||||||
|
kmsId: string;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user