Skip to content

Commit

Permalink
Merge pull request Infisical#2974 from Infisical/daniel/shared-secret…
Browse files Browse the repository at this point in the history
…-audit-logs

feat(audit-logs): shared secrets audit logs
  • Loading branch information
DanielHougaard authored Jan 10, 2025
2 parents d7ffa70 + 3d278b0 commit 258d19c
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 18 deletions.
48 changes: 45 additions & 3 deletions backend/src/ee/services/audit-log/audit-log-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -252,6 +255,8 @@ interface ScimClientActorMetadata {}

interface PlatformActorMetadata {}

interface UnknownUserActorMetadata {}

export interface UserActor {
type: ActorType.USER;
metadata: UserActorMetadata;
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -2083,4 +2122,7 @@ export type Event =
| GetAppConnectionEvent
| CreateAppConnectionEvent
| UpdateAppConnectionEvent
| DeleteAppConnectionEvent;
| DeleteAppConnectionEvent
| CreateSharedSecretEvent
| DeleteSharedSecretEvent
| ReadSharedSecretEvent;
10 changes: 9 additions & 1 deletion backend/src/server/plugins/audit-log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
45 changes: 45 additions & 0 deletions backend/src/server/routes/v1/secret-sharing-router.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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;
}
});
Expand Down Expand Up @@ -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 };
}
});
Expand Down Expand Up @@ -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 };
}
});
Expand Down
3 changes: 2 additions & 1 deletion backend/src/services/auth/auth-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/hooks/api/auditLogs/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 } = {
Expand Down
8 changes: 6 additions & 2 deletions frontend/src/hooks/api/auditLogs/enums.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ export enum ActorType {
PLATFORM = "platform",
USER = "user",
SERVICE = "service",
IDENTITY = "identity"
IDENTITY = "identity",
UNKNOWN_USER = "unknownUser"
}

export enum UserAgentType {
Expand Down Expand Up @@ -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"
}
6 changes: 5 additions & 1 deletion frontend/src/hooks/api/auditLogs/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -49,7 +49,6 @@ export const LogsFilter = ({
isOrgAuditLogs,
className,
control,
setValue,
reset,
watch
}: Props) => {
Expand All @@ -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:
Expand Down Expand Up @@ -129,6 +122,7 @@ export const LogsFilter = ({
>
<FilterableSelect
value={value}
isClearable
onChange={onChange}
placeholder="Select a project..."
options={workspacesInOrg.map(({ name, id }) => ({ name, id }))}
Expand Down
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -37,6 +40,17 @@ export const LogsTableRow = ({ auditLog, isOrgAuditLogs, showActorColumn }: Prop
<p>Machine Identity</p>
</Td>
);
case ActorType.UNKNOWN_USER:
return (
<Td>
<div className="flex items-center gap-2">
<p>Unknown User</p>
<Tooltip content="This action was performed by a user who was not authenticated at the time.">
<FontAwesomeIcon className="text-mineshaft-400" icon={faQuestionCircle} />
</Tooltip>
</div>
</Td>
);
default:
return <Td />;
}
Expand Down

0 comments on commit 258d19c

Please sign in to comment.