mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Merge pull request #4512 from Infisical/fix/address-azure-sql-server-dynamic-secret-integration
fix: address sql server dynamic secret integration
This commit is contained in:
@@ -165,6 +165,7 @@ export const DynamicSecretSqlDBSchema = z.object({
|
||||
revocationStatement: z.string().trim(),
|
||||
renewStatement: z.string().trim().optional(),
|
||||
ca: z.string().optional(),
|
||||
sslEnabled: z.boolean().optional(),
|
||||
gatewayId: z.string().nullable().optional()
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import handlebars from "handlebars";
|
||||
import RE2 from "re2";
|
||||
import knex from "knex";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -150,12 +151,30 @@ export const SqlDatabaseProvider = ({ gatewayService }: TSqlDatabaseProviderDTO)
|
||||
return { ...providerInputs, hostIp };
|
||||
};
|
||||
|
||||
const $getClient = async (providerInputs: z.infer<typeof DynamicSecretSqlDBSchema> & { hostIp: string }) => {
|
||||
const $getClient = async (
|
||||
providerInputs: z.infer<typeof DynamicSecretSqlDBSchema> & { hostIp: string; originalHost: string }
|
||||
) => {
|
||||
const ssl = providerInputs.ca
|
||||
? { rejectUnauthorized: false, ca: providerInputs.ca, servername: providerInputs.host }
|
||||
: undefined;
|
||||
|
||||
const isMsSQLClient = providerInputs.client === SqlProviders.MsSQL;
|
||||
|
||||
/*
|
||||
We route through the gateway by setting connection.host = "localhost".
|
||||
Azure SQL identifies the logical server from the TDS login name when the host
|
||||
isn’t the Azure FQDN. Therefore, when using the gateway, ensure username is
|
||||
"user@<azure-server-name>" so Azure opens the correct logical server.
|
||||
Direct connections to the Azure FQDN usually don’t require this suffix.
|
||||
*/
|
||||
const isAzureSql = isMsSQLClient && new RE2(/\.database\.windows\.net$/i).test(providerInputs.originalHost);
|
||||
const azureServerLabel =
|
||||
isAzureSql && providerInputs.gatewayId ? providerInputs.originalHost?.split(".")[0] : undefined;
|
||||
const effectiveUser =
|
||||
isAzureSql && !providerInputs.username.includes("@") && azureServerLabel
|
||||
? `${providerInputs.username}@${azureServerLabel}`
|
||||
: providerInputs.username;
|
||||
|
||||
const db = knex({
|
||||
client: providerInputs.client,
|
||||
connection: {
|
||||
@@ -165,7 +184,7 @@ export const SqlDatabaseProvider = ({ gatewayService }: TSqlDatabaseProviderDTO)
|
||||
providerInputs.client === SqlProviders.Postgres && !providerInputs.gatewayId
|
||||
? providerInputs.hostIp
|
||||
: providerInputs.host,
|
||||
user: providerInputs.username,
|
||||
user: effectiveUser,
|
||||
password: providerInputs.password,
|
||||
ssl,
|
||||
// @ts-expect-error this is because of knexjs type signature issue. This is directly passed to driver
|
||||
@@ -173,6 +192,7 @@ export const SqlDatabaseProvider = ({ gatewayService }: TSqlDatabaseProviderDTO)
|
||||
// https://github.com/tediousjs/tedious/blob/ebb023ed90969a7ec0e4b036533ad52739d921f7/test/config.ci.ts#L19
|
||||
options: isMsSQLClient
|
||||
? {
|
||||
...(providerInputs.sslEnabled !== undefined ? { encrypt: providerInputs.sslEnabled } : {}),
|
||||
trustServerCertificate: !providerInputs.ca,
|
||||
cryptoCredentialsDetails: providerInputs.ca ? { ca: providerInputs.ca } : {}
|
||||
}
|
||||
@@ -215,7 +235,13 @@ export const SqlDatabaseProvider = ({ gatewayService }: TSqlDatabaseProviderDTO)
|
||||
const providerInputs = await validateProviderInputs(inputs);
|
||||
let isConnected = false;
|
||||
const gatewayCallback = async (host = providerInputs.host, port = providerInputs.port) => {
|
||||
const db = await $getClient({ ...providerInputs, port, host, hostIp: providerInputs.hostIp });
|
||||
const db = await $getClient({
|
||||
...providerInputs,
|
||||
port,
|
||||
host,
|
||||
hostIp: providerInputs.hostIp,
|
||||
originalHost: providerInputs.host
|
||||
});
|
||||
// oracle needs from keyword
|
||||
const testStatement = providerInputs.client === SqlProviders.Oracle ? "SELECT 1 FROM DUAL" : "SELECT 1";
|
||||
|
||||
@@ -256,7 +282,12 @@ export const SqlDatabaseProvider = ({ gatewayService }: TSqlDatabaseProviderDTO)
|
||||
|
||||
const password = generatePassword(providerInputs.client, providerInputs.passwordRequirements);
|
||||
const gatewayCallback = async (host = providerInputs.host, port = providerInputs.port) => {
|
||||
const db = await $getClient({ ...providerInputs, port, host });
|
||||
const db = await $getClient({
|
||||
...providerInputs,
|
||||
port,
|
||||
host,
|
||||
originalHost: providerInputs.host
|
||||
});
|
||||
try {
|
||||
const expiration = new Date(expireAt).toISOString();
|
||||
|
||||
@@ -299,7 +330,12 @@ export const SqlDatabaseProvider = ({ gatewayService }: TSqlDatabaseProviderDTO)
|
||||
const username = entityId;
|
||||
const { database } = providerInputs;
|
||||
const gatewayCallback = async (host = providerInputs.host, port = providerInputs.port) => {
|
||||
const db = await $getClient({ ...providerInputs, port, host });
|
||||
const db = await $getClient({
|
||||
...providerInputs,
|
||||
port,
|
||||
host,
|
||||
originalHost: providerInputs.host
|
||||
});
|
||||
try {
|
||||
const revokeStatement = handlebars.compile(providerInputs.revocationStatement)({ username, database });
|
||||
const queries = revokeStatement.toString().split(";").filter(Boolean);
|
||||
@@ -334,7 +370,12 @@ export const SqlDatabaseProvider = ({ gatewayService }: TSqlDatabaseProviderDTO)
|
||||
if (!providerInputs.renewStatement) return { entityId };
|
||||
|
||||
const gatewayCallback = async (host = providerInputs.host, port = providerInputs.port) => {
|
||||
const db = await $getClient({ ...providerInputs, port, host });
|
||||
const db = await $getClient({
|
||||
...providerInputs,
|
||||
port,
|
||||
host,
|
||||
originalHost: providerInputs.host
|
||||
});
|
||||
const expiration = new Date(expireAt).toISOString();
|
||||
const { database } = providerInputs;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
SecretInput,
|
||||
Select,
|
||||
SelectItem,
|
||||
Switch,
|
||||
TextArea,
|
||||
Tooltip
|
||||
} from "@app/components/v2";
|
||||
@@ -66,6 +67,7 @@ const formSchema = z.object({
|
||||
creationStatement: z.string().min(1),
|
||||
revocationStatement: z.string().min(1),
|
||||
renewStatement: z.string().optional(),
|
||||
sslEnabled: z.boolean().optional(),
|
||||
ca: z.string().optional(),
|
||||
gatewayId: z.string().optional()
|
||||
}),
|
||||
@@ -200,6 +202,7 @@ export const SqlDatabaseInputForm = ({
|
||||
|
||||
const createDynamicSecret = useCreateDynamicSecret();
|
||||
const { data: gateways, isPending: isGatewaysLoading } = useQuery(gatewaysQueryKeys.list());
|
||||
const selectedClient = watch("provider.client");
|
||||
|
||||
const handleCreateDynamicSecret = async ({
|
||||
name,
|
||||
@@ -458,13 +461,34 @@ export const SqlDatabaseInputForm = ({
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
{selectedClient === SqlProviders.MsSQL && (
|
||||
<div className="mb-2 mt-2">
|
||||
<Controller
|
||||
control={control}
|
||||
name="provider.sslEnabled"
|
||||
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="sql-ds-ssl-enabled"
|
||||
thumbClassName="bg-mineshaft-800"
|
||||
isChecked={value}
|
||||
onCheckedChange={onChange}
|
||||
>
|
||||
Encrypt Connection (SSL)
|
||||
</Switch>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<Controller
|
||||
control={control}
|
||||
name="provider.ca"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isOptional
|
||||
label="CA(SSL)"
|
||||
label="CA (SSL)"
|
||||
isError={Boolean(error?.message)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
SecretInput,
|
||||
Select,
|
||||
SelectItem,
|
||||
Switch,
|
||||
TextArea,
|
||||
Tooltip
|
||||
} from "@app/components/v2";
|
||||
@@ -63,6 +64,7 @@ const formSchema = z.object({
|
||||
creationStatement: z.string().min(1),
|
||||
revocationStatement: z.string().min(1),
|
||||
renewStatement: z.string().optional(),
|
||||
sslEnabled: z.boolean().optional(),
|
||||
ca: z.string().optional(),
|
||||
gatewayId: z.string().optional().nullable()
|
||||
})
|
||||
@@ -151,6 +153,7 @@ export const EditDynamicSecretSqlProviderForm = ({
|
||||
});
|
||||
|
||||
const { data: gateways, isPending: isGatewaysLoading } = useQuery(gatewaysQueryKeys.list());
|
||||
const selectedClient = watch("inputs.client");
|
||||
|
||||
const updateDynamicSecret = useUpdateDynamicSecret();
|
||||
const selectedGatewayId = watch("inputs.gatewayId");
|
||||
@@ -407,13 +410,34 @@ export const EditDynamicSecretSqlProviderForm = ({
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
{selectedClient === SqlProviders.MsSQL && (
|
||||
<div className="mb-2 mt-2">
|
||||
<Controller
|
||||
control={control}
|
||||
name="inputs.sslEnabled"
|
||||
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="sql-ds-ssl-enabled"
|
||||
thumbClassName="bg-mineshaft-800"
|
||||
isChecked={Boolean(value)}
|
||||
onCheckedChange={onChange}
|
||||
>
|
||||
Encrypt Connection (SSL)
|
||||
</Switch>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<Controller
|
||||
control={control}
|
||||
name="inputs.ca"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isOptional
|
||||
label="CA(SSL)"
|
||||
label="CA (SSL)"
|
||||
isError={Boolean(error?.message)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user