Merge pull request #5011 from Infisical/PKI-37-add-acme-audit-logs

improvement(api): add acme audit logs
This commit is contained in:
Fang-Pen Lin
2025-12-11 15:56:33 -08:00
committed by GitHub
10 changed files with 366 additions and 35 deletions
@@ -49,6 +49,7 @@ import { TWebhookPayloads } from "@app/services/webhook/webhook-types";
import { WorkflowIntegration } from "@app/services/workflow-integration/workflow-integration-types"; import { WorkflowIntegration } from "@app/services/workflow-integration/workflow-integration-types";
import { KmipPermission } from "../kmip/kmip-enum"; import { KmipPermission } from "../kmip/kmip-enum";
import { AcmeChallengeType, AcmeIdentifierType } from "../pki-acme/pki-acme-schemas";
import { ApprovalStatus } from "../secret-approval-request/secret-approval-request-types"; import { ApprovalStatus } from "../secret-approval-request/secret-approval-request-types";
export type TListProjectAuditLogDTO = { export type TListProjectAuditLogDTO = {
@@ -78,7 +79,9 @@ export type TCreateAuditLogDTO = {
| ScimClientActor | ScimClientActor
| PlatformActor | PlatformActor
| UnknownUserActor | UnknownUserActor
| KmipClientActor; | KmipClientActor
| AcmeProfileActor
| AcmeAccountActor;
orgId?: string; orgId?: string;
projectId?: string; projectId?: string;
} & BaseAuthData; } & BaseAuthData;
@@ -574,7 +577,18 @@ export enum EventType {
APPROVAL_REQUEST_CANCEL = "approval-request-cancel", APPROVAL_REQUEST_CANCEL = "approval-request-cancel",
APPROVAL_REQUEST_GRANT_LIST = "approval-request-grant-list", APPROVAL_REQUEST_GRANT_LIST = "approval-request-grant-list",
APPROVAL_REQUEST_GRANT_GET = "approval-request-grant-get", APPROVAL_REQUEST_GRANT_GET = "approval-request-grant-get",
APPROVAL_REQUEST_GRANT_REVOKE = "approval-request-grant-revoke" APPROVAL_REQUEST_GRANT_REVOKE = "approval-request-grant-revoke",
// PKI ACME
CREATE_ACME_ACCOUNT = "create-acme-account",
RETRIEVE_ACME_ACCOUNT = "retrieve-acme-account",
CREATE_ACME_ORDER = "create-acme-order",
FINALIZE_ACME_ORDER = "finalize-acme-order",
DOWNLOAD_ACME_CERTIFICATE = "download-acme-certificate",
RESPOND_TO_ACME_CHALLENGE = "respond-to-acme-challenge",
PASS_ACME_CHALLENGE = "pass-acme-challenge",
ATTEMPT_ACME_CHALLENGE = "attempt-acme-challenge",
FAIL_ACME_CHALLENGE = "fail-acme-challenge"
} }
export const filterableSecretEvents: EventType[] = [ export const filterableSecretEvents: EventType[] = [
@@ -615,6 +629,15 @@ interface KmipClientActorMetadata {
name: string; name: string;
} }
interface AcmeProfileActorMetadata {
profileId: string;
}
interface AcmeAccountActorMetadata {
profileId: string;
accountId: string;
}
interface UnknownUserActorMetadata {} interface UnknownUserActorMetadata {}
export interface UserActor { export interface UserActor {
@@ -652,7 +675,25 @@ export interface ScimClientActor {
metadata: ScimClientActorMetadata; metadata: ScimClientActorMetadata;
} }
export type Actor = UserActor | ServiceActor | IdentityActor | ScimClientActor | PlatformActor | KmipClientActor; export interface AcmeProfileActor {
type: ActorType.ACME_PROFILE;
metadata: AcmeProfileActorMetadata;
}
export interface AcmeAccountActor {
type: ActorType.ACME_ACCOUNT;
metadata: AcmeAccountActorMetadata;
}
export type Actor =
| UserActor
| ServiceActor
| IdentityActor
| ScimClientActor
| PlatformActor
| KmipClientActor
| AcmeProfileActor
| AcmeAccountActor;
interface GetSecretsEvent { interface GetSecretsEvent {
type: EventType.GET_SECRETS; type: EventType.GET_SECRETS;
@@ -4368,6 +4409,84 @@ interface ApprovalRequestGrantRevokeEvent {
}; };
} }
interface CreateAcmeAccountEvent {
type: EventType.CREATE_ACME_ACCOUNT;
metadata: {
accountId: string;
publicKeyThumbprint: string;
emails?: string[];
};
}
interface RetrieveAcmeAccountEvent {
type: EventType.RETRIEVE_ACME_ACCOUNT;
metadata: {
accountId: string;
publicKeyThumbprint: string;
};
}
interface CreateAcmeOrderEvent {
type: EventType.CREATE_ACME_ORDER;
metadata: {
orderId: string;
identifiers: Array<{
type: AcmeIdentifierType;
value: string;
}>;
};
}
interface FinalizeAcmeOrderEvent {
type: EventType.FINALIZE_ACME_ORDER;
metadata: {
orderId: string;
csr: string;
};
}
interface DownloadAcmeCertificateEvent {
type: EventType.DOWNLOAD_ACME_CERTIFICATE;
metadata: {
orderId: string;
};
}
interface RespondToAcmeChallengeEvent {
type: EventType.RESPOND_TO_ACME_CHALLENGE;
metadata: {
challengeId: string;
type: AcmeChallengeType;
};
}
interface PassedAcmeChallengeEvent {
type: EventType.PASS_ACME_CHALLENGE;
metadata: {
challengeId: string;
type: AcmeChallengeType;
};
}
interface AttemptAcmeChallengeEvent {
type: EventType.ATTEMPT_ACME_CHALLENGE;
metadata: {
challengeId: string;
type: AcmeChallengeType;
retryCount: number;
errorMessage: string;
};
}
interface FailAcmeChallengeEvent {
type: EventType.FAIL_ACME_CHALLENGE;
metadata: {
challengeId: string;
type: AcmeChallengeType;
retryCount: number;
errorMessage: string;
};
}
export type Event = export type Event =
| CreateSubOrganizationEvent | CreateSubOrganizationEvent
| UpdateSubOrganizationEvent | UpdateSubOrganizationEvent
@@ -4768,4 +4887,13 @@ export type Event =
| ApprovalRequestCancelEvent | ApprovalRequestCancelEvent
| ApprovalRequestGrantListEvent | ApprovalRequestGrantListEvent
| ApprovalRequestGrantGetEvent | ApprovalRequestGrantGetEvent
| ApprovalRequestGrantRevokeEvent; | ApprovalRequestGrantRevokeEvent
| CreateAcmeAccountEvent
| RetrieveAcmeAccountEvent
| CreateAcmeOrderEvent
| FinalizeAcmeOrderEvent
| DownloadAcmeCertificateEvent
| RespondToAcmeChallengeEvent
| PassedAcmeChallengeEvent
| AttemptAcmeChallengeEvent
| FailAcmeChallengeEvent;
@@ -122,6 +122,11 @@ export const pkiAcmeChallengeDALFactory = (db: TDbClient) => {
const result = await (tx || db)(TableName.PkiAcmeChallenge) const result = await (tx || db)(TableName.PkiAcmeChallenge)
.join(TableName.PkiAcmeAuth, `${TableName.PkiAcmeChallenge}.authId`, `${TableName.PkiAcmeAuth}.id`) .join(TableName.PkiAcmeAuth, `${TableName.PkiAcmeChallenge}.authId`, `${TableName.PkiAcmeAuth}.id`)
.join(TableName.PkiAcmeAccount, `${TableName.PkiAcmeAuth}.accountId`, `${TableName.PkiAcmeAccount}.id`) .join(TableName.PkiAcmeAccount, `${TableName.PkiAcmeAuth}.accountId`, `${TableName.PkiAcmeAccount}.id`)
.join(
TableName.PkiCertificateProfile,
`${TableName.PkiAcmeAccount}.profileId`,
`${TableName.PkiCertificateProfile}.id`
)
.select( .select(
selectAllTableCols(TableName.PkiAcmeChallenge), selectAllTableCols(TableName.PkiAcmeChallenge),
db.ref("id").withSchema(TableName.PkiAcmeAuth).as("authId"), db.ref("id").withSchema(TableName.PkiAcmeAuth).as("authId"),
@@ -131,7 +136,9 @@ export const pkiAcmeChallengeDALFactory = (db: TDbClient) => {
db.ref("identifierValue").withSchema(TableName.PkiAcmeAuth).as("authIdentifierValue"), db.ref("identifierValue").withSchema(TableName.PkiAcmeAuth).as("authIdentifierValue"),
db.ref("expiresAt").withSchema(TableName.PkiAcmeAuth).as("authExpiresAt"), db.ref("expiresAt").withSchema(TableName.PkiAcmeAuth).as("authExpiresAt"),
db.ref("id").withSchema(TableName.PkiAcmeAccount).as("accountId"), db.ref("id").withSchema(TableName.PkiAcmeAccount).as("accountId"),
db.ref("publicKeyThumbprint").withSchema(TableName.PkiAcmeAccount).as("accountPublicKeyThumbprint") db.ref("publicKeyThumbprint").withSchema(TableName.PkiAcmeAccount).as("accountPublicKeyThumbprint"),
db.ref("profileId").withSchema(TableName.PkiAcmeAccount).as("profileId"),
db.ref("projectId").withSchema(TableName.PkiCertificateProfile).as("projectId")
) )
// For all challenges, acquire update lock on the auth to avoid race conditions // For all challenges, acquire update lock on the auth to avoid race conditions
.forUpdate(TableName.PkiAcmeAuth) .forUpdate(TableName.PkiAcmeAuth)
@@ -149,6 +156,8 @@ export const pkiAcmeChallengeDALFactory = (db: TDbClient) => {
authExpiresAt, authExpiresAt,
accountId, accountId,
accountPublicKeyThumbprint, accountPublicKeyThumbprint,
profileId,
projectId,
...challenge ...challenge
} = result; } = result;
return { return {
@@ -161,7 +170,11 @@ export const pkiAcmeChallengeDALFactory = (db: TDbClient) => {
expiresAt: authExpiresAt, expiresAt: authExpiresAt,
account: { account: {
id: accountId, id: accountId,
publicKeyThumbprint: accountPublicKeyThumbprint publicKeyThumbprint: accountPublicKeyThumbprint,
project: {
id: projectId
},
profileId
} }
} }
}; };
@@ -5,7 +5,9 @@ import { getConfig } from "@app/lib/config/env";
import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { isPrivateIp } from "@app/lib/ip/ipRange"; import { isPrivateIp } from "@app/lib/ip/ipRange";
import { logger } from "@app/lib/logger"; import { logger } from "@app/lib/logger";
import { ActorType } from "@app/services/auth/auth-type";
import { EventType, TAuditLogServiceFactory } from "../audit-log/audit-log-types";
import { TPkiAcmeChallengeDALFactory } from "./pki-acme-challenge-dal"; import { TPkiAcmeChallengeDALFactory } from "./pki-acme-challenge-dal";
import { import {
AcmeConnectionError, AcmeConnectionError,
@@ -25,10 +27,12 @@ type TPkiAcmeChallengeServiceFactoryDep = {
| "markAsInvalidCascadeById" | "markAsInvalidCascadeById"
| "updateById" | "updateById"
>; >;
auditLogService: Pick<TAuditLogServiceFactory, "createAuditLog">;
}; };
export const pkiAcmeChallengeServiceFactory = ({ export const pkiAcmeChallengeServiceFactory = ({
acmeChallengeDAL acmeChallengeDAL,
auditLogService
}: TPkiAcmeChallengeServiceFactoryDep): TPkiAcmeChallengeServiceFactory => { }: TPkiAcmeChallengeServiceFactoryDep): TPkiAcmeChallengeServiceFactory => {
const appCfg = getConfig(); const appCfg = getConfig();
const markChallengeAsReady = async (challengeId: string): Promise<TPkiAcmeChallenges> => { const markChallengeAsReady = async (challengeId: string): Promise<TPkiAcmeChallenges> => {
@@ -113,7 +117,25 @@ export const pkiAcmeChallengeServiceFactory = ({
} }
logger.info({ challengeId }, "ACME challenge response is correct, marking challenge as valid"); logger.info({ challengeId }, "ACME challenge response is correct, marking challenge as valid");
await acmeChallengeDAL.markAsValidCascadeById(challengeId); await acmeChallengeDAL.markAsValidCascadeById(challengeId);
await auditLogService.createAuditLog({
projectId: challenge.auth.account.project.id,
actor: {
type: ActorType.ACME_ACCOUNT,
metadata: {
profileId: challenge.auth.account.profileId,
accountId: challenge.auth.account.id
}
},
event: {
type: EventType.PASS_ACME_CHALLENGE,
metadata: {
challengeId,
type: challenge.type as AcmeChallengeType
}
}
});
} catch (exp) { } catch (exp) {
let finalAttempt = false;
if (retryCount >= 2) { if (retryCount >= 2) {
logger.error( logger.error(
exp, exp,
@@ -121,35 +143,59 @@ export const pkiAcmeChallengeServiceFactory = ({
); );
// This is the last attempt to validate the challenge response, if it fails, we mark the challenge as invalid // This is the last attempt to validate the challenge response, if it fails, we mark the challenge as invalid
await acmeChallengeDAL.markAsInvalidCascadeById(challengeId); await acmeChallengeDAL.markAsInvalidCascadeById(challengeId);
finalAttempt = true;
} }
// Properly type and inspect the error try {
if (axios.isAxiosError(exp)) { // Properly type and inspect the error
const axiosError = exp as AxiosError; if (axios.isAxiosError(exp)) {
const errorCode = axiosError.code; const axiosError = exp as AxiosError;
const errorMessage = axiosError.message; const errorCode = axiosError.code;
const errorMessage = axiosError.message;
if (errorCode === "ECONNREFUSED" || errorMessage.includes("ECONNREFUSED")) { if (errorCode === "ECONNREFUSED" || errorMessage.includes("ECONNREFUSED")) {
throw new AcmeConnectionError({ message: "Connection refused" }); throw new AcmeConnectionError({ message: "Connection refused" });
}
if (errorCode === "ENOTFOUND" || errorMessage.includes("ENOTFOUND")) {
throw new AcmeDnsFailureError({ message: "Hostname could not be resolved (DNS failure)" });
}
if (errorCode === "ECONNRESET" || errorMessage.includes("ECONNRESET")) {
throw new AcmeConnectionError({ message: "Connection reset by peer" });
}
if (errorCode === "ECONNABORTED" || errorMessage.includes("timeout")) {
logger.error(exp, "Connection timed out while validating ACME challenge response");
throw new AcmeConnectionError({ message: "Connection timed out" });
}
logger.error(exp, "Unknown error validating ACME challenge response");
throw new AcmeServerInternalError({ message: "Unknown error validating ACME challenge response" });
} }
if (errorCode === "ENOTFOUND" || errorMessage.includes("ENOTFOUND")) { if (exp instanceof Error) {
throw new AcmeDnsFailureError({ message: "Hostname could not be resolved (DNS failure)" }); logger.error(exp, "Error validating ACME challenge response");
} throw exp;
if (errorCode === "ECONNRESET" || errorMessage.includes("ECONNRESET")) {
throw new AcmeConnectionError({ message: "Connection reset by peer" });
}
if (errorCode === "ECONNABORTED" || errorMessage.includes("timeout")) {
logger.error(exp, "Connection timed out while validating ACME challenge response");
throw new AcmeConnectionError({ message: "Connection timed out" });
} }
logger.error(exp, "Unknown error validating ACME challenge response"); logger.error(exp, "Unknown error validating ACME challenge response");
throw new AcmeServerInternalError({ message: "Unknown error validating ACME challenge response" }); throw new AcmeServerInternalError({ message: "Unknown error validating ACME challenge response" });
} catch (outterExp) {
await auditLogService.createAuditLog({
projectId: challenge.auth.account.project.id,
actor: {
type: ActorType.ACME_ACCOUNT,
metadata: {
profileId: challenge.auth.account.profileId,
accountId: challenge.auth.account.id
}
},
event: {
type: finalAttempt ? EventType.FAIL_ACME_CHALLENGE : EventType.ATTEMPT_ACME_CHALLENGE,
metadata: {
challengeId,
type: challenge.type as AcmeChallengeType,
retryCount,
errorMessage: exp instanceof Error ? exp.message : "Unknown error"
}
}
});
throw outterExp;
} }
if (exp instanceof Error) {
logger.error(exp, "Error validating ACME challenge response");
throw exp;
}
logger.error(exp, "Unknown error validating ACME challenge response");
throw new AcmeServerInternalError({ message: "Unknown error validating ACME challenge response" });
} }
}; };
@@ -47,6 +47,7 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TProjectDALFactory } from "@app/services/project/project-dal"; import { TProjectDALFactory } from "@app/services/project/project-dal";
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns"; import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
import { EventType, TAuditLogServiceFactory } from "../audit-log/audit-log-types";
import { TLicenseServiceFactory } from "../license/license-service"; import { TLicenseServiceFactory } from "../license/license-service";
import { TPkiAcmeAccountDALFactory } from "./pki-acme-account-dal"; import { TPkiAcmeAccountDALFactory } from "./pki-acme-account-dal";
import { TPkiAcmeAuthDALFactory } from "./pki-acme-auth-dal"; import { TPkiAcmeAuthDALFactory } from "./pki-acme-auth-dal";
@@ -136,6 +137,7 @@ type TPkiAcmeServiceFactoryDep = {
certificateTemplateV2Service: Pick<TCertificateTemplateV2ServiceFactory, "validateCertificateRequest">; certificateTemplateV2Service: Pick<TCertificateTemplateV2ServiceFactory, "validateCertificateRequest">;
acmeChallengeService: Pick<TPkiAcmeChallengeServiceFactory, "markChallengeAsReady">; acmeChallengeService: Pick<TPkiAcmeChallengeServiceFactory, "markChallengeAsReady">;
pkiAcmeQueueService: Pick<TPkiAcmeQueueServiceFactory, "queueChallengeValidation">; pkiAcmeQueueService: Pick<TPkiAcmeQueueServiceFactory, "queueChallengeValidation">;
auditLogService: Pick<TAuditLogServiceFactory, "createAuditLog">;
}; };
export const pkiAcmeServiceFactory = ({ export const pkiAcmeServiceFactory = ({
@@ -159,7 +161,8 @@ export const pkiAcmeServiceFactory = ({
certificateV3Service, certificateV3Service,
certificateTemplateV2Service, certificateTemplateV2Service,
acmeChallengeService, acmeChallengeService,
pkiAcmeQueueService pkiAcmeQueueService,
auditLogService
}: TPkiAcmeServiceFactoryDep): TPkiAcmeServiceFactory => { }: TPkiAcmeServiceFactoryDep): TPkiAcmeServiceFactory => {
const validateAcmeProfile = async (profileId: string): Promise<TCertificateProfileWithConfigs> => { const validateAcmeProfile = async (profileId: string): Promise<TCertificateProfileWithConfigs> => {
const profile = await certificateProfileDAL.findByIdWithConfigs(profileId); const profile = await certificateProfileDAL.findByIdWithConfigs(profileId);
@@ -446,6 +449,23 @@ export const pkiAcmeServiceFactory = ({
throw new AcmeExternalAccountRequiredError({ message: "External account binding is required" }); throw new AcmeExternalAccountRequiredError({ message: "External account binding is required" });
} }
if (existingAccount) { if (existingAccount) {
await auditLogService.createAuditLog({
projectId: profile.projectId,
actor: {
type: ActorType.ACME_PROFILE,
metadata: {
profileId: profile.id
}
},
event: {
type: EventType.RETRIEVE_ACME_ACCOUNT,
metadata: {
accountId: existingAccount.id,
publicKeyThumbprint
}
}
});
return { return {
status: 200, status: 200,
body: { body: {
@@ -518,7 +538,25 @@ export const pkiAcmeServiceFactory = ({
publicKeyThumbprint, publicKeyThumbprint,
emails: contact ?? [] emails: contact ?? []
}); });
// TODO: create audit log here
await auditLogService.createAuditLog({
projectId: profile.projectId,
actor: {
type: ActorType.ACME_PROFILE,
metadata: {
profileId: profile.id
}
},
event: {
type: EventType.CREATE_ACME_ACCOUNT,
metadata: {
accountId: newAccount.id,
publicKeyThumbprint: newAccount.publicKeyThumbprint,
emails: newAccount.emails
}
}
});
return { return {
status: 201, status: 201,
body: { body: {
@@ -647,7 +685,26 @@ export const pkiAcmeServiceFactory = ({
})), })),
tx tx
); );
// TODO: create audit log here await auditLogService.createAuditLog({
projectId: profile.projectId,
actor: {
type: ActorType.ACME_ACCOUNT,
metadata: {
profileId: account.profileId,
accountId: account.id
}
},
event: {
type: EventType.CREATE_ACME_ORDER,
metadata: {
orderId: createdOrder.id,
identifiers: authorizations.map((auth) => ({
type: auth.identifierType as AcmeIdentifierType,
value: auth.identifierValue
}))
}
}
});
return { ...createdOrder, authorizations, account }; return { ...createdOrder, authorizations, account };
}); });
@@ -875,6 +932,23 @@ export const pkiAcmeServiceFactory = ({
throw error; throw error;
} }
order = updatedOrder; order = updatedOrder;
await auditLogService.createAuditLog({
projectId: profile.projectId,
actor: {
type: ActorType.ACME_ACCOUNT,
metadata: {
profileId,
accountId
}
},
event: {
type: EventType.FINALIZE_ACME_ORDER,
metadata: {
orderId: updatedOrder.id,
csr: updatedOrder.csr!
}
}
});
} else if (order.status !== AcmeOrderStatus.Valid) { } else if (order.status !== AcmeOrderStatus.Valid) {
throw new AcmeOrderNotReadyError({ message: "ACME order is not ready" }); throw new AcmeOrderNotReadyError({ message: "ACME order is not ready" });
} }
@@ -930,6 +1004,24 @@ export const pkiAcmeServiceFactory = ({
const certLeaf = certObj.toString("pem").trim().replace("\n", "\r\n"); const certLeaf = certObj.toString("pem").trim().replace("\n", "\r\n");
const certChain = certificateChain.trim().replace("\n", "\r\n"); const certChain = certificateChain.trim().replace("\n", "\r\n");
await auditLogService.createAuditLog({
projectId: profile.projectId,
actor: {
type: ActorType.ACME_ACCOUNT,
metadata: {
profileId,
accountId
}
},
event: {
type: EventType.DOWNLOAD_ACME_CERTIFICATE,
metadata: {
orderId
}
}
});
return { return {
status: 200, status: 200,
body: body:
@@ -1012,6 +1104,7 @@ export const pkiAcmeServiceFactory = ({
authzId: string; authzId: string;
challengeId: string; challengeId: string;
}): Promise<TAcmeResponse<TRespondToAcmeChallengeResponse>> => { }): Promise<TAcmeResponse<TRespondToAcmeChallengeResponse>> => {
const profile = await validateAcmeProfile(profileId);
const result = await acmeChallengeDAL.findByAccountAuthAndChallengeId(accountId, authzId, challengeId); const result = await acmeChallengeDAL.findByAccountAuthAndChallengeId(accountId, authzId, challengeId);
if (!result) { if (!result) {
throw new NotFoundError({ message: "ACME challenge not found" }); throw new NotFoundError({ message: "ACME challenge not found" });
@@ -1019,6 +1112,23 @@ export const pkiAcmeServiceFactory = ({
await acmeChallengeService.markChallengeAsReady(challengeId); await acmeChallengeService.markChallengeAsReady(challengeId);
await pkiAcmeQueueService.queueChallengeValidation(challengeId); await pkiAcmeQueueService.queueChallengeValidation(challengeId);
const challenge = (await acmeChallengeDAL.findByIdForChallengeValidation(challengeId))!; const challenge = (await acmeChallengeDAL.findByIdForChallengeValidation(challengeId))!;
await auditLogService.createAuditLog({
projectId: profile.projectId,
actor: {
type: ActorType.ACME_ACCOUNT,
metadata: {
profileId,
accountId
}
},
event: {
type: EventType.RESPOND_TO_ACME_CHALLENGE,
metadata: {
challengeId,
type: challenge.type as AcmeChallengeType
}
}
});
return { return {
status: 200, status: 200,
body: { body: {
+4 -2
View File
@@ -2303,7 +2303,8 @@ export const registerRoutes = async (
}); });
const acmeChallengeService = pkiAcmeChallengeServiceFactory({ const acmeChallengeService = pkiAcmeChallengeServiceFactory({
acmeChallengeDAL acmeChallengeDAL,
auditLogService
}); });
const pkiAcmeQueueService = await pkiAcmeQueueServiceFactory({ const pkiAcmeQueueService = await pkiAcmeQueueServiceFactory({
@@ -2332,7 +2333,8 @@ export const registerRoutes = async (
certificateV3Service, certificateV3Service,
certificateTemplateV2Service, certificateTemplateV2Service,
acmeChallengeService, acmeChallengeService,
pkiAcmeQueueService pkiAcmeQueueService,
auditLogService
}); });
const pkiSubscriberService = pkiSubscriberServiceFactory({ const pkiSubscriberService = pkiSubscriberServiceFactory({
+1
View File
@@ -41,6 +41,7 @@ export enum ActorType { // would extend to AWS, Azure, ...
IDENTITY = "identity", IDENTITY = "identity",
Machine = "machine", Machine = "machine",
SCIM_CLIENT = "scimClient", SCIM_CLIENT = "scimClient",
ACME_PROFILE = "acmeProfile",
ACME_ACCOUNT = "acmeAccount", ACME_ACCOUNT = "acmeAccount",
UNKNOWN_USER = "unknownUser" UNKNOWN_USER = "unknownUser"
} }
@@ -1,4 +1,6 @@
import { import {
AcmeAccountActor,
AcmeProfileActor,
IdentityActor, IdentityActor,
KmipClientActor, KmipClientActor,
PlatformActor, PlatformActor,
@@ -60,6 +62,8 @@ export type TSecretModifiedEvent = {
| ScimClientActor | ScimClientActor
| PlatformActor | PlatformActor
| UnknownUserActor | UnknownUserActor
| AcmeAccountActor
| AcmeProfileActor
| KmipClientActor; | KmipClientActor;
}; };
}; };
@@ -4,6 +4,8 @@ export enum ActorType {
USER = "user", USER = "user",
SERVICE = "service", SERVICE = "service",
IDENTITY = "identity", IDENTITY = "identity",
ACME_PROFILE = "acmeProfile",
ACME_ACCOUNT = "acmeAccount",
UNKNOWN_USER = "unknownUser" UNKNOWN_USER = "unknownUser"
} }
+20 -1
View File
@@ -38,6 +38,13 @@ interface KmipClientActorMetadata {
name: string; name: string;
} }
interface AcmeAccountActorMetadata {
profileId: string;
accountId: string;
}
interface AcmeProfileActorMetadata {
profileId: string;
}
interface UserActor { interface UserActor {
type: ActorType.USER; type: ActorType.USER;
metadata: UserActorMetadata; metadata: UserActorMetadata;
@@ -67,13 +74,25 @@ export interface UnknownUserActor {
type: ActorType.UNKNOWN_USER; type: ActorType.UNKNOWN_USER;
} }
export interface AcmeProfileActor {
type: ActorType.ACME_PROFILE;
metadata: AcmeProfileActorMetadata;
}
export interface AcmeAccountActor {
type: ActorType.ACME_ACCOUNT;
metadata: AcmeAccountActorMetadata;
}
export type Actor = export type Actor =
| UserActor | UserActor
| ServiceActor | ServiceActor
| IdentityActor | IdentityActor
| PlatformActor | PlatformActor
| UnknownUserActor | UnknownUserActor
| KmipClientActor; | KmipClientActor
| AcmeProfileActor
| AcmeAccountActor;
interface GetSecretsEvent { interface GetSecretsEvent {
type: EventType.GET_SECRETS; type: EventType.GET_SECRETS;
@@ -68,6 +68,12 @@ export const LogsTableRow = ({ auditLog, rowNumber, timezone }: Props) => {
{auditLog.actor.type === ActorType.IDENTITY && ( {auditLog.actor.type === ActorType.IDENTITY && (
<Tag label="identity_name" value={auditLog.actor.metadata.name} /> <Tag label="identity_name" value={auditLog.actor.metadata.name} />
)} )}
{auditLog.actor.type === ActorType.ACME_PROFILE && (
<Tag label="acme_profile_id" value={auditLog.actor.metadata.profileId} />
)}
{auditLog.actor.type === ActorType.ACME_ACCOUNT && (
<Tag label="acme_account_id" value={auditLog.actor.metadata.accountId} />
)}
</div> </div>
</Td> </Td>
</Tr> </Tr>