Привет, Хабр! Это Никита Амельчев и Павел Переслегин. Мы создаём Platform V DataGrid — распределённую базу данных, которая используется в сервисах Сбера и внешних клиентов. В статье расскажем, как мы усилили базовые функции шифрования TDE в нашем продукте и как решали вопрос совмещения полного шифрования и высокой производительности базы данных.

Зачем нужно TDE, и почему мы решили усилить шифрование в Platform V DataGrid

Если компания хранит и обрабатывает персональные и чувствительные данные, например биометрическую, финансовую информацию, данные о здоровье, то она обязана защищать их от раскрытия или утечки. Правила такой защиты регулируются различными стандартами: PCI DSS, GDPR, CCPA и другими.

Согласно этим стандартам одним из обязательных требований защиты персональных данных является шифрование на уровне приложения (data-at-rest). Реализовать такое шифрование можно разными способами, но один из самых надёжных — прозрачное шифрование (англ. TDE, Transparent Data Encryption).

TDE — технология шифрования баз данных на жёстком диске. При этом ни в памяти, ни в процессе передачи данных информация не шифруется. Для поддержки этого метода пользователю не нужно ничего менять в своих скриптах, схемах или приложениях, поэтому шифрование и называется «прозрачным».

TDE считается одним из самых надёжных по многим причинам: защищает данные даже в случае утраты дисков, файлов или резервных копий, ограждает от подмены данных через их изменение в файлах. Это важная функциональность для всех, кому необходимо шифрование посредством базы данных. Например, для финансовых организаций: им нужна сертификация по стандарту PCI DSS, регламентирующему правила защиты данных платёжных карт.

В Platform V DataGrid TDE было реализовано на первых этапах проектирования базы данных. Мы доработали всё до корпоративного уровня надёжности, безопасности и отказоустойчивости Ignite, чьи технологии использовались в Platform V DataGrid, и добавили базовые функции TDE: управление ключами и создание кэшей с шифрованием данных на диске.

Базовые функции удовлетворяли общим требованиям PCI DSS. Но не всем: для полного соответствия стандарту нужно было реализовать дополнительные свойства системы шифрования. Для этого предстояло научить систему двум вещам: менять мастер-ключ и кэш-ключ при компрометации и просто в соответствии с политикой безопасности.

Обе функции должны были работать без остановки кластера и работы с данными, так как помимо стандартов безопасности нужно было соблюсти ещё и требования к производительности базы данных.

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

Этап первый — смена мастер-ключа

Задача

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

Главная сложность заключалась в том, что эту смену нужно было реализовать без остановки кластера. Любая пауза грозила простоем системы и тянула за собой дополнительные сложности. Так, простаивающему кластеру понадобился бы запасной, на который можно было бы увести нагрузку, запасному — ещё один на случай отключения…

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

О мастер-ключах: где хранятся, как ротируются

Различные ключи идентифицируются по имени: master-key-1, master-key-2 и т. д. В Ignite разработан универсальный интерфейс для работы с операциями шифрования — EncryptionSpi. В него были добавлены методы для работы с разными ключами шифрования:

public interface EncryptionSpi extends IgniteSpi {
    // Имя текущего мастер-ключа
    String getMasterKeyName();
    
    // Хэш ключа
    byte[] masterKeyDigest();
    
    // Хэш ключа для нового мастер-ключа
    byte[] masterKeyDigest(String masterKeyName);
    
    // Задаёт новый мастер-ключ для операций шифрования ключей
    void setMasterKeyName(String masterKeyName) throws IgniteSpiException;

    // ...
}

Интерфейс позволяет реализовать хранение мастер-ключей в различных хранилищах, например Java KeyStore, аппаратных модулях безопасности (HSM), облачных сервисах.

«Из коробки» Ignite предоставляет реализацию для Java KeyStore (JKS) — KeystoreEncryptionSpi.

В конфигурации каждого узла указывается путь до хранилища JKS и имя мастер-ключа. Управлять ключами в хранилище можно через стандартную утилиту Java Keytool.

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

Мастер-ключ можно сменить с помощью утилиты администрирования кластером:

control.sh|bat --encryption change_master_key newMasterKeyName,

где newMasterKeyNam — имя нового мастер-ключа. Например, после смены ключа на master-key-2 в логах будет выведено:

Master key successfully changed [masterKeyName=master-key-2]

Также можно сменить через JMX или Java API.

Решение

Смену мастер-ключа в Platform V DataGrid реализовали в два подхода:

  1. Подготовка: проверили доступность нового ключа и его хэша на узлах.

  2. Смена мастер-ключа: установили в SPI новый мастер-ключ, перешифрование кэш-ключей и их запись на диск.

Каждый из этапов — распределённый процесс, для которого было разработано внутреннее API DistributedProcess, учитывающее атомарность результата и возможную нестабильность.

API включает три этапа:

  1. Отправка действия узлам.

  2. Сбор результатов со всех узлов координатором.

  3. Отправка результата на все узлы.

Дальше нужно обеспечить защиту от рисков, например от возможного отключения электричества. Процедура перешифрования затрагивает все кэш-ключи на узле. Чтобы предотвратить сценарий, в котором перешифруется только часть ключей, используем встроенное журналирование (WAL):

  • перешифровываем ключи в памяти;

  • делаем запись в журнал (WAL) с перешифрованными ключами и именем мастер-ключа;

  • обновляем кэш-ключи на диске (Metastorage).

