Любое современное приложение работает с конфиденциальной информацией. Персональные данные пользователей, финансовые данные, внутренние документы компаний — все это хранится, передается и обрабатывается в облачной инфраструктуре. И чем больше критически важных данных оказывается в облаке, тем острее встает вопрос их защиты.
Привет, Хабр! Меня зовут Никита Трунов, я — разработчик команды инфраструктурных сервисов K2 Cloud. Сегодня расскажу вам о нашем новом облачном сервисе управления ключами KMS и как он помогает с шифрованием данных в облаке. В этом материале мы разберемся, какие данные приходится защищать, какие существуют модели доверия к облачному провайдеру и как устроена архитектура современного сервиса управления ключами.
Какие данные в облаке приходится защищать и от кого
Данные могут находиться в одном из трёх «агрегатных» состояний:
in transit — когда они передаются по сети;
in use — когда данные попадают в кэши и регистры процессора, а также в оперативную память;
at rest — данные хранятся на физических носителях (например, на дисках).
С шифрованием in transit все просто — для шифрования сетевого трафика используются всем знакомые протоколы HTTPS, SSH и т.д. В этом случае используются сессионные ключи, то есть нам не нужно задумываться, где они хранятся и как ими управлять.
С in use тоже понятно — некоторые процессоры поддерживают аппаратное шифрование памяти. При этом ключами управляет сам процессор. На практике шифрование in use встречается редко, потому что атаки на такие данные сложно воспроизвести.
А вот данные at rest заставляют нас задуматься о ключах. С одной стороны, нам нужно хранить зашифрованные данные, а с другой — где-то хранить ключи, которыми мы шифруем эти данные. Именно поэтому шифрование at rest вызывает особый интерес.

Где живущие в облаке и хранящиеся на диске данные могут быть потенциально уязвимы:
на уровне ЦОДов, где потенциальным злоумышленником может стать инженер, имеющий физический доступ к диску;
на уровне хостов облака — доступ к ним есть у администраторов облака;
в ваших приложениях, которые вы строите поверх сервисов облачной платформы.
Доверяй, но проверяй: сценарии защиты данных в облаке
Существует три основных сценария защиты данных at rest в облаке: полностью доверить шифрование облачному провайдеру; шифровать данные самостоятельно, но хранить ключи в облаке; либо взять на себя полный контроль над шифрованием и управлением ключами. Рассмотрим каждый из этих сценариев подробнее.
Полностью доверить шифрование облаку. Здесь главный плюс заключается в том, что облако все делает за вас и вам ничего не нужно реализовывать. Данные at rest будут защищены в этом случае на уровне ЦОДов, а вот на уровне хостов облака защищенность теряется, потому что шифрованием управляет облако. При этом на уровне ваших приложений защиты нет вообще — сервисы облака отдают вам данные уже в расшифрованном виде.
Шифровать самостоятельно, но хранить ключи в облаке — это сбалансированный уровень контроля и доверия облаку. Его достаточно просто реализовать, потому что вам не надо думать о том, где хранить ключи. В этом случае ваши данные под защитой на уровне ЦОДа и на уровне ваших приложений, а вот на уровне хостов облака защита теряется, потому что ключами управляет облако.
Полностью управлять шифрованием самостоятельно — это консервативный сценарий, где вы полностью не доверяете облаку. Его сложно реализовать, так как фактически вам нужно построить полноценную инфраструктуру для хранения ключей. Но при этом с точки зрения защищенности данные будут в безопасности на всех уровнях.

Что в итоге? Сценарии с участием облака всегда предполагают определенный компромисс между контролем и удобством. В обмен на часть доверия облачный провайдер берет на себя значительную часть сложности, связанной с управлением ключами и организацией шифрования. Именно здесь в архитектуре появляется KMS.
Что это за зверь такой — KMS
Key Management Service (не путать с KMS для активации Windows) — это сервис, который берет на себя всю сложность работы с криптографическими ключами. Он отвечает за их создание, безопасное хранение, ротацию, уничтожение и разграничение доступа, а также предоставляет API для выполнения криптографических операций.
Главный принцип KMS прост: ключи никогда не покидают сервис. Если ключ можно получить, его можно скопировать, а значит, контроль над ним в какой-то момент может быть утрачен. Поэтому в KMS нет возможности извлечь ключевой материал, даже если речь идет о вашем собственном ключе. Возникает закономерный вопрос: как тогда пользоваться ключом, если его нельзя получить?
Когда пользователь создает ключ, он остается внутри KMS, а клиент получает только его идентификатор. Все дальнейшие криптографические операции выполняются непосредственно внутри сервиса. Если приложению нужно зашифровать или расшифровать данные, оно отправляет запрос в KMS, указывая идентификатор ключа, а сервис выполняет необходимую операцию и возвращает результат.

