====== 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}}