Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .infisicalignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,6 @@ k8-operator/config/samples/universalAuthIdentitySecret.yaml:generic-api-key:8
docs/integrations/app-connections/redis.mdx:generic-api-key:80
backend/src/ee/services/app-connections/chef/chef-connection-fns.ts:private-key:42
docs/documentation/platform/pki/enrollment-methods/api.mdx:generic-api-key:93
docs/documentation/platform/pki/enrollment-methods/api.mdx:private-key:139
docs/documentation/platform/pki/enrollment-methods/api.mdx:private-key:139
docs/documentation/platform/pki/certificate-syncs/aws-secrets-manager.mdx:private-key:62
docs/documentation/platform/pki/certificate-syncs/chef.mdx:private-key:61
9 changes: 7 additions & 2 deletions backend/e2e-test/routes/v1/secret-approval-policy.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { seedData1 } from "@app/db/seed-data";
import { ApproverType } from "@app/ee/services/access-approval-policy/access-approval-policy-types";

const createPolicy = async (dto: { name: string; secretPath: string; approvers: {type: ApproverType.User, id: string}[]; approvals: number }) => {
const createPolicy = async (dto: {
name: string;
secretPath: string;
approvers: { type: ApproverType.User; id: string }[];
approvals: number;
}) => {
const res = await testServer.inject({
method: "POST",
url: `/api/v1/secret-approvals`,
Expand All @@ -27,7 +32,7 @@ describe("Secret approval policy router", async () => {
const policy = await createPolicy({
secretPath: "/",
approvals: 1,
approvers: [{id:seedData1.id, type: ApproverType.User}],
approvers: [{ id: seedData1.id, type: ApproverType.User }],
name: "test-policy"
});

Expand Down
2 changes: 1 addition & 1 deletion backend/scripts/create-migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { execSync } from "child_process";
import path from "path";
import promptSync from "prompt-sync";
import slugify from "@sindresorhus/slugify"
import slugify from "@sindresorhus/slugify";

const prompt = promptSync({ sigint: true });

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ export const getChefServerUrl = async (serverUrl?: string) => {
return chefServerUrl;
};

const buildSecureUrl = (baseUrl: string, path: string): string => {
try {
const url = new URL(path, baseUrl);
return url.toString();
} catch (error) {
throw new BadRequestError({
message: "Invalid URL construction parameters"
});
}
};

// Helper to ensure private key is in proper PEM format
const formatPrivateKey = (key: string): string => {
let formattedKey = key.trim();
Expand Down Expand Up @@ -138,7 +149,8 @@ export const validateChefConnectionCredentials = async (config: TChefConnectionC

const headers = getChefAuthHeaders("GET", path, "", inputCredentials.userName, inputCredentials.privateKey);

await request.get(`${hostServerUrl}${path}`, {
const secureUrl = buildSecureUrl(hostServerUrl, path);
await request.get(secureUrl, {
headers
});
} catch (error: unknown) {
Expand Down Expand Up @@ -168,7 +180,8 @@ export const listChefDataBags = async (appConnection: TChefConnection): Promise<

const headers = getChefAuthHeaders("GET", path, body, userName, privateKey);

const res = await request.get<Record<string, string>>(`${hostServerUrl}${path}`, {
const secureUrl = buildSecureUrl(hostServerUrl, path);
const res = await request.get<Record<string, string>>(secureUrl, {
headers
});

Expand Down Expand Up @@ -203,7 +216,8 @@ export const listChefDataBagItems = async (

const headers = getChefAuthHeaders("GET", path, body, userName, privateKey);

const res = await request.get<Record<string, string>>(`${hostServerUrl}${path}`, {
const secureUrl = buildSecureUrl(hostServerUrl, path);
const res = await request.get<Record<string, string>>(secureUrl, {
headers
});

Expand Down Expand Up @@ -238,7 +252,8 @@ export const getChefDataBagItem = async ({

const headers = getChefAuthHeaders("GET", path, body, userName, privateKey);

const res = await request.get<TChefDataBagItemContent>(`${hostServerUrl}${path}`, {
const secureUrl = buildSecureUrl(hostServerUrl, path);
const res = await request.get<TChefDataBagItemContent>(secureUrl, {
headers
});

Expand All @@ -255,6 +270,38 @@ export const getChefDataBagItem = async ({
}
};

export const createChefDataBagItem = async ({
serverUrl,
userName,
privateKey,
orgName,
dataBagName,
data
}: Omit<TUpdateChefDataBagItem, "dataBagItemName">): Promise<void> => {
try {
const path = `/organizations/${orgName}/data/${dataBagName}`;
const body = JSON.stringify(data);

const hostServerUrl = await getChefServerUrl(serverUrl);

const headers = getChefAuthHeaders("POST", path, body, userName, privateKey);

const secureUrl = buildSecureUrl(hostServerUrl, path);
await request.post(secureUrl, data, {
headers
});
} catch (error) {
if (error instanceof AxiosError) {
throw new BadRequestError({
message: `Failed to create Chef data bag item: ${error.message || "Unknown error"}`
});
}
throw new BadRequestError({
message: "Unable to create Chef data bag item"
});
}
};

export const updateChefDataBagItem = async ({
serverUrl,
userName,
Expand All @@ -272,7 +319,8 @@ export const updateChefDataBagItem = async ({

const headers = getChefAuthHeaders("PUT", path, body, userName, privateKey);

await request.put(`${hostServerUrl}${path}`, data, {
const secureUrl = buildSecureUrl(hostServerUrl, path);
await request.put(secureUrl, data, {
headers
});
} catch (error) {
Expand All @@ -286,3 +334,35 @@ export const updateChefDataBagItem = async ({
});
}
};

export const removeChefDataBagItem = async ({
serverUrl,
userName,
privateKey,
orgName,
dataBagName,
dataBagItemName
}: Omit<TUpdateChefDataBagItem, "data">): Promise<void> => {
try {
const path = `/organizations/${orgName}/data/${dataBagName}/${dataBagItemName}`;
const body = "";

const hostServerUrl = await getChefServerUrl(serverUrl);

const headers = getChefAuthHeaders("DELETE", path, body, userName, privateKey);

const secureUrl = buildSecureUrl(hostServerUrl, path);
await request.delete(secureUrl, {
headers
});
} catch (error) {
if (error instanceof AxiosError) {
throw new BadRequestError({
message: `Failed to remove Chef data bag item: ${error.message || "Unknown error"}`
});
}
throw new BadRequestError({
message: "Unable to remove Chef data bag item"
});
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {
AWS_SECRETS_MANAGER_PKI_SYNC_LIST_OPTION,
AwsSecretsManagerPkiSyncSchema,
CreateAwsSecretsManagerPkiSyncSchema,
UpdateAwsSecretsManagerPkiSyncSchema
} from "@app/services/pki-sync/aws-secrets-manager";
import { PkiSync } from "@app/services/pki-sync/pki-sync-enums";

import { registerSyncPkiEndpoints } from "./pki-sync-endpoints";

export const registerAwsSecretsManagerPkiSyncRouter = async (server: FastifyZodProvider) =>
registerSyncPkiEndpoints({
destination: PkiSync.AwsSecretsManager,
server,
responseSchema: AwsSecretsManagerPkiSyncSchema,
createSchema: CreateAwsSecretsManagerPkiSyncSchema,
updateSchema: UpdateAwsSecretsManagerPkiSyncSchema,
syncOptions: {
canImportCertificates: AWS_SECRETS_MANAGER_PKI_SYNC_LIST_OPTION.canImportCertificates,
canRemoveCertificates: AWS_SECRETS_MANAGER_PKI_SYNC_LIST_OPTION.canRemoveCertificates
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ChefPkiSyncSchema, CreateChefPkiSyncSchema, UpdateChefPkiSyncSchema } from "@app/services/pki-sync/chef";
import { PkiSync } from "@app/services/pki-sync/pki-sync-enums";

import { registerSyncPkiEndpoints } from "./pki-sync-endpoints";

export const registerChefPkiSyncRouter = async (server: FastifyZodProvider) =>
registerSyncPkiEndpoints({
destination: PkiSync.Chef,
server,
responseSchema: ChefPkiSyncSchema,
createSchema: CreateChefPkiSyncSchema,
updateSchema: UpdateChefPkiSyncSchema,
syncOptions: {
canImportCertificates: false,
canRemoveCertificates: true
}
});
6 changes: 5 additions & 1 deletion backend/src/server/routes/v1/pki-sync-routers/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { PkiSync } from "@app/services/pki-sync/pki-sync-enums";

import { registerAwsCertificateManagerPkiSyncRouter } from "./aws-certificate-manager-pki-sync-router";
import { registerAwsSecretsManagerPkiSyncRouter } from "./aws-secrets-manager-pki-sync-router";
import { registerAzureKeyVaultPkiSyncRouter } from "./azure-key-vault-pki-sync-router";
import { registerChefPkiSyncRouter } from "./chef-pki-sync-router";

export * from "./pki-sync-router";

export const PKI_SYNC_REGISTER_ROUTER_MAP: Record<PkiSync, (server: FastifyZodProvider) => Promise<void>> = {
[PkiSync.AzureKeyVault]: registerAzureKeyVaultPkiSyncRouter,
[PkiSync.AwsCertificateManager]: registerAwsCertificateManagerPkiSyncRouter
[PkiSync.AwsCertificateManager]: registerAwsCertificateManagerPkiSyncRouter,
[PkiSync.AwsSecretsManager]: registerAwsSecretsManagerPkiSyncRouter,
[PkiSync.Chef]: registerChefPkiSyncRouter
};
28 changes: 21 additions & 7 deletions backend/src/server/routes/v3/certificates-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { mapEnumsForValidation } from "@app/services/certificate-common/certific
import { EnrollmentType } from "@app/services/certificate-profile/certificate-profile-types";
import { validateTemplateRegexField } from "@app/services/certificate-template/certificate-template-validators";

import { booleanSchema } from "../sanitizedSchemas";

interface CertificateRequestForService {
commonName?: string;
keyUsages?: CertKeyUsageType[];
Expand Down Expand Up @@ -87,7 +89,8 @@ export const registerCertificatesRouter = async (server: FastifyZodProvider) =>
)
.optional(),
signatureAlgorithm: z.nativeEnum(CertSignatureAlgorithm),
keyAlgorithm: z.nativeEnum(CertKeyAlgorithm)
keyAlgorithm: z.nativeEnum(CertKeyAlgorithm),
removeRootsFromChain: booleanSchema.default(false).optional()
})
.refine(validateTtlAndDateFields, {
message:
Expand Down Expand Up @@ -131,7 +134,8 @@ export const registerCertificatesRouter = async (server: FastifyZodProvider) =>
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
profileId: req.body.profileId,
certificateRequest: mappedCertificateRequest
certificateRequest: mappedCertificateRequest,
removeRootsFromChain: req.body.removeRootsFromChain
});

await server.services.auditLog.createAuditLog({
Expand Down Expand Up @@ -171,7 +175,8 @@ export const registerCertificatesRouter = async (server: FastifyZodProvider) =>
.min(1, "TTL cannot be empty")
.refine((val) => ms(val) > 0, "TTL must be a positive number"),
notBefore: validateCaDateField.optional(),
notAfter: validateCaDateField.optional()
notAfter: validateCaDateField.optional(),
removeRootsFromChain: booleanSchema.default(false).optional()
})
.refine(validateTtlAndDateFields, {
message:
Expand Down Expand Up @@ -206,7 +211,8 @@ export const registerCertificatesRouter = async (server: FastifyZodProvider) =>
},
notBefore: req.body.notBefore ? new Date(req.body.notBefore) : undefined,
notAfter: req.body.notAfter ? new Date(req.body.notAfter) : undefined,
enrollmentType: EnrollmentType.API
enrollmentType: EnrollmentType.API,
removeRootsFromChain: req.body.removeRootsFromChain
});

await server.services.auditLog.createAuditLog({
Expand Down Expand Up @@ -262,7 +268,8 @@ export const registerCertificatesRouter = async (server: FastifyZodProvider) =>
notAfter: validateCaDateField.optional(),
commonName: validateTemplateRegexField.optional(),
signatureAlgorithm: z.nativeEnum(CertSignatureAlgorithm),
keyAlgorithm: z.nativeEnum(CertKeyAlgorithm)
keyAlgorithm: z.nativeEnum(CertKeyAlgorithm),
removeRootsFromChain: booleanSchema.default(false).optional()
})
.refine(validateTtlAndDateFields, {
message:
Expand Down Expand Up @@ -325,7 +332,8 @@ export const registerCertificatesRouter = async (server: FastifyZodProvider) =>
notAfter: req.body.notAfter ? new Date(req.body.notAfter) : undefined,
signatureAlgorithm: req.body.signatureAlgorithm,
keyAlgorithm: req.body.keyAlgorithm
}
},
removeRootsFromChain: req.body.removeRootsFromChain
});

await server.services.auditLog.createAuditLog({
Expand Down Expand Up @@ -357,6 +365,11 @@ export const registerCertificatesRouter = async (server: FastifyZodProvider) =>
params: z.object({
certificateId: z.string().uuid()
}),
body: z
.object({
removeRootsFromChain: booleanSchema.default(false).optional()
})
.optional(),
response: {
200: z.object({
certificate: z.string().trim(),
Expand All @@ -375,7 +388,8 @@ export const registerCertificatesRouter = async (server: FastifyZodProvider) =>
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
certificateId: req.params.certificateId
certificateId: req.params.certificateId,
removeRootsFromChain: req.body?.removeRootsFromChain
});

await server.services.auditLog.createAuditLog({
Expand Down
3 changes: 2 additions & 1 deletion backend/src/services/app-connection/app-connection-fns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ const PKI_APP_CONNECTIONS = [
AppConnection.AWS,
AppConnection.Cloudflare,
AppConnection.AzureADCS,
AppConnection.AzureKeyVault
AppConnection.AzureKeyVault,
AppConnection.Chef
];

export const listAppConnectionOptions = (projectType?: ProjectType) => {
Expand Down
Loading
Loading