diff --git a/backend/src/ee/routes/v1/pam-account-routers/pam-account-router.ts b/backend/src/ee/routes/v1/pam-account-routers/pam-account-router.ts index 74bd5eeb1..c0477312f 100644 --- a/backend/src/ee/routes/v1/pam-account-routers/pam-account-router.ts +++ b/backend/src/ee/routes/v1/pam-account-routers/pam-account-router.ts @@ -3,6 +3,7 @@ import { z } from "zod"; import { PamFoldersSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { PamAccountOrderBy, PamAccountView } from "@app/ee/services/pam-account/pam-account-enums"; +import { SanitizedKubernetesAccountWithResourceSchema } from "@app/ee/services/pam-resource/kubernetes/kubernetes-resource-schemas"; import { SanitizedMySQLAccountWithResourceSchema } from "@app/ee/services/pam-resource/mysql/mysql-resource-schemas"; import { PamResource } from "@app/ee/services/pam-resource/pam-resource-enums"; import { SanitizedPostgresAccountWithResourceSchema } from "@app/ee/services/pam-resource/postgres/postgres-resource-schemas"; @@ -18,7 +19,8 @@ import { AuthMode } from "@app/services/auth/auth-type"; const SanitizedAccountSchema = z.union([ SanitizedSSHAccountWithResourceSchema, // ORDER MATTERS SanitizedPostgresAccountWithResourceSchema, - SanitizedMySQLAccountWithResourceSchema + SanitizedMySQLAccountWithResourceSchema, + SanitizedKubernetesAccountWithResourceSchema ]); export const registerPamAccountRouter = async (server: FastifyZodProvider) => { diff --git a/backend/src/ee/services/pam-resource/kubernetes/kubernetes-resource-factory.ts b/backend/src/ee/services/pam-resource/kubernetes/kubernetes-resource-factory.ts index 14aefc243..3afad5ae2 100644 --- a/backend/src/ee/services/pam-resource/kubernetes/kubernetes-resource-factory.ts +++ b/backend/src/ee/services/pam-resource/kubernetes/kubernetes-resource-factory.ts @@ -67,7 +67,6 @@ export const executeWithGateway = async ( async (proxyPort) => { const protocol = url.protocol === "https:" ? "https" : "http"; const baseUrl = `${protocol}://localhost:${proxyPort}`; - // const baseUrl = `http://localhost:${proxyPort}`; return operation(baseUrl, httpsAgent); }, { @@ -149,7 +148,7 @@ export const kubernetesResourceFactory: TPamResourceFactory< }); logger.info( - { serviceAccountName: credentials.serviceAccountName, namespace: connectionDetails.namespace }, + { namespace: connectionDetails.namespace }, "[Kubernetes Resource Factory] Kubernetes service account token authentication successful" ); } catch (error) { diff --git a/backend/src/ee/services/pam-resource/kubernetes/kubernetes-resource-schemas.ts b/backend/src/ee/services/pam-resource/kubernetes/kubernetes-resource-schemas.ts index 67bef8be0..19da74823 100644 --- a/backend/src/ee/services/pam-resource/kubernetes/kubernetes-resource-schemas.ts +++ b/backend/src/ee/services/pam-resource/kubernetes/kubernetes-resource-schemas.ts @@ -30,7 +30,6 @@ export const KubernetesResourceConnectionDetailsSchema = z.object({ export const KubernetesServiceAccountTokenCredentialsSchema = z.object({ authMethod: z.literal(KubernetesAuthMethod.ServiceAccountToken), - serviceAccountName: z.string().trim().max(255), serviceAccountToken: z.string().trim().max(10000) }); @@ -48,8 +47,7 @@ export const SanitizedKubernetesResourceSchema = BaseKubernetesResourceSchema.ex rotationAccountCredentials: z .discriminatedUnion("authMethod", [ z.object({ - authMethod: z.literal(KubernetesAuthMethod.ServiceAccountToken), - serviceAccountName: z.string() + authMethod: z.literal(KubernetesAuthMethod.ServiceAccountToken) }) ]) .nullable() @@ -82,8 +80,7 @@ export const UpdateKubernetesAccountSchema = BaseUpdatePamAccountSchema.extend({ export const SanitizedKubernetesAccountWithResourceSchema = BasePamAccountSchemaWithResource.extend({ credentials: z.discriminatedUnion("authMethod", [ z.object({ - authMethod: z.literal(KubernetesAuthMethod.ServiceAccountToken), - serviceAccountName: z.string() + authMethod: z.literal(KubernetesAuthMethod.ServiceAccountToken) }) ]) }); diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/KubernetesAccountForm.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/KubernetesAccountForm.tsx new file mode 100644 index 000000000..875bee2a0 --- /dev/null +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/KubernetesAccountForm.tsx @@ -0,0 +1,119 @@ +import { Controller, FormProvider, useForm, useFormContext } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; + +import { Button, FormControl, ModalClose, TextArea } from "@app/components/v2"; +import { KubernetesAuthMethod, TKubernetesAccount } from "@app/hooks/api/pam"; +import { UNCHANGED_PASSWORD_SENTINEL } from "@app/hooks/api/pam/constants"; + +import { GenericAccountFields, genericAccountFieldsSchema } from "./GenericAccountFields"; +import { rotateAccountFieldsSchema } from "./RotateAccountFields"; + +type Props = { + account?: TKubernetesAccount; + onSubmit: (formData: FormData) => Promise; +}; + +const KubernetesServiceAccountTokenCredentialsSchema = z.object({ + authMethod: z.literal(KubernetesAuthMethod.ServiceAccountToken), + serviceAccountToken: z.string().trim().min(1, "Service account token is required") +}); + +const formSchema = genericAccountFieldsSchema.extend(rotateAccountFieldsSchema.shape).extend({ + credentials: KubernetesServiceAccountTokenCredentialsSchema +}); + +type FormData = z.infer; + +const KubernetesAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { + const { control } = useFormContext(); + + return ( +
+ ( + +