mirror of
https://github.com/Infisical/infisical.git
synced 2025-08-07 17:58:25 +00:00
Compare commits
10 Commits
daniel/rot
...
audit-log-
Author | SHA1 | Date | |
---|---|---|---|
|
50e40e8bcf | ||
|
59cffe8cfb | ||
|
fa61867a72 | ||
|
f3694ca730 | ||
|
8fcd6d9997 | ||
|
45ff9a50b6 | ||
|
81cdfb9861 | ||
|
e1e553ce23 | ||
|
e7a6f46f56 | ||
|
e9f5055481 |
@@ -2,6 +2,7 @@ import { z } from "zod";
|
||||
|
||||
import { isValidIp } from "@app/lib/ip";
|
||||
import { isFQDN } from "@app/lib/validator/validate-url";
|
||||
import { TAltNameMapping, TAltNameType } from "@app/services/certificate/certificate-types";
|
||||
|
||||
const isValidDate = (dateString: string) => {
|
||||
const date = new Date(dateString);
|
||||
@@ -56,3 +57,19 @@ export const validateAltNamesField = z
|
||||
message: "Each alt name must be a valid hostname, email address, IP address or URL"
|
||||
}
|
||||
);
|
||||
|
||||
export const validateAndMapAltNameType = (name: string): TAltNameMapping | null => {
|
||||
if (isFQDN(name, { allow_wildcard: true, require_tld: false })) {
|
||||
return { type: TAltNameType.DNS, value: name };
|
||||
}
|
||||
if (z.string().url().safeParse(name).success) {
|
||||
return { type: TAltNameType.URL, value: name };
|
||||
}
|
||||
if (z.string().email().safeParse(name).success) {
|
||||
return { type: TAltNameType.EMAIL, value: name };
|
||||
}
|
||||
if (isValidIp(name)) {
|
||||
return { type: TAltNameType.IP, value: name };
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
@@ -1,7 +1,6 @@
|
||||
/* eslint-disable no-bitwise */
|
||||
import * as x509 from "@peculiar/x509";
|
||||
import RE2 from "re2";
|
||||
import { z } from "zod";
|
||||
|
||||
import { TCertificateTemplates, TPkiSubscribers } from "@app/db/schemas";
|
||||
import { TCertificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal";
|
||||
@@ -9,7 +8,6 @@ import { getConfig } from "@app/lib/config/env";
|
||||
import { crypto } from "@app/lib/crypto/cryptography";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { ms } from "@app/lib/ms";
|
||||
import { isFQDN } from "@app/lib/validator/validate-url";
|
||||
import { TCertificateBodyDALFactory } from "@app/services/certificate/certificate-body-dal";
|
||||
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
|
||||
import { TCertificateSecretDALFactory } from "@app/services/certificate/certificate-secret-dal";
|
||||
@@ -17,7 +15,8 @@ import {
|
||||
CertExtendedKeyUsage,
|
||||
CertKeyAlgorithm,
|
||||
CertKeyUsage,
|
||||
CertStatus
|
||||
CertStatus,
|
||||
TAltNameMapping
|
||||
} from "@app/services/certificate/certificate-types";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||
@@ -34,6 +33,7 @@ import {
|
||||
} from "../certificate-authority-fns";
|
||||
import { TCertificateAuthoritySecretDALFactory } from "../certificate-authority-secret-dal";
|
||||
import { TIssueCertWithTemplateDTO } from "./internal-certificate-authority-types";
|
||||
import { validateAndMapAltNameType } from "../certificate-authority-validators";
|
||||
|
||||
type TInternalCertificateAuthorityFnsDeps = {
|
||||
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findByIdWithAssociatedCa" | "findById">;
|
||||
@@ -152,27 +152,15 @@ export const InternalCertificateAuthorityFns = ({
|
||||
extensions.push(extendedKeyUsagesExtension);
|
||||
}
|
||||
|
||||
let altNamesArray: { type: "email" | "dns" | "ip" | "url"; value: string }[] = [];
|
||||
let altNamesArray: TAltNameMapping[] = [];
|
||||
|
||||
if (subscriber.subjectAlternativeNames?.length) {
|
||||
altNamesArray = subscriber.subjectAlternativeNames.map((altName) => {
|
||||
if (z.string().email().safeParse(altName).success) {
|
||||
return { type: "email", value: altName };
|
||||
const altNameType = validateAndMapAltNameType(altName);
|
||||
if (!altNameType) {
|
||||
throw new BadRequestError({ message: `Invalid SAN entry: ${altName}` });
|
||||
}
|
||||
|
||||
if (isFQDN(altName, { allow_wildcard: true, require_tld: false })) {
|
||||
return { type: "dns", value: altName };
|
||||
}
|
||||
|
||||
if (z.string().url().safeParse(altName).success) {
|
||||
return { type: "url", value: altName };
|
||||
}
|
||||
|
||||
if (z.string().ip().safeParse(altName).success) {
|
||||
return { type: "ip", value: altName };
|
||||
}
|
||||
|
||||
throw new BadRequestError({ message: `Invalid SAN entry: ${altName}` });
|
||||
return altNameType;
|
||||
});
|
||||
|
||||
const altNamesExtension = new x509.SubjectAlternativeNameExtension(altNamesArray, false);
|
||||
@@ -426,27 +414,15 @@ export const InternalCertificateAuthorityFns = ({
|
||||
);
|
||||
}
|
||||
|
||||
let altNamesArray: { type: "email" | "dns" | "ip" | "url"; value: string }[] = [];
|
||||
let altNamesArray: TAltNameMapping[] = [];
|
||||
|
||||
if (altNames) {
|
||||
altNamesArray = altNames.split(",").map((altName) => {
|
||||
if (z.string().email().safeParse(altName).success) {
|
||||
return { type: "email", value: altName };
|
||||
const altNameType = validateAndMapAltNameType(altName);
|
||||
if (!altNameType) {
|
||||
throw new BadRequestError({ message: `Invalid SAN entry: ${altName}` });
|
||||
}
|
||||
|
||||
if (isFQDN(altName, { allow_wildcard: true, require_tld: false })) {
|
||||
return { type: "dns", value: altName };
|
||||
}
|
||||
|
||||
if (z.string().url().safeParse(altName).success) {
|
||||
return { type: "url", value: altName };
|
||||
}
|
||||
|
||||
if (z.string().ip().safeParse(altName).success) {
|
||||
return { type: "ip", value: altName };
|
||||
}
|
||||
|
||||
throw new BadRequestError({ message: `Invalid SAN entry: ${altName}` });
|
||||
return altNameType;
|
||||
});
|
||||
|
||||
const altNamesExtension = new x509.SubjectAlternativeNameExtension(altNamesArray, false);
|
||||
|
@@ -2,7 +2,6 @@
|
||||
import { ForbiddenError, subject } from "@casl/ability";
|
||||
import * as x509 from "@peculiar/x509";
|
||||
import slugify from "@sindresorhus/slugify";
|
||||
import { z } from "zod";
|
||||
|
||||
import { ActionProjectType, TableName, TCertificateAuthorities, TCertificateTemplates } from "@app/db/schemas";
|
||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||
@@ -18,7 +17,6 @@ import { crypto } from "@app/lib/crypto/cryptography";
|
||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||
import { ms } from "@app/lib/ms";
|
||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||
import { isFQDN } from "@app/lib/validator/validate-url";
|
||||
import { TCertificateBodyDALFactory } from "@app/services/certificate/certificate-body-dal";
|
||||
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
@@ -34,7 +32,8 @@ import {
|
||||
CertExtendedKeyUsageOIDToName,
|
||||
CertKeyAlgorithm,
|
||||
CertKeyUsage,
|
||||
CertStatus
|
||||
CertStatus,
|
||||
TAltNameMapping
|
||||
} from "../../certificate/certificate-types";
|
||||
import { TCertificateTemplateDALFactory } from "../../certificate-template/certificate-template-dal";
|
||||
import { validateCertificateDetailsAgainstTemplate } from "../../certificate-template/certificate-template-fns";
|
||||
@@ -69,6 +68,7 @@ import {
|
||||
TSignIntermediateDTO,
|
||||
TUpdateCaDTO
|
||||
} from "./internal-certificate-authority-types";
|
||||
import { validateAndMapAltNameType } from "../certificate-authority-validators";
|
||||
|
||||
type TInternalCertificateAuthorityServiceFactoryDep = {
|
||||
certificateAuthorityDAL: Pick<
|
||||
@@ -1364,34 +1364,18 @@ export const internalCertificateAuthorityServiceFactory = ({
|
||||
);
|
||||
}
|
||||
|
||||
let altNamesArray: {
|
||||
type: "email" | "dns";
|
||||
value: string;
|
||||
}[] = [];
|
||||
let altNamesArray: TAltNameMapping[] = [];
|
||||
|
||||
if (altNames) {
|
||||
altNamesArray = altNames
|
||||
.split(",")
|
||||
.map((name) => name.trim())
|
||||
.map((altName) => {
|
||||
// check if the altName is a valid email
|
||||
if (z.string().email().safeParse(altName).success) {
|
||||
return {
|
||||
type: "email",
|
||||
value: altName
|
||||
};
|
||||
.map((altName): TAltNameMapping => {
|
||||
const altNameType = validateAndMapAltNameType(altName);
|
||||
if (!altNameType) {
|
||||
throw new Error(`Invalid altName: ${altName}`);
|
||||
}
|
||||
|
||||
// check if the altName is a valid hostname
|
||||
if (isFQDN(altName, { allow_wildcard: true })) {
|
||||
return {
|
||||
type: "dns",
|
||||
value: altName
|
||||
};
|
||||
}
|
||||
|
||||
// If altName is neither a valid email nor a valid hostname, throw an error or handle it accordingly
|
||||
throw new Error(`Invalid altName: ${altName}`);
|
||||
return altNameType;
|
||||
});
|
||||
|
||||
const altNamesExtension = new x509.SubjectAlternativeNameExtension(altNamesArray, false);
|
||||
@@ -1766,34 +1750,22 @@ export const internalCertificateAuthorityServiceFactory = ({
|
||||
}
|
||||
|
||||
let altNamesFromCsr: string = "";
|
||||
let altNamesArray: {
|
||||
type: "email" | "dns";
|
||||
value: string;
|
||||
}[] = [];
|
||||
let altNamesArray: TAltNameMapping[] = [];
|
||||
|
||||
if (altNames) {
|
||||
altNamesArray = altNames
|
||||
.split(",")
|
||||
.map((name) => name.trim())
|
||||
.map((altName) => {
|
||||
// check if the altName is a valid email
|
||||
if (z.string().email().safeParse(altName).success) {
|
||||
return {
|
||||
type: "email",
|
||||
value: altName
|
||||
};
|
||||
.map((altName): TAltNameMapping => {
|
||||
const altNameType = validateAndMapAltNameType(altName);
|
||||
if (!altNameType) {
|
||||
throw new Error(`Invalid altName: ${altName}`);
|
||||
}
|
||||
|
||||
// check if the altName is a valid hostname
|
||||
if (isFQDN(altName, { allow_wildcard: true })) {
|
||||
return {
|
||||
type: "dns",
|
||||
value: altName
|
||||
};
|
||||
}
|
||||
|
||||
// If altName is neither a valid email nor a valid hostname, throw an error or handle it accordingly
|
||||
throw new Error(`Invalid altName: ${altName}`);
|
||||
return altNameType;
|
||||
});
|
||||
|
||||
const altNamesExtension = new x509.SubjectAlternativeNameExtension(altNamesArray, false);
|
||||
extensions.push(altNamesExtension);
|
||||
} else {
|
||||
// attempt to read from CSR if altNames is not explicitly provided
|
||||
const sanExtension = csrObj.extensions.find((ext) => ext.type === "2.5.29.17");
|
||||
@@ -1801,11 +1773,16 @@ export const internalCertificateAuthorityServiceFactory = ({
|
||||
const sanNames = new x509.GeneralNames(sanExtension.value);
|
||||
|
||||
altNamesArray = sanNames.items
|
||||
.filter((value) => value.type === "email" || value.type === "dns")
|
||||
.map((name) => ({
|
||||
type: name.type as "email" | "dns",
|
||||
value: name.value
|
||||
}));
|
||||
.filter(
|
||||
(value) => value.type === "email" || value.type === "dns" || value.type === "url" || value.type === "ip"
|
||||
)
|
||||
.map((name): TAltNameMapping => {
|
||||
const altNameType = validateAndMapAltNameType(name.value);
|
||||
if (!altNameType) {
|
||||
throw new Error(`Invalid altName from CSR: ${name.value}`);
|
||||
}
|
||||
return altNameType;
|
||||
});
|
||||
|
||||
altNamesFromCsr = sanNames.items.map((item) => item.value).join(",");
|
||||
}
|
||||
|
@@ -104,3 +104,14 @@ export type TGetCertificateCredentialsDTO = {
|
||||
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;
|
||||
kmsService: Pick<TKmsServiceFactory, "decryptWithKmsKey" | "generateKmsKey">;
|
||||
};
|
||||
|
||||
export enum TAltNameType {
|
||||
EMAIL = "email",
|
||||
DNS = "dns",
|
||||
IP = "ip",
|
||||
URL = "url"
|
||||
}
|
||||
export type TAltNameMapping = {
|
||||
type: TAltNameType;
|
||||
value: string;
|
||||
};
|
||||
|
@@ -6,6 +6,7 @@ description: "Learn how to automatically rotate Azure Client Secrets."
|
||||
## Prerequisites
|
||||
|
||||
- Create an [Azure Client Secret Connection](/integrations/app-connections/azure-client-secrets).
|
||||
- Ensure your network security policies allow incoming requests from Infisical to this rotation provider, if network restrictions apply.
|
||||
|
||||
## Create an Azure Client Secret Rotation in Infisical
|
||||
|
||||
|
@@ -14,6 +14,7 @@ description: "Learn how to automatically rotate LDAP passwords."
|
||||
## Prerequisites
|
||||
|
||||
- Create an [LDAP Connection](/integrations/app-connections/ldap) with the **Secret Rotation** requirements
|
||||
- Ensure your network security policies allow incoming requests from Infisical to this rotation provider, if network restrictions apply.
|
||||
|
||||
## Create an LDAP Password Rotation in Infisical
|
||||
|
||||
|
@@ -30,6 +30,7 @@ An example creation statement might look like:
|
||||
To learn more about Microsoft SQL Server's permission system, please visit their [documentation](https://learn.microsoft.com/en-us/sql/t-sql/statements/grant-transact-sql?view=sql-server-ver16).
|
||||
</Tip>
|
||||
|
||||
3. Ensure your network security policies allow incoming requests from Infisical to this rotation provider, if network restrictions apply.
|
||||
|
||||
## Create a Microsoft SQL Server Credentials Rotation in Infisical
|
||||
|
||||
|
@@ -25,7 +25,7 @@ description: "Learn how to automatically rotate MySQL credentials."
|
||||
<Tip>
|
||||
To learn more about the MySQL permission system, please visit their [documentation](https://dev.mysql.com/doc/refman/8.4/en/grant.html).
|
||||
</Tip>
|
||||
|
||||
3. Ensure your network security policies allow incoming requests from Infisical to this rotation provider, if network restrictions apply.
|
||||
|
||||
## Create a MySQL Credentials Rotation in Infisical
|
||||
|
||||
|
@@ -31,6 +31,7 @@ description: "Learn how to automatically rotate Oracle Database credentials."
|
||||
To learn more about the Oracle Database permission system, please visit their [documentation](https://docs.oracle.com/en/database/oracle/oracle-database/19/dbseg/configuring-privilege-and-role-authorization.html).
|
||||
</Tip>
|
||||
|
||||
3. Ensure your network security policies allow incoming requests from Infisical to this rotation provider, if network restrictions apply.
|
||||
|
||||
## Create an Oracle Database Credentials Rotation in Infisical
|
||||
|
||||
|
@@ -27,6 +27,7 @@ description: "Learn how to automatically rotate PostgreSQL credentials."
|
||||
To learn more about PostgreSQL's permission system, please visit their [documentation](https://www.postgresql.org/docs/current/sql-grant.html).
|
||||
</Tip>
|
||||
|
||||
3. Ensure your network security policies allow incoming requests from Infisical to this rotation provider, if network restrictions apply.
|
||||
|
||||
## Create a PostgreSQL Credentials Rotation in Infisical
|
||||
|
||||
|
@@ -7,6 +7,7 @@ description: "Learn how to configure an AWS Parameter Store Sync for Infisical."
|
||||
|
||||
- Set up and add secrets to [Infisical Cloud](https://app.infisical.com)
|
||||
- Create an [AWS Connection](/integrations/app-connections/aws) with the required **Secret Sync** permissions
|
||||
- Ensure your network security policies allow incoming requests from Infisical to this secret sync provider, if network restrictions apply.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Infisical UI">
|
||||
|
@@ -7,6 +7,7 @@ description: "Learn how to configure an AWS Secrets Manager Sync for Infisical."
|
||||
|
||||
- Set up and add secrets to [Infisical Cloud](https://app.infisical.com)
|
||||
- Create an [AWS Connection](/integrations/app-connections/aws) with the required **Secret Sync** permissions
|
||||
- Ensure your network security policies allow incoming requests from Infisical to this secret sync provider, if network restrictions apply.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Infisical UI">
|
||||
|
@@ -7,6 +7,7 @@ description: "Learn how to configure an Azure App Configuration Sync for Infisic
|
||||
|
||||
- Set up and add secrets to [Infisical Cloud](https://app.infisical.com)
|
||||
- Create an [Azure App Configuration Connection](/integrations/app-connections/azure-app-configuration)
|
||||
- Ensure your network security policies allow incoming requests from Infisical to this secret sync provider, if network restrictions apply.
|
||||
|
||||
<Note>
|
||||
The Azure App Configuration Secret Sync requires the following permissions to be set on the user / service principal
|
||||
|
@@ -7,6 +7,7 @@ description: "Learn how to configure a Azure DevOps Sync for Infisical."
|
||||
|
||||
- Set up and add secrets to [Infisical Cloud](https://app.infisical.com)
|
||||
- Create an [Azure DevOps Connection](/integrations/app-connections/azure-devops)
|
||||
- Ensure your network security policies allow incoming requests from Infisical to this secret sync provider, if network restrictions apply.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Infisical UI">
|
||||
|
@@ -7,6 +7,7 @@ description: "Learn how to configure a Azure Key Vault Sync for Infisical."
|
||||
|
||||
- Set up and add secrets to [Infisical Cloud](https://app.infisical.com)
|
||||
- Create an [Azure Key Vault Connection](/integrations/app-connections/azure-key-vault)
|
||||
- Ensure your network security policies allow incoming requests from Infisical to this secret sync provider, if network restrictions apply.
|
||||
|
||||
<Note>
|
||||
The Azure Key Vault Secret Sync requires the following secrets permissions to be set on the user / service principal
|
||||
|
@@ -11,6 +11,7 @@ description: "Learn how to configure a GCP Secret Manager Sync for Infisical."
|
||||

|
||||

|
||||

|
||||
- Ensure your network security policies allow incoming requests from Infisical to this secret sync provider, if network restrictions apply.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Infisical UI">
|
||||
|
@@ -7,6 +7,7 @@ description: "Learn how to configure a GitHub Sync for Infisical."
|
||||
|
||||
- Set up and add secrets to [Infisical Cloud](https://app.infisical.com)
|
||||
- Create a [GitHub Connection](/integrations/app-connections/github)
|
||||
- Ensure your network security policies allow incoming requests from Infisical to this secret sync provider, if network restrictions apply.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Infisical UI">
|
||||
|
@@ -7,6 +7,7 @@ description: "Learn how to configure a GitLab Sync for Infisical."
|
||||
|
||||
- Set up and add secrets to [Infisical Cloud](https://app.infisical.com)
|
||||
- Create a [GitLab Connection](/integrations/app-connections/gitlab)
|
||||
- Ensure your network security policies allow incoming requests from Infisical to this secret sync provider, if network restrictions apply.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Infisical UI">
|
||||
|
@@ -14,6 +14,7 @@ description: "Learn how to configure an Oracle Cloud Infrastructure Vault Sync f
|
||||
- Create an [OCI Connection](/integrations/app-connections/oci) with the required **Secret Sync** permissions
|
||||
- [Create](https://docs.oracle.com/en-us/iaas/Content/Identity/compartments/To_create_a_compartment.htm) or use an existing OCI Compartment (which the OCI Connection is authorized to access)
|
||||
- [Create](https://docs.oracle.com/en-us/iaas/Content/KeyManagement/Tasks/managingvaults_topic-To_create_a_new_vault.htm#createnewvault) or use an existing OCI Vault
|
||||
- Ensure your network security policies allow incoming requests from Infisical to this secret sync provider, if network restrictions apply.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Infisical UI">
|
||||
|
@@ -119,7 +119,7 @@ export const LogsFilter = ({ presets, setFilter, filter, project }: Props) => {
|
||||
)}
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="mt-4 py-4">
|
||||
<DropdownMenuContent align="end" className="mt-4 overflow-visible py-4">
|
||||
<form onSubmit={handleSubmit(setFilter)}>
|
||||
<div className="flex min-w-64 flex-col font-inter">
|
||||
<div className="mb-3 flex items-center border-b border-b-mineshaft-500 px-3 pb-2">
|
||||
@@ -176,7 +176,8 @@ export const LogsFilter = ({ presets, setFilter, filter, project }: Props) => {
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="start"
|
||||
align="end"
|
||||
sideOffset={2}
|
||||
className="thin-scrollbar z-[100] max-h-80 overflow-hidden"
|
||||
>
|
||||
<div className="max-h-80 overflow-y-auto">
|
||||
@@ -258,6 +259,7 @@ export const LogsFilter = ({ presets, setFilter, filter, project }: Props) => {
|
||||
else setValue("userAgentType", e as UserAgentType, { shouldDirty: true });
|
||||
}}
|
||||
className={twMerge("w-full border border-mineshaft-500 bg-mineshaft-700")}
|
||||
position="popper"
|
||||
>
|
||||
<SelectItem value="all" key="all">
|
||||
All sources
|
||||
@@ -319,7 +321,6 @@ export const LogsFilter = ({ presets, setFilter, filter, project }: Props) => {
|
||||
<AnimatePresence initial={false}>
|
||||
{showSecretsSection && (
|
||||
<motion.div
|
||||
className="overflow-hidden"
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
animate={{ opacity: 1, height: "auto" }}
|
||||
exit={{ opacity: 0, height: 0 }}
|
||||
@@ -352,6 +353,7 @@ export const LogsFilter = ({ presets, setFilter, filter, project }: Props) => {
|
||||
>
|
||||
<FilterableSelect
|
||||
value={value}
|
||||
menuPlacement="top"
|
||||
key={value?.name || "filter-environment"}
|
||||
isClearable
|
||||
isDisabled={!selectedProject}
|
||||
|
Reference in New Issue
Block a user