Мінімізація даних у поштових логах: маскування IP і адрес для відповідності GDPR
Більшість мейл-адмінів вважають, що GDPR-відповідність логів зводиться до «зберігати 90 днів і видалити». Насправді проблема глибша: Postfix, Dovecot і rsyslog за замовчуванням пишуть повний IP, envelope-адреси й SASL-username у кожен рядок — і кожен такий рядок є персональними даними. Показуємо, як зменшувати деталізацію в момент запису, а не постфактум.
EvilMail Team22 липня 2026 р.11 хв читання
Ось один рядок з /var/log/mail.log на робочому MX:
Тут чотири одиниці персональних даних: клієнтський IP, PTR-ім'я хоста, SASL-username і — рядком нижче в qmgr — envelope-sender. Не «технічна телеметрія», а персональні дані в розумінні ст. 4(1) GDPR, причому в необробленому вигляді, який щойно торкнувся диска.
І ось теза, з якою більшість адмінів не згодні, поки не впораються з першим запитом на стирання: retention тут вторинний. Скільки ви тримаєте лог — 3 дні чи 90 — це третій за важливістю важіль. Первинне питання — скільки PII взагалі потрапляє в рядок у момент запису. Логи, які ніколи не містили повного IP, неможливо злити, неможливо помилково віддати за судовим запитом і не треба «стирати на вимогу». Це і є data protection by design зі ст. 25 — не політика, а конфіг.
Що саме в поштових логах є персональними даними
Мінімізація даних у поштових логах під GDPR: маскування IP і адрес — EvilMail Blog
Розберемо типовий життєвий цикл одного листа через Postfix і Dovecot.
`client=...[203.0.113.44]` — IP-адреса відправника. Recital 30 прямо називає online identifiers, включно з IP, персональними даними. Рішення CJEU у справі C-582/14 (Breyer, 2016) закрило дискусію про динамічні адреси: якщо оператор має легальні засоби ідентифікувати особу за IP (а мейл-провайдер їх має — через абузні запити до аплінку), то навіть динамічний IP є персональними даними для цього оператора.
`from=<[email protected]>`, `to=<[email protected]>` з qmgr/smtp — envelope-адреси, дані і про відправника, і про отримувача. Факт листування між двома адресами сам по собі персональні дані.
Message-ID — стабільний ідентифікатор, що дозволяє кореляцію між системами й у часі.
Аргумент «це ж просто службовий журнал» не є законною підставою за замовчуванням. Обробка потребує підстави за ст. 6; для логів це майже завжди legitimate interest (ст. 6(1)(f)), а він вимагає задокументованого балансуючого тесту (LIA) і — за ст. 5(1)(c) — мінімізації: обробляти лише те, що адекватно, релевантно й обмежено необхідним. Повний IP у кожному DEBUG-рядку цей поріг не проходить.
Три важелі мінімізації (і чому deletion — найслабший)
Ставимо каркас, щоб не плутати засоби:
1.Зменшити деталізацію запису — не писати повний IP / повну адресу туди, де достатньо /24 чи домену.
2.Псевдонімізувати те, що лишається — HMAC-хеш username замість plaintext.
3.Обмежити retention — видалити раніше.
Пункти 1 і 2 — це «by design» зі ст. 25. Вони працюють, навіть якщо ротація зламається, диск склонують у бекап або лог витече назовні: там просто немає повних даних. Пункт 3 захищає лише постфактум і лише якщо все інше спрацювало ідеально — а бекапи, реплікації syslog і забутий journald регулярно все псують. Тому будуємо зверху вниз: спершу ріжемо деталізацію, потім псевдонімізуємо, і лише в останню чергу говоримо про строки зберігання.
Маскування IP на рівні pipeline, а не в Postfix
Спокуса — «замаскувати IP у самому Postfix». Не робіть цього. Postfix не вміє анонімізувати IP нативно, а спроби підмінити його через фейкові PTR чи map ламають anti-abuse: postscreen, RBL-логіку, rate-аналіз. IP потрібен процесу в момент рішення про прийом листа. Маскувати треба на етапі транспортування логів — між застосунком і диском, у rsyslog чи Vector.
rsyslog має модуль mmanon саме для цього. Обнуляємо нижні 8 біт IPv4 (виходить /24) і нижні 80 біт IPv6 (виходить /48):
text
module(load="mmanon")
action(type="mmanon"
ipv4.enable="on" ipv4.bits="8" ipv4.mode="zero"
ipv6.enable="on" ipv6.bits="80" ipv6.anonmode="zero")
# після анонімізації — запис на диск
mail.* /var/log/mail.log
ipv4.bits="8" означає «обнулити 8 молодших біт», тобто 203.0.113.44 → 203.0.113.0. Для IPv6 80 біт відрізають host-частину до /48. Зверніть увагу на асиметрію імен параметрів: у IPv4 режим задається через ipv4.mode, у IPv6 — через ipv6.anonmode, це особливість самого модуля. Ключове — mmanon стоїть перед правилом запису, тому на диск лягає вже замаскований рядок. Сирий IP існує тільки в пам'яті rsyslog частки секунди.
Тим, хто вже гонить логи у Loki чи ELK через Vector, те саме роблять VRL-трансформом:
Компроміс /24 свідомий: цього достатньо для гео-дебагу, для виявлення «одна підмережа довбає SMTP-AUTH» і для rate-аналізу, але вже недостатньо, щоб однозначно вказати на конкретного абонента. Це і є пропорційність зі ст. 5(1)(c) у дії.
Обрізання envelope-адрес і зниження детальності журналів
IP — половина справи. Друга половина — не генерувати зайвих рядків із адресами взагалі.
Dovecot за замовчуванням стриманий, але один параметр перетворює журнал на катастрофу:
text
auth_verbose = no
auth_verbose_passwords = no # yes = ПАРОЛЬ у plaintext у логу
mail_debug = no
verbose_ssl = no
auth_verbose_passwords = yes (або sha1) пише в лог сам пароль чи його зліпок при кожній невдалій автентифікації. Якщо він увімкнений у вас у проді — це не мінімізація, це витік, і виправити треба сьогодні.
Postfix — прибираємо надлишкову деталізацію TLS і дебагу:
tls_loglevel 1 пише повну інформацію про кожне TLS-рукостискання; у проді це шум із метаданими, а debug_peer_list із заповненим значенням вмикає DEBUG-трасування для цілих доменів разом із повними адресами.
А там, де в cold-контурі потрібна лише статистика по доменах, обрізаємо local-part тим самим VRL-трансформом, лишаючи перший символ і домен:
Чесний контраргумент: розслідування спаму й фроду, контриб'юція в RBL, реакція на законні судові запити — все це вимагає повного IP і повної адреси. Замаскувати геть усе — означає осліпнути.
Рішення — двоконтурне логування. Короткоживучий «hot»-лог із повними даними (шифрований, доступ обмежений, retention 24–72 год, підстава — legitimate interest зі ст. 6(1)(f) плюс задокументований LIA) і довгоживучий «cold»-лог, уже анонімізований, для аналітики й трендів на 90–180 днів.
Розкладка по полях виглядає так:
client_ip — hot: повний, 48–72 год → cold: /24 (IPv4) чи /48 (IPv6), або взагалі drop.
recipient / sender — hot: повний, 24 год → cold: тільки домен.
sasl_username — hot: повний → cold: HMAC-SHA256 з ключем, що ротується (псевдонім стабільний у межах періоду, але необоротний).
Message-ID — hot: повний → cold: drop.
HMAC із ротованим ключем дає важливу властивість: у межах одного вікна ви бачите, що «псевдонім X» повторюється (можна ловити патерни зловживань), але без ключа звести псевдонім до реальної адреси не можна, а після ротації ключа стара кореляція обривається.
Retention і безпечне видалення
Тепер третій, найслабший важіль. logrotate із правильним maxage для hot-контуру:
rotate 3 без maxage недостатньо: за низького трафіку три ротації можуть покривати тижні. maxage 3 гарантує видалення за віком, а не за кількістю. І пам'ятайте, що rm не стирає дані на звичайній ФС — блоки лишаються. Для незашифрованих томів додавайте shred -u у postrotate, а краще — тримайте /var/log на LUKS, тоді видалення тому робить дані нечитабельними без окремого затирання. Бекапи логів — теж scope GDPR: право на стирання конфліктує з immutable-бекапами, тож або виключайте hot-логи з бекапу, або тримайте бекапи короткими й шифрованими.
Практичний чеклист
grep реальний mail.log і порахуйте PII-поля на рядок — це ваша базова лінія.
Вимкніть auth_verbose_passwords, auth_verbose, mail_debug у Dovecot (перше — критично).
Знизьте smtpd_tls_loglevel і smtp_tls_loglevel до 0, тримайте debug_peer_list порожнім.
Додайте mmanon у rsyslog перед правилом запису на диск (/24 для IPv4, /48 для IPv6).
Розділіть hot і cold pipeline; повний IP живе тільки в hot.
HMAC-псевдонімізуйте username у cold-контурі, ключ ротуйте.
logrotate із maxage 3 на hot-логах.
LUKS для /var/log або shred -u у postrotate для незашифрованих томів.
Задокументуйте LIA для hot-логів — без нього legitimate interest не тримається.
Маскуйте перед записом на диск, а не постобробкою: як тільки сирий рядок ліг у файл, він уже персональні дані на носії, і всі подальші зусилля — це прибирання, а не мінімізація. На evilmail.pro, де через temp-email проходить на порядок більше адрес, ніж у звичайного хостера, це різниця між системою, яку неможливо злити за визначенням, і системою, яку доводиться безперервно чистити.