Skip to content

Logging and incident handling

PKIFactor writes two kinds of records: technical logs, for operating the platform, and the audit trail, which records who did what and when. Both are written as structured JSON, filtered for secrets before they are written, and the audit trail can be forwarded to a SIEM.

Technical logs

Format

The backend writes one JSON object per line:

{"timestamp": "2026-10-26T09:14:03.512Z", "level": "WARNING", "logger": "PKIFactor.PKI",
 "message": "...", "context": {"trace_id": "5f0c...",
 "client_ip": "192.0.2.10", "origin": "network", "component": "api"},
 "src": "backend/connectors/...:642 _request"}
Field Meaning
timestamp UTC, millisecond precision
level, logger Severity and source module
context.trace_id Identifier of the request, shared by the frontend and the backend
context.user The signed-in user, taken from the verified session (since 1.8.29; never from a value sent by the browser)
context.client_ip Address of the client (see the note below)
src File, line and function, for warnings and errors
exception Stack trace, for errors

Source addresses

Since version 1.8.29 the address recorded in technical logs, in sign-in audit events and for the sign-in rate limit is the client's: nginx sets it (X-Real-IP, replacing any value sent by the client), the frontend relays it, and the backend trusts it only from an internal peer. Before 1.8.29 these records held the address of the proxy container. Other audit events may still record the internal peer; the nginx access log (access.log on the volume pkifactor_nginx_logs) always has the client address.

PKIFACTOR_LOG_FORMAT=text switches the general logs to plain text; the audit trail stays JSON whatever this setting.

Where they are

Logs go to the container output (docker logs pkifactor_backend) and to files in /app/backend/logs, on the persistent volume pkifactor_audit_logs:

File Content
audit.log The audit trail (always JSON)
auth.log, api.log, pki.log, credential.log, db.log, server.log Technical logs per area
error.log, access.log Errors, HTTP accesses (text format)
siem_deadletter.log Audit events not yet delivered to the SIEM

Files rotate at midnight and are kept for PKIFACTOR_LOG_RETENTION_DAYS days (7 by default). Keep the audit trail longer in your SIEM.

To limit noise, a message repeated more than 10 times in a minute is written once with a count (PKIFACTOR_LOG_REPEAT_MAX); errors and the audit trail are never reduced. Health probes are left out of the access log.

Tracing a failure

  • Every response carries an X-Trace-ID header. When an unexpected error occurs, the user sees a short reference (the first eight characters of the trace identifier) instead of internal details; search the logs for it.
  • Unexpected errors are logged with their probable origin: product (PKIFactor itself), external (a device or third-party service), network (timeout, DNS, TLS), configuration (refused credentials, missing object) or user (invalid input). This tells the support team which side to look at first.
  • Error responses never contain stack traces, SQL fragments or internal addresses.

The audit trail

What is recorded

Each event records:

Who What When and where
The actor (e-mail address, or system for the worker) Event name, action, resource type and identifier, outcome (success or failure), reason, sanitized details UTC timestamp, source address, trace identifier

Main event families:

Area Examples
Sessions LOGIN_SUCCESS, LOGIN_FAILED, LOGOUT, PASSWORD_CHANGED, PASSWORD_CHANGE_FAILED, ACCESS_DENIED
Certificates CERTIFICATE_REQUEST_PENDING, CERTIFICATE_ISSUED, CERTIFICATE_APPROVED_ISSUED, CERTIFICATE_REJECTED, CERTIFICATE_REVOKED, CERTIFICATE_TRANSFERRED, CERTIFICATE_ADOPTED, CERT_EARLY_RENEWAL_REQUESTED, RENEW_IDENTITY_CHANGED, CERT_PRIVATE_KEY_EXPORTED
Issuance policy POLICY_BLOCK, POLICY_REQUIRE_APPROVAL, POLICY_AUTO_ALLOWED, POLICY_EVAL_ERROR
Approvals APPROVAL_CLAIMED, APPROVAL_RELEASED, APPROVAL_DEMANDE_ALTEREE (request changed after approval), APPROVAL_OVERRIDE (decision by a non-validator administrator), VALIDATOR_DELEGATION_CREATED, VALIDATOR_DELEGATION_REVOKED
Administration ADMIN_CREATE_USER, ADMIN_UPDATE_ROLE, ADMIN_UPDATE_STATUS, ADMIN_RESET_PASSWORD, ADMIN_UPDATE_AUDIT_SCOPE, OPERATOR_ACCESS_UPDATED, organization, profile, team and validator changes, SETTINGS_UPDATED
Access control ORG_SCOPE_DENIED
Keys and backups KMS_PROVIDER_ACTIVATED, KMS_PROVIDER_MIGRATED, KMS_DEK_ROTATED, KMS_RELOADED, BACKUP_CREATED, BACKUP_FAILED, RESTORE_COMPLETED, RESTORE_FAILED
Platform LICENSE_ACTIVATED, LICENSE_QUOTA_THRESHOLD, LICENSE_EXPIRY_ALERT, SERVICE_TLS_REPLACED, SERVICE_TLS_AUTORENEW_FAILED, CLUSTER_RESTART, LOGS_PURGED
Integrations and gateways SERVICENOW_INBOUND_REQUEST, SERVICENOW_INBOUND_REQUEST_REFUSED, SERVICENOW_INBOUND_AUTH_FAILED, ACME_EAB_CREATED, EST_BASIC_UNVERIFIED, SCEP_UNAUTHENTICATED_BLOCKED
Certificate Transparency CT_ALERT, CT_ALERT_QUALIFIED, CT_RUN

