feat: session logging for ssh

This commit is contained in:
Sheen Capadngan
2025-11-13 21:18:18 +08:00
parent ace77b516e
commit f9965963e8
11 changed files with 438 additions and 165 deletions
@@ -5,7 +5,11 @@ import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { MySQLSessionCredentialsSchema } from "@app/ee/services/pam-resource/mysql/mysql-resource-schemas";
import { PostgresSessionCredentialsSchema } from "@app/ee/services/pam-resource/postgres/postgres-resource-schemas";
import { SSHSessionCredentialsSchema } from "@app/ee/services/pam-resource/ssh/ssh-resource-schemas";
import { PamSessionCommandLogSchema, SanitizedSessionSchema } from "@app/ee/services/pam-session/pam-session-schemas";
import {
PamSessionCommandLogSchema,
SanitizedSessionSchema,
TerminalEventSchema
} from "@app/ee/services/pam-session/pam-session-schemas";
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";
@@ -72,7 +76,7 @@ export const registerPamSessionRouter = async (server: FastifyZodProvider) => {
sessionId: z.string().uuid()
}),
body: z.object({
logs: PamSessionCommandLogSchema.array()
logs: z.array(z.union([PamSessionCommandLogSchema, TerminalEventSchema]))
}),
response: {
200: z.object({
@@ -2,7 +2,7 @@ import { TPamSessions } from "@app/db/schemas";
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { KmsDataKey } from "@app/services/kms/kms-types";
import { TPamSanitizedSession, TPamSessionCommandLog } from "./pam-session.types";
import { TPamSanitizedSession, TPamSessionCommandLog, TTerminalEvent } from "./pam-session.types";
export const decryptSessionCommandLogs = async ({
projectId,
@@ -22,7 +22,7 @@ export const decryptSessionCommandLogs = async ({
cipherTextBlob: encryptedLogs
});
return JSON.parse(decryptedPlainTextBlob.toString()) as TPamSessionCommandLog;
return JSON.parse(decryptedPlainTextBlob.toString()) as (TPamSessionCommandLog | TTerminalEvent)[];
};
export const decryptSession = async (
@@ -32,7 +32,7 @@ export const decryptSession = async (
) => {
return {
...session,
commandLogs: session.encryptedLogsBlob
logs: session.encryptedLogsBlob
? await decryptSessionCommandLogs({
projectId,
encryptedLogs: session.encryptedLogsBlob,
@@ -8,8 +8,18 @@ export const PamSessionCommandLogSchema = z.object({
timestamp: z.coerce.date()
});
// SSH Terminal Event schemas
export const TerminalEventTypeSchema = z.enum(["input", "output", "resize", "error"]);
export const TerminalEventSchema = z.object({
timestamp: z.coerce.date(),
eventType: TerminalEventTypeSchema,
data: z.string(), // Base64 encoded binary data
elapsedTime: z.number() // Seconds since session start (for replay)
});
export const SanitizedSessionSchema = PamSessionsSchema.omit({
encryptedLogsBlob: true
}).extend({
commandLogs: PamSessionCommandLogSchema.array()
logs: z.array(z.union([PamSessionCommandLogSchema, TerminalEventSchema]))
});
@@ -1,12 +1,13 @@
import { z } from "zod";
import { PamSessionCommandLogSchema, SanitizedSessionSchema } from "./pam-session-schemas";
import { PamSessionCommandLogSchema, SanitizedSessionSchema, TerminalEventSchema } from "./pam-session-schemas";
export type TPamSessionCommandLog = z.infer<typeof PamSessionCommandLogSchema>;
export type TTerminalEvent = z.infer<typeof TerminalEventSchema>;
export type TPamSanitizedSession = z.infer<typeof SanitizedSessionSchema>;
// DTOs
export type TUpdateSessionLogsDTO = {
sessionId: string;
logs: TPamSessionCommandLog[];
logs: (TPamSessionCommandLog | TTerminalEvent)[];
};