diff --git a/backend/src/ee/services/audit-log/audit-log-types.ts b/backend/src/ee/services/audit-log/audit-log-types.ts index a8d98977f..2a5657cf0 100644 --- a/backend/src/ee/services/audit-log/audit-log-types.ts +++ b/backend/src/ee/services/audit-log/audit-log-types.ts @@ -31,7 +31,7 @@ export type TListProjectAuditLogDTO = { export type TCreateAuditLogDTO = { event: Event; - actor: UserActor | IdentityActor | ServiceActor | ScimClientActor | PlatformActor; + actor: UserActor | IdentityActor | ServiceActor | ScimClientActor | PlatformActor | UnknownUserActor; orgId?: string; projectId?: string; } & BaseAuthData; @@ -229,7 +229,10 @@ export enum EventType { GET_APP_CONNECTION = "get-app-connection", CREATE_APP_CONNECTION = "create-app-connection", UPDATE_APP_CONNECTION = "update-app-connection", - DELETE_APP_CONNECTION = "delete-app-connection" + DELETE_APP_CONNECTION = "delete-app-connection", + CREATE_SHARED_SECRET = "create-shared-secret", + DELETE_SHARED_SECRET = "delete-shared-secret", + READ_SHARED_SECRET = "read-shared-secret" } interface UserActorMetadata { @@ -252,6 +255,8 @@ interface ScimClientActorMetadata {} interface PlatformActorMetadata {} +interface UnknownUserActorMetadata {} + export interface UserActor { type: ActorType.USER; metadata: UserActorMetadata; @@ -267,6 +272,11 @@ export interface PlatformActor { metadata: PlatformActorMetadata; } +export interface UnknownUserActor { + type: ActorType.UNKNOWN_USER; + metadata: UnknownUserActorMetadata; +} + export interface IdentityActor { type: ActorType.IDENTITY; metadata: IdentityActorMetadata; @@ -1907,6 +1917,35 @@ interface DeleteAppConnectionEvent { }; } +interface CreateSharedSecretEvent { + type: EventType.CREATE_SHARED_SECRET; + metadata: { + id: string; + accessType: string; + name?: string; + expiresAfterViews?: number; + usingPassword: boolean; + expiresAt: string; + }; +} + +interface DeleteSharedSecretEvent { + type: EventType.DELETE_SHARED_SECRET; + metadata: { + id: string; + name?: string; + }; +} + +interface ReadSharedSecretEvent { + type: EventType.READ_SHARED_SECRET; + metadata: { + id: string; + name?: string; + accessType: string; + }; +} + export type Event = | GetSecretsEvent | GetSecretEvent @@ -2083,4 +2122,7 @@ export type Event = | GetAppConnectionEvent | CreateAppConnectionEvent | UpdateAppConnectionEvent - | DeleteAppConnectionEvent; + | DeleteAppConnectionEvent + | CreateSharedSecretEvent + | DeleteSharedSecretEvent + | ReadSharedSecretEvent; diff --git a/backend/src/server/plugins/audit-log.ts b/backend/src/server/plugins/audit-log.ts index 3f49778e8..3b02b1528 100644 --- a/backend/src/server/plugins/audit-log.ts +++ b/backend/src/server/plugins/audit-log.ts @@ -32,13 +32,21 @@ export const getUserAgentType = (userAgent: string | undefined) => { export const injectAuditLogInfo = fp(async (server: FastifyZodProvider) => { server.decorateRequest("auditLogInfo", null); server.addHook("onRequest", async (req) => { - if (!req.auth) return; const userAgent = req.headers["user-agent"] ?? ""; const payload = { ipAddress: req.realIp, userAgent, userAgentType: getUserAgentType(userAgent) } as typeof req.auditLogInfo; + + if (!req.auth) { + payload.actor = { + type: ActorType.UNKNOWN_USER, + metadata: {} + }; + req.auditLogInfo = payload; + return; + } if (req.auth.actor === ActorType.USER) { payload.actor = { type: ActorType.USER, diff --git a/backend/src/server/routes/v1/secret-sharing-router.ts b/backend/src/server/routes/v1/secret-sharing-router.ts index 3363cc6c0..59e59ede7 100644 --- a/backend/src/server/routes/v1/secret-sharing-router.ts +++ b/backend/src/server/routes/v1/secret-sharing-router.ts @@ -1,6 +1,7 @@ import { z } from "zod"; import { SecretSharingSchema } from "@app/db/schemas"; +import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { SecretSharingAccessType } from "@app/lib/types"; import { publicEndpointLimit, @@ -88,6 +89,21 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) => orgId: req.permission?.orgId }); + if (sharedSecret.secret?.orgId) { + await server.services.auditLog.createAuditLog({ + orgId: sharedSecret.secret.orgId, + ...req.auditLogInfo, + event: { + type: EventType.READ_SHARED_SECRET, + metadata: { + id: req.params.id, + name: sharedSecret.secret.name || undefined, + accessType: sharedSecret.secret.accessType + } + } + }); + } + return sharedSecret; } }); @@ -151,6 +167,23 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) => actorOrgId: req.permission.orgId, ...req.body }); + + await server.services.auditLog.createAuditLog({ + orgId: req.permission.orgId, + ...req.auditLogInfo, + event: { + type: EventType.CREATE_SHARED_SECRET, + metadata: { + accessType: req.body.accessType, + expiresAt: req.body.expiresAt, + expiresAfterViews: req.body.expiresAfterViews, + name: req.body.name, + id: sharedSecret.id, + usingPassword: !!req.body.password + } + } + }); + return { id: sharedSecret.id }; } }); @@ -181,6 +214,18 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) => sharedSecretId }); + await server.services.auditLog.createAuditLog({ + orgId: req.permission.orgId, + ...req.auditLogInfo, + event: { + type: EventType.DELETE_SHARED_SECRET, + metadata: { + id: sharedSecretId, + name: deletedSharedSecret.name || undefined + } + } + }); + return { ...deletedSharedSecret }; } }); diff --git a/backend/src/services/auth/auth-type.ts b/backend/src/services/auth/auth-type.ts index c1bf2b6fb..05412a73a 100644 --- a/backend/src/services/auth/auth-type.ts +++ b/backend/src/services/auth/auth-type.ts @@ -39,7 +39,8 @@ export enum ActorType { // would extend to AWS, Azure, ... SERVICE = "service", IDENTITY = "identity", Machine = "machine", - SCIM_CLIENT = "scimClient" + SCIM_CLIENT = "scimClient", + UNKNOWN_USER = "unknownUser" } // This will be null unless the token-type is JWT diff --git a/frontend/src/hooks/api/auditLogs/constants.tsx b/frontend/src/hooks/api/auditLogs/constants.tsx index fd764f1f5..650798bc7 100644 --- a/frontend/src/hooks/api/auditLogs/constants.tsx +++ b/frontend/src/hooks/api/auditLogs/constants.tsx @@ -82,7 +82,10 @@ export const eventToNameMap: { [K in EventType]: string } = { "Update certificate template EST configuration", [EventType.UPDATE_PROJECT_SLACK_CONFIG]: "Update project slack configuration", [EventType.GET_PROJECT_SLACK_CONFIG]: "Get project slack configuration", - [EventType.INTEGRATION_SYNCED]: "Integration sync" + [EventType.INTEGRATION_SYNCED]: "Integration sync", + [EventType.CREATE_SHARED_SECRET]: "Create shared secret", + [EventType.DELETE_SHARED_SECRET]: "Delete shared secret", + [EventType.READ_SHARED_SECRET]: "Read shared secret" }; export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = { diff --git a/frontend/src/hooks/api/auditLogs/enums.tsx b/frontend/src/hooks/api/auditLogs/enums.tsx index 5e8adf5b1..c2c306a96 100644 --- a/frontend/src/hooks/api/auditLogs/enums.tsx +++ b/frontend/src/hooks/api/auditLogs/enums.tsx @@ -2,7 +2,8 @@ export enum ActorType { PLATFORM = "platform", USER = "user", SERVICE = "service", - IDENTITY = "identity" + IDENTITY = "identity", + UNKNOWN_USER = "unknownUser" } export enum UserAgentType { @@ -95,5 +96,8 @@ export enum EventType { GET_CERTIFICATE_TEMPLATE_EST_CONFIG = "get-certificate-template-est-config", UPDATE_PROJECT_SLACK_CONFIG = "update-project-slack-config", GET_PROJECT_SLACK_CONFIG = "get-project-slack-config", - INTEGRATION_SYNCED = "integration-synced" + INTEGRATION_SYNCED = "integration-synced", + CREATE_SHARED_SECRET = "create-shared-secret", + DELETE_SHARED_SECRET = "delete-shared-secret", + READ_SHARED_SECRET = "read-shared-secret" } diff --git a/frontend/src/hooks/api/auditLogs/types.tsx b/frontend/src/hooks/api/auditLogs/types.tsx index 62cf1b823..3a5070ef5 100644 --- a/frontend/src/hooks/api/auditLogs/types.tsx +++ b/frontend/src/hooks/api/auditLogs/types.tsx @@ -50,7 +50,11 @@ export interface PlatformActor { metadata: object; } -export type Actor = UserActor | ServiceActor | IdentityActor | PlatformActor; +export interface UnknownUserActor { + type: ActorType.UNKNOWN_USER; +} + +export type Actor = UserActor | ServiceActor | IdentityActor | PlatformActor | UnknownUserActor; interface GetSecretsEvent { type: EventType.GET_SECRETS; diff --git a/frontend/src/pages/organization/AuditLogsPage/components/LogsFilter.tsx b/frontend/src/pages/organization/AuditLogsPage/components/LogsFilter.tsx index ba7457128..3a21958ae 100644 --- a/frontend/src/pages/organization/AuditLogsPage/components/LogsFilter.tsx +++ b/frontend/src/pages/organization/AuditLogsPage/components/LogsFilter.tsx @@ -1,5 +1,5 @@ /* eslint-disable no-nested-ternary */ -import { useEffect, useState } from "react"; +import { useState } from "react"; import { Control, Controller, UseFormReset, UseFormSetValue, UseFormWatch } from "react-hook-form"; import { faCaretDown, faCheckCircle, faFilterCircleXmark } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -49,7 +49,6 @@ export const LogsFilter = ({ isOrgAuditLogs, className, control, - setValue, reset, watch }: Props) => { @@ -63,12 +62,6 @@ export const LogsFilter = ({ const { data, isPending } = useGetAuditLogActorFilterOpts(workspaces?.[0]?.id ?? ""); - useEffect(() => { - if (workspacesInOrg.length) { - setValue("project", workspacesInOrg[0]); - } - }, [workspaces]); - const renderActorSelectItem = (actor: Actor) => { switch (actor.type) { case ActorType.USER: @@ -129,6 +122,7 @@ export const LogsFilter = ({ > ({ name, id }))} diff --git a/frontend/src/pages/organization/AuditLogsPage/components/LogsTableRow.tsx b/frontend/src/pages/organization/AuditLogsPage/components/LogsTableRow.tsx index 4da98613e..5e663f283 100644 --- a/frontend/src/pages/organization/AuditLogsPage/components/LogsTableRow.tsx +++ b/frontend/src/pages/organization/AuditLogsPage/components/LogsTableRow.tsx @@ -1,4 +1,7 @@ -import { Td, Tr } from "@app/components/v2"; +import { faQuestionCircle } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +import { Td, Tooltip, Tr } from "@app/components/v2"; import { eventToNameMap, userAgentTTypeoNameMap } from "@app/hooks/api/auditLogs/constants"; import { ActorType, EventType } from "@app/hooks/api/auditLogs/enums"; import { Actor, AuditLog } from "@app/hooks/api/auditLogs/types"; @@ -37,6 +40,17 @@ export const LogsTableRow = ({ auditLog, isOrgAuditLogs, showActorColumn }: Prop

Machine Identity

); + case ActorType.UNKNOWN_USER: + return ( + +
+

Unknown User

+ + + +
+ + ); default: return ; }