improvements: final feedback and ssl enforcement

This commit is contained in:
Scott Wilson
2025-04-04 13:28:01 -07:00
parent cd333a7923
commit 06fc4e955d
9 changed files with 52 additions and 24 deletions
@@ -28,6 +28,7 @@ export async function up(knex: Knex): Promise<void> {
t.binary("encryptedLastRotationMessage"); // we encrypt this because it may contain sensitive info (SQL errors showing credentials)
t.string("lastRotationJobId");
t.datetime("nextRotationAt");
t.boolean("isLastRotationManual").notNullable().defaultTo(true); // creation is considered a "manual" rotation
});
await createOnUpdateTrigger(knex, TableName.SecretRotationV2);
+2 -2
View File
@@ -23,10 +23,10 @@ export const OrganizationsSchema = z.object({
defaultMembershipRole: z.string().default("member"),
enforceMfa: z.boolean().default(false),
selectedMfaMethod: z.string().nullable().optional(),
allowSecretSharingOutsideOrganization: z.boolean().default(true).nullable().optional(),
shouldUseNewPrivilegeSystem: z.boolean().default(true),
privilegeUpgradeInitiatedByUsername: z.string().nullable().optional(),
privilegeUpgradeInitiatedAt: z.date().nullable().optional(),
allowSecretSharingOutsideOrganization: z.boolean().default(true).nullable().optional()
privilegeUpgradeInitiatedAt: z.date().nullable().optional()
});
export type TOrganizations = z.infer<typeof OrganizationsSchema>;
@@ -30,7 +30,8 @@ export const SecretRotationsV2Schema = z.object({
lastRotatedAt: z.date(),
encryptedLastRotationMessage: zodBuffer.nullable().optional(),
lastRotationJobId: z.string().nullable().optional(),
nextRotationAt: z.date().nullable().optional()
nextRotationAt: z.date().nullable().optional(),
isLastRotationManual: z.boolean().default(true)
});
export type TSecretRotationsV2 = z.infer<typeof SecretRotationsV2Schema>;
@@ -597,7 +597,7 @@ export const secretRotationV2ServiceFactory = ({
const nextRotationAt = calculateNextRotationAt({
...(secretRotation as TSecretRotationV2),
...payload,
isManualRotation: false
isManualRotation: secretRotation.isLastRotationManual
});
let secretsMappingUpdated = false;
@@ -892,6 +892,7 @@ export const secretRotationV2ServiceFactory = ({
{
encryptedGeneratedCredentials: encryptedUpdatedCredentials,
activeIndex: inactiveIndex,
isLastRotationManual: isManualRotation,
lastRotatedAt: currentTime,
lastRotationAttemptedAt: currentTime,
nextRotationAt: calculateNextRotationAt({
+1
View File
@@ -60,6 +60,7 @@ const envSchema = z
HTTPS_ENABLED: zodStrBool,
ROTATION_DEVELOPMENT_MODE: zodStrBool.default("false").optional(),
DB_SSL_REJECT_UNAUTHORIZED: zodStrBool.default("true"),
DB_SSL_REQUIRED: zodStrBool.default("true"),
// smtp options
SMTP_HOST: zpStr(z.string().optional()),
SMTP_IGNORE_TLS: zodStrBool.default("false"),
@@ -19,18 +19,46 @@ const SQL_CONNECTION_CLIENT_MAP = {
[AppConnection.MsSql]: "mssql"
};
export const getSqlConnectionClient = async (appConnection: Pick<TSqlConnection, "credentials" | "app">) => {
const getConnectionConfig = ({
app,
credentials: { sslCertificate, host }
}: Pick<TSqlConnection, "credentials" | "app">) => {
const appCfg = getConfig();
switch (app) {
case AppConnection.Postgres: {
return {
ssl: appCfg.DB_SSL_REQUIRED
? {
rejectUnauthorized: appCfg.DB_SSL_REJECT_UNAUTHORIZED,
ca: sslCertificate,
servername: host
}
: false
};
}
case AppConnection.MsSql: {
return {
options: appCfg.DB_SSL_REQUIRED
? {
trustServerCertificate: !appCfg.DB_SSL_REJECT_UNAUTHORIZED,
encrypt: true,
cryptoCredentialsDetails: sslCertificate ? { ca: sslCertificate } : {}
}
: undefined
};
}
default:
throw new Error(`Unhandled SQL Connection Config: ${app as AppConnection}`);
}
};
export const getSqlConnectionClient = async (appConnection: Pick<TSqlConnection, "credentials" | "app">) => {
const {
app,
credentials: { host: baseHost, database, port, sslCertificate, password, username }
credentials: { host: baseHost, database, port, password, username }
} = appConnection;
const ssl = sslCertificate
? { rejectUnauthorized: appCfg.DB_SSL_REJECT_UNAUTHORIZED, ca: sslCertificate, servername: baseHost }
: undefined;
const [host] = await verifyHostInputValidity(baseHost);
const client = knex({
@@ -42,16 +70,7 @@ export const getSqlConnectionClient = async (appConnection: Pick<TSqlConnection,
user: username,
password,
connectionTimeoutMillis: EXTERNAL_REQUEST_TIMEOUT,
ssl,
// following dynamic secret mssql driver requirements (see sql-database.ts)
// @ts-expect-error this is because of knexjs type signature issue. This is directly passed to driver
options:
app === AppConnection.MsSql
? {
trustServerCertificate: !appCfg.DB_SSL_REJECT_UNAUTHORIZED,
cryptoCredentialsDetails: sslCertificate ? { ca: sslCertificate } : {}
}
: undefined
...getConnectionConfig(appConnection)
}
});