mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 18:41:21 +00:00
Merge branch 'main' into feat/azureClientSecretsRotation
This commit is contained in:
@@ -807,6 +807,8 @@ export const RAW_SECRETS = {
|
||||
tagIds: "The ID of the tags to be attached to the updated secret.",
|
||||
secretReminderRepeatDays: "Interval for secret rotation notifications, measured in days.",
|
||||
secretReminderNote: "Note to be attached in notification email.",
|
||||
secretReminderRecipients:
|
||||
"An array of user IDs that will receive the reminder email. If not specified, all project members will receive the reminder email.",
|
||||
newSecretName: "The new name for the secret."
|
||||
},
|
||||
DELETE: {
|
||||
@@ -1387,6 +1389,7 @@ export const SSH_HOSTS = {
|
||||
CREATE: {
|
||||
projectId: "The ID of the project to create the SSH host in.",
|
||||
hostname: "The hostname of the SSH host.",
|
||||
alias: "The alias for the SSH host.",
|
||||
userCertTtl: "The time to live for user certificates issued under this host.",
|
||||
hostCertTtl: "The time to live for host certificates issued under this host.",
|
||||
loginUser: "A login user on the remote machine (e.g. 'ec2-user', 'deploy', 'admin')",
|
||||
@@ -1401,6 +1404,7 @@ export const SSH_HOSTS = {
|
||||
UPDATE: {
|
||||
sshHostId: "The ID of the SSH host to update.",
|
||||
hostname: "The hostname of the SSH host to update to.",
|
||||
alias: "The alias for the SSH host to update to.",
|
||||
userCertTtl: "The time to live for user certificates issued under this host to update to.",
|
||||
hostCertTtl: "The time to live for host certificates issued under this host to update to.",
|
||||
loginUser: "A login user on the remote machine (e.g. 'ec2-user', 'deploy', 'admin')",
|
||||
@@ -1857,6 +1861,20 @@ export const AppConnections = {
|
||||
WINDMILL: {
|
||||
instanceUrl: "The Windmill instance URL to connect with (defaults to https://app.windmill.dev).",
|
||||
accessToken: "The access token to use to connect with Windmill."
|
||||
},
|
||||
LDAP: {
|
||||
provider: "The type of LDAP provider. Determines provider-specific behaviors.",
|
||||
url: "The LDAP/LDAPS URL to connect to (e.g., 'ldap://domain-or-ip:389' or 'ldaps://domain-or-ip:636').",
|
||||
dn: "The Distinguished Name (DN) of the principal to bind with (e.g., 'CN=John,CN=Users,DC=example,DC=com').",
|
||||
password: "The password to bind with for authentication.",
|
||||
sslRejectUnauthorized:
|
||||
"Whether or not to reject unauthorized SSL certificates (true/false) when using ldaps://. Set to false only in test environments.",
|
||||
sslCertificate:
|
||||
"The SSL certificate (PEM format) to use for secure connection when using ldaps:// with a self-signed certificate."
|
||||
},
|
||||
TEAMCITY: {
|
||||
instanceUrl: "The TeamCity instance URL to connect with.",
|
||||
accessToken: "The access token to use to connect with TeamCity."
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1996,6 +2014,10 @@ export const SecretSyncs = {
|
||||
WINDMILL: {
|
||||
workspace: "The Windmill workspace to sync secrets to.",
|
||||
path: "The Windmill workspace path to sync secrets to."
|
||||
},
|
||||
TEAMCITY: {
|
||||
project: "The TeamCity project to sync secrets to.",
|
||||
buildConfig: "The TeamCity build configuration to sync secrets to."
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2064,6 +2086,26 @@ export const SecretRotations = {
|
||||
AZURE_CLIENT_SECRET: {
|
||||
appId: "The ID of the Azure Application to rotate the client secret for.",
|
||||
appName: "The name of the Azure Application to rotate the client secret for."
|
||||
},
|
||||
LDAP_PASSWORD: {
|
||||
dn: "The Distinguished Name (DN) of the principal to rotate the password for."
|
||||
},
|
||||
GENERAL: {
|
||||
PASSWORD_REQUIREMENTS: {
|
||||
base: "The password requirements to use when generating the new password.",
|
||||
length: "The length of the password to generate.",
|
||||
required: {
|
||||
digits: "The amount of digits to require in the generated password.",
|
||||
lowercase: "The amount of lowercase characters to require in the generated password.",
|
||||
uppercase: "The amount of uppercase characters to require in the generated password.",
|
||||
symbols: "The amount of symbols to require in the generated password."
|
||||
},
|
||||
allowedSymbols: 'The allowed symbols to use in the generated password (defaults to "-_.~!*").'
|
||||
}
|
||||
},
|
||||
AWS_IAM_USER_SECRET: {
|
||||
userName: "The name of the client to rotate credentials for.",
|
||||
region: "The AWS region the client is present in."
|
||||
}
|
||||
},
|
||||
SECRETS_MAPPING: {
|
||||
@@ -2078,6 +2120,14 @@ export const SecretRotations = {
|
||||
AZURE_CLIENT_SECRET: {
|
||||
clientId: "The name of the secret that the client ID will be mapped to.",
|
||||
clientSecret: "The name of the secret that the rotated client secret will be mapped to."
|
||||
},
|
||||
LDAP_PASSWORD: {
|
||||
dn: "The name of the secret that the Distinguished Name (DN) of the principal will be mapped to.",
|
||||
password: "The name of the secret that the rotated password will be mapped to."
|
||||
},
|
||||
AWS_IAM_USER_SECRET: {
|
||||
accessKeyId: "The name of the secret that the access key ID will be mapped to.",
|
||||
secretAccessKey: "The name of the secret that the rotated secret access key will be mapped to."
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export const INFISICAL_PROVIDER_GITHUB_ACCESS_TOKEN = "x-infisical-github-auth-access-token";
|
||||
@@ -2,7 +2,7 @@ export const daysToMillisecond = (days: number) => days * 24 * 60 * 60 * 1000;
|
||||
|
||||
export const secondsToMillis = (seconds: number) => seconds * 1000;
|
||||
|
||||
export const applyJitter = (delayMs: number, jitterMs: number) => {
|
||||
const jitter = Math.floor(Math.random() * (2 * jitterMs)) - jitterMs;
|
||||
return delayMs + jitter;
|
||||
export const applyJitter = (delay: number, jitter: number) => {
|
||||
const jitterTime = Math.floor(Math.random() * (2 * jitter)) - jitter;
|
||||
return delay + jitterTime;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
import { Knex } from "knex";
|
||||
import { Tables } from "knex/types/tables";
|
||||
|
||||
import { TableName } from "@app/db/schemas";
|
||||
|
||||
import { DatabaseError } from "../errors";
|
||||
import { buildDynamicKnexQuery, TKnexDynamicOperator } from "./dynamic";
|
||||
|
||||
@@ -25,28 +27,41 @@ export type TFindFilter<R extends object = object> = Partial<R> & {
|
||||
$search?: Partial<{ [k in keyof R]: R[k] }>;
|
||||
$complex?: TKnexDynamicOperator<R>;
|
||||
};
|
||||
|
||||
export const buildFindFilter =
|
||||
<R extends object = object>({ $in, $notNull, $search, $complex, ...filter }: TFindFilter<R>) =>
|
||||
<R extends object = object>(
|
||||
{ $in, $notNull, $search, $complex, ...filter }: TFindFilter<R>,
|
||||
tableName?: TableName,
|
||||
excludeKeys?: Array<keyof R>
|
||||
) =>
|
||||
(bd: Knex.QueryBuilder<R, R>) => {
|
||||
void bd.where(filter);
|
||||
const processedFilter = tableName
|
||||
? Object.fromEntries(
|
||||
Object.entries(filter)
|
||||
.filter(([key]) => !excludeKeys || !excludeKeys.includes(key as keyof R))
|
||||
.map(([key, value]) => [`${tableName}.${key}`, value])
|
||||
)
|
||||
: filter;
|
||||
|
||||
void bd.where(processedFilter);
|
||||
if ($in) {
|
||||
Object.entries($in).forEach(([key, val]) => {
|
||||
if (val) {
|
||||
void bd.whereIn(key as never, val as never);
|
||||
void bd.whereIn([`${tableName ? `${tableName}.` : ""}${key}`] as never, val as never);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if ($notNull?.length) {
|
||||
$notNull.forEach((key) => {
|
||||
void bd.whereNotNull(key as never);
|
||||
void bd.whereNotNull([`${tableName ? `${tableName}.` : ""}${key as string}`] as never);
|
||||
});
|
||||
}
|
||||
|
||||
if ($search) {
|
||||
Object.entries($search).forEach(([key, val]) => {
|
||||
if (val) {
|
||||
void bd.whereILike(key as never, val as never);
|
||||
void bd.whereILike([`${tableName ? `${tableName}.` : ""}${key}`] as never, val as never);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export const DistinguishedNameRegex =
|
||||
// DN format, ie; CN=user,OU=users,DC=example,DC=com
|
||||
/^(?:(?:[a-zA-Z0-9]+=[^,+="<>#;\\\\]+)(?:(?:\\+[a-zA-Z0-9]+=[^,+="<>#;\\\\]+)*)(?:,(?:[a-zA-Z0-9]+=[^,+="<>#;\\\\]+)(?:(?:\\+[a-zA-Z0-9]+=[^,+="<>#;\\\\]+)*))*)?$/;
|
||||
@@ -16,3 +16,17 @@ export const fetchGithubEmails = async (accessToken: string) => {
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
||||
type TGithubUser = {
|
||||
name?: string;
|
||||
login: string;
|
||||
};
|
||||
|
||||
export const fetchGithubUser = async (accessToken: string) => {
|
||||
const { data } = await request.get<TGithubUser>(`${INTEGRATION_GITHUB_API_URL}/user`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -15,13 +15,13 @@ export const blockLocalAndPrivateIpAddresses = async (url: string) => {
|
||||
|
||||
const validUrl = new URL(url);
|
||||
const inputHostIps: string[] = [];
|
||||
if (isIPv4(validUrl.host)) {
|
||||
inputHostIps.push(validUrl.host);
|
||||
if (isIPv4(validUrl.hostname)) {
|
||||
inputHostIps.push(validUrl.hostname);
|
||||
} else {
|
||||
if (validUrl.host === "localhost" || validUrl.host === "host.docker.internal") {
|
||||
if (validUrl.hostname === "localhost" || validUrl.hostname === "host.docker.internal") {
|
||||
throw new BadRequestError({ message: "Local IPs not allowed as URL" });
|
||||
}
|
||||
const resolvedIps = await dns.resolve4(validUrl.host);
|
||||
const resolvedIps = await dns.resolve4(validUrl.hostname);
|
||||
inputHostIps.push(...resolvedIps);
|
||||
}
|
||||
const isInternalIp = inputHostIps.some((el) => isPrivateIp(el));
|
||||
|
||||
Reference in New Issue
Block a user