Files
2026-05-09 20:08:13 -05:00

5.3 KiB
Raw Permalink Blame History

GDPR Compliance

This stack processes telemetry that is likely to contain personal data (IPs, user IDs, request bodies, emails). The deployment is hosted by Hetzner in Nuremberg, Germany — all data stays within the EU.

Roles

  • Data Controller: the operator deploying this stack.
  • Data Processor (infrastructure): Hetzner Online GmbH (DE).
  • Sub-processors: none by default.

Document the basis for each tenant under docs/gdpr-compliance.md (per-tenant section to be filled in). Typical bases:

  • Art. 6(1)(f) legitimate interest — operational logging.
  • Art. 6(1)(b) contract performance — telemetry necessary to deliver service.

Required documents

Document Status Notes
Data Processing Agreement with Hetzner sign in Cloud Console required Art. 28
Record of Processing Activities (RoPA) template below required Art. 30
Data Protection Impact Assessment (DPIA) required Art. 35 — high-risk processing
Breach response runbook docs/runbook.md Art. 33/34

Data residency

All telemetry buckets live in nbg1 (Hetzner, Nuremberg). The OpenTofu state lives in Cloudflare R2 — operators must configure R2 to use only EU jurisdictions (Jurisdiction: EU) when creating the state bucket, otherwise state metadata may be replicated outside the EU.

Retention register

Signal Application Retention Bucket Lifecycle Effective Erasure Window
Logs 30 days (Loki) 90 days (S3 lifecycle) 30 days (compactor)
Metrics 90 days (Mimir) 365 days (S3 lifecycle) 90 days (compactor)
Traces 14 days (Tempo) 30 days (S3 lifecycle) 14 days (compactor)

Bucket-level lifecycle is a safety net — application-level retention is the primary erasure mechanism. The wider lifecycle window allows application-level rollback in case of a misconfiguration.

PII minimization

Collector-side scrubbing

Clients run Grafana Alloy with the redaction pipeline at config/alloy/config.alloy.example. Patterns redacted:

  • IPv4 / IPv6 addresses → [REDACTED-IP*]
  • Email addresses → [REDACTED-EMAIL]
  • JWT tokens → [REDACTED-JWT]
  • Bearer tokens in Authorization headers → [REDACTED-TOKEN]
  • Card numbers (PAN, 13–19 digits) → [REDACTED-PAN]
  • UUIDs → [REDACTED-UUID]
  • Lines containing password=, ssn=, cvv=, cvc= → dropped

OTLP attribute scrubbing

The otelcol.processor.attributes block hashes/deletes these attributes before traces reach Tempo:

Attribute Action
enduser.id hashed (correlatable but not reversible)
user.email deleted
client.address deleted
http.request.header.authorization deleted
http.request.header.cookie deleted
http.request.body deleted

Label / cardinality discipline

Mimir and Tempo do not support per-record deletion. To stay compliant, no PII may ever appear in metric labels or trace resource attributes. Tenants must use opaque identifiers (UUIDs hashed at the collector, opaque session IDs) — never emails, names, or phone numbers as label values.

Right to erasure (Art. 17)

Signal Mechanism RTO
Logs Loki Delete API via playbooks/gdpr-purge.yml hours
Metrics Retention only — short window + label discipline ≤90 days
Traces Retention only — 14-day window ≤14 days

Document each erasure in /var/log/observability/gdpr-audit.log (the playbook appends automatically). Notify the data subject within one month per Art. 12(3).

Encryption

Layer Mechanism
In transit (client → server) WireGuard (ChaCha20-Poly1305)
In transit (server → S3) TLS 1.2+
At rest (local WAL/Grafana DB) LUKS2
At rest (S3) Hetzner SSE

Access control & audit

  • WireGuard: each peer has its own key; revoke by removing from wg0.conf.
  • Host firewall: nftables with default-drop input policy. Service ports are bound to 10.8.0.1 (wg0) and unreachable on the public interface. SSH and WireGuard are restricted to administrator CIDRs (admin_allow_ipv4 / admin_allow_ipv6) and rate-limited at the kernel.
  • fail2ban: brute-force defense for SSH (jail sshd) plus a recidive jail that long-bans repeat offenders. Bans are enforced via fail2ban's own nftables table (inet f2b-table).
  • Grafana: [auditing] enabled — all dashboard / API actions logged to /var/log/grafana/audit.log with rotation.
  • SSH: ed25519 keys only, root password auth disabled.
  • Tenant isolation: enforced by X-Scope-OrgID at Mimir/Loki/Tempo plus Grafana Org RBAC.

Breach response (Art. 33/34)

72-hour notification to the Bayerisches Landesamt für Datenschutzaufsicht (BayLDA) — Bavaria's supervisory authority. Procedure documented in docs/runbook.md § Breach Response.

RoPA template

For each tenant, fill in:

  • Name & contact of controller
  • Categories of data subjects
  • Categories of personal data processed in telemetry
  • Recipients (none — internal only)
  • Transfers outside EEA (none)
  • Retention periods (per signal — see above)
  • Technical & organisational measures (this document)