С точки зрения безопасности это принципиально меняет модель работы: появляется единая контролируемая точка управления криптографией. Все ключи, права доступа и операции с ними сосредоточены в одном месте, что существенно упрощает управление, аудит и контроль безопасности.
Кто охраняет охранника: как KMS хранит свои ключи
Если KMS хранит ключи пользователей и отвечает за их безопасность, то кто защищает сам KMS? Иными словами, чем шифруются ключи внутри сервиса управления ключами? Ответ здесь опирается на идею иерархии ключей.
В начале этой цепочки находятся пользовательские ключи. Они не хранятся в открытом виде и зашифрованы мастер-ключами, которые, в свою очередь, могут быть зашифрованы другими мастер-ключами более высокого уровня. Теоретически такую цепочку можно продолжать достаточно долго, но на практике мы неизбежно приходим к финальной точке — корневому ключу. Именно он становится фундаментом всей системы: его компрометация означает компрометацию всей инфраструктуры управления ключами. В итоге задача защиты множества ключей сводится к защите одного — корневого.

Но как защитить сам корневой ключ? Обычно здесь используют два подхода: хранение в TPM или разделение секрета по схеме Шамира.
TPM (Trusted Platform Module) — это специальный аппаратный чип, который предназначен для безопасного хранения криптографических ключей и выполнения операций с ними. Даже при физическом доступе к устройству извлечь ключи из TPM невозможно — они остаются защищёнными на уровне железа. При этом TPM не рассчитан на высокую производительность и хранение большого количества ключей, однако для задач вроде хранения корневого ключа его возможностей более чем достаточно.

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

Сравнивая подходы, можно сказать, что при использовании TPM безопасность корневого ключа обеспечивается аппаратной защитой хранения, а в схеме Шамира — распределённым хранением вне облака. Как это часто бывает, у каждого подхода есть свои ограничения. TPM делает KMS зависимым от железа, тогда как схема Шамира предполагает ручные операции ввода частей корневого ключа. На практике они выполняются редко, поэтому мы в K2 Cloud остановились на схеме Шамира.
Когда программной защиты уже недостаточно: зачем нужен HSM
У программной реализации хранилища ключей есть фундаментальное ограничение: чтобы использовать ключ, система должна восстановить его в оперативной памяти. А значит, ключи оказываются в состоянии in use — мы обсуждали это в начале статьи. Да, атаки на данные в памяти встречаются редко и обычно сложны в реализации, но полностью исключать такую угрозу нельзя.
Для сценариев, где такие риски считаются неприемлемыми, используется другой подход — аппаратное хранилище ключей на базе HSM (Hardware Security Module). По сути, HSM представляет собой специализированное устройство, предназначенное для хранения криптографических ключей и выполнения криптографических операций. В отличие от программной реализации, пользовательские ключи KMS здесь существуют внутри защищенного аппаратного устройства и не покидают его.

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

Как защититься от подмены данных
До сих пор мы говорили в основном о безопасном хранении ключей. Но не менее важный аспект — выбор криптографических алгоритмов.
Для шифрования данных в KMS используется алгоритм AES — фактический отраслевой стандарт среди симметричных алгоритмов. Он безопасен, производителен и широко поддерживается. Однако сам по себе AES обеспечивает только конфиденциальность данных, а этого недостаточно. Необходимо также защищаться от атак, связанных с подменой информации. Поэтому в KMS применяется режим AES-GCM, который одновременно обеспечивает шифрование и контроль целостности данных.
Представим базу данных пользователей. Злоумышленник получил доступ к хранилищу, но не имеет доступа к ключам. В этом случае он может не пытаться читать данные, а ограничиться их подменой — например, подставить зашифрованные данные одного пользователя другому.
Для защиты от таких сценариев в KMS предусмотрен механизм Encryption Context. При шифровании вместе с данными передаётся дополнительный набор параметров (например, идентификатор пользователя), который однозначно связывает данные с их владельцем. При расшифровании контекст должен полностью совпадать с исходным. В противном случае система обнаруживает несоответствие и не позволяет расшифровать данные.

