mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-04 07:26:11 +00:00
make resource rotation account credentials write-only
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { PamResource } from "@app/ee/services/pam-resource/pam-resource-enums";
|
import { PamResource } from "@app/ee/services/pam-resource/pam-resource-enums";
|
||||||
import {
|
import {
|
||||||
CreatePostgresResourceSchema,
|
CreatePostgresResourceSchema,
|
||||||
PostgresResourceSchema,
|
SanitizedPostgresResourceSchema,
|
||||||
UpdatePostgresResourceSchema
|
UpdatePostgresResourceSchema
|
||||||
} from "@app/ee/services/pam-resource/postgres/postgres-resource-schemas";
|
} from "@app/ee/services/pam-resource/postgres/postgres-resource-schemas";
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ export const PAM_RESOURCE_REGISTER_ROUTER_MAP: Record<PamResource, (server: Fast
|
|||||||
registerPamResourceEndpoints({
|
registerPamResourceEndpoints({
|
||||||
server,
|
server,
|
||||||
resourceType: PamResource.Postgres,
|
resourceType: PamResource.Postgres,
|
||||||
resourceResponseSchema: PostgresResourceSchema,
|
resourceResponseSchema: SanitizedPostgresResourceSchema,
|
||||||
createResourceSchema: CreatePostgresResourceSchema,
|
createResourceSchema: CreatePostgresResourceSchema,
|
||||||
updateResourceSchema: UpdatePostgresResourceSchema
|
updateResourceSchema: UpdatePostgresResourceSchema
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ import { z } from "zod";
|
|||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import {
|
import {
|
||||||
PostgresResourceListItemSchema,
|
PostgresResourceListItemSchema,
|
||||||
PostgresResourceSchema
|
SanitizedPostgresResourceSchema
|
||||||
} from "@app/ee/services/pam-resource/postgres/postgres-resource-schemas";
|
} from "@app/ee/services/pam-resource/postgres/postgres-resource-schemas";
|
||||||
import { readLimit } from "@app/server/config/rateLimiter";
|
import { readLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
// Use z.union([...]) when more resources are added
|
// Use z.union([...]) when more resources are added
|
||||||
const ResourceSchema = PostgresResourceSchema;
|
const SanitizedResourceSchema = SanitizedPostgresResourceSchema;
|
||||||
|
|
||||||
const ResourceOptionsSchema = z.discriminatedUnion("resource", [PostgresResourceListItemSchema]);
|
const ResourceOptionsSchema = z.discriminatedUnion("resource", [PostgresResourceListItemSchema]);
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ export const registerPamResourceRouter = async (server: FastifyZodProvider) => {
|
|||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
resources: ResourceSchema.array()
|
resources: SanitizedResourceSchema.array()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
|||||||
|
|
||||||
import { TGatewayV2ServiceFactory } from "../gateway-v2/gateway-v2-service";
|
import { TGatewayV2ServiceFactory } from "../gateway-v2/gateway-v2-service";
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { encryptAccountCredentials } from "../pam-account/pam-account-fns";
|
import { decryptAccountCredentials, encryptAccountCredentials } from "../pam-account/pam-account-fns";
|
||||||
import { TPamResourceDALFactory } from "./pam-resource-dal";
|
import { TPamResourceDALFactory } from "./pam-resource-dal";
|
||||||
import { PamResource } from "./pam-resource-enums";
|
import { PamResource } from "./pam-resource-enums";
|
||||||
import { PAM_RESOURCE_FACTORY_MAP } from "./pam-resource-factory";
|
import { PAM_RESOURCE_FACTORY_MAP } from "./pam-resource-factory";
|
||||||
@@ -192,8 +192,19 @@ export const pamResourceServiceFactory = ({
|
|||||||
gatewayV2Service
|
gatewayV2Service
|
||||||
);
|
);
|
||||||
|
|
||||||
const validatedRotationAccountCredentials =
|
// Logic to prevent overwriting unedited censored values
|
||||||
await factory.validateAccountCredentials(rotationAccountCredentials);
|
const finalCredentials = { ...rotationAccountCredentials };
|
||||||
|
if (resource.encryptedRotationAccountCredentials && rotationAccountCredentials.password === "******") {
|
||||||
|
const decryptedCredentials = await decryptAccountCredentials({
|
||||||
|
encryptedCredentials: resource.encryptedRotationAccountCredentials,
|
||||||
|
projectId: resource.projectId,
|
||||||
|
kmsService
|
||||||
|
});
|
||||||
|
|
||||||
|
finalCredentials.password = decryptedCredentials.password;
|
||||||
|
}
|
||||||
|
|
||||||
|
const validatedRotationAccountCredentials = await factory.validateAccountCredentials(finalCredentials);
|
||||||
|
|
||||||
updateDoc.encryptedRotationAccountCredentials = await encryptAccountCredentials({
|
updateDoc.encryptedRotationAccountCredentials = await encryptAccountCredentials({
|
||||||
credentials: validatedRotationAccountCredentials,
|
credentials: validatedRotationAccountCredentials,
|
||||||
|
|||||||
@@ -26,6 +26,15 @@ export const PostgresResourceSchema = BasePostgresResourceSchema.extend({
|
|||||||
rotationAccountCredentials: PostgresAccountCredentialsSchema.nullable().optional()
|
rotationAccountCredentials: PostgresAccountCredentialsSchema.nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const SanitizedPostgresResourceSchema = BasePostgresResourceSchema.extend({
|
||||||
|
connectionDetails: PostgresResourceConnectionDetailsSchema,
|
||||||
|
rotationAccountCredentials: PostgresAccountCredentialsSchema.pick({
|
||||||
|
username: true
|
||||||
|
})
|
||||||
|
.nullable()
|
||||||
|
.optional()
|
||||||
|
});
|
||||||
|
|
||||||
export const PostgresResourceListItemSchema = z.object({
|
export const PostgresResourceListItemSchema = z.object({
|
||||||
name: z.literal("PostgreSQL"),
|
name: z.literal("PostgreSQL"),
|
||||||
resource: z.literal(PamResource.Postgres)
|
resource: z.literal(PamResource.Postgres)
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import {
|
|||||||
faTrash
|
faTrash
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { twMerge } from "tailwind-merge";
|
|
||||||
import { formatDistance } from "date-fns";
|
import { formatDistance } from "date-fns";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
import { createNotification } from "@app/components/notifications";
|
import { createNotification } from "@app/components/notifications";
|
||||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||||
|
|||||||
+20
-12
@@ -31,17 +31,25 @@ export const PostgresResourceForm = ({ resource, onSubmit }: Props) => {
|
|||||||
|
|
||||||
const form = useForm<FormData>({
|
const form = useForm<FormData>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
defaultValues: resource ?? {
|
defaultValues: resource
|
||||||
resourceType: PamResourceType.Postgres,
|
? {
|
||||||
connectionDetails: {
|
...resource,
|
||||||
host: "",
|
rotationAccountCredentials: {
|
||||||
port: 5432,
|
...resource.rotationAccountCredentials,
|
||||||
database: "default",
|
password: "******"
|
||||||
sslEnabled: true,
|
}
|
||||||
sslRejectUnauthorized: true,
|
}
|
||||||
sslCertificate: undefined
|
: {
|
||||||
}
|
resourceType: PamResourceType.Postgres,
|
||||||
}
|
connectionDetails: {
|
||||||
|
host: "",
|
||||||
|
port: 5432,
|
||||||
|
database: "default",
|
||||||
|
sslEnabled: true,
|
||||||
|
sslRejectUnauthorized: true,
|
||||||
|
sslCertificate: undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -62,7 +70,7 @@ export const PostgresResourceForm = ({ resource, onSubmit }: Props) => {
|
|||||||
selectedTabIndex={selectedTabIndex}
|
selectedTabIndex={selectedTabIndex}
|
||||||
setSelectedTabIndex={setSelectedTabIndex}
|
setSelectedTabIndex={setSelectedTabIndex}
|
||||||
/>
|
/>
|
||||||
<SqlRotateAccountFields />
|
<SqlRotateAccountFields isUpdate={isUpdate} />
|
||||||
<div className="mt-6 flex items-center">
|
<div className="mt-6 flex items-center">
|
||||||
<Button
|
<Button
|
||||||
className="mr-4"
|
className="mr-4"
|
||||||
|
|||||||
+16
-5
@@ -6,11 +6,10 @@ import {
|
|||||||
AccordionItem,
|
AccordionItem,
|
||||||
AccordionTrigger,
|
AccordionTrigger,
|
||||||
FormControl,
|
FormControl,
|
||||||
Input,
|
Input
|
||||||
SecretInput
|
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
|
|
||||||
export const SqlRotateAccountFields = () => {
|
export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => {
|
||||||
const { control } = useFormContext();
|
const { control } = useFormContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -49,9 +48,21 @@ export const SqlRotateAccountFields = () => {
|
|||||||
isError={Boolean(error?.message)}
|
isError={Boolean(error?.message)}
|
||||||
label="Password"
|
label="Password"
|
||||||
>
|
>
|
||||||
<SecretInput
|
<Input
|
||||||
containerClassName="text-gray-400 group-focus-within:border-primary-400/50! border border-mineshaft-500 bg-mineshaft-900 px-2.5 py-1.5"
|
|
||||||
{...field}
|
{...field}
|
||||||
|
type="password"
|
||||||
|
onFocus={(e) => {
|
||||||
|
if (isUpdate && field.value === "******") {
|
||||||
|
field.onChange("");
|
||||||
|
}
|
||||||
|
e.target.type = "text";
|
||||||
|
}}
|
||||||
|
onBlur={(e) => {
|
||||||
|
if (isUpdate && field.value === "") {
|
||||||
|
field.onChange("******");
|
||||||
|
}
|
||||||
|
e.target.type = "password";
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user