Релиз nxs-anomaly: отечественная альтернатива Grafana OnCall для управления дежурствами, маршрутизации оповещений и эскалации инцидентов. Доступен на GitHub
Все статьи

nxs-data-anonymizer: анонимизация данных для тестовых и динамических окружений

Удобный инструмент для анонимизации баз данных

Время чтения
7 минут
Раздел
Инструменты
nxs-data-anonymizer: анонимизация данных для тестовых и динамических окружений

nxs-data-anonymizer

При разработке и тестировании приложения часто требуется несколько окружений: production, stage, тестовые и динамические среды. Для каждого из них необходима база данных, максимально приближенная к боевой.

Использовать пустую базу неудобно: на ней невозможно полноценно проверить работу приложения. Синтетические данные требуют отдельной подготовки и не всегда позволяют воспроизвести реальные сценарии.

При этом использовать данные непосредственно из production нельзя, поскольку в базе могут находиться чувствительные данные.

Одним из решений становится создание копии production-базы с предварительной анонимизацией данных. Для автоматизации этого процесса НИКСИС разработал инструмент nxs-data-anonymizer.

Зачем нужна анонимизация данных

Один из вариантов — один раз скопировать production-базу, удалить из неё чувствительные данные и использовать подготовленную БД для разработки.

Однако такой подход имеет недостатки. Если несколько разработчиков работают с одной базой, изменения одного человека могут повлиять на работу остальных.

Другой вариант — использовать заранее подготовленный и очищенный дамп для развёртывания изолированных окружений. Но структура базы и сами данные постоянно меняются. Поэтому подготовку свежего дампа приходится регулярно повторять.

Ручная обработка базы в таком случае требует времени и увеличивает затраты, а также влияет на Time-to-Market.

Для автоматизации этого процесса можно использовать анонимайзеры. Это могут быть как простые скрипты на PHP или Bash, так и специализированные инструменты.

Почему появился nxs-data-anonymizer

В работе Nixys часто используются две СУБД — PostgreSQL и MySQL.

Для PostgreSQL используется решение от Evrone. На момент разработки nxs-data-anonymizer оно не поддерживало MySQL, поэтому для MySQL приходилось использовать собственные Bash-скрипты.

Проблема такого подхода заключается в отсутствии единого решения. Скрипты приходилось адаптировать практически под каждый проект. В результате появилось множество вариантов исходного кода, а при подключении к новому проекту инженерам требовалось разбираться в конкретной реализации практически с нуля.

Поэтому был разработан собственный инструмент, который можно было использовать как готовое решение в разных проектах.

Разработка, тестирование и подготовка инструмента заняли около месяца. Изначально nxs-data-anonymizer создавался только для MySQL, однако затем его функциональность была расширена поддержкой PostgreSQL.

Поскольку MySQL был первой поддерживаемой СУБД, примеры ниже приведены для него. Информация по PostgreSQL доступна на странице проекта в GitHub.

Основные идеи

Решение получилось достаточно гибким и простым в эксплуатации, и строится на следующих основных идеях:


1. Потоковая обработка. Инструменту не обязательно предварительно сохранять исходный дамп на диске. Данные могут передаваться в stdin, изменяться на лету и выводиться через stdout. Благодаря этому nxs-data-anonymizer можно непосредственно встроить в цепочку команд между двумя pipe.

2. Go templates. Правила замены значений задаются с помощью Go templates. Подход аналогичен шаблонам, которые используются в Helm. При этом доступны привычные функции, в том числе функции генерации случайных строк и чисел.

3. Условия и значения других ячеек. Фильтры могут учитывать значения других ячеек той же строки. Это позволяет выполнять разные подстановки в зависимости от исходного значения данных.

4. Проверка уникальности данных. При генерации новых значений, например API-ключей, может возникнуть ситуация, когда два случайно созданных значения совпадут.

Если колонка в БД должна содержать уникальные значения, такой дамп невозможно будет загрузить.

nxs-data-anonymizer позволяет указать, что генерируемые значения должны быть уникальными.

Пример анонимизации MySQL

Предположим, в production есть таблица users:

id - username - api_key
1 - admin - epezyj0cj5rqrdtxklnzxr3f333uibtz6avek7926141t1c918
2 - alice - 2od4vfsx2irj98hgjaoi6n7wjr02dg79cvqnmet4kyuhol877z
3 - bob - owp7hob5s3o083d5hmursxgcv9wc4foyl20cbxbrr73egj6jkx

Необходимо получить анонимизированную копию со следующими правилами:
  • для пользователя admin сохранить имя и заменить api_key на заранее заданное значение, отличающееся от production;
  • для остальных пользователей заменить username на значение формата user_N, где N — идентификатор пользователя;
  • для остальных пользователей сгенерировать случайные и уникальные api_key.

Для этого используется конфигурация:

filters:
users:
columns:
username:
value: "{{ if eq .Values.username \"admin\" }}{{ .Values.username }}{{ else }}user_{{ .Values.id }}{{ end }}"
api_key:
value: "{{ if eq .Values.username \"admin\" }}preset_admin_api_key{{ else }}{{- randAlphaNum 50 | nospace | lower -}}{{ end }}"
unique: true