Маленький IV — большие проблемы: почему нельзя бесконечно шифровать на одном ключе
На этом этапе может показаться, что задача решена: есть надёжный алгоритм шифрования, защита от подмены и централизованное управление ключами. Но у AES-GCM есть важное практическое ограничение.
Для каждой операции AES-GCM требуется сгенерировать специальное значение — вектор инициализации (Initialization Vector, IV). Он не является секретным, но должен быть уникальным для каждого шифрования на одном и том же ключе. Проблема возникает при повторном использовании одного и того же IV. Для режима GCM это критическая ситуация: повторение вектора инициализации может привести к компрометации криптографической стойкости алгоритма.
Из-за этого AES-GCM накладывает практический лимит на количество операций шифрования на одном ключе. При длине 96 бит вероятность повторного использования IV при его случайной генерации становится значительной уже после примерно 4 миллиардов шифрований. Кажется, что это очень много, но в высоконагруженных системах вроде облака такой предел может быть достигнут за считанные часы.
Как масштабировать шифрование на сотни лет вперед
Мы только что выяснили, что AES-GCM имеет ограничение на количество безопасных операций на одном ключе. Очевидное решение — увеличить частоту ротации ключей. Однако это приводит к усложнению управления ключами в системе. Здесь на помощь приходит идея производных ключей.
В KMS пользовательский ключ выступает основой для генерации производных ключей с использованием алгоритма HKDF (HMAC-based Key Derivation Function). При каждой операции шифрования система получает новый производный ключ, который используется в AES-GCM, тогда как пользовательский ключ напрямую в шифровании не участвует. При расшифровании производный ключ детерминировано выводится из пользовательского ключа повторно.

Риск повторения вектора инициализации распределяется между большим количеством независимых ключей. По сути, вместо одного ключа с лимитом порядка 4 миллиардов операций мы получаем целое семейство производных ключей, каждый из которых имеет собственный «запас прочности».
Так как пространство 256-битных ключей практически неисчерпаемо, число возможных производных ключей становится огромным. В итоге суммарный объём безопасных операций шифрования увеличивается на несколько порядков и может достигать квадриллионных значений. Для высоконагруженного облачного сервиса это уже не годы, а сотни лет непрерывного шифрования до достижения теоретических ограничений алгоритма.
Почему данные почти никогда не шифруются напрямую
А теперь логичный вопрос: если KMS умеет выполнять криптографические операции, почему бы просто не отправлять ему все данные для шифрования? На первый взгляд такая схема кажется простой и удобной, но на практике у нее есть несколько серьезных недостатков.
Во-первых, чувствительные данные приходится передавать по сети в KMS. Это означает, что сервису нужно доверять не только ключи, но и сами данные. Во-вторых, каждая операция шифрования превращается в сетевой запрос, а значит, добавляет задержки. Наконец, KMS — это высоконагруженный сервис, поэтому он неизбежно ограничивает количество запросов в секунду и объем данных, которые можно зашифровать за один запрос. Если выполнять шифрование каждого объекта через KMS, очень быстро можно упереться в эти ограничения.
Вместо того, чтобы передавать в KMS все данные для шифрования, на практике обычно используют подход Envelope Encryption. Когда приложению нужно зашифровать данные, оно запрашивает у KMS специальный ключ шифрования данных — Data Key. KMS генерирует случайный Data Key, шифрует его пользовательским ключом и возвращает две версии: открытый Data Key и его зашифрованную копию.
Далее все происходит локально. Приложение использует открытый Data Key для шифрования данных, после чего сохраняет зашифрованные данные вместе с зашифрованной копией Data Key, а сам открытый ключ удаляет из памяти.

Когда потребуется расшифровать данные, приложение отправит в KMS зашифрованную копию Data Key. Сервис расшифрует ее с помощью пользовательского ключа и вернет исходный Data Key, который затем будет использован для локального расшифрования данных.
Таким образом можно с любой частотой шифровать произвольный объем данных без дополнительных задержек. В каком-то смысле зашифрованная копия Data Key действительно похожа на конверт: внутри находится ключ шифрования данных, а открыть его можно только с помощью пользовательского ключа в KMS.
Перейдем к выводам
Управление ключами — задача со звездочкой. Нужно решить множество вопросов: где и как хранить ключи, как обеспечить их защиту, как организовать ротацию и контроль доступа, какие алгоритмы шифрования использовать и как масштабировать криптографические операции.
Облачный KMS избавляет от необходимости самостоятельно строить и поддерживать инфраструктуру для шифрования, предоставляя готовый набор удобных механизмов. Конечно, вопрос доверия к облаку каждый решает самостоятельно. Кто-то полностью доверяет провайдеру, а кто-то по-прежнему считает, что ключи не должны попасть к третьим лицам. Но независимо от того, доверяете ли вы управление ключами облаку или предпочитаете полностью контролировать их самостоятельно, вопросы хранения, защиты и использования ключей никуда не исчезают — меняется лишь то, кто берет эту ответственность на себя.