Получилась практически новая база данных с поддержкой репликации. Данные можно безопасно и надёжно хранить прямо в буфере обмена. Сам буфер обмена поддерживает тёмную тему, что является одним из его основных преимуществ.
Я бы добавил: а вот если бы начали использовать эрланг, то до сих пор бы были в процессе попыток начать использовать эрланг. А бухгалтерию вели на бумажке.
Плюс "убогих go и Kubernetes" наверное в том, что можно взять и уже завтра получить что-то более менее работающее и расширяемое. Не такое может красивое, зато завтра. Потому что послезавтра у это будет уже не нужно, а нужно будет что-то другое.
Новосибирский Новотелеком (куплен ДОМ ру лет 7 назад) поднимает стоимость тарифа ежегодно. Для некоторых тарифов за 7 лет стоимости выросла раза в 2, для некоторых в 6 раз.
Был такой тариф "для пенсионеров", назывался Социальный. 512кбит за 30р в месяц. Появился он когда сотовые операторы повально безлимиты предлагали.
Так вот, этот тариф сначала стоил 30р, потом 40р, далее 60р, 100р. Сейчас уже 190р. Цену не забывают индексировать. Но скорость так и осталась 512кбит, как 10-15 лет назад.
Да, 190р/мес сейчас - это не деньги. И почему происходит индексация - тоже понятно. Но и полмегабита - это не связь. Ребята наверное не знают, что на такой скорости даже госуслуги (то, для чего якобы позиционируется тариф) сейчас не работают. Проще иметь мобильную связь рублей за 500, которая работает везде, а не только дома, и не со скоростью черепахи.
Итого, проводные операторы повышают цены, которые за 10 лет в среднем выросли раза в 2. Мобильные - тоже. Так что гайки может быть и крутит ФАС, но не намертво.
Хороший пример. Вот мне не даёт покоя вопрос - когда и где гипотетический хороший джун из первого примера должен все это узнать и всему этому научиться. Ну не так, чтобы "знать эти слова", а ещё и понимать немножко глубже. В школе на продленке этому сейчас учат? Ну нет. В ВУЗе? Ну от части что-то затрагивают, но зависит даже не от ВУЗа или специальности, а от программы конкретного преподавателя. В итоге это какое-то самообразование. То есть кандидат сначала должен сделать для себя один-два проекта уровня, как вы описали выше, набить все шишки, столкнуться со всеми нюансами. И только потом может искать работу уровня джуна.
Если взять джуна, то он будет писать код с помощью LLM. Худо-бедно будет закрывать задачи, и через год-полтора сможет делать что-то более сложное. И гораздо быстрее. Но только с LLM. Предложи написать все самому без LLM - процесс затормозится значительно, а скорее всего даже встанет. Пограммируя с помощью LLM джун не научился кодить без него. Но ещё через год может все получится.
Вчера
Если взять джуна, то используя хороший фреймворк и IDE он сможет делать типовые задачки, а через год-полтора - что-то более сложное, и гораздо быстрее. Но дай ему текстовый редактор и компилятор, и скажи, что библиотеками пользоваться нельзя - процесс затормозится значительно, а скорее всего даже встанет. Пограммируя с помощью ide и фреймворков джун не научился кодить без них. Но ещё через год может все получится.
Позавчера
Взять джуна, через год он сможет писать на C сетевые клиент-серверверные приложения под ОС Linux. Но предложи ему реализовать работу ТСР на контроллере, под который есть только asm и нет библиотек tcp - процесс создания таких приложений под контроллер резко затормозится. И даже встанет. Программируя под ОС джун не научился кодить для систем без ОС. Но ещё через год может все получится.
Тут я как раз привел классический "неправильный" пример, когда вместо select count(*) where a=b сделали select * , а потом в приложении сравнили a=b и посчитали количество.
ORM таким часто грешит, если неудачно что-то написать в коде.
Так вот, если СУБД и приложение на одном сервере, то время работы метода приложения будет небольшим. Хотя это не оптимально, но все равно быстро. И проблемы как бы нет. А если разнести на разные серверы, то метод будет выполняться долго. И появятся жалобы у пользователей.
В конечном итоге пользователю не важно, что там в базе происходит, а важно "время ответа при нажатии кнопки на сайте" или подобная метрика.
"Выносите СУБД на отдельный сервер" - немного спорное утверждение. В некоторых случаях это полезно, а некоторых - даже вредно.
Например, диагностика проблем с нагрузкой в случае отдельного сервера СУБД значительно проще. Не нужно "выяснять", что грузит диск или CPU - это база, ведь больше ничего нет. Не нужно выяснять, насколько нагрузка на CPU Django приложением замедляет процесс чтения из БД, потому что в этот момент БД тоже хочет получить доступ к CPU. И не нужно выяснять, сколько бы данных почиталось из дискового кэша, если бы вы не заняли память данными из Redis.
Но это только так кажется. В реальности ваша СУБД на отдельном железном сервере может работать быстрее просто потому, что вместо одного сервера вы использовали два. Потратили в 2 раза больше денег, получили в два раза больше ресурсов. Никакой магии.
Если вы используете виртуализацию, то вдруг оказывается, что отдельный сервер никакой не отдельный, а ресурсы все такие же разделяемые. Просто каждая виртуалка ограничена сверху максимально возможными потребляемыми ресурсами. Причем ограничение влияния очень условно. Гипотетически, на мелкой виртуалке с 2Гб ОЗУ можно запустить стресс-тест памяти на чтение/запись, что приведет к деградации работы с памятью другой виртуалки. Если не выставлены лимиты на операции с диском - тоже самое можно сделать с диском.
В общем случае отдельный сервер хорош тем, что ваши ресурсы не сможет "отжать" какой-то другой сервис. И этим же и плох - вы не сможете "позаимствовать" ресурсов сверх возможности железки, когда сервисам на соседних серверах эти ресурсы не нужны. И в итоге вынуждены платить х2-х5 за независимость сервисов и удобство диагностики.
Я обещал ещё кейс, когда СУБД на отдельном сервере - это вредно. Очень простой пример прямо из этой статьи: SELECT * .. WHERE 1. Если клиент и сервер находятся на одном сервере, тот запрос будет выполнен или со скоростью чтения с диска, или со скоростью чтения из памяти (если данные в кэше). В современных серверах (если я не ошибся в размерности, пока приводил все к гигаБайтам в секунду) скорость памяти порядка 100Гб/с, скорость работы с диском 10Гб/с, а скорость сети 1Гб/с. Значит, если приложение находится на другом сервере, то этот, безусловно "плохой", запрос будет выполнен в 10, а то и в 100 раз раз медленнее, если бы приложение и СУБД находились на одном сервере. Рецепт конечно прост - не делайте "плохих" запросов. Но на практике я их вижу из года в год в разных проектах.
Ну и в заключении. Лично я согласен с автором и предпочитаю разносить приложения и БД на разные сервера. Особенно, если за них платит кто-то другой ) Это в разы упрощает диагностику и возможности тонкой настройки. Но это подходит не всем.
Теперь стало понятнее, что именно вас смущает - вас гложет "проблема нулевого пароля", и вам кажется, что решения нет.
На самом деле их много разных. Напишу парочку вариантов:
Допустим вы запускаете ваше приложение в контейнере кубернетес. При запуске внутрь контейнера может быть помещен jwt, с помощью которого можно аутентифицироваться в Сервисе секретов, и получить оттуда пароль от базы данных.
Причем если точно такой же контейнер из того же самого образа будет запущен в другом неймспейсе этого кластера кубернетес, или в другом кластере кубернетес, он уже не получит доступ к секрету.
То есть вы переходите с схемы "дай доступ к базе по этому паролю (не знаю кому, кто придет - тому и дай)" к схеме "дай этому приложению в этом кластере доступ к базе". Дополнительно можно настроить, чтобы jwt был выписан на короткий срок, поэтому аутентифицироваться с ним в СервисеСекретов можно только сразу после запуска приложения, потом этот токен будет не действительный. Если в результате некорректной работы сервиса внутрь контейнера попадет вредоносный код (не прямо в момент запуска, а чуть позже), то внутри контейнера уже нет никаких действительных паролей, с которыми можно подключиться к БД.
Другой вариант - помещать рядом с приложением wrapped secret для подключения к СервисуСекретов. Его можно использовать только один раз, обменяв на токен доступа к СервисуСекретов. А оттуда уже получать временные пароли к БД.
Из коробки базы данных (в нашем примере) не поддерживают одноразовые пароли, а при использовании СервисаСекретов такая схема реализуется не очень сложно.
Ну и вообще никто не утверждал, что "секрет от сервиса секретов" вообще не существует. Он существует, просто очень короткое время. Он появляется на момент запуска, и потом становится недействительным. А так как обычное состояние системы совсем не перманентная перезагрузка, то и шанс утащить такой секрет гораздо меньше, чем если он был где-то рядом с сервисом.
Итого, секрет от СервисаСкретов1 не хранится ни в каком СервисеСекретов2. Как правило, он создаётся по требованию, причем он может быть:
Одноразовый
С коротким временем действия
Выданный для конкретного приложения
Запущенного из конкретного образа
В конкретном кластере Kubernetes
Запущенном на конкретной ноде или группе нод
С конкретным IP или диапазоном IP
Созданный в определенное время суток или день недели
Комбинации условий получения такого секрета могут быть на ваш выбор. Вы переходите от паролей, которые сложно контролировать, сразу же после создания, к описанию условий доступа.
Причем такой подход работает не только для подключения приложения к базе по паролю, а одинаково для чего угодно - токены API, сертификаты, ключи шифрования и т.п.
Хочу отдельно поблагодарить вас про упоминание проблемы доставки секретов. Вы отметили, что "она у нас не закрыта". Как раз напротив, в нашей платформе DKP для этого есть специальный модуль secrets-store-integration, который инжектирует секреты из СервисаСекретов прямо в env ПРОЦЕССА с приложением (подсвечу ещё раз - не в контейнер, а в процесс). Основываясь как раз на правилах доступа, варианты которых я выше описал. С точки зрения приложения, секрет - это объект в памяти вашего процесса, который недоступен другим приложениям/процессам в этом же контейнере (ну насколько может быть недоступна память соседнего процесса в ОС Linux)
Интересный вывод. А можете пояснить, почему "обязательно"? И что вообще в этом плохого?
Допустим у меня есть сервис секретов, который шифрует свои "секреты" (например, ключи шифрования), а заодно и свою конфигурацию, через HSM. Допустим, какой нибудь Rutoken ЭЦП. Поэтому без доступа к HSM нельзя ни секреты поменять, ни доступ к ним поменять.
Для того, чтобы обеспечить защиту HSM нужно сделать простые и понятные вещи - обеспечить физическую защиту "флешки" с HSM. Например, помещение с замком, охранником, видеонаблюдением, сигнализацией.
А теперь представьте, что у вас 1000 приложений, и под ними 1000 баз данных, и все это должно как-то безопасно друг с другом взаимодействовать. Например, передявляя какой-то короткоживущие пароль, или короткоживущий сертификат (даже если их "украдут", то сложно будет ими воспользоваться, так как пройдет срок действия. Так вот, реализовать отдельное помещение с замком, охранником и сигнализацией для каждого приложения или базы данных будет проблематично. Но можно пользоваться общим сервисом, которому все доверяют, потому что точно знают, что там охранник есть, и конфигурация доступа несанкционированно поменяться не может. Этот сервис управляет "секретами", или, если хотите, правами доступов одних сервисов к другим. Причем доступы могут быть как одноразовые, так и сессионные, так и отзываемые. То есть даже в случае утечки быть с большой долей вероятности бесполезными через несколько часов или минут.
Причем вариант с HSM не обязателен, если мы считаем, что охранник охраняет не "флешку", а сервер, на котором запущен сервис. На сервере нет сетевого доступа по ssh вообще, только с клавиатуры можно что-то делать. Обеспечить безопасность одного сервера все ещё проще, чем сотен серверов с 1000 сервисов и 1000 баз данных. Поэтому сервис хранения секретов для сервиса секретов вовсе не обязателен. Зависит от вашей паранойи или требований ИБ.
Впрочем, другие способы обеспечения безопасности доступа к сервисам вроде network policy, mTLS или кросс-сервисной аутентификации через JWT никто не отменял, и их можно использовать совместно с "классическими секретами" вроде "паролей от базы"
Может и перебрасывает, но в webview не видно адресной строки. Может быть страница, которая отображается в приложении, и есть страница госуслуг. И данные, которые вы введёте в форму, тоже уйдут на сайт госуслуг. Но вы это никак проверить не можете.
Не пользовался госключом, но как вы поняли, что это не webview, выполняющий аутентификацию через oauth, а именно запрос пароля в своем окне? Мне казалось, что в случае с webview у пользователя нет никакой возможности понять (и проверить), куда он вводит свой пароль. Во всяком случае мне такой способ неизвестен. И я с вами абсолютно согласен, что это большая проблема.
Когда открывается окно приложения - тут вроде все понятно становится. Но это может зависеть от настроек безопасности телефона (во всяком случае в Android), разрешено ли приложению Госуслуги автоматом открывать ссылки на госуслуги. Если разрешено, то откроется приложение Госуслуги, и там может быть вход по биометрии. А если не разрешено, то обычное окно webview, "встроенное" в другое приложение, и там работает только пароль.
Спасибо за статью, очень интересно, особенно кейс с рейтлимитом при вычитке из Кафки.
А не приходилось бороться с "шумными соседями", которые данные не пишут, а читают? Например разносить индексы разных продуктов по разным нодам opensearch. Какой вообще rps на поиск, и сколько чтения выполняет какой-то средний запрос?
И про подход к хранению в opensearch тоже интересно. Разные продукты пишут в разные индексы? Индекс, куда идёт запись, задаёт отправитель, или он вычисляется например в логстэше? Количество шардов у индекса как-то автоматически регулируется в зависимости от объема данных, или регулируется вручную?
Не думали переливать старые данные, по которым объективно никто не ищет, но формально их нужно хранить, в другое хранилище? С снапшотами в S3 понятно, но если логи деиндексировать (сделать из них строку) и сжать текст, то гипотетически коэффициент сжатия будет х10, и при этом не будет индексов. И уже это переложить в S3. В подобном формате данные хранит loki. Как вариант, в loki можно сразу из kafka читать вторым потоком, и он поместит все в S3. Профит будет не х20, а х200 (наверное). Соответственно, при прочих равных, данные можно хранить не год, а 10 лет
Помимо совместимости есть ещё и проблема производительности. Если условный AES работает быстро, пользуясь инструкциями процессора (если у вас конечная точка это ПК), то ГОСТ шифрование в буржуйских intel-ах (arm-ах, mips-ах) конечно же не реализовано. И скорее всего не будет в сколько-то обозримом будущем.
На стороне клиента это может быть не очень большой проблемой, но если обслуживаются сотни и тысячи соединений, то проблема становится заметной. Сейчас про это редко вспоминают лишь потому что шифрованием каналов связи ГОСТ-ом мало кто пользуется.
Как вы думаете, есть ли реальная необходимость писать документацию, в том числе с помощью нейронок, если сейчас массово вместо чтения документации пользователи используют запросы к нейронкам? Кто, по вашему мнению, реальный читатель документации, написанной с помощью AI? Человек или другой AI?
В своём опыте от документации мне часто требуются только общие примеры использования, потому что частные случаи о ответы на вопрос "а как оно там внутри реально работает" я предпочитаю искать непосредственно в коде (если он доступен). Ведь код не обманывает. В отличие от документации, которая может быть не полной, устаревшей, противоречивой. В каком-то смысле код можно считать "самой полной документацией, какая только может быть"
Согласен, не все пользователи смогут читать код, но и документацию тоже не все могут читать. В итоге все переходят к запросам к условному chat-gpt. Да и в чем смысл читать документацию, написанную AI, когда можно задавать в AI более четкий вопрос по вашей задаче. Если будет возможность сгружать в AI полный код проекта, а потом задавать интересующие вопросы по его работе, то имеет ли смысл писать документацию?
Контейнеры, и их оркестраторы вроде Кубернетес популярны потому что они предоставляют какие-то унифицированные правила для различных приложений, не важно на каком ЯП они написаны или с использованием какого фреймворка.
Например, для любых приложений можно сделать rolling update версий, или service discovery, или балансировку запросов в приложения, или обновление конфигурации. И будет это работать примерно одинаково , хоть у вас C++, хоть python. Не нужно для каждого фреймворка поддерживать свой велосипед, хотя в каждом конкретном случае этот велосипед может быть конечно лучше, чем какое-то обобщенное решение.
Разумеется не нужно все пихать в контейнеры просто ради контейнеров. Если вы точно знаете, что без контейнеров это работает лучше - пусть так и будет. Но нужно не забывать, что обслуживание любого кастома отнимает больше ресурсов, и требует больше знаний от команды эксплуатации.
Я абсолютный ноль в Erlang, я скорее из невежественных девопсов. Меня заинтересовал момент про сохранение стейта процесса при перезапуске/миграции, но я не уловил куда этот стейт сохраняется. Выгружается в другую ноду кластера на другом хосте? Или все в рамках одного контейнера или хоста происходит. Можете немного развернуть? Возможно тут есть проблема в терминологии, что считать хостом, и что процессом.
Если сейчас кто-то столкнется с похожей проблемой, то нагуглить возможное решение будет проще (будет найдена эта статья). Не надо будет тратить на это три года. А завтра на этот вопрос ответит уже chat-gpt
Так что здорово, что автор поделился своей историей.
То что ответ был "где-то в компьютере, который у вас в руках" - это очевидно. Но что с этим делать - непонятно. Прочитать и понять 40 миллионов строк ядра?
У меня сейчас ноут от такого же вендора, со сканером отпечатка. Который работает 1 раз. Если сканирование сразу не прошло, то потом на несколько минут "устройство занято". Пользоваться в общем невозможно, ну я и не пользуюсь, ввожу пароль по старинке. При этом я пробовал нагуглить - и не нагуглил. Но был бы рад, чтобы нагуглилось. Пробовал разобраться, посмотрел issues, код драйвера, код библиотеки, которая со сканером работает. Потратил 2-3 часа, и решил что не так-то уж этот сканер мне нужен. Но может быть когда-нибудь выйдет статья на хабре )
А за за статью автору спасибо, было интересно почитать.
А вы замечали, сколько исходников есть на github? И на 50-90 процентов приложения написаны используя эти библиотеки. В том числе stdlib. То есть если вы не видите исходный код самого приложения, то вполне вероятно, что у вас есть исходники большинства используемых библиотек.
Выходит, что нужно начинать читать весь гитхаб на предмет TODO и README
Он может в том числе выполнять сборку образов. И он решает вопрос воспроизводимости сборок несколько иначе. Werf кэширует промежуточные слои в реджистри. Разные сборки на разных раннерах используют общие слои. Таким образом решаются 2 задачи - ускорение сборки и повторяемость. Бонусом идёт кейс, что если исходные источники устанавливаемых пакетов более недоступны, то пока у вас есть промежуточный слой в реджистри, где вы их когда-то успешно установили, то вас это не заботит. Не важно, делали ли вы prune или нет, если слой был когда-то собран, то более он пересобираться не будет.
Так же werf сам следит за своими образами в реджистри, на основании истории git, удаляя "лишние" слои только тогда, когда нет веток/тэгов в git, ссылающихся на них
На самом деле зашифрованы только данные, которые лежат на диске. Или в любом другом бэкенде. Если вы получите доступ только к файлам, или дампу БД, тогда да - данные не расшифровать.
Но если вы попали на сервер, где запущен работающий Vault, то тут простор для фантазии. Ключ шифрования находится в памяти, можно дампнуть память процесса. Можно потрейсить процесс или подключиться дебаггером. Можно подгрузить eBPF правила, которые будут сливать часть инфы. Можно воткнуть MITM-прокси (сертифкаты лежат на ноде в виде файлов) и получить токены пользователей, которые делают запросы, а так же посмотреть данные, которые им отправляет Vault.
Получилась практически новая база данных с поддержкой репликации. Данные можно безопасно и надёжно хранить прямо в буфере обмена. Сам буфер обмена поддерживает тёмную тему, что является одним из его основных преимуществ.
Я бы добавил: а вот если бы начали использовать эрланг, то до сих пор бы были в процессе попыток начать использовать эрланг. А бухгалтерию вели на бумажке.
Плюс "убогих go и Kubernetes" наверное в том, что можно взять и уже завтра получить что-то более менее работающее и расширяемое. Не такое может красивое, зато завтра. Потому что послезавтра у это будет уже не нужно, а нужно будет что-то другое.
Новосибирский Новотелеком (куплен ДОМ ру лет 7 назад) поднимает стоимость тарифа ежегодно. Для некоторых тарифов за 7 лет стоимости выросла раза в 2, для некоторых в 6 раз.
Был такой тариф "для пенсионеров", назывался Социальный. 512кбит за 30р в месяц. Появился он когда сотовые операторы повально безлимиты предлагали.
Так вот, этот тариф сначала стоил 30р, потом 40р, далее 60р, 100р. Сейчас уже 190р. Цену не забывают индексировать. Но скорость так и осталась 512кбит, как 10-15 лет назад.
Да, 190р/мес сейчас - это не деньги. И почему происходит индексация - тоже понятно. Но и полмегабита - это не связь. Ребята наверное не знают, что на такой скорости даже госуслуги (то, для чего якобы позиционируется тариф) сейчас не работают. Проще иметь мобильную связь рублей за 500, которая работает везде, а не только дома, и не со скоростью черепахи.
Итого, проводные операторы повышают цены, которые за 10 лет в среднем выросли раза в 2. Мобильные - тоже. Так что гайки может быть и крутит ФАС, но не намертво.
Хороший пример. Вот мне не даёт покоя вопрос - когда и где гипотетический хороший джун из первого примера должен все это узнать и всему этому научиться. Ну не так, чтобы "знать эти слова", а ещё и понимать немножко глубже. В школе на продленке этому сейчас учат? Ну нет. В ВУЗе? Ну от части что-то затрагивают, но зависит даже не от ВУЗа или специальности, а от программы конкретного преподавателя. В итоге это какое-то самообразование. То есть кандидат сначала должен сделать для себя один-два проекта уровня, как вы описали выше, набить все шишки, столкнуться со всеми нюансами. И только потом может искать работу уровня джуна.
Сегодня
Если взять джуна, то он будет писать код с помощью LLM. Худо-бедно будет закрывать задачи, и через год-полтора сможет делать что-то более сложное. И гораздо быстрее. Но только с LLM. Предложи написать все самому без LLM - процесс затормозится значительно, а скорее всего даже встанет. Пограммируя с помощью LLM джун не научился кодить без него. Но ещё через год может все получится.
Вчера
Если взять джуна, то используя хороший фреймворк и IDE он сможет делать типовые задачки, а через год-полтора - что-то более сложное, и гораздо быстрее. Но дай ему текстовый редактор и компилятор, и скажи, что библиотеками пользоваться нельзя - процесс затормозится значительно, а скорее всего даже встанет. Пограммируя с помощью ide и фреймворков джун не научился кодить без них. Но ещё через год может все получится.
Позавчера
Взять джуна, через год он сможет писать на C сетевые клиент-серверверные приложения под ОС Linux. Но предложи ему реализовать работу ТСР на контроллере, под который есть только asm и нет библиотек tcp - процесс создания таких приложений под контроллер резко затормозится. И даже встанет. Программируя под ОС джун не научился кодить для систем без ОС. Но ещё через год может все получится.
Тут я как раз привел классический "неправильный" пример, когда вместо select count(*) where a=b сделали select * , а потом в приложении сравнили a=b и посчитали количество.
ORM таким часто грешит, если неудачно что-то написать в коде.
Так вот, если СУБД и приложение на одном сервере, то время работы метода приложения будет небольшим. Хотя это не оптимально, но все равно быстро. И проблемы как бы нет. А если разнести на разные серверы, то метод будет выполняться долго. И появятся жалобы у пользователей.
В конечном итоге пользователю не важно, что там в базе происходит, а важно "время ответа при нажатии кнопки на сайте" или подобная метрика.
"Выносите СУБД на отдельный сервер" - немного спорное утверждение. В некоторых случаях это полезно, а некоторых - даже вредно.
Например, диагностика проблем с нагрузкой в случае отдельного сервера СУБД значительно проще. Не нужно "выяснять", что грузит диск или CPU - это база, ведь больше ничего нет. Не нужно выяснять, насколько нагрузка на CPU Django приложением замедляет процесс чтения из БД, потому что в этот момент БД тоже хочет получить доступ к CPU. И не нужно выяснять, сколько бы данных почиталось из дискового кэша, если бы вы не заняли память данными из Redis.
Но это только так кажется. В реальности ваша СУБД на отдельном железном сервере может работать быстрее просто потому, что вместо одного сервера вы использовали два. Потратили в 2 раза больше денег, получили в два раза больше ресурсов. Никакой магии.
Если вы используете виртуализацию, то вдруг оказывается, что отдельный сервер никакой не отдельный, а ресурсы все такие же разделяемые. Просто каждая виртуалка ограничена сверху максимально возможными потребляемыми ресурсами. Причем ограничение влияния очень условно. Гипотетически, на мелкой виртуалке с 2Гб ОЗУ можно запустить стресс-тест памяти на чтение/запись, что приведет к деградации работы с памятью другой виртуалки. Если не выставлены лимиты на операции с диском - тоже самое можно сделать с диском.
В общем случае отдельный сервер хорош тем, что ваши ресурсы не сможет "отжать" какой-то другой сервис. И этим же и плох - вы не сможете "позаимствовать" ресурсов сверх возможности железки, когда сервисам на соседних серверах эти ресурсы не нужны. И в итоге вынуждены платить х2-х5 за независимость сервисов и удобство диагностики.
Я обещал ещё кейс, когда СУБД на отдельном сервере - это вредно. Очень простой пример прямо из этой статьи: SELECT * .. WHERE 1. Если клиент и сервер находятся на одном сервере, тот запрос будет выполнен или со скоростью чтения с диска, или со скоростью чтения из памяти (если данные в кэше). В современных серверах (если я не ошибся в размерности, пока приводил все к гигаБайтам в секунду) скорость памяти порядка 100Гб/с, скорость работы с диском 10Гб/с, а скорость сети 1Гб/с. Значит, если приложение находится на другом сервере, то этот, безусловно "плохой", запрос будет выполнен в 10, а то и в 100 раз раз медленнее, если бы приложение и СУБД находились на одном сервере. Рецепт конечно прост - не делайте "плохих" запросов. Но на практике я их вижу из года в год в разных проектах.
Ну и в заключении. Лично я согласен с автором и предпочитаю разносить приложения и БД на разные сервера. Особенно, если за них платит кто-то другой ) Это в разы упрощает диагностику и возможности тонкой настройки. Но это подходит не всем.
Теперь стало понятнее, что именно вас смущает - вас гложет "проблема нулевого пароля", и вам кажется, что решения нет.
На самом деле их много разных. Напишу парочку вариантов:
Допустим вы запускаете ваше приложение в контейнере кубернетес. При запуске внутрь контейнера может быть помещен jwt, с помощью которого можно аутентифицироваться в Сервисе секретов, и получить оттуда пароль от базы данных.
Причем если точно такой же контейнер из того же самого образа будет запущен в другом неймспейсе этого кластера кубернетес, или в другом кластере кубернетес, он уже не получит доступ к секрету.
То есть вы переходите с схемы "дай доступ к базе по этому паролю (не знаю кому, кто придет - тому и дай)" к схеме "дай этому приложению в этом кластере доступ к базе". Дополнительно можно настроить, чтобы jwt был выписан на короткий срок, поэтому аутентифицироваться с ним в СервисеСекретов можно только сразу после запуска приложения, потом этот токен будет не действительный. Если в результате некорректной работы сервиса внутрь контейнера попадет вредоносный код (не прямо в момент запуска, а чуть позже), то внутри контейнера уже нет никаких действительных паролей, с которыми можно подключиться к БД.
Другой вариант - помещать рядом с приложением wrapped secret для подключения к СервисуСекретов. Его можно использовать только один раз, обменяв на токен доступа к СервисуСекретов. А оттуда уже получать временные пароли к БД.
Из коробки базы данных (в нашем примере) не поддерживают одноразовые пароли, а при использовании СервисаСекретов такая схема реализуется не очень сложно.
Ну и вообще никто не утверждал, что "секрет от сервиса секретов" вообще не существует. Он существует, просто очень короткое время. Он появляется на момент запуска, и потом становится недействительным. А так как обычное состояние системы совсем не перманентная перезагрузка, то и шанс утащить такой секрет гораздо меньше, чем если он был где-то рядом с сервисом.
Итого, секрет от СервисаСкретов1 не хранится ни в каком СервисеСекретов2. Как правило, он создаётся по требованию, причем он может быть:
Одноразовый
С коротким временем действия
Выданный для конкретного приложения
Запущенного из конкретного образа
В конкретном кластере Kubernetes
Запущенном на конкретной ноде или группе нод
С конкретным IP или диапазоном IP
Созданный в определенное время суток или день недели
Комбинации условий получения такого секрета могут быть на ваш выбор. Вы переходите от паролей, которые сложно контролировать, сразу же после создания, к описанию условий доступа.
Причем такой подход работает не только для подключения приложения к базе по паролю, а одинаково для чего угодно - токены API, сертификаты, ключи шифрования и т.п.
Хочу отдельно поблагодарить вас про упоминание проблемы доставки секретов. Вы отметили, что "она у нас не закрыта". Как раз напротив, в нашей платформе DKP для этого есть специальный модуль secrets-store-integration, который инжектирует секреты из СервисаСекретов прямо в env ПРОЦЕССА с приложением (подсвечу ещё раз - не в контейнер, а в процесс). Основываясь как раз на правилах доступа, варианты которых я выше описал. С точки зрения приложения, секрет - это объект в памяти вашего процесса, который недоступен другим приложениям/процессам в этом же контейнере (ну насколько может быть недоступна память соседнего процесса в ОС Linux)
Интересный вывод. А можете пояснить, почему "обязательно"? И что вообще в этом плохого?
Допустим у меня есть сервис секретов, который шифрует свои "секреты" (например, ключи шифрования), а заодно и свою конфигурацию, через HSM. Допустим, какой нибудь Rutoken ЭЦП. Поэтому без доступа к HSM нельзя ни секреты поменять, ни доступ к ним поменять.
Для того, чтобы обеспечить защиту HSM нужно сделать простые и понятные вещи - обеспечить физическую защиту "флешки" с HSM. Например, помещение с замком, охранником, видеонаблюдением, сигнализацией.
А теперь представьте, что у вас 1000 приложений, и под ними 1000 баз данных, и все это должно как-то безопасно друг с другом взаимодействовать. Например, передявляя какой-то короткоживущие пароль, или короткоживущий сертификат (даже если их "украдут", то сложно будет ими воспользоваться, так как пройдет срок действия. Так вот, реализовать отдельное помещение с замком, охранником и сигнализацией для каждого приложения или базы данных будет проблематично. Но можно пользоваться общим сервисом, которому все доверяют, потому что точно знают, что там охранник есть, и конфигурация доступа несанкционированно поменяться не может. Этот сервис управляет "секретами", или, если хотите, правами доступов одних сервисов к другим. Причем доступы могут быть как одноразовые, так и сессионные, так и отзываемые. То есть даже в случае утечки быть с большой долей вероятности бесполезными через несколько часов или минут.
Причем вариант с HSM не обязателен, если мы считаем, что охранник охраняет не "флешку", а сервер, на котором запущен сервис. На сервере нет сетевого доступа по ssh вообще, только с клавиатуры можно что-то делать. Обеспечить безопасность одного сервера все ещё проще, чем сотен серверов с 1000 сервисов и 1000 баз данных. Поэтому сервис хранения секретов для сервиса секретов вовсе не обязателен. Зависит от вашей паранойи или требований ИБ.
Впрочем, другие способы обеспечения безопасности доступа к сервисам вроде network policy, mTLS или кросс-сервисной аутентификации через JWT никто не отменял, и их можно использовать совместно с "классическими секретами" вроде "паролей от базы"
Не сказать что неправда, но ещё точнее было бы "без малого 30 лет".
Может и перебрасывает, но в webview не видно адресной строки. Может быть страница, которая отображается в приложении, и есть страница госуслуг. И данные, которые вы введёте в форму, тоже уйдут на сайт госуслуг. Но вы это никак проверить не можете.
Не пользовался госключом, но как вы поняли, что это не webview, выполняющий аутентификацию через oauth, а именно запрос пароля в своем окне? Мне казалось, что в случае с webview у пользователя нет никакой возможности понять (и проверить), куда он вводит свой пароль. Во всяком случае мне такой способ неизвестен. И я с вами абсолютно согласен, что это большая проблема.
Когда открывается окно приложения - тут вроде все понятно становится. Но это может зависеть от настроек безопасности телефона (во всяком случае в Android), разрешено ли приложению Госуслуги автоматом открывать ссылки на госуслуги. Если разрешено, то откроется приложение Госуслуги, и там может быть вход по биометрии. А если не разрешено, то обычное окно webview, "встроенное" в другое приложение, и там работает только пароль.
Спасибо за статью, очень интересно, особенно кейс с рейтлимитом при вычитке из Кафки.
А не приходилось бороться с "шумными соседями", которые данные не пишут, а читают? Например разносить индексы разных продуктов по разным нодам opensearch. Какой вообще rps на поиск, и сколько чтения выполняет какой-то средний запрос?
И про подход к хранению в opensearch тоже интересно. Разные продукты пишут в разные индексы? Индекс, куда идёт запись, задаёт отправитель, или он вычисляется например в логстэше? Количество шардов у индекса как-то автоматически регулируется в зависимости от объема данных, или регулируется вручную?
Не думали переливать старые данные, по которым объективно никто не ищет, но формально их нужно хранить, в другое хранилище? С снапшотами в S3 понятно, но если логи деиндексировать (сделать из них строку) и сжать текст, то гипотетически коэффициент сжатия будет х10, и при этом не будет индексов. И уже это переложить в S3. В подобном формате данные хранит loki. Как вариант, в loki можно сразу из kafka читать вторым потоком, и он поместит все в S3. Профит будет не х20, а х200 (наверное). Соответственно, при прочих равных, данные можно хранить не год, а 10 лет
Помимо совместимости есть ещё и проблема производительности. Если условный AES работает быстро, пользуясь инструкциями процессора (если у вас конечная точка это ПК), то ГОСТ шифрование в буржуйских intel-ах (arm-ах, mips-ах) конечно же не реализовано. И скорее всего не будет в сколько-то обозримом будущем.
На стороне клиента это может быть не очень большой проблемой, но если обслуживаются сотни и тысячи соединений, то проблема становится заметной. Сейчас про это редко вспоминают лишь потому что шифрованием каналов связи ГОСТ-ом мало кто пользуется.
Как вы думаете, есть ли реальная необходимость писать документацию, в том числе с помощью нейронок, если сейчас массово вместо чтения документации пользователи используют запросы к нейронкам? Кто, по вашему мнению, реальный читатель документации, написанной с помощью AI? Человек или другой AI?
В своём опыте от документации мне часто требуются только общие примеры использования, потому что частные случаи о ответы на вопрос "а как оно там внутри реально работает" я предпочитаю искать непосредственно в коде (если он доступен). Ведь код не обманывает. В отличие от документации, которая может быть не полной, устаревшей, противоречивой. В каком-то смысле код можно считать "самой полной документацией, какая только может быть"
Согласен, не все пользователи смогут читать код, но и документацию тоже не все могут читать. В итоге все переходят к запросам к условному chat-gpt. Да и в чем смысл читать документацию, написанную AI, когда можно задавать в AI более четкий вопрос по вашей задаче. Если будет возможность сгружать в AI полный код проекта, а потом задавать интересующие вопросы по его работе, то имеет ли смысл писать документацию?
Контейнеры, и их оркестраторы вроде Кубернетес популярны потому что они предоставляют какие-то унифицированные правила для различных приложений, не важно на каком ЯП они написаны или с использованием какого фреймворка.
Например, для любых приложений можно сделать rolling update версий, или service discovery, или балансировку запросов в приложения, или обновление конфигурации. И будет это работать примерно одинаково , хоть у вас C++, хоть python. Не нужно для каждого фреймворка поддерживать свой велосипед, хотя в каждом конкретном случае этот велосипед может быть конечно лучше, чем какое-то обобщенное решение.
Разумеется не нужно все пихать в контейнеры просто ради контейнеров. Если вы точно знаете, что без контейнеров это работает лучше - пусть так и будет. Но нужно не забывать, что обслуживание любого кастома отнимает больше ресурсов, и требует больше знаний от команды эксплуатации.
Я абсолютный ноль в Erlang, я скорее из невежественных девопсов. Меня заинтересовал момент про сохранение стейта процесса при перезапуске/миграции, но я не уловил куда этот стейт сохраняется. Выгружается в другую ноду кластера на другом хосте? Или все в рамках одного контейнера или хоста происходит. Можете немного развернуть? Возможно тут есть проблема в терминологии, что считать хостом, и что процессом.
Если сейчас кто-то столкнется с похожей проблемой, то нагуглить возможное решение будет проще (будет найдена эта статья). Не надо будет тратить на это три года. А завтра на этот вопрос ответит уже chat-gpt
Так что здорово, что автор поделился своей историей.
То что ответ был "где-то в компьютере, который у вас в руках" - это очевидно. Но что с этим делать - непонятно. Прочитать и понять 40 миллионов строк ядра?
У меня сейчас ноут от такого же вендора, со сканером отпечатка. Который работает 1 раз. Если сканирование сразу не прошло, то потом на несколько минут "устройство занято". Пользоваться в общем невозможно, ну я и не пользуюсь, ввожу пароль по старинке. При этом я пробовал нагуглить - и не нагуглил. Но был бы рад, чтобы нагуглилось. Пробовал разобраться, посмотрел issues, код драйвера, код библиотеки, которая со сканером работает. Потратил 2-3 часа, и решил что не так-то уж этот сканер мне нужен. Но может быть когда-нибудь выйдет статья на хабре )
А за за статью автору спасибо, было интересно почитать.
А вы замечали, сколько исходников есть на github? И на 50-90 процентов приложения написаны используя эти библиотеки. В том числе stdlib. То есть если вы не видите исходный код самого приложения, то вполне вероятно, что у вас есть исходники большинства используемых библиотек.
Выходит, что нужно начинать читать весь гитхаб на предмет TODO и README
Есть такой инструмент werf (werf.io)
Он может в том числе выполнять сборку образов. И он решает вопрос воспроизводимости сборок несколько иначе. Werf кэширует промежуточные слои в реджистри. Разные сборки на разных раннерах используют общие слои. Таким образом решаются 2 задачи - ускорение сборки и повторяемость. Бонусом идёт кейс, что если исходные источники устанавливаемых пакетов более недоступны, то пока у вас есть промежуточный слой в реджистри, где вы их когда-то успешно установили, то вас это не заботит. Не важно, делали ли вы prune или нет, если слой был когда-то собран, то более он пересобираться не будет.
Так же werf сам следит за своими образами в реджистри, на основании истории git, удаляя "лишние" слои только тогда, когда нет веток/тэгов в git, ссылающихся на них
Это частое заблуждение на тему Vault.
На самом деле зашифрованы только данные, которые лежат на диске. Или в любом другом бэкенде. Если вы получите доступ только к файлам, или дампу БД, тогда да - данные не расшифровать.
Но если вы попали на сервер, где запущен работающий Vault, то тут простор для фантазии. Ключ шифрования находится в памяти, можно дампнуть память процесса. Можно потрейсить процесс или подключиться дебаггером. Можно подгрузить eBPF правила, которые будут сливать часть инфы. Можно воткнуть MITM-прокси (сертифкаты лежат на ноде в виде файлов) и получить токены пользователей, которые делают запросы, а так же посмотреть данные, которые им отправляет Vault.