mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
improvements: add ssl options to sql connections and update ui/docs
This commit is contained in:
@@ -7,7 +7,20 @@ export const MSSQL_CREDENTIALS_ROTATION_LIST_OPTION: TSecretRotationV2ListItem =
|
||||
type: SecretRotation.MsSqlCredentials,
|
||||
connection: AppConnection.MsSql,
|
||||
template: {
|
||||
createUserStatement: `CREATE LOGIN [my_mssql_user] WITH PASSWORD = 'my_temporary_password'; CREATE USER [my_mssql_user] FOR LOGIN [my_mssql_user]; GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO [my_mssql_user];`,
|
||||
createUserStatement: `-- Create login at the server level
|
||||
CREATE LOGIN [infisical_user] WITH PASSWORD = 'my-password';
|
||||
|
||||
-- Grant server-level connect permission
|
||||
GRANT CONNECT SQL TO [infisical_user];
|
||||
|
||||
-- Switch to the database where you want to create the user
|
||||
USE my_database;
|
||||
|
||||
-- Create the database user mapped to the login
|
||||
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];`,
|
||||
secretsMapping: {
|
||||
username: "MSSQL_DB_USERNAME",
|
||||
password: "MSSQL_DB_PASSWORD"
|
||||
|
||||
@@ -7,7 +7,14 @@ export const POSTGRES_CREDENTIALS_ROTATION_LIST_OPTION: TSecretRotationV2ListIte
|
||||
type: SecretRotation.PostgresCredentials,
|
||||
connection: AppConnection.Postgres,
|
||||
template: {
|
||||
createUserStatement: `CREATE USER "my_pg_user" WITH ENCRYPTED PASSWORD 'temporary_password'; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "my_pg_user";`,
|
||||
createUserStatement: `-- create user role
|
||||
CREATE USER infisical_user WITH ENCRYPTED PASSWORD 'temporary_password';
|
||||
|
||||
-- grant database connection permissions
|
||||
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;`,
|
||||
secretsMapping: {
|
||||
username: "POSTGRES_DB_USERNAME",
|
||||
password: "POSTGRES_DB_PASSWORD"
|
||||
|
||||
@@ -1691,6 +1691,8 @@ export const AppConnections = {
|
||||
database: "The name of the database to connect to.",
|
||||
username: "The username to connect to the database with.",
|
||||
password: "The password to connect to the database with.",
|
||||
sslEnabled: "Whether or not to use SSL when connecting to the database.",
|
||||
sslRejectUnauthorized: "Whether or not to reject unauthorized SSL certificates.",
|
||||
sslCertificate: "The SSL certificate to use for connection."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,6 @@ const envSchema = z
|
||||
QUEUE_WORKERS_ENABLED: zodStrBool.default("true"),
|
||||
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"),
|
||||
|
||||
@@ -29,7 +29,9 @@ export const SanitizedMsSqlConnectionSchema = z.discriminatedUnion("method", [
|
||||
host: true,
|
||||
database: true,
|
||||
port: true,
|
||||
username: true
|
||||
username: true,
|
||||
sslEnabled: true,
|
||||
sslRejectUnauthorized: true
|
||||
})
|
||||
})
|
||||
]);
|
||||
|
||||
@@ -27,7 +27,9 @@ export const SanitizedPostgresConnectionSchema = z.discriminatedUnion("method",
|
||||
host: true,
|
||||
database: true,
|
||||
port: true,
|
||||
username: true
|
||||
username: true,
|
||||
sslEnabled: true,
|
||||
sslRejectUnauthorized: true
|
||||
})
|
||||
})
|
||||
]);
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
TSqlCredentialsRotationGeneratedCredentials,
|
||||
TSqlCredentialsRotationWithConnection
|
||||
} from "@app/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-types";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { BadRequestError, DatabaseError } from "@app/lib/errors";
|
||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
@@ -21,16 +20,14 @@ const SQL_CONNECTION_CLIENT_MAP = {
|
||||
|
||||
const getConnectionConfig = ({
|
||||
app,
|
||||
credentials: { sslCertificate, host }
|
||||
credentials: { host, sslCertificate, sslEnabled, sslRejectUnauthorized }
|
||||
}: Pick<TSqlConnection, "credentials" | "app">) => {
|
||||
const appCfg = getConfig();
|
||||
|
||||
switch (app) {
|
||||
case AppConnection.Postgres: {
|
||||
return {
|
||||
ssl: appCfg.DB_SSL_REQUIRED
|
||||
ssl: sslEnabled
|
||||
? {
|
||||
rejectUnauthorized: appCfg.DB_SSL_REJECT_UNAUTHORIZED,
|
||||
rejectUnauthorized: sslRejectUnauthorized,
|
||||
ca: sslCertificate,
|
||||
servername: host
|
||||
}
|
||||
@@ -39,13 +36,13 @@ const getConnectionConfig = ({
|
||||
}
|
||||
case AppConnection.MsSql: {
|
||||
return {
|
||||
options: appCfg.DB_SSL_REQUIRED
|
||||
options: sslEnabled
|
||||
? {
|
||||
trustServerCertificate: !appCfg.DB_SSL_REJECT_UNAUTHORIZED,
|
||||
trustServerCertificate: !sslRejectUnauthorized,
|
||||
encrypt: true,
|
||||
cryptoCredentialsDetails: sslCertificate ? { ca: sslCertificate } : {}
|
||||
}
|
||||
: undefined
|
||||
: { encrypt: false }
|
||||
};
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -8,5 +8,12 @@ export const BaseSqlUsernameAndPasswordConnectionSchema = z.object({
|
||||
database: z.string().trim().min(1, "Database required").describe(AppConnections.CREDENTIALS.SQL_CONNECTION.database),
|
||||
username: z.string().trim().min(1, "Username required").describe(AppConnections.CREDENTIALS.SQL_CONNECTION.username),
|
||||
password: z.string().trim().min(1, "Password required").describe(AppConnections.CREDENTIALS.SQL_CONNECTION.password),
|
||||
sslCertificate: z.string().trim().optional().describe(AppConnections.CREDENTIALS.SQL_CONNECTION.sslCertificate)
|
||||
sslEnabled: z.boolean().describe(AppConnections.CREDENTIALS.SQL_CONNECTION.sslEnabled),
|
||||
sslRejectUnauthorized: z.boolean().describe(AppConnections.CREDENTIALS.SQL_CONNECTION.sslRejectUnauthorized),
|
||||
sslCertificate: z
|
||||
.string()
|
||||
.trim()
|
||||
.transform((value) => value || undefined)
|
||||
.optional()
|
||||
.describe(AppConnections.CREDENTIALS.SQL_CONNECTION.sslCertificate)
|
||||
});
|
||||
|
||||
@@ -11,19 +11,19 @@ description: "Learn how to automatically rotate Microsoft SQL Server credentials
|
||||
An example creation statement might look like:
|
||||
```SQL
|
||||
-- create server-level logins
|
||||
CREATE LOGIN infisical_user_1 WITH PASSWORD = 'my-password';
|
||||
CREATE LOGIN infisical_user_2 WITH PASSWORD = 'my-password';
|
||||
CREATE LOGIN [infisical_user_1] WITH PASSWORD = 'my-password';
|
||||
CREATE LOGIN [infisical_user_2] WITH PASSWORD = 'my-password';
|
||||
GRANT CONNECT SQL TO [infisical_user_1];
|
||||
GRANT CONNECT SQL TO [infisical_user_2];
|
||||
|
||||
-- create database-level users with login from above
|
||||
USE my_database;
|
||||
CREATE USER infisical_user_1 FOR LOGIN infisical_user_1;
|
||||
CREATE USER infisical_user_2 FOR LOGIN infisical_user_2;
|
||||
GRANT CONNECT TO infisical_user_1;
|
||||
GRANT CONNECT TO infisical_user_2;
|
||||
CREATE USER [infisical_user_1] FOR LOGIN [infisical_user_1];
|
||||
CREATE USER [infisical_user_2] FOR LOGIN [infisical_user_2];
|
||||
|
||||
-- grant relevant permissions
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO infisical_user_1;
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO infisical_user_2;
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO [infisical_user_1];
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO [infisical_user_2];
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
@@ -10,14 +10,16 @@ description: "Learn how to automatically rotate PostgreSQL credentials."
|
||||
|
||||
An example creation statement might look like:
|
||||
```SQL
|
||||
-- first user
|
||||
-- create user roles
|
||||
CREATE USER infisical_user_1 WITH ENCRYPTED PASSWORD 'temporary_password';
|
||||
GRANT CONNECT ON DATABASE my_database TO infisical_user_1;
|
||||
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO infisical_user_1;
|
||||
|
||||
-- second user
|
||||
CREATE USER infisical_user_2 WITH ENCRYPTED PASSWORD 'temporary_password';
|
||||
|
||||
-- grant database connection permissions
|
||||
GRANT CONNECT ON DATABASE my_database TO infisical_user_1;
|
||||
GRANT CONNECT ON DATABASE my_database TO infisical_user_2;
|
||||
|
||||
-- grant relevant table permissions
|
||||
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO infisical_user_1;
|
||||
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO infisical_user_2;
|
||||
```
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 792 KiB After Width: | Height: | Size: 826 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 790 KiB After Width: | Height: | Size: 825 KiB |
@@ -11,16 +11,20 @@ Infisical supports connecting to Microsoft SQL Server using database principals.
|
||||
<Step title="Create a Principal">
|
||||
Infisical recommends creating a designated server login and database user in your Microsoft SQL Server database for your connection.
|
||||
```SQL
|
||||
-- create server-level login
|
||||
CREATE LOGIN infisical_login WITH PASSWORD = 'my-password';
|
||||
-- Create login at the server level
|
||||
CREATE LOGIN [infisical_app] WITH PASSWORD = 'my-password';
|
||||
|
||||
-- create database-level user with login from above
|
||||
-- Grant server-level connect permission
|
||||
GRANT CONNECT SQL TO [infisical_app];
|
||||
|
||||
-- Switch to the specific database where you want to create the user
|
||||
USE my_database;
|
||||
CREATE USER infisical_user FOR LOGIN infisical_login;
|
||||
GRANT CONNECT TO infisical_user;
|
||||
|
||||
-- Create the database user mapped to the login
|
||||
CREATE USER [infisical_app] FOR LOGIN [infisical_app];
|
||||
|
||||
-- If you intend to use Platform Managed Credentials (see below)
|
||||
GRANT ALTER ANY LOGIN TO infisical_login;
|
||||
GRANT ALTER ANY LOGIN TO [infisical_app];
|
||||
```
|
||||
</Step>
|
||||
<Step title="Grant Relevant Permissions">
|
||||
@@ -95,6 +99,8 @@ Infisical supports connecting to Microsoft SQL Server using database principals.
|
||||
"database": "default",
|
||||
"username": "infisical_login",
|
||||
"password": "my-password",
|
||||
"sslEnabled": true,
|
||||
"sslRejectUnauthorized": true
|
||||
},
|
||||
}'
|
||||
```
|
||||
@@ -117,7 +123,9 @@ Infisical supports connecting to Microsoft SQL Server using database principals.
|
||||
"host": "123.4.5.6",
|
||||
"port": 1433,
|
||||
"database": "default",
|
||||
"username": "infisical_login"
|
||||
"username": "infisical_login",
|
||||
"sslEnabled": true,
|
||||
"sslRejectUnauthorized": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ Infisical supports connecting to PostgreSQL using a database role.
|
||||
Infisical recommends creating a designated role in your PostgreSQL database for your connection.
|
||||
```SQL
|
||||
-- create user role
|
||||
CREATE ROLE infisical_role WITH LOGIN PASSWORD 'my-password'
|
||||
CREATE ROLE infisical_role WITH LOGIN PASSWORD 'my-password';
|
||||
|
||||
-- grant login access to the specified database
|
||||
GRANT CONNECT ON DATABASE my_database TO infisical_role;
|
||||
@@ -27,6 +27,7 @@ Infisical supports connecting to PostgreSQL using a database role.
|
||||
<Tab title="Secret Rotation">
|
||||
For Secret Rotations, your Infisical user will require the ability to alter other users' passwords:
|
||||
```SQL
|
||||
-- enable permissions to alter login credentials
|
||||
ALTER ROLE infisical_role WITH CREATEROLE;
|
||||
```
|
||||
</Tab>
|
||||
@@ -88,6 +89,8 @@ Infisical supports connecting to PostgreSQL using a database role.
|
||||
"database": "default",
|
||||
"username": "infisical_role",
|
||||
"password": "my-password",
|
||||
"sslEnabled": true,
|
||||
"sslRejectUnauthorized": true
|
||||
},
|
||||
}'
|
||||
```
|
||||
@@ -110,7 +113,9 @@ Infisical supports connecting to PostgreSQL using a database role.
|
||||
"host": "123.4.5.6",
|
||||
"port": 5432,
|
||||
"database": "default",
|
||||
"username": "infisical_role"
|
||||
"username": "infisical_role",
|
||||
"sslEnabled": true,
|
||||
"sslRejectUnauthorized": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,19 +439,6 @@ When set, all visits to the Infisical login page will automatically redirect use
|
||||
information.
|
||||
</Accordion>
|
||||
|
||||
## External Database Connections
|
||||
|
||||
<ParamField query="DB_SSL_REJECT_UNAUTHORIZED" type="boolean" default="true" optional>
|
||||
Specify whether external database connections should reject unauthorized SSL certificates.
|
||||
We highly recommend keeping this value set to `true` for production use-cases.
|
||||
</ParamField>
|
||||
|
||||
<ParamField query="DB_SSL_REQUIRED" type="boolean" default="true" optional>
|
||||
Specify whether external database connections should require SSL.
|
||||
We highly recommend keeping this value set to `true` for production use-cases.
|
||||
</ParamField>
|
||||
|
||||
|
||||
## App Connections
|
||||
|
||||
You can configure third-party app connections for re-use across Infisical Projects.
|
||||
|
||||
@@ -57,7 +57,7 @@ export const SqlRotationParametersFields = () => {
|
||||
to suit your needs.
|
||||
</p>
|
||||
<p className="mb-3 text-sm">
|
||||
<pre className="whitespace-pre-wrap rounded border border-mineshaft-700 bg-mineshaft-800 p-2 text-mineshaft-300">
|
||||
<pre className="max-h-[10rem] overflow-y-auto whitespace-pre-wrap rounded border border-mineshaft-700 bg-mineshaft-800 p-2 text-mineshaft-300">
|
||||
{rotationOption!.template.createUserStatement}
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
@@ -4,4 +4,6 @@ export type TBaseSqlConnectionCredentials = {
|
||||
username: string;
|
||||
password: string;
|
||||
database: string;
|
||||
sslEnabled: boolean;
|
||||
sslRejectUnauthorized: boolean;
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
|
||||
type Props = {
|
||||
appConnection?: TAwsConnection;
|
||||
onSubmit: (formData: FormData) => void;
|
||||
onSubmit: (formData: FormData) => Promise<void>;
|
||||
};
|
||||
|
||||
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
|
||||
type Props = {
|
||||
appConnection?: TDatabricksConnection;
|
||||
onSubmit: (formData: FormData) => void;
|
||||
onSubmit: (formData: FormData) => Promise<void>;
|
||||
};
|
||||
|
||||
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
|
||||
type Props = {
|
||||
appConnection?: TGcpConnection;
|
||||
onSubmit: (formData: FormData) => void;
|
||||
onSubmit: (formData: FormData) => Promise<void>;
|
||||
};
|
||||
|
||||
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
|
||||
type Props = {
|
||||
appConnection?: THumanitecConnection;
|
||||
onSubmit: (formData: FormData) => void;
|
||||
onSubmit: (formData: FormData) => Promise<void>;
|
||||
};
|
||||
|
||||
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
|
||||
type Props = {
|
||||
appConnection?: TMsSqlConnection;
|
||||
onSubmit: (formData: FormData) => void;
|
||||
onSubmit: (formData: FormData) => Promise<void>;
|
||||
};
|
||||
|
||||
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
||||
@@ -44,6 +44,7 @@ type FormData = z.infer<typeof formSchema>;
|
||||
export const MsSqlConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
||||
const isUpdate = Boolean(appConnection);
|
||||
const [showConfirmation, setShowConfirmation] = useState(false);
|
||||
const [selectedTabIndex, setSelectedTabIndex] = useState(0);
|
||||
|
||||
const form = useForm<FormData>({
|
||||
resolver: zodResolver(formSchema),
|
||||
@@ -56,7 +57,9 @@ export const MsSqlConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
||||
database: "default",
|
||||
username: "",
|
||||
password: "",
|
||||
sslCertificate: ""
|
||||
sslEnabled: true,
|
||||
sslRejectUnauthorized: true,
|
||||
sslCertificate: undefined
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -69,18 +72,23 @@ export const MsSqlConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
||||
|
||||
const isPlatformManagedCredentials = appConnection?.isPlatformManagedCredentials ?? false;
|
||||
|
||||
const confirmSubmit = (formData: FormData) => {
|
||||
const confirmSubmit = async (formData: FormData) => {
|
||||
if (formData.isPlatformManagedCredentials) {
|
||||
setShowConfirmation(true);
|
||||
return;
|
||||
}
|
||||
|
||||
onSubmit(formData);
|
||||
await onSubmit(formData);
|
||||
};
|
||||
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<form onSubmit={handleSubmit(confirmSubmit)}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
setSelectedTabIndex(0);
|
||||
handleSubmit(confirmSubmit)(e);
|
||||
}}
|
||||
>
|
||||
{!isUpdate && <GenericAppConnectionsFields />}
|
||||
<Controller
|
||||
name="method"
|
||||
@@ -113,7 +121,11 @@ export const MsSqlConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<SqlConnectionFields isPlatformManagedCredentials={isPlatformManagedCredentials} />
|
||||
<SqlConnectionFields
|
||||
isPlatformManagedCredentials={isPlatformManagedCredentials}
|
||||
selectedTabIndex={selectedTabIndex}
|
||||
setSelectedTabIndex={setSelectedTabIndex}
|
||||
/>
|
||||
{isPlatformManagedCredentials ? (
|
||||
<PlatformManagedNoticeBanner />
|
||||
) : (
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
|
||||
type Props = {
|
||||
appConnection?: TPostgresConnection;
|
||||
onSubmit: (formData: FormData) => void;
|
||||
onSubmit: (formData: FormData) => Promise<void>;
|
||||
};
|
||||
|
||||
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
||||
@@ -41,6 +41,7 @@ type FormData = z.infer<typeof formSchema>;
|
||||
export const PostgresConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
||||
const isUpdate = Boolean(appConnection);
|
||||
const [showConfirmation, setShowConfirmation] = useState(false);
|
||||
const [selectedTabIndex, setSelectedTabIndex] = useState(0);
|
||||
|
||||
const form = useForm<FormData>({
|
||||
resolver: zodResolver(formSchema),
|
||||
@@ -53,7 +54,9 @@ export const PostgresConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
||||
database: "default",
|
||||
username: "",
|
||||
password: "",
|
||||
sslCertificate: ""
|
||||
sslEnabled: true,
|
||||
sslRejectUnauthorized: true,
|
||||
sslCertificate: undefined
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -66,18 +69,23 @@ export const PostgresConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
||||
|
||||
const isPlatformManagedCredentials = appConnection?.isPlatformManagedCredentials ?? false;
|
||||
|
||||
const confirmSubmit = (formData: FormData) => {
|
||||
const confirmSubmit = async (formData: FormData) => {
|
||||
if (formData.isPlatformManagedCredentials) {
|
||||
setShowConfirmation(true);
|
||||
return;
|
||||
}
|
||||
|
||||
onSubmit(formData);
|
||||
await onSubmit(formData);
|
||||
};
|
||||
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<form onSubmit={handleSubmit(confirmSubmit)}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
setSelectedTabIndex(0);
|
||||
handleSubmit(confirmSubmit)(e);
|
||||
}}
|
||||
>
|
||||
{!isUpdate && <GenericAppConnectionsFields />}
|
||||
<Controller
|
||||
name="method"
|
||||
@@ -110,7 +118,11 @@ export const PostgresConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<SqlConnectionFields isPlatformManagedCredentials={isPlatformManagedCredentials} />
|
||||
<SqlConnectionFields
|
||||
isPlatformManagedCredentials={isPlatformManagedCredentials}
|
||||
selectedTabIndex={selectedTabIndex}
|
||||
setSelectedTabIndex={setSelectedTabIndex}
|
||||
/>
|
||||
{isPlatformManagedCredentials ? (
|
||||
<PlatformManagedNoticeBanner />
|
||||
) : (
|
||||
|
||||
@@ -1,122 +1,207 @@
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import { faQuestionCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Tab } from "@headlessui/react";
|
||||
|
||||
import { FormControl, Input, SecretInput, Switch, TextArea, Tooltip } from "@app/components/v2";
|
||||
|
||||
type Props = {
|
||||
isPlatformManagedCredentials: boolean;
|
||||
selectedTabIndex: number;
|
||||
setSelectedTabIndex: Dispatch<SetStateAction<number>>;
|
||||
};
|
||||
|
||||
export const SqlConnectionFields = ({ isPlatformManagedCredentials }: Props) => {
|
||||
const { control } = useFormContext();
|
||||
export const SqlConnectionFields = ({
|
||||
isPlatformManagedCredentials,
|
||||
setSelectedTabIndex,
|
||||
selectedTabIndex
|
||||
}: Props) => {
|
||||
const { control, watch } = useFormContext();
|
||||
|
||||
const sslEnabled = watch("credentials.sslEnabled");
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-start gap-2">
|
||||
<Controller
|
||||
name="credentials.host"
|
||||
control={control}
|
||||
shouldUnregister
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
className="flex-1"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Host"
|
||||
>
|
||||
<Input {...field} isDisabled={isPlatformManagedCredentials} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="credentials.database"
|
||||
control={control}
|
||||
shouldUnregister
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
className="flex-1"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Database Name"
|
||||
>
|
||||
<Input {...field} isDisabled={isPlatformManagedCredentials} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="credentials.port"
|
||||
control={control}
|
||||
shouldUnregister
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
className="w-28"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Port"
|
||||
>
|
||||
<Input type="number" {...field} isDisabled={isPlatformManagedCredentials} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<Controller
|
||||
name="credentials.username"
|
||||
control={control}
|
||||
shouldUnregister
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Username"
|
||||
className="flex-1"
|
||||
>
|
||||
<Input {...field} isDisabled={isPlatformManagedCredentials} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="credentials.password"
|
||||
control={control}
|
||||
shouldUnregister
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Password"
|
||||
className="flex-1"
|
||||
>
|
||||
<SecretInput
|
||||
containerClassName="text-gray-400 w-full group-focus-within:!border-primary-400/50 border border-mineshaft-500 bg-mineshaft-900 px-2.5 py-1.5"
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
isDisabled={isPlatformManagedCredentials}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Controller
|
||||
name="credentials.sslCertificate"
|
||||
control={control}
|
||||
shouldUnregister
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="SSL Certificate"
|
||||
isOptional
|
||||
<Tab.Group selectedIndex={selectedTabIndex} onChange={setSelectedTabIndex}>
|
||||
<Tab.List className="-pb-1 mb-6 w-full border-b-2 border-mineshaft-600">
|
||||
<Tab
|
||||
className={({ selected }) =>
|
||||
`w-30 -mb-[0.14rem] px-4 py-2 text-sm font-medium outline-none disabled:opacity-60 ${
|
||||
selected ? "border-b-2 border-mineshaft-300 text-mineshaft-200" : "text-bunker-300"
|
||||
}`
|
||||
}
|
||||
>
|
||||
<TextArea
|
||||
className="!resize-none"
|
||||
rows={1}
|
||||
{...field}
|
||||
isDisabled={isPlatformManagedCredentials}
|
||||
Configuration
|
||||
</Tab>
|
||||
<Tab
|
||||
className={({ selected }) =>
|
||||
`w-30 -mb-[0.14rem] px-4 py-2 text-sm font-medium outline-none disabled:opacity-60 ${
|
||||
selected ? "border-b-2 border-mineshaft-300 text-mineshaft-200" : "text-bunker-300"
|
||||
}`
|
||||
}
|
||||
>
|
||||
SSL ({sslEnabled ? "Enabled" : "Disabled"})
|
||||
</Tab>
|
||||
</Tab.List>
|
||||
<Tab.Panels className="mb-4 rounded border border-mineshaft-600 bg-mineshaft-700/70 p-3 pb-0">
|
||||
<Tab.Panel>
|
||||
<div className="mt-[0.675rem] flex items-start gap-2">
|
||||
<Controller
|
||||
name="credentials.host"
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
className="flex-1"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Host"
|
||||
>
|
||||
<Input {...field} isDisabled={isPlatformManagedCredentials} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="credentials.database"
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
className="flex-1"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Database Name"
|
||||
>
|
||||
<Input {...field} isDisabled={isPlatformManagedCredentials} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="credentials.port"
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
className="w-28"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Port"
|
||||
>
|
||||
<Input type="number" {...field} isDisabled={isPlatformManagedCredentials} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-[0.675rem] flex items-start gap-2">
|
||||
<Controller
|
||||
name="credentials.username"
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Username"
|
||||
className="flex-1"
|
||||
>
|
||||
<Input {...field} isDisabled={isPlatformManagedCredentials} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="credentials.password"
|
||||
control={control}
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Password"
|
||||
className="flex-1"
|
||||
>
|
||||
<SecretInput
|
||||
containerClassName="text-gray-400 w-full group-focus-within:!border-primary-400/50 border border-mineshaft-500 bg-mineshaft-900 px-2.5 py-1.5"
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
isDisabled={isPlatformManagedCredentials}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</Tab.Panel>
|
||||
<Tab.Panel>
|
||||
<Controller
|
||||
name="credentials.sslEnabled"
|
||||
control={control}
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl isError={Boolean(error?.message)} errorText={error?.message}>
|
||||
<Switch
|
||||
className="bg-mineshaft-400/50 shadow-inner data-[state=checked]:bg-green/80"
|
||||
id="platform-managed"
|
||||
thumbClassName="bg-mineshaft-800"
|
||||
isChecked={value}
|
||||
onCheckedChange={onChange}
|
||||
isDisabled={isPlatformManagedCredentials}
|
||||
>
|
||||
Enable SSL
|
||||
</Switch>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Controller
|
||||
name="credentials.sslCertificate"
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
className={sslEnabled ? "" : "opacity-50"}
|
||||
label="SSL Certificate"
|
||||
isOptional
|
||||
>
|
||||
<TextArea
|
||||
className="h-[3.5rem] !resize-none"
|
||||
{...field}
|
||||
isDisabled={isPlatformManagedCredentials || !sslEnabled}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="credentials.sslRejectUnauthorized"
|
||||
control={control}
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
className={sslEnabled ? "" : "opacity-50"}
|
||||
isError={Boolean(error?.message)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Switch
|
||||
className="bg-mineshaft-400/50 shadow-inner data-[state=checked]:bg-green/80"
|
||||
id="platform-managed"
|
||||
thumbClassName="bg-mineshaft-800"
|
||||
isChecked={sslEnabled ? value : false}
|
||||
onCheckedChange={onChange}
|
||||
isDisabled={isPlatformManagedCredentials || !sslEnabled}
|
||||
>
|
||||
<p className="w-[9.5rem]">
|
||||
Reject Unauthorized
|
||||
<Tooltip
|
||||
className="max-w-md"
|
||||
content={
|
||||
<p>
|
||||
If enabled, Infisical will only connect to servers that have valid,
|
||||
trusted SSL certificates.
|
||||
</p>
|
||||
}
|
||||
>
|
||||
<FontAwesomeIcon icon={faQuestionCircle} size="sm" className="ml-1" />
|
||||
</Tooltip>
|
||||
</p>
|
||||
</Switch>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Tab.Panel>
|
||||
</Tab.Panels>
|
||||
</Tab.Group>
|
||||
{!isPlatformManagedCredentials && (
|
||||
<Controller
|
||||
name="isPlatformManagedCredentials"
|
||||
|
||||
@@ -6,5 +6,11 @@ export const BaseSqlUsernameAndPasswordConnectionSchema = z.object({
|
||||
database: z.string().trim().min(1, "Database required").default("default"),
|
||||
username: z.string().trim().min(1, "Username required"),
|
||||
password: z.string().trim().min(1, "Password required"),
|
||||
sslCertificate: z.string().trim().optional()
|
||||
sslEnabled: z.boolean().default(true),
|
||||
sslRejectUnauthorized: z.boolean().default(true),
|
||||
sslCertificate: z
|
||||
.string()
|
||||
.trim()
|
||||
.transform((value) => value || undefined)
|
||||
.optional()
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user