diff --git a/backend/src/ee/services/pki-acme/pki-acme-challenge-service.ts b/backend/src/ee/services/pki-acme/pki-acme-challenge-service.ts
index 510d05c044..52fd0efb56 100644
--- a/backend/src/ee/services/pki-acme/pki-acme-challenge-service.ts
+++ b/backend/src/ee/services/pki-acme/pki-acme-challenge-service.ts
@@ -6,6 +6,7 @@ import { TPkiAcmeChallenges } from "@app/db/schemas/pki-acme-challenges";
import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
+import { isValidIp } from "@app/lib/ip";
import { isPrivateIp } from "@app/lib/ip/ipRange";
import { logger } from "@app/lib/logger";
import { ActorType } from "@app/services/auth/auth-type";
@@ -20,7 +21,6 @@ import {
} from "./pki-acme-errors";
import { AcmeAuthStatus, AcmeChallengeStatus, AcmeChallengeType } from "./pki-acme-schemas";
import { TPkiAcmeChallengeServiceFactory } from "./pki-acme-types";
-import { isValidIp } from "@app/lib/ip";
type TPkiAcmeChallengeServiceFactoryDep = {
acmeChallengeDAL: Pick<
diff --git a/backend/src/ee/services/secret-rotation-v2/mongodb-credentials/mongodb-credentials-rotation-schemas.ts b/backend/src/ee/services/secret-rotation-v2/mongodb-credentials/mongodb-credentials-rotation-schemas.ts
index 9a5335f5f6..f94de22f76 100644
--- a/backend/src/ee/services/secret-rotation-v2/mongodb-credentials/mongodb-credentials-rotation-schemas.ts
+++ b/backend/src/ee/services/secret-rotation-v2/mongodb-credentials/mongodb-credentials-rotation-schemas.ts
@@ -16,8 +16,13 @@ import { SecretNameSchema } from "@app/server/lib/schemas";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
export const MongoDBCredentialsRotationGeneratedCredentialsSchema = SqlCredentialsRotationGeneratedCredentialsSchema;
-export const MongoDBCredentialsRotationParametersSchema = SqlCredentialsRotationParametersSchema;
-export const MongoDBCredentialsRotationTemplateSchema = SqlCredentialsRotationTemplateSchema;
+export const MongoDBCredentialsRotationParametersSchema = SqlCredentialsRotationParametersSchema.omit({
+ rotationStatement: true,
+ passwordRequirements: true
+});
+export const MongoDBCredentialsRotationTemplateSchema = SqlCredentialsRotationTemplateSchema.omit({
+ rotationStatement: true
+});
const MongoDBCredentialsRotationSecretsMappingSchema = z.object({
username: SecretNameSchema.describe(SecretRotations.SECRETS_MAPPING.MONGODB_CREDENTIALS.username),
diff --git a/backend/src/ee/services/secret-rotation-v2/mssql-credentials/mssql-credentials-rotation-constants.ts b/backend/src/ee/services/secret-rotation-v2/mssql-credentials/mssql-credentials-rotation-constants.ts
index b256bd77fb..d318d0c85e 100644
--- a/backend/src/ee/services/secret-rotation-v2/mssql-credentials/mssql-credentials-rotation-constants.ts
+++ b/backend/src/ee/services/secret-rotation-v2/mssql-credentials/mssql-credentials-rotation-constants.ts
@@ -21,6 +21,7 @@ CREATE USER [infisical_user] FOR LOGIN [infisical_user];
-- Grant permissions to the user on the schema in this database
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO [infisical_user];`,
+ rotationStatement: `ALTER LOGIN [{{username}}] WITH PASSWORD = '{{password}}'`,
secretsMapping: {
username: "MSSQL_DB_USERNAME",
password: "MSSQL_DB_PASSWORD"
diff --git a/backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-constants.ts b/backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-constants.ts
index bae7a81660..588e6dc4f6 100644
--- a/backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-constants.ts
+++ b/backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-constants.ts
@@ -15,6 +15,7 @@ GRANT ALL PRIVILEGES ON my_database.* TO 'infisical_user'@'%';
-- apply the privilege changes
FLUSH PRIVILEGES;`,
+ rotationStatement: `ALTER USER '{{username}}'@'%' IDENTIFIED BY '{{password}}'`,
secretsMapping: {
username: "MYSQL_USERNAME",
password: "MYSQL_PASSWORD"
diff --git a/backend/src/ee/services/secret-rotation-v2/oracledb-credentials/oracledb-credentials-rotation-constants.ts b/backend/src/ee/services/secret-rotation-v2/oracledb-credentials/oracledb-credentials-rotation-constants.ts
index dd685041c6..6a0cda1770 100644
--- a/backend/src/ee/services/secret-rotation-v2/oracledb-credentials/oracledb-credentials-rotation-constants.ts
+++ b/backend/src/ee/services/secret-rotation-v2/oracledb-credentials/oracledb-credentials-rotation-constants.ts
@@ -12,6 +12,7 @@ CREATE USER INFISICAL_USER IDENTIFIED BY "temporary_password";
-- grant all privileges
GRANT ALL PRIVILEGES TO INFISICAL_USER;`,
+ rotationStatement: `ALTER USER "{{username}}" IDENTIFIED BY "{{password}}"`,
secretsMapping: {
username: "ORACLEDB_USERNAME",
password: "ORACLEDB_PASSWORD"
diff --git a/backend/src/ee/services/secret-rotation-v2/postgres-credentials/postgres-credentials-rotation-constants.ts b/backend/src/ee/services/secret-rotation-v2/postgres-credentials/postgres-credentials-rotation-constants.ts
index 395ed46d1b..7408d9173b 100644
--- a/backend/src/ee/services/secret-rotation-v2/postgres-credentials/postgres-credentials-rotation-constants.ts
+++ b/backend/src/ee/services/secret-rotation-v2/postgres-credentials/postgres-credentials-rotation-constants.ts
@@ -15,6 +15,7 @@ GRANT CONNECT ON DATABASE my_database TO infisical_user;
-- grant relevant table permissions
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO infisical_user;`,
+ rotationStatement: `ALTER USER "{{username}}" WITH PASSWORD '{{password}}'`,
secretsMapping: {
username: "POSTGRES_DB_USERNAME",
password: "POSTGRES_DB_PASSWORD"
diff --git a/backend/src/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-fns.ts b/backend/src/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-fns.ts
index 965516c3eb..91dc65b622 100644
--- a/backend/src/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-fns.ts
+++ b/backend/src/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-fns.ts
@@ -1,3 +1,4 @@
+import handlebars from "handlebars";
import { Knex } from "knex";
import {
@@ -44,13 +45,19 @@ export const sqlCredentialsRotationFactory: TRotationFactory<
> = (secretRotation, _appConnectionDAL, _kmsService, gatewayService, gatewayV2Service) => {
const {
connection,
- parameters: { username1, username2 },
+ parameters: {
+ username1,
+ username2,
+ rotationStatement: userProvidedRotationStatement,
+ passwordRequirements: userProvidedPasswordRequirements
+ },
activeIndex,
secretsMapping
} = secretRotation;
- const passwordRequirement =
+ const defaultPasswordRequirement =
connection.app === AppConnection.OracleDB ? ORACLE_PASSWORD_REQUIREMENTS : DEFAULT_PASSWORD_REQUIREMENTS;
+ const passwordRequirement = userProvidedPasswordRequirements || defaultPasswordRequirement;
const executeOperation = (
operation: (client: Knex) => Promise,
@@ -82,21 +89,38 @@ export const sqlCredentialsRotationFactory: TRotationFactory<
}
};
+ const $executeQuery = async (tx: Knex, username: string, password: string) => {
+ if (userProvidedRotationStatement) {
+ const revokeStatement = handlebars.compile(userProvidedRotationStatement)({
+ username,
+ password,
+ database: connection.credentials.database
+ });
+ const queries = revokeStatement.toString().split(";").filter(Boolean);
+ for await (const query of queries) {
+ await tx.raw(query);
+ }
+ } else {
+ await tx.raw(...SQL_CONNECTION_ALTER_LOGIN_STATEMENT[connection.app]({ username, password }));
+ }
+ };
+
const issueCredentials: TRotationFactoryIssueCredentials = async (
callback
) => {
// For SQL, since we get existing users, we change both their passwords
// on issue to invalidate their existing passwords
- const credentialsSet = [
- { username: username1, password: generatePassword(passwordRequirement) },
- { username: username2, password: generatePassword(passwordRequirement) }
- ];
+ const credentialsSet = [{ username: username1, password: generatePassword(passwordRequirement) }];
+ // if both are same username like for mysql dual password rotation - we don't want to reissue twice loosing first cred access
+ if (username1 !== username2) {
+ credentialsSet.push({ username: username2, password: generatePassword(passwordRequirement) });
+ }
try {
await executeOperation(async (client) => {
await client.transaction(async (tx) => {
for await (const credentials of credentialsSet) {
- await tx.raw(...SQL_CONNECTION_ALTER_LOGIN_STATEMENT[connection.app](credentials));
+ await $executeQuery(tx, credentials.username, credentials.password);
}
});
});
@@ -125,7 +149,7 @@ export const sqlCredentialsRotationFactory: TRotationFactory<
await client.transaction(async (tx) => {
for await (const credentials of revokedCredentials) {
// invalidate previous passwords
- await tx.raw(...SQL_CONNECTION_ALTER_LOGIN_STATEMENT[connection.app](credentials));
+ await $executeQuery(tx, credentials.username, credentials.password);
}
});
});
@@ -148,7 +172,7 @@ export const sqlCredentialsRotationFactory: TRotationFactory<
try {
await executeOperation(async (client) => {
- await client.raw(...SQL_CONNECTION_ALTER_LOGIN_STATEMENT[connection.app](credentials));
+ await $executeQuery(client, credentials.username, credentials.password);
});
} catch (error) {
throw new Error(redactPasswords(error, [credentials]));
diff --git a/backend/src/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-schemas.ts b/backend/src/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-schemas.ts
index 7ec47741f1..f9ec88e2c7 100644
--- a/backend/src/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-schemas.ts
+++ b/backend/src/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-schemas.ts
@@ -1,8 +1,11 @@
import { z } from "zod";
import { SecretRotations } from "@app/lib/api-docs";
+import { isValidHandleBarTemplate } from "@app/lib/template/validate-handlebars";
import { SecretNameSchema } from "@app/server/lib/schemas";
+import { PasswordRequirementsSchema } from "../general";
+
export const SqlCredentialsRotationGeneratedCredentialsSchema = z
.object({
username: z.string(),
@@ -22,7 +25,25 @@ export const SqlCredentialsRotationParametersSchema = z.object({
.string()
.trim()
.min(1, "Username2 Required")
- .describe(SecretRotations.PARAMETERS.SQL_CREDENTIALS.username2)
+ .describe(SecretRotations.PARAMETERS.SQL_CREDENTIALS.username2),
+ rotationStatement: z
+ .string()
+ .trim()
+ .min(1, "Rotation Statement Required")
+ .describe(SecretRotations.PARAMETERS.SQL_CREDENTIALS.rotationStatement)
+ .refine(
+ (el) =>
+ isValidHandleBarTemplate(el, {
+ allowedExpressions: (val) => ["username", "password", "database"].includes(val)
+ }),
+ "Invalid expression detected in rotation statement"
+ )
+ .refine(
+ (el) => el.includes("{{username}}") && el.includes("{{password}}"),
+ "Rotation statement must have username and password template expression"
+ )
+ .optional(),
+ passwordRequirements: PasswordRequirementsSchema.optional()
});
export const SqlCredentialsRotationSecretsMappingSchema = z.object({
@@ -32,6 +53,7 @@ export const SqlCredentialsRotationSecretsMappingSchema = z.object({
export const SqlCredentialsRotationTemplateSchema = z.object({
createUserStatement: z.string(),
+ rotationStatement: z.string(),
secretsMapping: z.object({
username: z.string(),
password: z.string()
diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts
index 60e930e691..16d2e68f2e 100644
--- a/backend/src/lib/api-docs/constants.ts
+++ b/backend/src/lib/api-docs/constants.ts
@@ -2876,7 +2876,8 @@ export const SecretRotations = {
username1:
"The username of the first login to rotate passwords for. This user must already exists in your database.",
username2:
- "The username of the second login to rotate passwords for. This user must already exists in your database."
+ "The username of the second login to rotate passwords for. This user must already exists in your database.",
+ rotationStatement: "The SQL template query used for rotation."
},
AUTH0_CLIENT_SECRET: {
clientId: "The client ID of the Auth0 Application to rotate the client secret for."
diff --git a/docs/api-reference/endpoints/app-connections/mongodb/available.mdx b/docs/api-reference/endpoints/app-connections/mongodb/available.mdx
new file mode 100644
index 0000000000..cf9f372f9c
--- /dev/null
+++ b/docs/api-reference/endpoints/app-connections/mongodb/available.mdx
@@ -0,0 +1,4 @@
+---
+title: "Available"
+openapi: "GET /api/v1/app-connections/mongodb/available"
+---
diff --git a/docs/api-reference/endpoints/app-connections/mongodb/create.mdx b/docs/api-reference/endpoints/app-connections/mongodb/create.mdx
new file mode 100644
index 0000000000..f32c1e8e17
--- /dev/null
+++ b/docs/api-reference/endpoints/app-connections/mongodb/create.mdx
@@ -0,0 +1,10 @@
+---
+title: "Create"
+openapi: "POST /api/v1/app-connections/mongodb"
+---
+
+
+ Check out the configuration docs for [MongoDB
+ Connections](/integrations/app-connections/mongodb) to learn how to obtain the
+ required credentials.
+
diff --git a/docs/api-reference/endpoints/app-connections/mongodb/delete.mdx b/docs/api-reference/endpoints/app-connections/mongodb/delete.mdx
new file mode 100644
index 0000000000..81d717eabb
--- /dev/null
+++ b/docs/api-reference/endpoints/app-connections/mongodb/delete.mdx
@@ -0,0 +1,4 @@
+---
+title: "Delete"
+openapi: "DELETE /api/v1/app-connections/mongodb/{connectionId}"
+---
diff --git a/docs/api-reference/endpoints/app-connections/mongodb/get-by-id.mdx b/docs/api-reference/endpoints/app-connections/mongodb/get-by-id.mdx
new file mode 100644
index 0000000000..50018e753e
--- /dev/null
+++ b/docs/api-reference/endpoints/app-connections/mongodb/get-by-id.mdx
@@ -0,0 +1,4 @@
+---
+title: "Get by ID"
+openapi: "GET /api/v1/app-connections/mongodb/{connectionId}"
+---
diff --git a/docs/api-reference/endpoints/app-connections/mongodb/get-by-name.mdx b/docs/api-reference/endpoints/app-connections/mongodb/get-by-name.mdx
new file mode 100644
index 0000000000..aac30b2bcc
--- /dev/null
+++ b/docs/api-reference/endpoints/app-connections/mongodb/get-by-name.mdx
@@ -0,0 +1,4 @@
+---
+title: "Get by Name"
+openapi: "GET /api/v1/app-connections/mongodb/connection-name/{connectionName}"
+---
diff --git a/docs/api-reference/endpoints/app-connections/mongodb/list.mdx b/docs/api-reference/endpoints/app-connections/mongodb/list.mdx
new file mode 100644
index 0000000000..2969f67e87
--- /dev/null
+++ b/docs/api-reference/endpoints/app-connections/mongodb/list.mdx
@@ -0,0 +1,4 @@
+---
+title: "List"
+openapi: "GET /api/v1/app-connections/mongodb"
+---
diff --git a/docs/api-reference/endpoints/app-connections/mongodb/update.mdx b/docs/api-reference/endpoints/app-connections/mongodb/update.mdx
new file mode 100644
index 0000000000..70672f789a
--- /dev/null
+++ b/docs/api-reference/endpoints/app-connections/mongodb/update.mdx
@@ -0,0 +1,10 @@
+---
+title: "Update"
+openapi: "PATCH /api/v1/app-connections/mongodb/{connectionId}"
+---
+
+
+ Check out the configuration docs for [MongoDB
+ Connections](/integrations/app-connections/mongodb) to learn how to obtain the
+ required credentials.
+
diff --git a/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/create.mdx b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/create.mdx
new file mode 100644
index 0000000000..4ebb4bc903
--- /dev/null
+++ b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/create.mdx
@@ -0,0 +1,10 @@
+---
+title: "Create"
+openapi: "POST /api/v2/secret-rotations/mongodb-credentials"
+---
+
+
+ Check out the configuration docs for [MongoDB
+ Credentials Rotations](/documentation/platform/secret-rotation/mongodb-credentials) to learn how to obtain the
+ required parameters.
+
diff --git a/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/delete.mdx b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/delete.mdx
new file mode 100644
index 0000000000..c54d6b382a
--- /dev/null
+++ b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/delete.mdx
@@ -0,0 +1,4 @@
+---
+title: "Delete"
+openapi: "DELETE /api/v2/secret-rotations/mongodb-credentials/{rotationId}"
+---
diff --git a/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/get-by-id.mdx b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/get-by-id.mdx
new file mode 100644
index 0000000000..ba701e9c8a
--- /dev/null
+++ b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/get-by-id.mdx
@@ -0,0 +1,4 @@
+---
+title: "Get by ID"
+openapi: "GET /api/v2/secret-rotations/mongodb-credentials/{rotationId}"
+---
diff --git a/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/get-by-name.mdx b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/get-by-name.mdx
new file mode 100644
index 0000000000..789b90d41b
--- /dev/null
+++ b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/get-by-name.mdx
@@ -0,0 +1,4 @@
+---
+title: "Get by Name"
+openapi: "GET /api/v2/secret-rotations/mongodb-credentials/rotation-name/{rotationName}"
+---
diff --git a/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/get-generated-credentials-by-id.mdx b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/get-generated-credentials-by-id.mdx
new file mode 100644
index 0000000000..9a550878e8
--- /dev/null
+++ b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/get-generated-credentials-by-id.mdx
@@ -0,0 +1,4 @@
+---
+title: "Get Credentials by ID"
+openapi: "GET /api/v2/secret-rotations/mongodb-credentials/{rotationId}/generated-credentials"
+---
diff --git a/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/list.mdx b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/list.mdx
new file mode 100644
index 0000000000..9974a806fe
--- /dev/null
+++ b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/list.mdx
@@ -0,0 +1,4 @@
+---
+title: "List"
+openapi: "GET /api/v2/secret-rotations/mongodb-credentials"
+---
diff --git a/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/rotate-secrets.mdx b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/rotate-secrets.mdx
new file mode 100644
index 0000000000..a005b99a77
--- /dev/null
+++ b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/rotate-secrets.mdx
@@ -0,0 +1,4 @@
+---
+title: "Rotate Secrets"
+openapi: "POST /api/v2/secret-rotations/mongodb-credentials/{rotationId}/rotate-secrets"
+---
diff --git a/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/update.mdx b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/update.mdx
new file mode 100644
index 0000000000..da95338e45
--- /dev/null
+++ b/docs/api-reference/endpoints/secret-rotations/mongodb-credentials/update.mdx
@@ -0,0 +1,10 @@
+---
+title: "Update"
+openapi: "PATCH /api/v2/secret-rotations/mongodb-credentials/{rotationId}"
+---
+
+
+ Check out the configuration docs for [MongoDB
+ Credentials Rotations](/documentation/platform/secret-rotation/mongodb-credentials) to learn how to obtain the
+ required parameters.
+
diff --git a/docs/documentation/platform/secret-rotation/mssql-credentials.mdx b/docs/documentation/platform/secret-rotation/mssql-credentials.mdx
index f609d11c54..a4c00d2cd2 100644
--- a/docs/documentation/platform/secret-rotation/mssql-credentials.mdx
+++ b/docs/documentation/platform/secret-rotation/mssql-credentials.mdx
@@ -56,6 +56,11 @@ An example creation statement might look like:
- **Database Username 1** - the username of the first user that will be used for rotation.
- **Database Username 2** - the username of the second user that will be used for rotation.
+ 
+
+ - **Rotation Statement** - the template string query to generate password for the rotated user.
+ - **Password Requirements** - the requirements for the password of the MySQL users that will be created for the rotation.
+
5. Specify the secret names that the active credentials should be mapped to. Then click **Next**.

diff --git a/docs/documentation/platform/secret-rotation/mysql-credentials.mdx b/docs/documentation/platform/secret-rotation/mysql-credentials.mdx
index 349b5b893e..b6e77d009d 100644
--- a/docs/documentation/platform/secret-rotation/mysql-credentials.mdx
+++ b/docs/documentation/platform/secret-rotation/mysql-credentials.mdx
@@ -51,6 +51,11 @@ description: "Learn how to automatically rotate MySQL credentials."
- **Database Username 1** - the username of the first user that will be used for rotation.
- **Database Username 2** - the username of the second user that will be used for rotation.
+ 
+
+ - **Rotation Statement** - the template string query to generate password for the rotated user.
+ - **Password Requirements** - the requirements for the password of the MySQL users that will be created for the rotation.
+
5. Specify the secret names that the active credentials should be mapped to. Then click **Next**.

diff --git a/docs/documentation/platform/secret-rotation/oracledb-credentials.mdx b/docs/documentation/platform/secret-rotation/oracledb-credentials.mdx
index 0f72d62fae..82e67b2d7a 100644
--- a/docs/documentation/platform/secret-rotation/oracledb-credentials.mdx
+++ b/docs/documentation/platform/secret-rotation/oracledb-credentials.mdx
@@ -61,6 +61,11 @@ description: "Learn how to automatically rotate Oracle Database credentials."
If your Oracle usernames were created without "quotes", Oracle sees them as UPPERCASE. Please use UPPERCASE for those names in the fields above.
+ 
+
+ - **Rotation Statement** - the template string query to generate password for the rotated user.
+ - **Password Requirements** - the requirements for the password of the MySQL users that will be created for the rotation.
+
5. Specify the secret names that the active credentials should be mapped to. Then click **Next**.

diff --git a/docs/documentation/platform/secret-rotation/postgres-credentials.mdx b/docs/documentation/platform/secret-rotation/postgres-credentials.mdx
index e8cddb0f4f..64644a5c6a 100644
--- a/docs/documentation/platform/secret-rotation/postgres-credentials.mdx
+++ b/docs/documentation/platform/secret-rotation/postgres-credentials.mdx
@@ -53,6 +53,11 @@ description: "Learn how to automatically rotate PostgreSQL credentials."
- **Database Username 1** - the username of the first user that will be used for rotation.
- **Database Username 2** - the username of the second user that will be used for rotation.
+ 
+
+ - **Rotation Statement** - the template string query to generate password for the rotated user.
+ - **Password Requirements** - the requirements for the password of the MySQL users that will be created for the rotation.
+
5. Specify the secret names that the active credentials should be mapped to. Then click **Next**.

diff --git a/docs/images/secret-rotations-v2/mssql-credentials/mssql-credentials-advance-parameters.png b/docs/images/secret-rotations-v2/mssql-credentials/mssql-credentials-advance-parameters.png
new file mode 100644
index 0000000000..6fdd4a4767
Binary files /dev/null and b/docs/images/secret-rotations-v2/mssql-credentials/mssql-credentials-advance-parameters.png differ
diff --git a/docs/images/secret-rotations-v2/mssql-credentials/mssql-credentials-parameters.png b/docs/images/secret-rotations-v2/mssql-credentials/mssql-credentials-parameters.png
index 2778bad8e4..4edb1dfb57 100644
Binary files a/docs/images/secret-rotations-v2/mssql-credentials/mssql-credentials-parameters.png and b/docs/images/secret-rotations-v2/mssql-credentials/mssql-credentials-parameters.png differ
diff --git a/docs/images/secret-rotations-v2/mysql-credentials/mysql-credentials-advance-parameters.png b/docs/images/secret-rotations-v2/mysql-credentials/mysql-credentials-advance-parameters.png
new file mode 100644
index 0000000000..d8249d0d46
Binary files /dev/null and b/docs/images/secret-rotations-v2/mysql-credentials/mysql-credentials-advance-parameters.png differ
diff --git a/docs/images/secret-rotations-v2/mysql-credentials/mysql-credentials-parameters.png b/docs/images/secret-rotations-v2/mysql-credentials/mysql-credentials-parameters.png
index c889e047a0..74fd243e13 100644
Binary files a/docs/images/secret-rotations-v2/mysql-credentials/mysql-credentials-parameters.png and b/docs/images/secret-rotations-v2/mysql-credentials/mysql-credentials-parameters.png differ
diff --git a/docs/images/secret-rotations-v2/oracledb-credentials/oracledb-credentials-advance-parameters.png b/docs/images/secret-rotations-v2/oracledb-credentials/oracledb-credentials-advance-parameters.png
new file mode 100644
index 0000000000..e2cac518ef
Binary files /dev/null and b/docs/images/secret-rotations-v2/oracledb-credentials/oracledb-credentials-advance-parameters.png differ
diff --git a/docs/images/secret-rotations-v2/oracledb-credentials/oracledb-credentials-parameters.png b/docs/images/secret-rotations-v2/oracledb-credentials/oracledb-credentials-parameters.png
index 5dcc68c322..82c1dd62cf 100644
Binary files a/docs/images/secret-rotations-v2/oracledb-credentials/oracledb-credentials-parameters.png and b/docs/images/secret-rotations-v2/oracledb-credentials/oracledb-credentials-parameters.png differ
diff --git a/docs/images/secret-rotations-v2/postgres-credentials/postgres-credentials-advance-parameters.png b/docs/images/secret-rotations-v2/postgres-credentials/postgres-credentials-advance-parameters.png
new file mode 100644
index 0000000000..39e8d111cb
Binary files /dev/null and b/docs/images/secret-rotations-v2/postgres-credentials/postgres-credentials-advance-parameters.png differ
diff --git a/docs/images/secret-rotations-v2/postgres-credentials/postgres-credentials-parameters.png b/docs/images/secret-rotations-v2/postgres-credentials/postgres-credentials-parameters.png
index 800d9d8230..f4e8a033fe 100644
Binary files a/docs/images/secret-rotations-v2/postgres-credentials/postgres-credentials-parameters.png and b/docs/images/secret-rotations-v2/postgres-credentials/postgres-credentials-parameters.png differ
diff --git a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2Form.tsx b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2Form.tsx
index 320793ed19..c11b448dae 100644
--- a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2Form.tsx
+++ b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2Form.tsx
@@ -101,12 +101,7 @@ export const SecretRotationV2Form = ({
reValidateMode: "onChange"
});
- const onSubmit = async ({
- environment,
- connection,
-
- ...formData
- }: TSecretRotationV2Form) => {
+ const onSubmit = async ({ environment, connection, ...formData }: TSecretRotationV2Form) => {
const mutation = secretRotation
? updateSecretRotation.mutateAsync({
rotationId: secretRotation.id,
diff --git a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/MongoRotationParametersFields.tsx b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/MongoRotationParametersFields.tsx
new file mode 100644
index 0000000000..3f6598eeb6
--- /dev/null
+++ b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/MongoRotationParametersFields.tsx
@@ -0,0 +1,66 @@
+import { Controller, useFormContext } from "react-hook-form";
+
+import { TSecretRotationV2Form } from "@app/components/secret-rotations-v2/forms/schemas";
+import { FormControl, Input } from "@app/components/v2";
+import { NoticeBannerV2 } from "@app/components/v2/NoticeBannerV2/NoticeBannerV2";
+import { SecretRotation, useSecretRotationV2Option } from "@app/hooks/api/secretRotationsV2";
+
+export const MongoRotationParametersFields = () => {
+ const { control, watch } = useFormContext<
+ TSecretRotationV2Form & {
+ type: SecretRotation.MongoDBCredentials;
+ }
+ >();
+ const type = watch("type");
+
+ const { rotationOption } = useSecretRotationV2Option(type);
+
+ return (
+ <>
+ (
+
+
+
+ )}
+ control={control}
+ name="parameters.username1"
+ />
+ (
+
+
+
+ )}
+ control={control}
+ name="parameters.username2"
+ />
+
+
+ Infisical requires two database users to be created for rotation.
+
+
+ These users are intended to be solely managed by Infisical. Altering their login after
+ rotation may cause unexpected failure.
+
+
+ Below is an example statement for creating the required users. You may need to modify it
+ to suit your needs.
+
+
+
+ {rotationOption!.template.createUserStatement}
+
+
+
+ >
+ );
+};
diff --git a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/SecretRotationV2ParametersFields.tsx b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/SecretRotationV2ParametersFields.tsx
index 1ae0dc9a9a..6e4947fa29 100644
--- a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/SecretRotationV2ParametersFields.tsx
+++ b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/SecretRotationV2ParametersFields.tsx
@@ -7,6 +7,7 @@ import { Auth0ClientSecretRotationParametersFields } from "./Auth0ClientSecretRo
import { AwsIamUserSecretRotationParametersFields } from "./AwsIamUserSecretRotationParametersFields";
import { AzureClientSecretRotationParametersFields } from "./AzureClientSecretRotationParametersFields";
import { LdapPasswordRotationParametersFields } from "./LdapPasswordRotationParametersFields";
+import { MongoRotationParametersFields } from "./MongoRotationParametersFields";
import { OktaClientSecretRotationParametersFields } from "./OktaClientSecretRotationParametersFields";
import { RedisCredentialsRotationParametersFields } from "./RedisCredentialsRotationParametersFields";
import { SqlCredentialsRotationParametersFields } from "./shared";
@@ -22,7 +23,7 @@ const COMPONENT_MAP: Record = {
[SecretRotation.AwsIamUserSecret]: AwsIamUserSecretRotationParametersFields,
[SecretRotation.OktaClientSecret]: OktaClientSecretRotationParametersFields,
[SecretRotation.RedisCredentials]: RedisCredentialsRotationParametersFields,
- [SecretRotation.MongoDBCredentials]: SqlCredentialsRotationParametersFields
+ [SecretRotation.MongoDBCredentials]: MongoRotationParametersFields
};
export const SecretRotationV2ParametersFields = () => {
diff --git a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/shared/SqlCredentialsRotationParametersFields.tsx b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/shared/SqlCredentialsRotationParametersFields.tsx
index 8d6f3797d2..e5b8628462 100644
--- a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/shared/SqlCredentialsRotationParametersFields.tsx
+++ b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/shared/SqlCredentialsRotationParametersFields.tsx
@@ -1,84 +1,259 @@
import { Controller, useFormContext } from "react-hook-form";
import { TSecretRotationV2Form } from "@app/components/secret-rotations-v2/forms/schemas";
-import { FormControl, Input } from "@app/components/v2";
+import { FormControl, Input, Tab, TabList, TabPanel, Tabs, TextArea } from "@app/components/v2";
import { NoticeBannerV2 } from "@app/components/v2/NoticeBannerV2/NoticeBannerV2";
import { AppConnection } from "@app/hooks/api/appConnections/enums";
import { SecretRotation, useSecretRotationV2Option } from "@app/hooks/api/secretRotationsV2";
+import { DEFAULT_PASSWORD_REQUIREMENTS } from "../../schemas/shared";
+
+enum ParameterTab {
+ Statement = "statement",
+ Advanced = "advance"
+}
+
export const SqlCredentialsRotationParametersFields = () => {
const { control, watch } = useFormContext<
TSecretRotationV2Form & {
- type: SecretRotation.PostgresCredentials | SecretRotation.MsSqlCredentials;
+ type:
+ | SecretRotation.PostgresCredentials
+ | SecretRotation.MsSqlCredentials
+ | SecretRotation.OracleDBCredentials;
}
>();
-
const type = watch("type");
const { rotationOption } = useSecretRotationV2Option(type);
return (
- <>
- (
-
-
+
+ General
+ Advanced
+
+
+ (
+
+
+
+ )}
+ control={control}
+ name="parameters.username1"
+ />
+ (
+
+
+
+ )}
+ control={control}
+ name="parameters.username2"
+ />
+
+
+ Infisical requires two database users to be created for rotation.
+
+
+ These users are intended to be solely managed by Infisical. Altering their login after
+ rotation may cause unexpected failure.
+
+
+ Below is an example statement for creating the required users. You may need to modify it
+ to suit your needs.
+
+
+
+ {rotationOption!.template.createUserStatement}
+
+
+
+
+
+ (
+
+
+
+ )}
+ />
+
+
+ Password Requirements
+
+
+
+
+
);
};
diff --git a/frontend/src/components/secret-rotations-v2/forms/schemas/shared/sql-credentials-rotation-schema.ts b/frontend/src/components/secret-rotations-v2/forms/schemas/shared/sql-credentials-rotation-schema.ts
index 4332249983..f027e1c7e9 100644
--- a/frontend/src/components/secret-rotations-v2/forms/schemas/shared/sql-credentials-rotation-schema.ts
+++ b/frontend/src/components/secret-rotations-v2/forms/schemas/shared/sql-credentials-rotation-schema.ts
@@ -2,10 +2,14 @@ import { z } from "zod";
import { SecretNameSchema } from "@app/lib/schemas";
+import { PasswordRequirementsSchema } from "./password-requirements-schema";
+
export const SqlCredentialsRotationSchema = z.object({
parameters: z.object({
username1: z.string().trim().min(1, "Database Username 1 Required"),
- username2: z.string().trim().min(1, "Database Username 2 Required")
+ username2: z.string().trim().min(1, "Database Username 2 Required"),
+ rotationStatement: z.string().trim().min(1).optional(),
+ passwordRequirements: PasswordRequirementsSchema.optional()
}),
secretsMapping: z.object({
username: SecretNameSchema,
diff --git a/frontend/src/hooks/api/secretRotationsV2/types/shared/sql-credentials-rotation.ts b/frontend/src/hooks/api/secretRotationsV2/types/shared/sql-credentials-rotation.ts
index a242425103..ea5ac32cab 100644
--- a/frontend/src/hooks/api/secretRotationsV2/types/shared/sql-credentials-rotation.ts
+++ b/frontend/src/hooks/api/secretRotationsV2/types/shared/sql-credentials-rotation.ts
@@ -27,6 +27,7 @@ export type TSqlCredentialsRotationOption = {
template: {
secretsMapping: TSqlCredentialsRotationProperties["secretsMapping"];
createUserStatement: string;
+ rotationStatement: string;
};
};
diff --git a/sink/docker-command-mssql.sh b/sink/docker-command-mssql.sh
new file mode 100644
index 0000000000..bcfc6e68d1
--- /dev/null
+++ b/sink/docker-command-mssql.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+set -e
+
+CONTAINER_NAME="mssql"
+SA_PASSWORD="StrongP@ssw0rd!"
+IMAGE="mcr.microsoft.com/mssql/server:2022-latest"
+
+echo "๐ Starting SQL Server 2022 container..."
+
+docker run -d \
+ --platform=linux/amd64 \
+ --name "${CONTAINER_NAME}" \
+ -p 1433:1433 \
+ -e "ACCEPT_EULA=Y" \
+ -e "SA_PASSWORD=${SA_PASSWORD}" \
+ "${IMAGE}"
+
+echo "โณ Waiting for SQL Server to be ready..."
+# Check logs for ready message
+until docker logs "${CONTAINER_NAME}" 2>&1 | grep -q "SQL Server is now ready for client connections."; do
+ sleep 5
+done
+
+echo ""
+echo "โ
SQL Server is ready!"
+echo ""
+echo "๐ Connection details:"
+echo "------------------------------------"
+echo "Host: localhost"
+echo "Port: 1433"
+echo "Username: sa"
+echo "Password: ${SA_PASSWORD}"
+echo "Database: master"
+echo ""
+echo "๐ JDBC URL:"
+echo "jdbc:sqlserver://localhost:1433;databaseName=master;user=sa;password=${SA_PASSWORD}"
+echo ""
+echo "๐งช Connect using sqlcmd:"
+echo "sqlcmd -S localhost,1433 -U sa -P '${SA_PASSWORD}'"
+echo "------------------------------------"
diff --git a/sink/docker-command-oracle.sh b/sink/docker-command-oracle.sh
new file mode 100644
index 0000000000..a6f0978424
--- /dev/null
+++ b/sink/docker-command-oracle.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+set -e
+
+CONTAINER_NAME="oracle-free"
+ORACLE_PASSWORD="oracle"
+IMAGE="gvenzl/oracle-free:23-slim"
+
+echo "๐ Starting Oracle Free 23c container..."
+
+docker run -d \
+ --name "${CONTAINER_NAME}" \
+ -p 1521:1521 \
+ -p 5500:5500 \
+ -e ORACLE_PASSWORD="${ORACLE_PASSWORD}" \
+ "${IMAGE}"
+
+echo "โณ Waiting for Oracle database to be ready..."
+until docker logs "${CONTAINER_NAME}" 2>&1 | grep -q "DATABASE IS READY TO USE"; do
+ sleep 5
+done
+
+echo ""
+echo "โ
Oracle Database is ready!"
+echo ""
+echo "๐ Connection details:"
+echo "------------------------------------"
+echo "Host: localhost"
+echo "Port: 1521"
+echo "Service: FREEPDB1"
+echo "Username: system"
+echo "Password: ${ORACLE_PASSWORD}"
+echo ""
+echo "๐ JDBC URL:"
+echo "jdbc:oracle:thin:@localhost:1521/FREEPDB1"
+echo ""
+echo "๐งช Connect using SQL*Plus:"
+echo "sqlplus system/${ORACLE_PASSWORD}@FREEPDB1"
+echo "------------------------------------"