Building an audit trail: enabling audit logs, audit event types, file and index output formats, event filtering, and compliance considerations for GDPR, data retention policies, and access tracking.

Authentication and encryption make access secure. But security isn't complete without accountability: if an incident occurs, you must be able to answer "who accessed what, when, and with what result?". That's the role of audit logging — and that answer is also a legal requirement in many industries (GDPR, SOC 2, HIPAA).
Episode 17 covers audit logging in Elasticsearch: enabling it, event types, output formats (file and index), event filtering so it doesn't burden storage, and compliance practices — GDPR, retention policies, personal data handling, and access tracking.
Audit logging is an Elasticsearch security feature that records security- and access-related activity. Enable it in elasticsearch.yml:
xpack.security.audit.enabled: true
xpack.security.audit.logfile.events.include:
- access_denied
- access_granted
- authentication_failed
- connection_denied
- run_as_granted
- run_as_denied
- anonymous_access_deniedAfter a restart, each selected event is recorded in the audit log file. Because this feature is sensitive to performance and storage, only enable the events you actually need.
Audit events are grouped into several categories:
| Event | Meaning |
|---|---|
authentication_success | Login succeeded |
authentication_failed | Login failed (wrong password) |
access_granted | User was granted access to a resource |
access_denied | User was denied access to a resource |
run_as_granted / run_as_denied | Execution under another identity (impersonation) |
connection_granted / connection_denied | Network connection accepted/rejected |
index_document / document_deleted | Write activity on documents |
security_config_change | Security configuration changes |
Warning
Recording index_document and document_deleted on a cluster with high write traffic can explode the log size and pressure performance. Enable them only when genuinely needed — for example during an investigation, not across the entire production load.
Audit logging writes to a file by default (logs/<cluster>-audit.log). The format is JSON per line, easy to parse:
{"type":"audit","event_type":"authentication_success","principal":"arman","request.method":"POST","request.path":"/_security/user","result.type":"success"}Files are suitable for offline archiving and forensic analysis.
Audit events can also be sent to a dedicated audit index inside Elasticsearch itself — making search and dashboards easy. Additional configuration:
xpack.security.audit.index.settings.enabled: true
xpack.security.audit.index.events.include: [access_denied, access_granted, authentication_failed]Danger
Be careful writing audit logs to the same Elasticsearch index as business data: if the cluster goes down from an incident, you lose the audit trail exactly when you need it most. Best practice: send audits to a separate cluster, or keep them in files and archive periodically. Some organizations use cross-cluster (episode 22) for this.
Not every event deserves to be recorded — for example health check logs that appear every second. Filtering reduces noise and storage:
xpack.security.audit.logfile.events.ignore_filters:
health_check:
users: ["system"]
actions: ["access_granted"]
paths: ["/_cluster/health", "/_nodes/stats"]With the filter above, the system user's access to health check endpoints doesn't enter the audit. Rule of thumb: filter selectively and documented — don't cancel out the benefit of auditing. Security teams usually decide what may be filtered.
GDPR (and other regulations) demands three things from personal data controllers:
Retention isn't just "keep everything forever" — storing personal data longer than needed actually violates GDPR. Apply a layered retention policy:
All of this can be automated with ILM (episode 10) — a delete phase at the end of the lifecycle, plus downsampling/anonymization for data that must be retained.
Before personal data enters Elasticsearch, ask: does this field really need to be indexed? Use the following pattern:
{
"mappings": {
"properties": {
"email": { "type": "keyword", "index": false },
"credit_card": { "type": "keyword", "index": false },
"ip_address": { "type": "ip" }
}
}
}A field with index: false can't be searched — disabling searchability of personal fields from the mapping onward. For data that shouldn't even appear in _source, use an ingest pipeline (episode 12) to strip it before it enters, or FLS from episode 15.
Tip
Compliance is a system, not a feature: retention policies, access control, audit logs, and deletion processes must work as one unit and be tested. Simulate a subject access request (DSAR): can you show all access to a user's data in the last 30 days? If the answer isn't within minutes, your audit logging isn't sufficient.
Enabling all events. Storage and performance break — choose the relevant events.
Audit logs in the same cluster as the data. Lost during an incident — separate the cluster or archive.
Storing personal data indefinitely. Violates GDPR — apply retention with ILM.
Overly aggressive filtering. The audit trail becomes empty — document and get it approved by security.
Indexing searchable personal fields. Consider index: false or remove them in a pipeline.
In episode 17 you mastered audit logging and compliance: enabling audit logs, event categories (authentication, access, run_as, document writes), file and index output, event filtering, and compliance practices — GDPR, layered retention policies with ILM, personal data handling with index: false and pipelines, and access tracking for DSAR.
Key takeaways:
index: false) from the mapping onward.So far we've worked on a small cluster. Time to scale up. In episode 18 we'll cover scaling Elasticsearch clusters: horizontal scaling by adding nodes, shard allocation strategies, the ideal 10–50 GB shard size, hot-warm-cold implementation, when to scale up vs scale out, and SSD vs HDD storage considerations. See you there!