addressed reviews

This commit is contained in:
x032205
2025-10-02 18:46:14 -04:00
parent 1678fba06e
commit e77c024af5
37 changed files with 1011 additions and 856 deletions
+32 -13
View File
@@ -23,7 +23,8 @@ import { registerLdapRouter } from "./ldap-router";
import { registerLicenseRouter } from "./license-router";
import { registerOidcRouter } from "./oidc-router";
import { registerOrgRoleRouter } from "./org-role-router";
import { registerPamAccountRouter } from "./pam-account-router";
import { PAM_ACCOUNT_REGISTER_ROUTER_MAP } from "./pam-account-routers";
import { registerPamAccountRouter } from "./pam-account-routers/pam-account-router";
import { registerPamFolderRouter } from "./pam-folder-router";
import { PAM_RESOURCE_REGISTER_ROUTER_MAP } from "./pam-resource-routers";
import { registerPamResourceRouter } from "./pam-resource-routers/pam-resource-router";
@@ -172,21 +173,39 @@ export const registerV1EERoutes = async (server: FastifyZodProvider) => {
{ prefix: "/kmip" }
);
await server.register(registerPamFolderRouter, { prefix: "/pam/folders" });
await server.register(registerPamAccountRouter, { prefix: "/pam/accounts" });
await server.register(registerPamSessionRouter, { prefix: "/pam/sessions" });
await server.register(
async (pamResourceRouter) => {
await pamResourceRouter.register(registerPamResourceRouter);
async (pamRouter) => {
await pamRouter.register(registerPamFolderRouter, { prefix: "/folders" });
await pamRouter.register(registerPamSessionRouter, { prefix: "/sessions" });
// Provider-specific endpoints
await Promise.all(
Object.entries(PAM_RESOURCE_REGISTER_ROUTER_MAP).map(([provider, router]) =>
pamResourceRouter.register(router, { prefix: `/${provider}` })
)
await pamRouter.register(
async (pamAccountRouter) => {
await pamAccountRouter.register(registerPamAccountRouter);
// Provider-specific endpoints
await Promise.all(
Object.entries(PAM_ACCOUNT_REGISTER_ROUTER_MAP).map(([provider, router]) =>
pamAccountRouter.register(router, { prefix: `/${provider}` })
)
);
},
{ prefix: "/accounts" }
);
await pamRouter.register(
async (pamResourceRouter) => {
await pamResourceRouter.register(registerPamResourceRouter);
// Provider-specific endpoints
await Promise.all(
Object.entries(PAM_RESOURCE_REGISTER_ROUTER_MAP).map(([provider, router]) =>
pamResourceRouter.register(router, { prefix: `/${provider}` })
)
);
},
{ prefix: "/resources" }
);
},
{ prefix: "/pam/resources" }
{ prefix: "/pam" }
);
};
@@ -0,0 +1,20 @@
import { PamResource } from "@app/ee/services/pam-resource/pam-resource-enums";
import {
CreatePostgresAccountSchema,
SanitizedPostgresAccountWithResourceSchema,
UpdatePostgresAccountSchema
} from "@app/ee/services/pam-resource/postgres/postgres-resource-schemas";
import { registerPamResourceEndpoints } from "./pam-account-endpoints";
export const PAM_ACCOUNT_REGISTER_ROUTER_MAP: Record<PamResource, (server: FastifyZodProvider) => Promise<void>> = {
[PamResource.Postgres]: async (server: FastifyZodProvider) => {
registerPamResourceEndpoints({
server,
resourceType: PamResource.Postgres,
accountResponseSchema: SanitizedPostgresAccountWithResourceSchema,
createAccountSchema: CreatePostgresAccountSchema,
updateAccountSchema: UpdatePostgresAccountSchema
});
}
};
@@ -0,0 +1,159 @@
import { z } from "zod";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { PamResource } from "@app/ee/services/pam-resource/pam-resource-enums";
import { TPamAccount } from "@app/ee/services/pam-resource/pam-resource-types";
import { writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerPamResourceEndpoints = <C extends TPamAccount>({
server,
resourceType,
createAccountSchema,
updateAccountSchema,
accountResponseSchema
}: {
server: FastifyZodProvider;
resourceType: PamResource;
createAccountSchema: z.ZodType<{
credentials: C["credentials"];
resourceId: C["resourceId"];
folderId?: C["folderId"];
name: C["name"];
description?: C["description"];
}>;
updateAccountSchema: z.ZodType<{
credentials?: C["credentials"];
name?: C["name"];
description?: C["description"];
}>;
accountResponseSchema: z.ZodTypeAny;
}) => {
server.route({
method: "POST",
url: "/",
config: {
rateLimit: writeLimit
},
schema: {
description: "Create PAM account",
body: createAccountSchema,
response: {
200: z.object({
account: accountResponseSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const account = await server.services.pamAccount.create(req.body, req.permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: account.projectId,
event: {
type: EventType.PAM_ACCOUNT_CREATE,
metadata: {
resourceId: req.body.resourceId,
resourceType,
folderId: req.body.folderId,
name: req.body.name,
description: req.body.description
}
}
});
return { account };
}
});
server.route({
method: "PATCH",
url: "/:accountId",
config: {
rateLimit: writeLimit
},
schema: {
description: "Update PAM account",
params: z.object({
accountId: z.string().uuid()
}),
body: updateAccountSchema,
response: {
200: z.object({
account: accountResponseSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const account = await server.services.pamAccount.updateById(
{
...req.body,
accountId: req.params.accountId
},
req.permission
);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: account.projectId,
event: {
type: EventType.PAM_ACCOUNT_UPDATE,
metadata: {
accountId: req.params.accountId,
resourceId: account.resourceId,
resourceType,
name: req.body.name,
description: req.body.description
}
}
});
return { account };
}
});
server.route({
method: "DELETE",
url: "/:accountId",
config: {
rateLimit: writeLimit
},
schema: {
description: "Delete PAM account",
params: z.object({
accountId: z.string().uuid()
}),
response: {
200: z.object({
account: accountResponseSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const account = await server.services.pamAccount.deleteById(req.params.accountId, req.permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: account.projectId,
event: {
type: EventType.PAM_ACCOUNT_DELETE,
metadata: {
accountId: req.params.accountId,
accountName: account.name,
resourceId: account.resourceId,
resourceType
}
}
});
return { account };
}
});
};
@@ -34,7 +34,7 @@ export const registerPamAccountRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const response = await server.services.pamResource.listAccounts(req.query.projectId, req.permission);
const response = await server.services.pamAccount.list(req.query.projectId, req.permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
@@ -55,21 +55,18 @@ export const registerPamAccountRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/:accountId/access",
url: "/access",
config: {
rateLimit: writeLimit
},
schema: {
description: "Access PAM account",
params: z.object({
accountId: z.string().uuid()
}),
body: z.object({
accountId: z.string().uuid(),
duration: z
.string()
.optional()
.min(1)
.transform((val, ctx) => {
if (val === undefined) return undefined;
const parsedMs = ms(val);
if (typeof parsedMs !== "number" || parsedMs <= 0) {
@@ -98,13 +95,13 @@ export const registerPamAccountRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
// To prevent type errors when accessing req.auth
if (req.auth.authMode !== AuthMode.JWT) {
throw new BadRequestError({ message: "You can only access PAM accounts using JWT auth tokens." });
}
const response = await server.services.pamResource.accessAccount(
const response = await server.services.pamAccount.access(
{
accountId: req.params.accountId,
actorEmail: req.auth.user.email ?? "",
actorIp: req.realIp,
actorName: `${req.auth.user.firstName ?? ""} ${req.auth.user.lastName ?? ""}`.trim(),
@@ -121,7 +118,8 @@ export const registerPamAccountRouter = async (server: FastifyZodProvider) => {
event: {
type: EventType.PAM_ACCOUNT_ACCESS,
metadata: {
accountId: req.params.accountId,
accountId: req.body.accountId,
accountName: response.account.name,
duration: req.body.duration ? new Date(req.body.duration).toISOString() : undefined
}
}
@@ -138,6 +138,7 @@ export const registerPamFolderRouter = async (server: FastifyZodProvider) => {
event: {
type: EventType.PAM_FOLDER_DELETE,
metadata: {
folderName: folder.name,
folderId: req.params.folderId
}
}
@@ -1,10 +1,7 @@
import { PamResource } from "@app/ee/services/pam-resource/pam-resource-enums";
import {
CreatePostgresAccountSchema,
CreatePostgresResourceSchema,
PostgresResourceSchema,
SanitizedPostgresAccountWithResourceSchema,
UpdatePostgresAccountSchema,
UpdatePostgresResourceSchema
} from "@app/ee/services/pam-resource/postgres/postgres-resource-schemas";
@@ -16,11 +13,8 @@ export const PAM_RESOURCE_REGISTER_ROUTER_MAP: Record<PamResource, (server: Fast
server,
resourceType: PamResource.Postgres,
resourceResponseSchema: PostgresResourceSchema,
accountResponseSchema: SanitizedPostgresAccountWithResourceSchema,
createResourceSchema: CreatePostgresResourceSchema,
createAccountSchema: CreatePostgresAccountSchema,
updateResourceSchema: UpdatePostgresResourceSchema,
updateAccountSchema: UpdatePostgresAccountSchema
updateResourceSchema: UpdatePostgresResourceSchema
});
}
};
@@ -2,20 +2,17 @@ import { z } from "zod";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { PamResource } from "@app/ee/services/pam-resource/pam-resource-enums";
import { TPamAccount, TPamResource } from "@app/ee/services/pam-resource/pam-resource-types";
import { TPamResource } from "@app/ee/services/pam-resource/pam-resource-types";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerPamResourceEndpoints = <T extends TPamResource, C extends TPamAccount>({
export const registerPamResourceEndpoints = <T extends TPamResource>({
server,
resourceType,
createResourceSchema,
updateResourceSchema,
createAccountSchema,
updateAccountSchema,
resourceResponseSchema,
accountResponseSchema
resourceResponseSchema
}: {
server: FastifyZodProvider;
resourceType: PamResource;
@@ -25,24 +22,12 @@ export const registerPamResourceEndpoints = <T extends TPamResource, C extends T
gatewayId: T["gatewayId"];
name: T["name"];
}>;
createAccountSchema: z.ZodType<{
credentials: C["credentials"];
folderId?: C["folderId"];
name: C["name"];
description?: C["description"];
}>;
updateResourceSchema: z.ZodType<{
connectionDetails?: T["connectionDetails"];
gatewayId?: T["gatewayId"];
name?: T["name"];
}>;
updateAccountSchema: z.ZodType<{
credentials?: C["credentials"];
name?: C["name"];
description?: C["description"];
}>;
resourceResponseSchema: z.ZodTypeAny;
accountResponseSchema: z.ZodTypeAny;
}) => {
server.route({
method: "GET",
@@ -210,142 +195,4 @@ export const registerPamResourceEndpoints = <T extends TPamResource, C extends T
return { resource };
}
});
// PAM Accounts
server.route({
method: "POST",
url: "/:resourceId/accounts",
config: {
rateLimit: writeLimit
},
schema: {
description: "Create PAM resource account",
params: z.object({
resourceId: z.string().uuid()
}),
body: createAccountSchema,
response: {
200: z.object({
account: accountResponseSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const account = await server.services.pamResource.createAccount(
{
...req.body,
resourceId: req.params.resourceId
},
req.permission
);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: account.projectId,
event: {
type: EventType.PAM_ACCOUNT_CREATE,
metadata: {
resourceId: req.params.resourceId,
resourceType,
folderId: req.body.folderId,
name: req.body.name,
description: req.body.description
}
}
});
return { account };
}
});
server.route({
method: "PATCH",
url: "/:resourceId/accounts/:accountId",
config: {
rateLimit: writeLimit
},
schema: {
description: "Update PAM resource account",
params: z.object({
resourceId: z.string().uuid(),
accountId: z.string().uuid()
}),
body: updateAccountSchema,
response: {
200: z.object({
account: accountResponseSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const account = await server.services.pamResource.updateAccountById(
{
...req.body,
accountId: req.params.accountId
},
req.permission
);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: account.projectId,
event: {
type: EventType.PAM_ACCOUNT_UPDATE,
metadata: {
accountId: req.params.accountId,
resourceId: req.params.resourceId,
resourceType,
name: req.body.name,
description: req.body.description
}
}
});
return { account };
}
});
server.route({
method: "DELETE",
url: "/:resourceId/accounts/:accountId",
config: {
rateLimit: writeLimit
},
schema: {
description: "Delete PAM resource account",
params: z.object({
resourceId: z.string().uuid(),
accountId: z.string().uuid()
}),
response: {
200: z.object({
account: accountResponseSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const account = await server.services.pamResource.deleteAccountById(req.params.accountId, req.permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: account.projectId,
event: {
type: EventType.PAM_ACCOUNT_DELETE,
metadata: {
accountId: req.params.accountId,
resourceId: req.params.resourceId,
resourceType
}
}
});
return { account };
}
});
};
@@ -32,7 +32,7 @@ export const registerPamSessionRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { credentials, projectId } = await server.services.pamResource.getSessionCredentials(
const { credentials, projectId, account } = await server.services.pamAccount.getSessionCredentials(
req.params.sessionId,
req.permission
);
@@ -44,7 +44,8 @@ export const registerPamSessionRouter = async (server: FastifyZodProvider) => {
event: {
type: EventType.PAM_SESSION_START,
metadata: {
sessionId: req.params.sessionId
sessionId: req.params.sessionId,
accountName: account.name
}
}
});
@@ -93,7 +94,8 @@ export const registerPamSessionRouter = async (server: FastifyZodProvider) => {
event: {
type: EventType.PAM_SESSION_LOGS_UPDATE,
metadata: {
sessionId: req.params.sessionId
sessionId: req.params.sessionId,
accountName: session.accountName
}
}
});