mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 11:29:42 +00:00
feaet(e2e-tests): secret rotation tests
This commit is contained in:
@@ -9,7 +9,7 @@ import { getDbConnectionHost } from "@app/lib/knex";
|
||||
export const verifyHostInputValidity = async (host: string, isGateway = false) => {
|
||||
const appCfg = getConfig();
|
||||
|
||||
if (appCfg.isDevelopmentMode) return [host];
|
||||
if (appCfg.isDevelopmentMode || appCfg.isTestMode) return [host];
|
||||
|
||||
if (isGateway) return [host];
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ export const getDefaultOnPremFeatures = () => {
|
||||
caCrl: false,
|
||||
sshHostGroups: false,
|
||||
enterpriseSecretSyncs: false,
|
||||
enterpriseAppConnections: false
|
||||
enterpriseAppConnections: true
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -14,14 +14,17 @@ import { OKTA_CLIENT_SECRET_ROTATION_LIST_OPTION } from "./okta-client-secret";
|
||||
import { ORACLEDB_CREDENTIALS_ROTATION_LIST_OPTION } from "./oracledb-credentials";
|
||||
import { POSTGRES_CREDENTIALS_ROTATION_LIST_OPTION } from "./postgres-credentials";
|
||||
import { SecretRotation, SecretRotationStatus } from "./secret-rotation-v2-enums";
|
||||
import { TSecretRotationV2ServiceFactoryDep } from "./secret-rotation-v2-service";
|
||||
import { TSecretRotationV2ServiceFactory, TSecretRotationV2ServiceFactoryDep } from "./secret-rotation-v2-service";
|
||||
import {
|
||||
TSecretRotationRotateSecretsJobPayload,
|
||||
TSecretRotationV2,
|
||||
TSecretRotationV2GeneratedCredentials,
|
||||
TSecretRotationV2ListItem,
|
||||
TSecretRotationV2Raw,
|
||||
TUpdateSecretRotationV2DTO
|
||||
} from "./secret-rotation-v2-types";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { TSecretRotationV2DALFactory } from "./secret-rotation-v2-dal";
|
||||
|
||||
const SECRET_ROTATION_LIST_OPTIONS: Record<SecretRotation, TSecretRotationV2ListItem> = {
|
||||
[SecretRotation.PostgresCredentials]: POSTGRES_CREDENTIALS_ROTATION_LIST_OPTION,
|
||||
@@ -74,6 +77,10 @@ export const getNextUtcRotationInterval = (rotateAtUtc?: TSecretRotationV2["rota
|
||||
const appCfg = getConfig();
|
||||
|
||||
if (appCfg.isRotationDevelopmentMode) {
|
||||
if (appCfg.isTestMode) {
|
||||
// if its test mode, it should always rotate
|
||||
return new Date(Date.now() + 365 * 24 * 60 * 60 * 1000); // Current time + 1 year
|
||||
}
|
||||
return getNextUTCMinuteInterval(rotateAtUtc);
|
||||
}
|
||||
|
||||
@@ -263,3 +270,51 @@ export const throwOnImmutableParameterUpdate = (
|
||||
// do nothing
|
||||
}
|
||||
};
|
||||
|
||||
export const rotateSecretsFns = async ({
|
||||
job,
|
||||
secretRotationV2DAL,
|
||||
secretRotationV2Service
|
||||
}: {
|
||||
job: {
|
||||
data: TSecretRotationRotateSecretsJobPayload;
|
||||
id: string;
|
||||
retryCount: number;
|
||||
retryLimit: number;
|
||||
};
|
||||
secretRotationV2DAL: Pick<TSecretRotationV2DALFactory, "findById">;
|
||||
secretRotationV2Service: Pick<TSecretRotationV2ServiceFactory, "rotateGeneratedCredentials">;
|
||||
}) => {
|
||||
const { rotationId, queuedAt, isManualRotation } = job.data;
|
||||
const { retryCount, retryLimit } = job;
|
||||
|
||||
const logDetails = `[rotationId=${rotationId}] [jobId=${job.id}] retryCount=[${retryCount}/${retryLimit}]`;
|
||||
|
||||
try {
|
||||
const secretRotation = await secretRotationV2DAL.findById(rotationId);
|
||||
|
||||
if (!secretRotation) throw new Error(`Secret rotation ${rotationId} not found`);
|
||||
|
||||
if (!secretRotation.isAutoRotationEnabled) {
|
||||
logger.info(`secretRotationV2Queue: Skipping Rotation - Auto-Rotation Disabled Since Queue ${logDetails}`);
|
||||
}
|
||||
|
||||
if (new Date(secretRotation.lastRotatedAt).getTime() >= new Date(queuedAt).getTime()) {
|
||||
// rotated since being queued, skip rotation
|
||||
logger.info(`secretRotationV2Queue: Skipping Rotation - Rotated Since Queue ${logDetails}`);
|
||||
return;
|
||||
}
|
||||
|
||||
await secretRotationV2Service.rotateGeneratedCredentials(secretRotation, {
|
||||
jobId: job.id,
|
||||
shouldSendNotification: true,
|
||||
isFinalAttempt: retryCount === retryLimit,
|
||||
isManualRotation
|
||||
});
|
||||
|
||||
logger.info(`secretRotationV2Queue: Secrets Rotated ${logDetails}`);
|
||||
} catch (error) {
|
||||
logger.error(error, `secretRotationV2Queue: Failed to Rotate Secrets ${logDetails}`);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import { ProjectMembershipRole } from "@app/db/schemas";
|
||||
import { TSecretRotationV2DALFactory } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-dal";
|
||||
import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums";
|
||||
import {
|
||||
getNextUtcRotationInterval,
|
||||
getSecretRotationRotateSecretJobOptions
|
||||
getSecretRotationRotateSecretJobOptions,
|
||||
rotateSecretsFns
|
||||
} from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-fns";
|
||||
import { SECRET_ROTATION_NAME_MAP } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-maps";
|
||||
import { TSecretRotationV2ServiceFactory } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-service";
|
||||
@@ -63,6 +66,26 @@ export const secretRotationV2QueueServiceFactory = async ({
|
||||
rotation.lastRotatedAt
|
||||
).toISOString()}] [rotateAt=${new Date(rotation.nextRotationAt!).toISOString()}]`
|
||||
);
|
||||
|
||||
const data = {
|
||||
rotationId: rotation.id,
|
||||
queuedAt: currentTime
|
||||
} as TSecretRotationRotateSecretsJobPayload;
|
||||
|
||||
if (appCfg.isTestMode) {
|
||||
logger.warn("secretRotationV2Queue: Manually rotating secrets for test mode");
|
||||
await rotateSecretsFns({
|
||||
job: {
|
||||
id: uuidv4(),
|
||||
data,
|
||||
retryCount: 0,
|
||||
retryLimit: 0
|
||||
},
|
||||
secretRotationV2DAL,
|
||||
secretRotationV2Service
|
||||
});
|
||||
}
|
||||
|
||||
await queueService.queuePg(
|
||||
QueueJobs.SecretRotationV2RotateSecrets,
|
||||
{
|
||||
@@ -87,38 +110,14 @@ export const secretRotationV2QueueServiceFactory = async ({
|
||||
await queueService.startPg<QueueName.SecretRotationV2>(
|
||||
QueueJobs.SecretRotationV2RotateSecrets,
|
||||
async ([job]) => {
|
||||
const { rotationId, queuedAt, isManualRotation } = job.data as TSecretRotationRotateSecretsJobPayload;
|
||||
const { retryCount, retryLimit } = job;
|
||||
|
||||
const logDetails = `[rotationId=${rotationId}] [jobId=${job.id}] retryCount=[${retryCount}/${retryLimit}]`;
|
||||
|
||||
try {
|
||||
const secretRotation = await secretRotationV2DAL.findById(rotationId);
|
||||
|
||||
if (!secretRotation) throw new Error(`Secret rotation ${rotationId} not found`);
|
||||
|
||||
if (!secretRotation.isAutoRotationEnabled) {
|
||||
logger.info(`secretRotationV2Queue: Skipping Rotation - Auto-Rotation Disabled Since Queue ${logDetails}`);
|
||||
}
|
||||
|
||||
if (new Date(secretRotation.lastRotatedAt).getTime() >= new Date(queuedAt).getTime()) {
|
||||
// rotated since being queued, skip rotation
|
||||
logger.info(`secretRotationV2Queue: Skipping Rotation - Rotated Since Queue ${logDetails}`);
|
||||
return;
|
||||
}
|
||||
|
||||
await secretRotationV2Service.rotateGeneratedCredentials(secretRotation, {
|
||||
jobId: job.id,
|
||||
shouldSendNotification: true,
|
||||
isFinalAttempt: retryCount === retryLimit,
|
||||
isManualRotation
|
||||
});
|
||||
|
||||
logger.info(`secretRotationV2Queue: Secrets Rotated ${logDetails}`);
|
||||
} catch (error) {
|
||||
logger.error(error, `secretRotationV2Queue: Failed to Rotate Secrets ${logDetails}`);
|
||||
throw error;
|
||||
}
|
||||
await rotateSecretsFns({
|
||||
job: {
|
||||
...job,
|
||||
data: job.data as TSecretRotationRotateSecretsJobPayload
|
||||
},
|
||||
secretRotationV2DAL,
|
||||
secretRotationV2Service
|
||||
});
|
||||
},
|
||||
{
|
||||
batchSize: 1,
|
||||
|
||||
@@ -345,7 +345,9 @@ const envSchema = z
|
||||
isSmtpConfigured: Boolean(data.SMTP_HOST),
|
||||
isRedisConfigured: Boolean(data.REDIS_URL || data.REDIS_SENTINEL_HOSTS),
|
||||
isDevelopmentMode: data.NODE_ENV === "development",
|
||||
isRotationDevelopmentMode: data.NODE_ENV === "development" && data.ROTATION_DEVELOPMENT_MODE,
|
||||
isTestMode: data.NODE_ENV === "test",
|
||||
isRotationDevelopmentMode:
|
||||
(data.NODE_ENV === "development" && data.ROTATION_DEVELOPMENT_MODE) || data.NODE_ENV === "test",
|
||||
isProductionMode: data.NODE_ENV === "production" || IS_PACKAGED,
|
||||
isRedisSentinelMode: Boolean(data.REDIS_SENTINEL_HOSTS),
|
||||
REDIS_SENTINEL_HOSTS: data.REDIS_SENTINEL_HOSTS?.trim()
|
||||
|
||||
Reference in New Issue
Block a user