mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 17:27:40 +00:00
feat(audit-logs): shared secrets audit logs
This commit is contained in:
@@ -31,7 +31,7 @@ export type TListProjectAuditLogDTO = {
|
|||||||
|
|
||||||
export type TCreateAuditLogDTO = {
|
export type TCreateAuditLogDTO = {
|
||||||
event: Event;
|
event: Event;
|
||||||
actor: UserActor | IdentityActor | ServiceActor | ScimClientActor | PlatformActor;
|
actor: UserActor | IdentityActor | ServiceActor | ScimClientActor | PlatformActor | UnknownUserActor;
|
||||||
orgId?: string;
|
orgId?: string;
|
||||||
projectId?: string;
|
projectId?: string;
|
||||||
} & BaseAuthData;
|
} & BaseAuthData;
|
||||||
@@ -229,7 +229,10 @@ export enum EventType {
|
|||||||
GET_APP_CONNECTION = "get-app-connection",
|
GET_APP_CONNECTION = "get-app-connection",
|
||||||
CREATE_APP_CONNECTION = "create-app-connection",
|
CREATE_APP_CONNECTION = "create-app-connection",
|
||||||
UPDATE_APP_CONNECTION = "update-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 {
|
interface UserActorMetadata {
|
||||||
@@ -252,6 +255,8 @@ interface ScimClientActorMetadata {}
|
|||||||
|
|
||||||
interface PlatformActorMetadata {}
|
interface PlatformActorMetadata {}
|
||||||
|
|
||||||
|
interface UnknownUserActorMetadata {}
|
||||||
|
|
||||||
export interface UserActor {
|
export interface UserActor {
|
||||||
type: ActorType.USER;
|
type: ActorType.USER;
|
||||||
metadata: UserActorMetadata;
|
metadata: UserActorMetadata;
|
||||||
@@ -267,6 +272,11 @@ export interface PlatformActor {
|
|||||||
metadata: PlatformActorMetadata;
|
metadata: PlatformActorMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UnknownUserActor {
|
||||||
|
type: ActorType.UNKNOWN_USER;
|
||||||
|
metadata: UnknownUserActorMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IdentityActor {
|
export interface IdentityActor {
|
||||||
type: ActorType.IDENTITY;
|
type: ActorType.IDENTITY;
|
||||||
metadata: IdentityActorMetadata;
|
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 =
|
export type Event =
|
||||||
| GetSecretsEvent
|
| GetSecretsEvent
|
||||||
| GetSecretEvent
|
| GetSecretEvent
|
||||||
@@ -2083,4 +2122,7 @@ export type Event =
|
|||||||
| GetAppConnectionEvent
|
| GetAppConnectionEvent
|
||||||
| CreateAppConnectionEvent
|
| CreateAppConnectionEvent
|
||||||
| UpdateAppConnectionEvent
|
| UpdateAppConnectionEvent
|
||||||
| DeleteAppConnectionEvent;
|
| DeleteAppConnectionEvent
|
||||||
|
| CreateSharedSecretEvent
|
||||||
|
| DeleteSharedSecretEvent
|
||||||
|
| ReadSharedSecretEvent;
|
||||||
|
|||||||
@@ -32,13 +32,21 @@ export const getUserAgentType = (userAgent: string | undefined) => {
|
|||||||
export const injectAuditLogInfo = fp(async (server: FastifyZodProvider) => {
|
export const injectAuditLogInfo = fp(async (server: FastifyZodProvider) => {
|
||||||
server.decorateRequest("auditLogInfo", null);
|
server.decorateRequest("auditLogInfo", null);
|
||||||
server.addHook("onRequest", async (req) => {
|
server.addHook("onRequest", async (req) => {
|
||||||
if (!req.auth) return;
|
|
||||||
const userAgent = req.headers["user-agent"] ?? "";
|
const userAgent = req.headers["user-agent"] ?? "";
|
||||||
const payload = {
|
const payload = {
|
||||||
ipAddress: req.realIp,
|
ipAddress: req.realIp,
|
||||||
userAgent,
|
userAgent,
|
||||||
userAgentType: getUserAgentType(userAgent)
|
userAgentType: getUserAgentType(userAgent)
|
||||||
} as typeof req.auditLogInfo;
|
} as typeof req.auditLogInfo;
|
||||||
|
|
||||||
|
if (!req.auth) {
|
||||||
|
payload.actor = {
|
||||||
|
type: ActorType.UNKNOWN_USER,
|
||||||
|
metadata: {}
|
||||||
|
};
|
||||||
|
req.auditLogInfo = payload;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (req.auth.actor === ActorType.USER) {
|
if (req.auth.actor === ActorType.USER) {
|
||||||
payload.actor = {
|
payload.actor = {
|
||||||
type: ActorType.USER,
|
type: ActorType.USER,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { SecretSharingSchema } from "@app/db/schemas";
|
import { SecretSharingSchema } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { SecretSharingAccessType } from "@app/lib/types";
|
import { SecretSharingAccessType } from "@app/lib/types";
|
||||||
import {
|
import {
|
||||||
publicEndpointLimit,
|
publicEndpointLimit,
|
||||||
@@ -88,6 +89,21 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) =>
|
|||||||
orgId: req.permission?.orgId
|
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;
|
return sharedSecret;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -151,6 +167,23 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) =>
|
|||||||
actorOrgId: req.permission.orgId,
|
actorOrgId: req.permission.orgId,
|
||||||
...req.body
|
...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 };
|
return { id: sharedSecret.id };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -181,6 +214,18 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) =>
|
|||||||
sharedSecretId
|
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 };
|
return { ...deletedSharedSecret };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ export enum ActorType { // would extend to AWS, Azure, ...
|
|||||||
SERVICE = "service",
|
SERVICE = "service",
|
||||||
IDENTITY = "identity",
|
IDENTITY = "identity",
|
||||||
Machine = "machine",
|
Machine = "machine",
|
||||||
SCIM_CLIENT = "scimClient"
|
SCIM_CLIENT = "scimClient",
|
||||||
|
UNKNOWN_USER = "unknownUser"
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will be null unless the token-type is JWT
|
// This will be null unless the token-type is JWT
|
||||||
|
|||||||
@@ -82,7 +82,10 @@ export const eventToNameMap: { [K in EventType]: string } = {
|
|||||||
"Update certificate template EST configuration",
|
"Update certificate template EST configuration",
|
||||||
[EventType.UPDATE_PROJECT_SLACK_CONFIG]: "Update project slack configuration",
|
[EventType.UPDATE_PROJECT_SLACK_CONFIG]: "Update project slack configuration",
|
||||||
[EventType.GET_PROJECT_SLACK_CONFIG]: "Get 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 } = {
|
export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = {
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ export enum ActorType {
|
|||||||
PLATFORM = "platform",
|
PLATFORM = "platform",
|
||||||
USER = "user",
|
USER = "user",
|
||||||
SERVICE = "service",
|
SERVICE = "service",
|
||||||
IDENTITY = "identity"
|
IDENTITY = "identity",
|
||||||
|
UNKNOWN_USER = "unknownUser"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum UserAgentType {
|
export enum UserAgentType {
|
||||||
@@ -95,5 +96,8 @@ export enum EventType {
|
|||||||
GET_CERTIFICATE_TEMPLATE_EST_CONFIG = "get-certificate-template-est-config",
|
GET_CERTIFICATE_TEMPLATE_EST_CONFIG = "get-certificate-template-est-config",
|
||||||
UPDATE_PROJECT_SLACK_CONFIG = "update-project-slack-config",
|
UPDATE_PROJECT_SLACK_CONFIG = "update-project-slack-config",
|
||||||
GET_PROJECT_SLACK_CONFIG = "get-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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,11 @@ export interface PlatformActor {
|
|||||||
metadata: object;
|
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 {
|
interface GetSecretsEvent {
|
||||||
type: EventType.GET_SECRETS;
|
type: EventType.GET_SECRETS;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable no-nested-ternary */
|
/* 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 { Control, Controller, UseFormReset, UseFormSetValue, UseFormWatch } from "react-hook-form";
|
||||||
import { faCaretDown, faCheckCircle, faFilterCircleXmark } from "@fortawesome/free-solid-svg-icons";
|
import { faCaretDown, faCheckCircle, faFilterCircleXmark } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
@@ -49,7 +49,6 @@ export const LogsFilter = ({
|
|||||||
isOrgAuditLogs,
|
isOrgAuditLogs,
|
||||||
className,
|
className,
|
||||||
control,
|
control,
|
||||||
setValue,
|
|
||||||
reset,
|
reset,
|
||||||
watch
|
watch
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
@@ -63,12 +62,6 @@ export const LogsFilter = ({
|
|||||||
|
|
||||||
const { data, isPending } = useGetAuditLogActorFilterOpts(workspaces?.[0]?.id ?? "");
|
const { data, isPending } = useGetAuditLogActorFilterOpts(workspaces?.[0]?.id ?? "");
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (workspacesInOrg.length) {
|
|
||||||
setValue("project", workspacesInOrg[0]);
|
|
||||||
}
|
|
||||||
}, [workspaces]);
|
|
||||||
|
|
||||||
const renderActorSelectItem = (actor: Actor) => {
|
const renderActorSelectItem = (actor: Actor) => {
|
||||||
switch (actor.type) {
|
switch (actor.type) {
|
||||||
case ActorType.USER:
|
case ActorType.USER:
|
||||||
@@ -129,6 +122,7 @@ export const LogsFilter = ({
|
|||||||
>
|
>
|
||||||
<FilterableSelect
|
<FilterableSelect
|
||||||
value={value}
|
value={value}
|
||||||
|
isClearable
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
placeholder="Select a project..."
|
placeholder="Select a project..."
|
||||||
options={workspacesInOrg.map(({ name, id }) => ({ name, id }))}
|
options={workspacesInOrg.map(({ name, id }) => ({ name, id }))}
|
||||||
|
|||||||
@@ -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 { eventToNameMap, userAgentTTypeoNameMap } from "@app/hooks/api/auditLogs/constants";
|
||||||
import { ActorType, EventType } from "@app/hooks/api/auditLogs/enums";
|
import { ActorType, EventType } from "@app/hooks/api/auditLogs/enums";
|
||||||
import { Actor, AuditLog } from "@app/hooks/api/auditLogs/types";
|
import { Actor, AuditLog } from "@app/hooks/api/auditLogs/types";
|
||||||
@@ -37,6 +40,17 @@ export const LogsTableRow = ({ auditLog, isOrgAuditLogs, showActorColumn }: Prop
|
|||||||
<p>Machine Identity</p>
|
<p>Machine Identity</p>
|
||||||
</Td>
|
</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:
|
default:
|
||||||
return <Td />;
|
return <Td />;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user