Exporting a private key (PKCS#12 download) has its own event with the certificate, the actor and the address.

Approval records

Each approval request also keeps, in the database, a snapshot of the request as the validator saw it and its SHA-256 fingerprint. The audit screen recomputes the fingerprint on display and shows whether it still matches (column Integrity). The fingerprint detects a snapshot changed after the fact; it is not a signature, so it does not protect against someone who can write to the database and recompute it.

Who can read it

Role Approval records Security events (audit.log)
Administrator, auditor with Audit scope set to Whole estate (the default) All organizations Yes
Auditor with Audit scope set to Own organisations only Their organizations only No
Operator with the Read the audit trail permission (granted by default) Their organizations only No
Validator, user No No

The screens and exports (CSV, JSON) are described in Audit trail.

What is never logged

Before an audit event is written, its details are sanitized:

  • fields whose name contains password, secret, token, api_key, private_key, client_secret, passphrase, encryption_key, credential (and a few more), and fields named dek, kek or wrapped_dek, are replaced by ***REDACTED***, at any depth;
  • any value that looks like a private key (PEM block) is replaced, whatever its field name;
  • line breaks are escaped, so a value cannot forge a new log line.

Every log file and the container output also pass through a filter that removes private key blocks, CSRs, encrypted values, session tokens, and password=...-style pairs from any message.

Certificates and public keys are not secrets and can appear in logs.

Forwarding to a SIEM

Each audit event is forwarded as it is written, over UDP, TCP or TCP with TLS, in CEF or syslog (RFC 5424) with JSON data. Configuration: SIEM and syslog.

Delivery is not allowed to block an operation, and no event is lost silently:

  • an event that cannot be delivered is appended to siem_deadletter.log, and the failure is logged;
  • the worker replays that file every 2 minutes once the collector answers, and keeps only the events that still fail;
  • audit.log stays the local reference, independently of the SIEM.

Incident handling hooks

Signal Use
GET /health/ready ready, degraded (KMS unavailable, issuance suspended) or HTTP 503 (database unreachable or schema error). The probe needs no authentication and returns only the state. Point your monitoring and load balancer at it
SIEM rules Alert on LOGIN_FAILED bursts, ORG_SCOPE_DENIED, APPROVAL_OVERRIDE, CT_ALERT, CERT_PRIVATE_KEY_EXPORTED, KMS_*, RESTORE_*, ADMIN_UPDATE_ROLE, SETTINGS_UPDATED outside change windows
ServiceNow A failed deployment, a refused key custody or an expiry warning opens an incident; a device that needs a manual installation step opens a change request. A repeated event updates the open ticket instead of opening another (ServiceNow)
E-mail Expiry and approval notifications (E-mail and notifications)

First steps after a suspected compromise

  1. Deactivate the accounts concerned (Administration workspace, Governance > Users): their tokens stop working immediately. Resetting a local account's password also ends every session opened before the reset.
  2. Export the audit trail for the period (Oversight workspace, Compliance > Audit Trail) and keep a copy of audit.log before it rotates.
  3. Search the SIEM by actor and trace identifier, and the nginx access log for client addresses.
  4. If a platform secret may have leaked, rotate it (Secrets and key management); if a certificate's private key may have leaked, revoke the certificate.
  5. Take an appliance backup of the state for analysis, then restore a known good state if needed (Backup and restore).