Clearway2 часа назадОбъяснить с
PKI-шторм: что делать, если Kubernetes одновременно запрашивает 100 тысяч сертификатов
Уровень сложностиСреднийВремя на прочтение9 минОхват и читатели2.8KИнформационная безопасность*Kubernetes*DevOps*Системное администрирование*Криптография*КейсPKI-штормВ инфраструктуре крупной организации TLS-сертификаты нужны буквально повсюду: сервисам, рабочим станциям, контейнерам, внутренним API и интеграциям между системами. Когда таких потребителей тысячи, PKI работает уже не с отдельными сертификатами, а с массовым потоком запросов. В нашем случае речь идёт примерно о 320 млн. запросов на выпуск сертификатов в год.
Для автоматизации работы с сертификатами у заказчика используется ЦУГИ ЕСАУС. Система отвечает за выдачу, доставку и установку TLS-сертификатов и SSH-ключей для серверов, рабочих станций и платформ контейнерной оркестрации. ЕСАУС проверяет запросы на соответствие установленным политикам безопасности и передаёт их во внешние центры сертификации. Сам ЕСАУС сертификаты не выпускает.
Для Kubernetes с Istio у заказчика используется специальный компонент ЕСАУС – Цитадель. В Istio он настраивается как источник сертификатов вместо встроенного ЦС. Цитадель принимает запросы на выпуск сертификатов, проверяет их параметры и контекст на соответствие установленным политикам безопасности и только после успешной проверки передаёт их через ЕСАУС в корпоративные центры сертификации. Таким образом, Kubernetes становится частью корпоративной PKI с едиными правилами выпуска и доверия для внутренних и внешних взаимодействий.
Здесь появляется важная зависимость: скорость восстановления Kubernetes начинает зависеть от производительности внешнего ЦС.
Представьте, что после аварии начинает восстанавливаться целый ЦОД, а вместе с ним одновременно поднимаются десятки тысяч pod'ов Kubernetes. Поскольку взаимодействие между сервисами построено на mTLS, каждому pod'у для работы нужен собственный сертификат и соответствующий ему закрытый ключ.
В штатном режиме запросы распределены во времени и не создают проблем. Но при массовом восстановлении всё происходит практически одновременно: за короткий промежуток времени во внешний центр сертификации отправляется порядка 100 тысяч запросов.
Именно с такой ситуацией мы и столкнулись у одного из наших заказчиков.
В этой статье мы разберём, почему даже многократного запаса производительности ЦС оказалось недостаточно, почему простое масштабирование оказалось не самым выгодным решением и как в итоге мы пришли к разделению процессов выпуска и потребления сертификатов.
Почему штатная нагрузка не вызывала опасений
Если перевести годовой объём запросов на выпуск сертификатов в среднюю нагрузку, получится всего около 10–11 запросов в секунду. Штатная производительность центров сертификации обычно порядка 100 RPS, но на практике реальная производительность используемых ЦС при этом составляет около 50–70 RPS. То есть в запас производительности ЦС нашего заказчика был многократным.
Казалось, всё было хорошо. Но именно там и скрывалась проблема: средняя нагрузка почти ничего не говорила о том, что может произойти при массовом восстановлении инфраструктуры.
Когда 10 RPS превращаются в 100 тысяч запросов
В один из дней у заказчика произошло отключение ЦОД.
После восстановления начали одновременно запускаться десятки тысяч pod'ов Kubernetes. Для работы сервисам требовались сертификаты с соответствующими закрытыми ключами, поэтому они практически одновременно пошли через ЕСАУС в центр сертификации. В результате вместо привычных 10–11 RPS ЦС получил очередь примерно из 100 тысяч запросов.
При производительности около 70 RPS даже в идеальных условиях обработка такого объёма занимает почти 24 минуты. Но реальность оказалась хуже арифметики.
Часть запросов слишком долго ожидала ответа и завершалась по таймауту. После этого приложения выполняли повторные попытки, снова попадали в очередь и создавали дополнительную нагрузку.
Получился эффект, близкий к thundering herd: тысячи восстанавливающихся сервисов одновременно пытались получить доступ к ресурсу с ограниченной пропускной способностью.
Так мы увидели, что проблема была не в недоступности Kubernetes или ЦС как таковых. Инфраструктура просто восстанавливалась быстрее, чем центр сертификации успевал выпускать для неё сертификаты.
Первое решение, которое приходит в голову
Когда обнаруживается узкое место, логичная реакция — сделать его шире.
В нашем случае это означало увеличить производительность ЦС: выполнить вертикальное или горизонтальное масштабирование.
Посмотрим, что это даёт.
Производительность ЦСШтатная загрузкаВремя обработки штормаОтносительное увеличение производительности70 RPS~15 %~24 мин1х210 RPS~5 %~8 мин~3x1050 RPS~1 %~1,5 мин~15xЧтобы сократить теоретическое время обработки шторма с 24 до 1,5 минут, производительность ЦС пришлось бы увеличить более чем в 15 раз.
Технически такой подход вполне рабочий. Проблема в экономике: столь высокая производительность нужна лишь в редкие моменты массового восстановления, а большую часть времени (более 99%) инфраструктура будет использоваться лишь на малую долю своей мощности.
Получается, что мы масштабируем ЦС под несколько минут аварии, но оплачиваем этот запас постоянно.
Кроме того, остаётся более фундаментальная проблема: зависимость запуска приложения от способности ЦС прямо сейчас подписать новый сертификат.
Именно поэтому мы решили посмотреть на ситуацию с другой стороны.
А обязательно ли выпускать сертификат именно в момент запроса?
Если производство ресурса сравнительно медленное и предсказуемое, а потребление может быть резким и массовым, логично попытаться развязать эти процессы.
Это не новая идея. Данные кешируют, задания складывают в очереди, товары производят заранее и держат на складе. С сертификатами можно использовать похожий принцип.
В штатном режиме центр сертификации продолжает обрабатывать обычный поток запросов, а свободный запас производительности использует для формирования резерва заранее выпущенных сертификатов и соответствующих им закрытых ключей.
Этот резерв помещается в отдельное защищённое хранилище.
Пока всё работает штатно, архитектура почти не меняется. Но при массовом восстановлении сервису уже не нужно ждать полного цикла выпуска сертификата — подписанный сертификат и соответствующий ему закрытый ключ можно получить из резерва.
Таким образом, мы фактически разделили два процесса:
• производство сертификатов — сравнительно медленное и равномерное;
• потребление сертификатов — потенциально очень быстрое и неравномерное.На уровне архитектуры решение выглядело логично. Но сразу возник следующий вопрос: где безопасно хранить сотни тысяч заранее сгенерированных закрытых ключей и соответствующих подписанных для них сертификатов?
От проблемы производительности — к проблеме безопасности
Сертификат сам по себе не является секретом. Но вместе с ним необходимо хранить соответствующий закрытый ключ, а это уже критичный криптографический материал.
Просто сложить тысячи таких контейнеров в обычную базу данных или на файловую систему означало бы решить проблему доступности и одновременно создать новую — уже в области безопасности. Поэтому требования к хранилищу оказались значительно шире, чем просто «уметь быстро отдавать данные».
Нам были нужны централизованное защищённое хранение, строгая аутентификация потребителей, разграничение прав, аудит операций с секретами, отказоустойчивая кластерная архитектура, высокая скорость чтения и управление жизненным циклом хранимых объектов.
Кроме того, важно было масштабировать именно контур потребления, не заставляя нас вместе с ним масштабировать и центр сертификации. Задача перестала быть исключительно задачей PKI и превратилась в полноценную задачу управления секретами.
Так в архитектуре появился отдельный слой для защищённого хранения заранее выпущенных сертификатов и их закрытых ключей — Единое Хранилище Секретов (ЕХС).
При этом важно не перепутать роли компонентов. ЕХС не заменяет центр сертификации: ЦС по-прежнему остаётся источником подписи сертификатов. Хранилище лишь позволяет развязать момент подписи сертификата и момент, когда он понадобится конкретному сервису.
Не перенесли ли мы узкое место с ЦС на хранилище?
Это был один из первых вопросов к новой архитектуре. Если раньше 100 тысяч запросов упирались в ЦС, а теперь они идут в хранилище, не превратится ли уже оно в новый bottleneck?
Благодаря реализованному режиму «performance» ЕХС обеспечивает возможность чтения секретов со standby-узлов кластера, что позволяет достигать порядка 14 тыс. RPS на выдачу существующих секретов.
Конечно, конкретные показатели зависят от конфигурации, используемой инфраструктуры, размера секретов и сетевых задержек. Поэтому здесь важна не столько сама цифра, сколько принцип: чтение готовой пары сертификата и его закрытого ключа можно масштабировать независимо от контура её выпуска.
В штатном режиме ЦС продолжает работать с обычной нагрузкой и параллельно пополнять резерв. А в момент PKI-шторма основная burst-нагрузка переносится с операции выпуска на операцию чтения из хранилища.
В результате архитектура стала выглядеть так.
Штатный режим
Шторм запросов
ЦС при этом продолжает работать со своей обычной производительностью и не обязан за несколько минут переваривать нагрузку, которая в десятки или сотни раз превышает штатную.
Такой подход позволил сократить время обработки аварийного пика с десятков минут до единиц секунд и существенно ускорить восстановление зависимых сервисов.
Бесплатных архитектурных решений не бывает
Предварительный выпуск сертификатов хорошо решает проблему burst-нагрузки, но создаёт новые вопросы.
Сколько сертификатов держать в резерве?
Если запас окажется слишком маленьким, он закончится раньше, чем восстановятся все сервисы. Если слишком большим — часть сертификатов так и не будет использована.
Поэтому размер резерва приходится рассчитывать исходя из возможного сценария аварии, числа потребителей и скорости, с которой ЦС способен его восполнить.
Что делать со сроком действия?
Сертификат начинает «стареть» с момента выпуска, а не с момента выдачи сервису.
Чем дольше он лежит в резерве, тем меньше остаточный срок действия к моменту использования. Значит, необходимо автоматически обновлять запас и своевременно выводить из него сертификаты, которые приближаются к окончанию срока действия.
Что произойдёт, если запас закончится?
В этом случае уже будет необходимо заранее продумать failback: переход на обычный выпуск через ЦС, постановка запросов в очередь или работа в ограниченном режиме.
Что делать с закрытыми ключами?
Повышая доступность системы, мы централизуем большое количество критичных секретов в одном инфраструктурном слое. Поэтому требования к его защите, модели доступа, журналированию и отказоустойчивости становятся значительно выше.
От запаса сертификатов — к управлению секретами
После появления централизованного хранилища быстро выяснилось, что проблема хранения закрытых ключей вовсе не ограничивается аварийным резервом.
Возьмём обычный mTLS. Каждому сервису нужна собственная ключевая пара сертификата, и на практике закрытый ключ нередко просто лежит на файловой системе рядом с приложением.
Отсюда сразу появляются знакомые вопросы: кто имеет к нему доступ, когда он последний раз менялся, можно ли отследить его чтение, что произойдёт при компрометации сервера?
Поэтому постепенно в централизованное хранилище начали перемещаться не только резервные сертификаты, но и секреты, необходимые для обычной работы инфраструктурных компонентов.
Так решение, которое изначально появилось как реакция на вполне конкретный эксплуатационный инцидент, постепенно превратилось в отдельный инфраструктурный слой управления секретами.
А что насчёт критичных ключей?
Отдельный класс задач — управление ключами, потеря или компрометация которых имеет особенно серьёзные последствия.
Хорошим примером является механизм Key Recovery Agent (сокращенно KRA), предназначенный для восстановления архивированных закрытых ключей пользователей.
При генерации ключевой пары пользователь шифрует свой закрытый ключ с использованием открытого ключа KRA и передаёт его в центр сертификации, который сохраняет уже зашифрованную копию закрытого ключа в своей базе.
Если пользователь утратил свой закрытый ключ, выделенная роль Key Recovery Agent может выполнить его восстановление с помощью соответствующего закрытого ключа KRA.
Но здесь возникает очевидная проблема – закрытый ключ KRA фактически открывает доступ не к одному секрету, а потенциально к большому количеству архивных пользовательских ключей. Поэтому постоянно держать его доступным непосредственно в контуре ЦС – спорная идея с точки зрения минимизации последствий компрометации.
Благодаря ЕХС закрытый ключ KRA хранится отдельно и предоставляется выделенной роли только на время согласованной операции восстановления.
Сценарий уже другой, но принцип остаётся тем же: чем критичнее секрет и чем реже он нужен, тем меньше причин постоянно держать его непосредственно рядом с компонентом, который периодически его использует.
Какие выводы мы сделали
Главный урок этой истории оказался не про конкретный центр сертификации и даже не про Kubernetes.
Вывод № 1 – средняя нагрузка плохо описывает поведение инфраструктуры во время аварии.
Можно иметь многократный запас производительности и всё равно получить длительный простой, если тысячи потребителей появляются практически одновременно.
Вывод № 2 — не каждое узкое место имеет смысл устранять масштабированием.
Если один компонент производит ресурс относительно медленно, а другой способен потребить огромное количество этого ресурса почти мгновенно, иногда эффективнее не ускорять производителя, а разделить производство и потребление дополнительным слоем.
Вывод № 3 — любое такое решение переносит сложность, а не устраняет её.
Создав запас заранее выпущенных сертификатов, мы сняли пиковую нагрузку с центра сертификации, но взамен получили другие задачи: безопасно хранить большое количество закрытых ключей, управлять доступом к ним, контролировать их жизненный цикл и защищать само хранилище.
Так задача повышения устойчивости PKI постепенно превратилась для нас в гораздо более широкую задачу управления корпоративными секретами.
Продолжение следует
Централизованное хранение секретов — это только половина задачи.
Рано или поздно их всё равно нужно доставить приложению, администратору или пользователю. Причём желательно сделать это так, чтобы после построения защищённого централизованного хранилища секрет снова не оказался в файле на рабочем столе, конфиге или очередном ручном copy-paste.
Об этом поговорим в следующем материале и познакомимся с локальным кошельком секретов Wallet.Теги:• kubernetes
• pki
• tls
• mtls
• devops
• информационная безопасность
• центры сертификации
• сертификаты
• управление секретами
• отказоустойчивостьХабы:• Информационная безопасность
• Kubernetes
• DevOps
• Системное администрирование
• Криптография
Получайте больше инсайтов о систематизации бизнеса
Подписывайтесь на Telegram-канал Business Operations — ежедневные материалы о бизнес-процессах, операционном управлении и повышении эффективности
💬 Подписаться на канал→ Оригинальная статья