====== Audit Logging ====== **Complexity:** Medium \\ **Duration:** 1-2 hours setup \\ **Compliance:** NIS2, ISO 27001, BSI Basic Protection Compliance-conformant logging of all PKI operations for audits and forensics. ---- ===== Architecture ===== flowchart LR subgraph SOURCES["SOURCES"] S1[CA Operations] S2[API Requests] S3[Admin Actions] S4[System Events] end subgraph COLLECT["COLLECTION"] C1[Syslog] C2[Filebeat] C3[Fluentd] end subgraph STORE["STORAGE"] ST1[(Elasticsearch)] ST2[(Loki)] ST3[S3/Archive] end subgraph ANALYZE["ANALYSIS"] A1[Kibana] A2[Grafana] end S1 & S2 & S3 & S4 --> C1 & C2 C1 & C2 & C3 --> ST1 & ST2 ST1 --> A1 ST2 --> A2 ST1 & ST2 --> ST3 style ST1 fill:#e3f2fd style A1 fill:#e8f5e9 ---- ===== Audit Events ===== | Category | Event | Criticality | |----------|-------|-------------| | **Certificate** | Issued | Info | | **Certificate** | Renewed | Info | | **Certificate** | Revoked | High | | **CA** | CRL generated | Info | | **CA** | CA key used | Medium | | **Admin** | Login | Medium | | **Admin** | Configuration change | High | | **System** | Service start/stop | Medium | | **Security** | Failed authentication | High | ---- ===== Log Format ===== ==== Structured JSON Format ==== { "timestamp": "2024-12-15T10:30:00.000Z", "level": "INFO", "event_type": "certificate_issued", "source": "ca-service", "actor": { "id": "operator-01", "ip": "10.0.0.50", "role": "pki-operator" }, "subject": { "type": "certificate", "serial": "01:23:45:67:89:AB:CD:EF", "cn": "server.example.com", "validity_days": 365 }, "details": { "algorithm": "ML-DSA-65", "mode": "Hybrid", "issuer_serial": "AA:BB:CC:DD", "request_id": "REQ-2024-12345" }, "result": "success" } ==== Syslog Format ==== Dec 15 10:30:00 ca-server pki-ca[12345]: [INFO] certificate_issued actor=operator-01 serial=01:23:45:67 cn=server.example.com algo=ML-DSA-65 result=success ---- ===== Linux: Rsyslog + ELK ===== ==== Rsyslog Configuration ==== # /etc/rsyslog.d/50-pki.conf # PKI logs in separate file :programname, isequal, "pki-ca" /var/log/pki/ca.log :programname, isequal, "pki-ocsp" /var/log/pki/ocsp.log # JSON template for Elasticsearch template(name="pki-json" type="list") { constant(value="{") constant(value="\"timestamp\":\"") property(name="timereported" dateFormat="rfc3339") constant(value="\",\"host\":\"") property(name="hostname") constant(value="\",\"program\":\"") property(name="programname") constant(value="\",\"message\":\"") property(name="msg" format="json") constant(value="\"}\n") } # Send to Elasticsearch module(load="omelasticsearch") action(type="omelasticsearch" server="elasticsearch.example.com" serverport="9200" template="pki-json" searchIndex="pki-audit" bulkmode="on" queue.type="linkedlist" queue.size="10000" queue.dequeuebatchsize="300" action.resumeRetryCount="-1") ==== Filebeat Configuration ==== # /etc/filebeat/filebeat.yml filebeat.inputs: - type: log enabled: true paths: - /var/log/pki/*.log json.keys_under_root: true json.add_error_key: true fields: log_type: pki-audit output.elasticsearch: hosts: ["elasticsearch.example.com:9200"] index: "pki-audit-%{+yyyy.MM.dd}" setup.template.name: "pki-audit" setup.template.pattern: "pki-audit-*" ---- ===== Application Logging (C#) ===== // PkiAuditLogger.cs using Microsoft.Extensions.Logging; using System.Text.Json; public class PkiAuditLogger { private readonly ILogger _logger; public PkiAuditLogger(ILogger logger) { _logger = logger; } public void LogCertificateIssued( X509Certificate2 cert, string actor, string requestId, CryptoMode mode) { var auditEvent = new { event_type = "certificate_issued", timestamp = DateTimeOffset.UtcNow, actor = new { id = actor }, subject = new { serial = cert.SerialNumber, cn = cert.GetNameInfo(X509NameType.SimpleName, false), not_after = cert.NotAfter }, details = new { algorithm = cert.SignatureAlgorithm.FriendlyName, mode = mode.ToString(), request_id = requestId }, result = "success" }; _logger.LogInformation( "AUDIT: {Event}", JsonSerializer.Serialize(auditEvent)); } public void LogCertificateRevoked( string serial, X509RevocationReason reason, string actor) { var auditEvent = new { event_type = "certificate_revoked", timestamp = DateTimeOffset.UtcNow, actor = new { id = actor }, subject = new { serial }, details = new { reason = reason.ToString() }, result = "success" }; _logger.LogWarning( "AUDIT: {Event}", JsonSerializer.Serialize(auditEvent)); } } ---- ===== Elasticsearch Index Template ===== PUT _index_template/pki-audit { "index_patterns": ["pki-audit-*"], "template": { "settings": { "number_of_shards": 1, "number_of_replicas": 1, "index.lifecycle.name": "pki-audit-policy" }, "mappings": { "properties": { "timestamp": { "type": "date" }, "level": { "type": "keyword" }, "event_type": { "type": "keyword" }, "source": { "type": "keyword" }, "actor.id": { "type": "keyword" }, "actor.ip": { "type": "ip" }, "actor.role": { "type": "keyword" }, "subject.type": { "type": "keyword" }, "subject.serial": { "type": "keyword" }, "subject.cn": { "type": "text" }, "result": { "type": "keyword" } } } } } ==== ILM Policy (Retention) ==== PUT _ilm/policy/pki-audit-policy { "policy": { "phases": { "hot": { "actions": { "rollover": { "max_size": "10GB", "max_age": "7d" } } }, "warm": { "min_age": "30d", "actions": { "shrink": { "number_of_shards": 1 }, "forcemerge": { "max_num_segments": 1 } } }, "cold": { "min_age": "90d", "actions": { "allocate": { "require": { "data": "cold" } } } }, "delete": { "min_age": "365d", "actions": { "delete": {} } } } } } ---- ===== Kibana Dashboards ===== ==== Audit Overview ==== { "title": "PKI Audit Dashboard", "panels": [ { "title": "Events per Day", "type": "visualization", "visState": { "type": "line", "aggs": [ { "type": "date_histogram", "field": "timestamp", "interval": "1d" } ] } }, { "title": "Events by Type", "type": "visualization", "visState": { "type": "pie", "aggs": [ { "type": "terms", "field": "event_type" } ] } }, { "title": "Revocations", "type": "visualization", "visState": { "type": "metric", "aggs": [ { "type": "count", "filter": { "term": { "event_type": "certificate_revoked" } } } ] } } ] } ---- ===== Compliance Requirements ===== | Standard | Requirement | Implementation | |----------|-------------|----------------| | **NIS2 Art. 21** | Incident logging | Log all PKI events | | **ISO 27001 A.12.4** | Log integrity | Tamper-proof storage | | **BSI C5** | Retention | Min. 1 year | | **GDPR Art. 30** | Processing records | Access logs | ---- ===== Log Archiving ===== #!/bin/bash # /usr/local/bin/archive-pki-logs.sh # Archive logs older than 90 days find /var/log/pki -name "*.log" -mtime +90 -exec gzip {} \; # Upload archive to S3 aws s3 sync /var/log/pki/*.gz s3://pki-audit-archive/$(date +%Y/%m)/ # Delete local archives older than 365 days find /var/log/pki -name "*.gz" -mtime +365 -delete ---- ===== Checklist ===== | # | Checkpoint | Done | |---|------------|------| | 1 | Log format defined (JSON) | | | 2 | All PKI events logged | | | 3 | Central collection (ELK/Loki) | | | 4 | Retention policy configured | | | 5 | Dashboard created | | | 6 | Archiving set up | | | 7 | Compliance review | | ---- ===== Related Documentation ===== * [[.:alerting-setup|Alerting Setup]] - Notifications * [[en:int:pqcrypt:business:compliance|Compliance]] - Regulatory requirements * [[en:int:pqcrypt:administrator:betrieb|Operations]] - System maintenance ---- << [[.:revocation-check|<- Revocation Check]] | [[.:alerting-setup|-> Alerting Setup]] >> ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional// {{tag>audit logging elk elasticsearch compliance nis2 operator}}