Оба эти варианта безопасны, потому что, даже если вы получите доступ к базе Vault-а, где хранятся секреты, сами секреты вы всё равно не получите, т.к. они зашифрованы master ключом, который зашифрован root ключом, который тоже зашифрован.
А все эти ключи для расшифровки секретов знает только тот, кто развёртывал Vault, и вряд ли это вы (тот кто хочет угнать секреты) :)
Но чисто теоретически, никто не мешает открыть соединение вне DataSource к БД чтобы проверить что пришли валидные пользователь/пароль, и только после этого запихивать их в HikariCP MXBean.
[Про проверку валидности секретов] Если система критическая и она обязана работать - то должен сработать переход на emergency credentials и оповещение операторов что система ушла в резервный режим (чтобы потом ротировали вручную emergency secrets)
У нас практически так и сделано: откидывание метрик и логированием ERROR, если поступил "кривой" новый секрет. Сопровождение, увидев такие метрики, идёт в Vault исправлять проблему.
чтобы секреты применялись в разные моменты времени - можно через стандартный spring-cloud-vault через параметры min-renewal и expiry-threshold. Их можно менять программно ...
Так и так кастомизация hot reload-а секретов получается. Но спасибо за наводку.
не хранить в виде String а хранить в виде char[] и затирать после использования
Да, так и делаем. С подключенными библиотеками, действительно, сложнее (HikariCP и встроенный в Spring Tomcat). Но сам JDK при построении SSLContext-а принимает char[], а не String. Судя по тому, что это известная best practice, то библиотеки постепенно подтянутся к этому.
В кубере для Аутентификации используется токен от ServiceAccount-а, который автоматически монтируется в pod Vault Agent sidecar-а (самим кубером). Сам Vault при этом интегрирован с кластером кубера: знает про токены каждого namespace-а (аутентификация) и знает какому namespace-у какие секреты можно давать.
На виртуалках для Аутентификации используется Approle (пара логин и пароль). Здесь самый тонкий момент, про который вы как раз и пишите. Approle доставляется на каждую виртуалку при деплое сервиса в виде wrapped token-а - это одноразовая сущность, имеющая время жизни. Сервис при старте использует wrapped token, чтобы "развернуть" (достать) из него Approle и получить с помощью неё секреты. Далее во время работы сервиса он периодически приносит себе новый wrapped token с Approle-ью внутри, не доводя до превышения времени жизни. Это позволяет в любой момент рестартовать сервис.
Как видите, не нужен ни какой ПровайдерСекретов2 ;)
Bootstrap-контекст сходит в Vault и вытащит секреты, скажем, в проперти. Дальше уже в нормальном application-context ссылайтесь на эти проперти - и будет счастье.
Читать секреты в Spring property небезопасно, т.к. эти глобальные переменные обязательно окажутся в снятом heap dump-е. Мы читаем секреты, находящиеся в каталоге, смонтированном в tmpfs, доступ к которому имеет только учётка, из-под которой работает приложение.
Плюс ко всему, у нас custom-изированный алгоритм ротации секретов, использующий:
random-ную задержку перед применением (чтобы в каждом pod-е применение происходило в разные моменты времени)
sanity-проверку валидности пришедших новых секретов (невалидные секреты не будут применяться с откидыванием метрик и логированием ERROR, но не сломают приложение).
Такую custom-изацию не сделать ни с помощью SSL bundles из Spring Boot, ни с помощью @RefreshScope из Spring Cloud (проверяли).
С помощью MXBean-а от HikariCP разве можно сделать такую custom-ную ротацию кредов БД?
В правильных организациях открытие провайдера секретов делается аппаратным способом. То есть по определенному протоколу взять карту из сейфа в присутствии представителя СБ, открыть серверную, и приложить к считывателю. Потом вернуть в сейф и опечатать.
Добрый день! Для доступа к самому провайдеру секретов используется только публичный сертификат для установки TLS соединения. Далее при использовании HTTP API провайдера можно получать секреты, но:
каждое обращение аутентифицируется (либо уже имеющийся токен, либо токен ServiceAccount-а из namespace кубера, либо Approle, т.е. логин и пароль, по сути, либо множество других вариантов аутентификации)
каждое аутентифицированное обращение за секретом авторизуется (гибкими политиками в провайдере секретов настроено, что и кому можно отдавать)
Таким образом, злоумышленник не сможет получить секреты из провайдера, обращаясь к нему, используя публичный сертификат для TLS.
При создании каждой новой сессии запросы распределяются по мастер-узлам равномерно с помощью RoundRobin балансировки.
А запросы в рамках уже созданной сессии (прочитать/записать данные) идут строго в тот мастер-узел, где сессия была создана. Вот здесь уже используется sticky session.
В продакшене постоянно есть нескончаемый поток как первых запросов, так и вторых, поэтому RoundRobin и sticky session работают параллельно (в разных запросах).
Пробовал различные вариации JSON-сериализации и различные варианты бинарной сериализации - общая тенденция такова, что бинарные форматы быстрее за счёт того, что в них нет логически лишних данных для хранения разметки.
Конкретно, Fast JSON я нарочно не игнорировал - думаю, стоит попробовать "пропустить" через benchmark. Спасибо за наводку!
Оба эти варианта безопасны, потому что, даже если вы получите доступ к базе Vault-а, где хранятся секреты, сами секреты вы всё равно не получите, т.к. они зашифрованы master ключом, который зашифрован root ключом, который тоже зашифрован.
А все эти ключи для расшифровки секретов знает только тот, кто развёртывал Vault, и вряд ли это вы (тот кто хочет угнать секреты) :)
Так и делаем.
У нас практически так и сделано: откидывание метрик и логированием ERROR, если поступил "кривой" новый секрет.
Сопровождение, увидев такие метрики, идёт в Vault исправлять проблему.
Так и так кастомизация hot reload-а секретов получается. Но спасибо за наводку.
Да, так и делаем. С подключенными библиотеками, действительно, сложнее (HikariCP и встроенный в Spring Tomcat). Но сам JDK при построении SSLContext-а принимает char[], а не String. Судя по тому, что это известная best practice, то библиотеки постепенно подтянутся к этому.
Так, понятно.
Используем 2 варианта:
В кубере для Аутентификации используется токен от ServiceAccount-а, который автоматически монтируется в pod Vault Agent sidecar-а (самим кубером).
Сам Vault при этом интегрирован с кластером кубера: знает про токены каждого namespace-а (аутентификация) и знает какому namespace-у какие секреты можно давать.
На виртуалках для Аутентификации используется Approle (пара логин и пароль).
Здесь самый тонкий момент, про который вы как раз и пишите.
Approle доставляется на каждую виртуалку при деплое сервиса в виде wrapped token-а - это одноразовая сущность, имеющая время жизни.
Сервис при старте использует wrapped token, чтобы "развернуть" (достать) из него Approle и получить с помощью неё секреты.
Далее во время работы сервиса он периодически приносит себе новый wrapped token с Approle-ью внутри, не доводя до превышения времени жизни.
Это позволяет в любой момент рестартовать сервис.
Как видите, не нужен ни какой ПровайдерСекретов2 ;)
Коллеги, предлагаю дождаться второй части статьи где я подробно разберу, как мы обновляем секреты «на горячую»:
серверные SSL-сертификаты Tomcat-а
клиентские SSL-сертификаты для отправки HTTPS-запросов
креды БД и SSL-сертификаты для HikariDataSource
Читать секреты в Spring property небезопасно, т.к. эти глобальные переменные обязательно окажутся в снятом heap dump-е.
Мы читаем секреты, находящиеся в каталоге, смонтированном в tmpfs, доступ к которому имеет только учётка, из-под которой работает приложение.
Плюс ко всему, у нас custom-изированный алгоритм ротации секретов, использующий:
random-ную задержку перед применением
(чтобы в каждом pod-е применение происходило в разные моменты времени)
sanity-проверку валидности пришедших новых секретов
(невалидные секреты не будут применяться с откидыванием метрик и логированием ERROR, но не сломают приложение).
Такую custom-изацию не сделать ни с помощью SSL bundles из Spring Boot, ни с помощью @RefreshScope из Spring Cloud (проверяли).
С помощью MXBean-а от HikariCP разве можно сделать такую custom-ную ротацию кредов БД?
Не от того аккаунта опубликовали статью изначально. Прошу понять и простить )
Это верх автоматизации! Будущее так не наступит.
Добрый день!
Для доступа к самому провайдеру секретов используется только публичный сертификат для установки TLS соединения. Далее при использовании HTTP API провайдера можно получать секреты, но:
каждое обращение аутентифицируется
(либо уже имеющийся токен, либо токен ServiceAccount-а из namespace кубера, либо Approle, т.е. логин и пароль, по сути, либо множество других вариантов аутентификации)
каждое аутентифицированное обращение за секретом авторизуется
(гибкими политиками в провайдере секретов настроено, что и кому можно отдавать)
Таким образом, злоумышленник не сможет получить секреты из провайдера, обращаясь к нему, используя публичный сертификат для TLS.
Я правильно понял, что эта проблема решена в DataGrid-е, а в Apache Ignite решения до сих пор нет?
Так Сбер (а точнее СберТех) уже ппреименовал Ignite в DataGrid.
Такой проблемы нет, потому что:
Очень много сессий в online (в СберБанк Онлайн полмиллиона-миллион). И все они равномерно распределены по мастер-узлам.
Абсолютное большинство сессий всё-таки более-менее однородные (в пляне "тяжести" создаваемой нагрузки).
Поэтому нагрузка, создаваемая такими сессиями, очень равномерно нагружает CPU на всех мастер-узлах кластера.
Статья про backend.
Отставить негатив про frontend!
При создании каждой новой сессии запросы распределяются по мастер-узлам равномерно с помощью RoundRobin балансировки.
А запросы в рамках уже созданной сессии (прочитать/записать данные) идут строго в тот мастер-узел, где сессия была создана. Вот здесь уже используется sticky session.
В продакшене постоянно есть нескончаемый поток как первых запросов, так и вторых, поэтому RoundRobin и sticky session работают параллельно (в разных запросах).
Ребят, давайте по делу. Согласен, это боль, но она не относится к теме статьи.
Пробовал различные вариации JSON-сериализации и различные варианты бинарной сериализации - общая тенденция такова, что бинарные форматы быстрее за счёт того, что в них нет логически лишних данных для хранения разметки.
Конкретно, Fast JSON я нарочно не игнорировал - думаю, стоит попробовать "пропустить" через benchmark. Спасибо за наводку!
java.lang.Object
с полями объекта