mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-21 20:28:17 +00:00
Merge pull request #4685 from Infisical/ENG-3925
feat(pam): account credential rotation
This commit is contained in:
+27
-12
@@ -5,9 +5,12 @@ import { z } from "zod";
|
||||
|
||||
import { Button, ModalClose } from "@app/components/v2";
|
||||
import { PamResourceType, TPostgresResource } from "@app/hooks/api/pam";
|
||||
import { UNCHANGED_PASSWORD_SENTINEL } from "@app/hooks/api/pam/constants";
|
||||
import { BaseSqlAccountSchema } from "@app/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas";
|
||||
|
||||
import { BaseSqlResourceSchema } from "./shared/sql-resource-schemas";
|
||||
import { SqlResourceFields } from "./shared/SqlResourceFields";
|
||||
import { SqlRotateAccountFields } from "./shared/SqlRotateAccountFields";
|
||||
import { GenericResourceFields, genericResourceFieldsSchema } from "./GenericResourceFields";
|
||||
|
||||
type Props = {
|
||||
@@ -17,7 +20,8 @@ type Props = {
|
||||
|
||||
const formSchema = genericResourceFieldsSchema.extend({
|
||||
resourceType: z.literal(PamResourceType.Postgres),
|
||||
connectionDetails: BaseSqlResourceSchema
|
||||
connectionDetails: BaseSqlResourceSchema,
|
||||
rotationAccountCredentials: BaseSqlAccountSchema.nullable().optional()
|
||||
});
|
||||
|
||||
type FormData = z.infer<typeof formSchema>;
|
||||
@@ -28,17 +32,27 @@ export const PostgresResourceForm = ({ resource, onSubmit }: Props) => {
|
||||
|
||||
const form = useForm<FormData>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: resource ?? {
|
||||
resourceType: PamResourceType.Postgres,
|
||||
connectionDetails: {
|
||||
host: "",
|
||||
port: 5432,
|
||||
database: "default",
|
||||
sslEnabled: true,
|
||||
sslRejectUnauthorized: true,
|
||||
sslCertificate: undefined
|
||||
}
|
||||
}
|
||||
defaultValues: resource
|
||||
? {
|
||||
...resource,
|
||||
rotationAccountCredentials: resource.rotationAccountCredentials
|
||||
? {
|
||||
...resource.rotationAccountCredentials,
|
||||
password: UNCHANGED_PASSWORD_SENTINEL
|
||||
}
|
||||
: resource.rotationAccountCredentials
|
||||
}
|
||||
: {
|
||||
resourceType: PamResourceType.Postgres,
|
||||
connectionDetails: {
|
||||
host: "",
|
||||
port: 5432,
|
||||
database: "default",
|
||||
sslEnabled: true,
|
||||
sslRejectUnauthorized: true,
|
||||
sslCertificate: undefined
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const {
|
||||
@@ -59,6 +73,7 @@ export const PostgresResourceForm = ({ resource, onSubmit }: Props) => {
|
||||
selectedTabIndex={selectedTabIndex}
|
||||
setSelectedTabIndex={setSelectedTabIndex}
|
||||
/>
|
||||
<SqlRotateAccountFields isUpdate={isUpdate} />
|
||||
<div className="mt-6 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Controller, useFormContext, useWatch } from "react-hook-form";
|
||||
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
FormControl,
|
||||
Input
|
||||
} from "@app/components/v2";
|
||||
import { UNCHANGED_PASSWORD_SENTINEL } from "@app/hooks/api/pam/constants";
|
||||
|
||||
export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => {
|
||||
const { control } = useFormContext();
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const password = useWatch({ control, name: "credentials.password" });
|
||||
|
||||
useEffect(() => {
|
||||
if (password === UNCHANGED_PASSWORD_SENTINEL) {
|
||||
setShowPassword(false);
|
||||
}
|
||||
}, [password]);
|
||||
|
||||
return (
|
||||
<Accordion type="single" collapsible className="w-full">
|
||||
<AccordionItem value="advance-settings" className="data-[state=open]:border-none">
|
||||
<AccordionTrigger className="h-fit flex-none pl-1 text-sm">
|
||||
<div className="order-1 ml-3">Rotation Account</div>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent childrenClassName="px-0 py-0">
|
||||
<p className="mb-2 text-xs">
|
||||
Credentials of the privileged account which will be used for rotating other accounts
|
||||
under this resource
|
||||
</p>
|
||||
<div className="flex gap-2">
|
||||
<Controller
|
||||
name="rotationAccountCredentials.username"
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
className="mb-0 flex-1"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Username"
|
||||
>
|
||||
<Input {...field} autoComplete="off" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="rotationAccountCredentials.password"
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
className="mb-0 flex-1"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Password"
|
||||
>
|
||||
<Input
|
||||
{...field}
|
||||
type={showPassword ? "text" : "password"}
|
||||
autoComplete="new-password"
|
||||
onFocus={() => {
|
||||
if (isUpdate && field.value === UNCHANGED_PASSWORD_SENTINEL) {
|
||||
field.onChange("");
|
||||
}
|
||||
setShowPassword(true);
|
||||
}}
|
||||
onBlur={() => {
|
||||
if (isUpdate && field.value === "") {
|
||||
field.onChange(UNCHANGED_PASSWORD_SENTINEL);
|
||||
}
|
||||
setShowPassword(false);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user