После этого production-дамп можно пропустить через nxs-data-anonymizer и сразу загрузить в dev:

mysqldump -u root -ppassword prod | /path/to/nxs-data-anonymizer -t mysql -c /path/to/nxs-data-anonymizer.conf | mysql -u root -ppassword dev
В результате в dev будет получена таблица:

id - username - api_key
1 - admin - preset_admin_api_key
2 - user_2 - dhx4mccxyd8ux5uf1khpbqsws8qqeqs4efex1vhfltzhtjcwcu
3 - user_3 - lgkkq3csskuyew8fr52vfjjenjzudokmiidg3cohl2bertc93x

Таким образом, production-данные сохраняют необходимую структуру и содержание для работы приложения, но чувствительные значения заменяются.

Использование в CI/CD

Что касается использования инструмента в реальных задачах, то там не намного сложнее.

Рассмотрим пример, в который включим наиболее распространённые случаи использования анонимизации данных, а затем приведём те части pipeline для GitLab, которые это реализуют. 

Есть микросервис, который для хранения данных использует MySQL. 

Для разработки используется два окружения — production и stage. В stage должна быть база, максимально приближённая к продакшену, но поскольку к этому окружению имеет доступ большое количество человек, то данные должны быть фейковыми. 

Ещё в проекте есть динамические окружения, которые создаются и разворачиваются при появлении нового бранча с именем в специальном формате. Там тоже в MySQL должны быть фейковые данные. 

И последний штрих — это локальные среды разработчиков. Не важно, как они будут разворачиваться, но данные для нашего микросервиса тоже нужно анонимизировать. 

Решение этой задачи может быть следующим:

1. При релизе в прод, например по специальному тегу в Git, сначала выполняется стандартный для таких случаев набор действий: сборка приложения, различные тесты, деплой в куб, запуск миграций и прочее. 

2. Затем с помощью nxs-data-anonymizer происходит сбор дампа боевой базы и её анонимизация. Эта же стадия должна включать в себя возможность ручного запуска job по обновлению анонимизированного дампа.

3. Полученный дамп загружается в нужное хранилище, например S3. Никакого версионирования тут не используется — нужна только последняя актуальная копия.

4. Если БД в stage тоже необходимо обновлять, не важно автоматически или вручную, то из хранилища берётся последняя актуальная версия дампа и просто загружается в stage.

5. Аналогично происходит и для динамических, и для локальных окружений — просто используются анонимизированные дампы продакшена из хранилища, к которым имеет доступ вся команда разработки.

Графически это описание будет таким:


GitLab CI

А вот и интересующие нас моменты описанного выше решения.

Начнём со стадии anonymize, которая запускается автоматически сразу после завершения деплоя приложения в прод и миграций БД:

anonymize:
stage: anonymize
image: nixyslab/nxs-data-anonymizer:latest
variables:
GIT_STRATEGY: none
MYSQL_HOST: ${MYSQL_HOST_PROD}
MYSQL_USER: ${MYSQL_USER_PROD}
MYSQL_PASSWORD: ${MYSQL_PASS_PROD}
before_script:
- echo "${S3CMD_CFG}" > ~/.s3cmd
- echo "${NXS_DA_CFG}" > /nxs-data-anonymizer.conf
script:
- mysqldump -h ${MYSQL_HOST} -u ${MYSQL_USER} -p${MYSQL_PASSWORD} ${MYSQL_DATABASE} | /nxs-data-anonymizer -t mysql -c /nxs-data-anonymizer.conf | gzip | s3cmd put - s3://bucket/anondump.sql.gz
only:
- /^v.*$/
except:
- branches
- merge_requests

Далее уже на эту БД можно накатывать миграции для новых версий приложения и проверять, как они отработают на проде при релизе, сводя к минимуму неприятные сюрпризы.

Инструмент легко встраивается в CI/CD любой платформы, будь то GitLab CI, GitHub Actions или что-то ещё.

Ограничения

Здесь описан наиболее распространённый относительно простой случай.

Один из минусов такого подхода — это время на разворачивание дампов больших БД.

Что дальше?

На момент публикации статьи были выделены следующие фичи, которые планировалось реализовать в первую очередь:

  • Удаление таблиц и строк в таблицах из результирующего дампа. Иногда требуется не только изменить какие-то реальные данные, но и удалить их. Например, когда делается дамп БД таск-трекера, нужно полностью удалить некоторые проекты со всеми их задачами.
  • Глобальные переменные. Это специальный блок в конфигурационном файле, который будет содержать значения разных типов — строки, словари и прочее. Эти данные можно будет использовать в любом фильтре. Если при анонимизации имён пользователей хочется получать что-то более приближённое к реальности, чем user_N, эта возможность позволит это сделать.

Свои идеи и предложения по развитию инструмента можно отправить разработчикам проекта.

Оставьте заявку, чтобы обсудить проект

Ваши контакты
О вашем проекте

Нажав на кнопку, соглашаюсь на обработку персональных данных, Ознакомлен со всеми документами, размещенными на сайте

См. Политику обработки персональных данных
См. Пользовательское соглашение