====== Audit logging ====== **Complessità:** Media \\ **Durata:** 1-2 ore per il setup \\ **Compliance:** NIS2, ISO 27001, AGID Registrazione conforme alla compliance di tutte le operazioni PKI per audit e analisi forense. ---- ===== Architettura ===== flowchart LR subgraph SOURCES["📝 FONTI"] S1[Operazioni CA] S2[Richieste API] S3[Azioni Admin] S4[Eventi sistema] end subgraph COLLECT["📥 RACCOLTA"] C1[Syslog] C2[Filebeat] C3[Fluentd] end subgraph STORE["💾 ARCHIVIAZIONE"] ST1[(Elasticsearch)] ST2[(Loki)] ST3[S3/Archivio] end subgraph ANALYZE["🔍 ANALISI"] 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 ---- ===== Eventi di audit ===== | Categoria | Evento | Criticità | |-----------|--------|-----------| | **Certificato** | Emesso | Info | | **Certificato** | Rinnovato | Info | | **Certificato** | Revocato | Alta | | **CA** | CRL generata | Info | | **CA** | Chiave CA utilizzata | Media | | **Admin** | Login | Media | | **Admin** | Modifica configurazione | Alta | | **Sistema** | Avvio/Arresto servizio | Media | | **Sicurezza** | Autenticazione fallita | Alta | ---- ===== Formato log ===== ==== Formato JSON strutturato ==== { "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" } ==== Formato Syslog ==== 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 ===== ==== Configurazione Rsyslog ==== # /etc/rsyslog.d/50-pki.conf # Log PKI in file separato :programname, isequal, "pki-ca" /var/log/pki/ca.log :programname, isequal, "pki-ocsp" /var/log/pki/ocsp.log # Template JSON per 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") } # Invio a 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") ==== Configurazione Filebeat ==== # /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-*" ---- ===== Logging applicativo (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)); } } ---- ===== Template indice Elasticsearch ===== 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" } } } } } ==== Policy ILM (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": {} } } } } } ---- ===== Dashboard Kibana ===== ==== Panoramica audit ==== { "title": "PKI Audit Dashboard", "panels": [ { "title": "Eventi per giorno", "type": "visualization", "visState": { "type": "line", "aggs": [ { "type": "date_histogram", "field": "timestamp", "interval": "1d" } ] } }, { "title": "Eventi per tipo", "type": "visualization", "visState": { "type": "pie", "aggs": [ { "type": "terms", "field": "event_type" } ] } }, { "title": "Revoche", "type": "visualization", "visState": { "type": "metric", "aggs": [ { "type": "count", "filter": { "term": { "event_type": "certificate_revoked" } } } ] } } ] } ---- ===== Requisiti di compliance ===== | Standard | Requisito | Implementazione | |----------|-----------|-----------------| | **NIS2 Art. 21** | Registrazione incidenti | Log di tutti gli eventi PKI | | **ISO 27001 A.12.4** | Integrità log | Storage tamper-proof | | **AGID** | Conservazione | Min. 1 anno | | **GDPR Art. 30** | Registro trattamenti | Log degli accessi | ---- ===== Archiviazione log ===== #!/bin/bash # /usr/local/bin/archive-pki-logs.sh # Archiviare log più vecchi di 90 giorni find /var/log/pki -name "*.log" -mtime +90 -exec gzip {} \; # Upload archivio su S3 aws s3 sync /var/log/pki/*.gz s3://pki-audit-archive/$(date +%Y/%m)/ # Eliminare archivi locali più vecchi di 365 giorni find /var/log/pki -name "*.gz" -mtime +365 -delete ---- ===== Checklist ===== | # | Punto di verifica | ✓ | |---|-------------------|---| | 1 | Formato log definito (JSON) | ☐ | | 2 | Tutti gli eventi PKI registrati | ☐ | | 3 | Raccolta centralizzata (ELK/Loki) | ☐ | | 4 | Policy Retention configurata | ☐ | | 5 | Dashboard creata | ☐ | | 6 | Archiviazione configurata | ☐ | | 7 | Review compliance | ☐ | ---- ===== Documentazione correlata ===== * [[.:alerting-setup|Configurazione alerting]] – Notifiche * [[it:int:pqcrypt:business:compliance|Compliance]] – Requisiti normativi * [[it:int:pqcrypt:administrator:betrieb|Esercizio]] – Manutenzione sistema ---- << [[.:revocation-check|← Verifica revoca]] | [[.:alerting-setup|→ Configurazione alerting]] >> ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional// {{tag>audit logging elk elasticsearch compliance nis2 operator}}