From 0793e70c266bd9be150bca5b9f183185a30d60ad Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Wed, 27 Mar 2024 13:46:16 +0530 Subject: [PATCH 1/4] fix(server): resolved failing to use dynamic secret due to superuser --- .../secret-rotation-queue-fn.ts | 12 +- .../dynamic-secret/providers/sql-database.ts | 12 +- frontend/src/components/v2/Card/Card.tsx | 16 +- frontend/src/components/v2/Modal/Modal.tsx | 7 +- .../CreateDynamicSecretForm.tsx | 6 +- .../SqlDatabaseInputForm.tsx | 456 +++++++++--------- 6 files changed, 268 insertions(+), 241 deletions(-) diff --git a/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts b/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts index 5a2e478e1..8eade1626 100644 --- a/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts +++ b/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts @@ -90,7 +90,17 @@ export const secretRotationDbFn = async ({ const appCfg = getConfig(); const ssl = ca ? { rejectUnauthorized: false, ca } : undefined; - if (host === "localhost" || host === "127.0.0.1" || getDbConnectionHost(appCfg.DB_CONNECTION_URI) === host) + const dbHost = appCfg.DB_HOST || getDbConnectionHost(appCfg.DB_CONNECTION_URI); + if ( + host === "localhost" || + host === "127.0.0.1" || + // database infisical uses + dbHost === host || + // internal ips + host === "host.docker.internal" || + host.match(/^10\.\d+\.\d+\.\d+/) || + host.match(/^192\.168\.\d+\.\d+/) + ) throw new Error("Invalid db host"); const db = knex({ diff --git a/backend/src/services/dynamic-secret/providers/sql-database.ts b/backend/src/services/dynamic-secret/providers/sql-database.ts index c0744031e..7107fe3a3 100644 --- a/backend/src/services/dynamic-secret/providers/sql-database.ts +++ b/backend/src/services/dynamic-secret/providers/sql-database.ts @@ -23,7 +23,17 @@ export const SqlDatabaseProvider = (): TDynamicProviderFns => { const dbHost = appCfg.DB_HOST || getDbConnectionHost(appCfg.DB_CONNECTION_URI); const providerInputs = await DynamicSecretSqlDBSchema.parseAsync(inputs); - if (providerInputs.host === "localhost" || providerInputs.host === "127.0.0.1" || dbHost === providerInputs.host) + if ( + // localhost + providerInputs.host === "localhost" || + providerInputs.host === "127.0.0.1" || + // database infisical uses + dbHost === providerInputs.host || + // internal ips + providerInputs.host === "host.docker.internal" || + providerInputs.host.match(/^10\.\d+\.\d+\.\d+/) || + providerInputs.host.match(/^192\.168\.\d+\.\d+/) + ) throw new BadRequestError({ message: "Invalid db host" }); return providerInputs; }; diff --git a/frontend/src/components/v2/Card/Card.tsx b/frontend/src/components/v2/Card/Card.tsx index 0e86d0357..a0a1f8338 100644 --- a/frontend/src/components/v2/Card/Card.tsx +++ b/frontend/src/components/v2/Card/Card.tsx @@ -1,4 +1,4 @@ -import { forwardRef, ReactNode } from "react"; +import { CSSProperties, forwardRef, ReactNode } from "react"; import { twMerge } from "tailwind-merge"; export type CardTitleProps = { @@ -31,10 +31,13 @@ export const CardFooter = ({ children, className }: CardFooterProps) => ( export type CardBodyProps = { children: ReactNode; className?: string; + style?: CSSProperties; }; -export const CardBody = ({ children, className }: CardBodyProps) => ( -
{children}
+export const CardBody = ({ children, className, style }: CardBodyProps) => ( +
+ {children} +
); export type CardProps = { @@ -44,10 +47,14 @@ export type CardProps = { isRounded?: boolean; isPlain?: boolean; isHoverable?: boolean; + style?: CSSProperties; }; export const Card = forwardRef( - ({ children, isFullHeight, isRounded, isHoverable, isPlain, className }, ref): JSX.Element => { + ( + { children, isFullHeight, isRounded, isHoverable, isPlain, className, style }, + ref + ): JSX.Element => { return (
( isHoverable && "hover:shadow-xl", className )} + style={style} > {children}
diff --git a/frontend/src/components/v2/Modal/Modal.tsx b/frontend/src/components/v2/Modal/Modal.tsx index 250feeff1..90abfecbd 100644 --- a/frontend/src/components/v2/Modal/Modal.tsx +++ b/frontend/src/components/v2/Modal/Modal.tsx @@ -29,12 +29,15 @@ export const ModalContent = forwardRef( {title && {title}} - {children} + + {children} + {footerContent && {footerContent}} void; - projectSlug:string; + projectSlug: string; environment: string; secretPath: string; }; @@ -42,7 +42,7 @@ export const CreateDynamicSecretForm = ({ {wizardStep === WizardSteps.SelectProvider && ( @@ -56,7 +56,7 @@ export const CreateDynamicSecretForm = ({
Select a service to connect to:
{ diff --git a/frontend/src/views/SecretMainPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx b/frontend/src/views/SecretMainPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx index 75b347361..c0300ea80 100644 --- a/frontend/src/views/SecretMainPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx +++ b/frontend/src/views/SecretMainPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx @@ -25,7 +25,7 @@ const formSchema = z.object({ provider: z.object({ client: z.nativeEnum(SqlProviders), host: z.string().toLowerCase().min(1), - port: z.number(), + port: z.coerce.number(), database: z.string().min(1), username: z.string().min(1), password: z.string().min(1), @@ -54,9 +54,7 @@ const formSchema = z.object({ if (valMs > 24 * 60 * 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); }), - name: z - .string() - .refine((val) => val.toLowerCase() === val, "Must be lowercase") + name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase") }); type TForm = z.infer; @@ -84,14 +82,14 @@ export const SqlDatabaseInputForm = ({ defaultValues: { provider: { creationStatement: - "CREATE USER \"{{username}}\" WITH SUPERUSER ENCRYPTED PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';\nGRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO \"{{username}}\";", + "CREATE USER \"{{username}}\" WITH ENCRYPTED PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';\nGRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO \"{{username}}\";", renewStatement: "ALTER ROLE \"{{username}}\" VALID UNTIL '{{expiration}}';", revocationStatement: 'REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM "{{username}}";\nDROP OWNED BY "{{username}}";\nDROP ROLE "{{username}}";' } } }); - + const createDynamicSecret = useCreateDynamicSecret(); const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => { @@ -119,238 +117,236 @@ export const SqlDatabaseInputForm = ({ return (
-
-
- ( - - - - )} - /> -
-
- ( - } - isError={Boolean(error?.message)} - errorText={error?.message} - > - - - )} - /> -
-
- ( - } - isError={Boolean(error?.message)} - errorText={error?.message} - > - - - )} - /> -
-
-
- Configuration +
+
+ ( + + + + )} + /> +
+
+ ( + } + isError={Boolean(error?.message)} + errorText={error?.message} + > + + + )} + /> +
+
+ ( + } + isError={Boolean(error?.message)} + errorText={error?.message} + > + + + )} + /> +
-
-
Service
- ( - - - - )} - /> -
- ( - - - - )} - /> - ( - - field.onChange(parseInt(el.target.value, 10))} - /> - - )} - /> +
+
+ Configuration
-
+
+
Service
( - - + name="provider.client" + defaultValue={SqlProviders.Postgres} + render={({ field: { value, onChange }, fieldState: { error } }) => ( + + )} /> - ( - - - - )} - /> - ( - - - - )} - /> -
-
- ( - - - - )} - /> - - - Modify SQL Statements - - ( - -