Узел может отключиться на любом из этапов, но при новом старте узла будут восстановлены записи из журнала WAL. Если там найдётся запись (2), которая станет источником изменений. В противном случае узел останется с ключами, зашифрованными старым мастер-ключом.

Бывают ситуации, когда смену нужно осуществить при условии, что часть узлов выведена из кластера. В таком случае узлы, пропустившие смену ключа, не смогут присоединиться к кластеру:

Master key digest differs! Node join is rejected.

Чтобы узлы перед попыткой присоединения к кластеру сменили мастер-ключ на актуальный, нужно запустить узел с системной переменной:

IGNITE_MASTER_KEY_NAME_TO_CHANGE_BEFORE_STARTUP=newMasterKeyName

значение которой — имя актуального мастер-ключа.

Итог

Смена мастер-ключа — необходимое условие PCI DSS. Но даже вне стандарта эта процедура является важным элементом защиты всей системы, потому что:

  • уменьшает объём информации, доступной для криптоанализа;

  • ограничивает ареал распространения угрозы при компрометации ключа;

  • защищает от ошибок в алгоритме, ведущих к сокращению срока жизни ключа.

В нашем случае функция обеспечивала покрытие технической части стандарта. Но для соответствия внутренним требованиям безопасности банка одной смены мастер-ключа было недостаточно. Поэтому мы приступили ко второму этапу операции.

Этап второй — смена кэш-ключа

Задача

Обычно кэш-ключом шифруются данные на диске, в том числе и WAL-сегменты. У каждой кэш-группы свой ключ, но на всех узлах он един. Процедура смены подразумевает полную перезапись всех существующих данных кэш-группы. Это ресурсоёмкая и длительная процедура, которая сказывается на производительности СУБД.

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

План действий

Первое, что пришло в голову — сделать полное перешифрование данных в офлайн-режиме, то есть на неактивном кластере. Для этого делаем полную копию партиций. Расшифровываем с использованием текущего ключа и зашифровываем с использованием нового. Эту же процедуру необходимо проделать с WAL. После завершения копирования всех партиций просто подменяем их.

Вроде бы звучит неплохо, но у такого подхода есть пара недостатков:

  1. Необходимо иметь достаточное количество дискового пространства, чтобы сделать полную копию кэш-группы.

  2. Кластер должен оставаться неактивным весьма продолжительное время.

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

В теории это возможно, а на практике есть много «но»:

  • Процесс онлайн-копирования партиции немного сложнее — необходимо скопировать сам файл партиции и при этом поддерживать синхронизацию его обновлений с оригинальным файлом. То есть фактически дублировать обновления в обе партиции.

  • При этом нужно как можно меньше аффектить текущие операции, а значит процедура копирования данных может занять намного больше времени, чем планировалось.

  • Нужно не забыть перешифровать WAL.

  • В конце процедуры нужно «переключиться» на новые партиции и WAL.

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

Решение

В Platform V DataGrid добавлена возможность работы сразу с двумя ключами. Использован старый ключ для чтения архивных данных, а новые данные начали писать новым. Всё это полностью соответствует стандартам PCI DSS — после смены ключа новые данные должны шифроваться новым ключом.

Такой подход избавил от необходимости специально перешифровывать WAL-сегменты: по мере того как они ротируются, весь WAL оказывается зашифрован новым ключом. То же происходит и с самими данными партиции. Новые данные пишутся новым ключом, а старые перешифровываются сами при обновлении.

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

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

  2. В силу архитектурных особенностей в Platform V DataGrid нет механизма, который помог бы понять, что данные в партиции полностью перезаписались после смены ключа.

Чтобы убрать эти риски, мы добавили отдельный фоновый поток, который занимается перезаписью существующих данных вслед за сменой кэш-ключа. Его задача — пометить страницы партиции как грязные, таким образом заставив Platform V DataGrid перезаписать их на диск.

Прогресс перезаписи страниц сохраняется на специальной странице партиции с метаинформацией (metapage): то есть он устойчив к различного рода отказам и способен продолжать работу с определённого места. Но есть несколько нюансов:

  1. Для каждой изменённой страницы сохраняется её копия в WAL — это необходимо для восстановления в случае сбоя.

Важно убедиться в достаточной глубине WAL-архива. Фоновое перешифрование порождает много дополнительных записей. WAL используется не только для восстановления после сбоя, но, например, для ускорения ребалансировки, поэтому нужно учитывать последствия кратного увеличения интенсивности записи в него.

  1. Фоновый процесс может оказывать влияние на производительность.

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

Итог

Чтобы сменить кэш-ключ, необходимо выполнить команду:

control.sh|bat --encryption change_cache_key cacheName.

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

control.sh|bat --encryption reencryption_status cacheName.

Кроме того, можно просматривать, какие кэш-ключи есть сейчас:

control.sh|bat --encryption cache_key_ids cacheName.

Так как процедура смены кэш-ключа крайне редкая, перед её использованием в промышленной эксплуатации настоятельно рекомендуется предварительно провести нагрузочные тесты и подобрать правильные настройки.

Заключение

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

Эффективность системы подтверждает активная промышленная эксплуатация в Сбере. Сегодня Platform V DataGrid развёрнута более чем на 3 000 серверах и используется в 127 сервисах банка, среди которых платформа кибербезопасности для отслеживания фрод-операций, единый профиль розничного клиента, системы процессинга, кредитного скоринга и виртуальные помощники «Салют».

Комментарии (0)