Inhaltsverzeichnis

Audit-Logging

Komplexität: Mittel
Dauer: 1-2 Stunden Setup
Compliance: NIS2, ISO 27001, BSI-Grundschutz

Compliance-konforme Protokollierung aller PKI-Operationen für Audits und Forensik.


Architektur

flowchart LR subgraph SOURCES["📝 QUELLEN"] S1[CA Operations] S2[API Requests] S3[Admin Actions] S4[System Events] end subgraph COLLECT["📥 SAMMLUNG"] C1[Syslog] C2[Filebeat] C3[Fluentd] end subgraph STORE["💾 SPEICHERUNG"] ST1[(Elasticsearch)] ST2[(Loki)] ST3[S3/Archive] end subgraph ANALYZE["🔍 ANALYSE"] 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-Ereignisse

Kategorie Ereignis Kritikalität
———–———-————–
Zertifikat Ausgestellt Info
Zertifikat Erneuert Info
Zertifikat Widerrufen Hoch
CA CRL generiert Info
CA CA-Schlüssel verwendet Mittel
Admin Login Mittel
Admin Konfigurationsänderung Hoch
System Service Start/Stop Mittel
Security Fehlgeschlagene Auth Hoch

Log-Format

Strukturiertes 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 Konfiguration

# /etc/rsyslog.d/50-pki.conf
 
# PKI-Logs in separater Datei
:programname, isequal, "pki-ca" /var/log/pki/ca.log
:programname, isequal, "pki-ocsp" /var/log/pki/ocsp.log
 
# JSON-Template für 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")
}
 
# An Elasticsearch senden
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 Konfiguration

# /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-*"

Anwendungs-Logging (C#)

// PkiAuditLogger.cs
using Microsoft.Extensions.Logging;
using System.Text.Json;
 
public class PkiAuditLogger
{
    private readonly ILogger _logger;
 
    public PkiAuditLogger(ILogger<PkiAuditLogger> 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-Übersicht

{
  "title": "PKI Audit Dashboard",
  "panels": [
    {
      "title": "Events pro Tag",
      "type": "visualization",
      "visState": {
        "type": "line",
        "aggs": [
          { "type": "date_histogram", "field": "timestamp", "interval": "1d" }
        ]
      }
    },
    {
      "title": "Events nach Typ",
      "type": "visualization",
      "visState": {
        "type": "pie",
        "aggs": [
          { "type": "terms", "field": "event_type" }
        ]
      }
    },
    {
      "title": "Widerrufe",
      "type": "visualization",
      "visState": {
        "type": "metric",
        "aggs": [
          { "type": "count", "filter": { "term": { "event_type": "certificate_revoked" } } }
        ]
      }
    }
  ]
}

Compliance-Anforderungen

Standard Anforderung Umsetzung
———-————-———–
NIS2 Art. 21 Incident-Protokollierung Alle PKI-Events loggen
ISO 27001 A.12.4 Log-Integrität Tamper-proof Storage
BSI C5 Aufbewahrung Min. 1 Jahr
DSGVO Art. 30 Verarbeitungsverzeichnis Zugriffslogs

Log-Archivierung

#!/bin/bash
# /usr/local/bin/archive-pki-logs.sh
 
# Logs älter als 90 Tage archivieren
find /var/log/pki -name "*.log" -mtime +90 -exec gzip {} \;
 
# Archiv nach S3 hochladen
aws s3 sync /var/log/pki/*.gz s3://pki-audit-archive/$(date +%Y/%m)/
 
# Lokale Archive älter als 365 Tage löschen
find /var/log/pki -name "*.gz" -mtime +365 -delete

Checkliste

# Prüfpunkt
———–
1 Log-Format definiert (JSON)
2 Alle PKI-Events geloggt
3 Zentrale Sammlung (ELK/Loki)
4 Retention Policy konfiguriert
5 Dashboard erstellt
6 Archivierung eingerichtet
7 Compliance-Review

Verwandte Dokumentation


« ← Revocation-Check | → Alerting Setup »


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional