Inhaltsverzeichnis

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<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));
    }
}

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


« ← Verifica revoca | → Configurazione alerting »


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