Подводные камни и альтернативы этой распространенной практики GitOps при переносе развертываний в рабочую среду.

GitOps — это практика представления конфигурации системы в репозитории Git с последующим использованием рабочих процессов Git для управления изменениями этой конфигурации и обновлениями системы.

Этот процесс представления конфигурации системы в репозитории изначально прост: заполнение файлов конфигурации, копирование декларативных запросов из документации по продукту и, возможно, даже случайная последовательность сценариев.

Поначалу вы чувствуете, что прогресс неизбежен, а успех ждет несколько коммитов за углом, а затем вы сталкиваетесь с окончательным фольгой GitOps: секретами.

Почему простые секреты — это плохо

Хотя может быть очевидно, что размещение простых учетных данных в репозитории Git — не лучшая идея, все же стоит объяснить, почему это проблематично, чтобы кто-то не подумал, что это может быть приемлемым компромиссом при использовании частного репозитория:

Люди, работающие с репозиторием GitOps, могут отличаться от тех, кто уполномочен управлять целевыми средами.

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

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

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

Закрытое решение

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

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

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

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

Причина №1: ключи к какой среде?

Допустим, у вас есть конвейер развертывания с последовательностью сред «разработка», «тестирование», «стадия» и «производство». В каждой среде будет работать одно и то же программное обеспечение, но если вы используете хорошие методы безопасности, они будут использовать разные наборы учетных данных.

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

В случае дерева папок для каждой целевой среды репозиторий git должен иметь отдельные местоположения для ключей для каждой среды. Когда вы работаете с повсеместным присутствием кластеров Kubernetes на предприятии, вы будете иметь дело с отдельными «секретными» ресурсами, распределенными по нескольким пространствам имен, что делает неизбежным разрастание папок и файлов.

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

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

Причина № 2: секреты… прямо здесь.

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

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

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

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

Отказ от всех линий защиты от кибератак и возложение всех надежд на защиту единственной точки отказа — ужасная отправная точка для безопасной системы.

(Обновление от 8 августа) Уоррен Парад отметил, что создание частных репозиториев может уменьшить эту опасность. Создание частного репозитория приводит к другим соображениям и предположениям о потенциальном пуле участников, но это может быть вариантом для некоторых последователей.

Причина № 3: ключ для защиты всех ключей по-прежнему остается ключом.

Жизненный цикл секретов в репозитории может различаться в зависимости от того, что они защищают. Учетные данные базы данных могут истечь каждые 30 дней, а учетные данные кластера — каждые 60 дней.

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

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

Причина № 4: есть лучшие решения.

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

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

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

Придерживаясь примера Kubernetes, где вы, вероятно, будете использовать ArgoCD и Flux для своих практик GitOps, в настоящее время им не хватает встроенной интеграции для чтения значений ключей непосредственно от поставщика KMS.

Например, в документации ArgoCD говорится: Argo CD не высказывает мнения о том, как управляются секреты, но далее предлагается длинный список решений для интеграции с выделенными службами. И хотя Flux CD поддерживает глобальную расшифровку ключей из KMS в своем контроллере kustomize, он по-прежнему требует, чтобы эти секреты хранились (зашифровывались) в репозитории git.

Более многообещающий подход запускается через проект External Secrets Operator, который синхронизирует секреты из различных служб управления ключами в локальные секреты в кластере Kubernetes (за эту ссылку спасибо моему коллеге Carlos Santana).

(Обновление от 16.03) Томас Бергер упомянул в разделе комментариев о другой альтернативе закрытым секретам: использование SOPS с Flux и Argo.

(Обновление от 8 августа) Стефан Продан назвал неверным обобщение о том, что Flux не имеет встроенной интеграции с провайдерами KMS, на основании поддержки Flux глобальной расшифровки ключей. Я переписал это заявление, чтобы пояснить, что Flux (как и Argo CD) не имеет возможности считывать секреты напрямую от поставщика KMS. На сегодняшний день Flux может использовать поставщика KMS для шифрования артефактов до их включения. в репозитории Git.

Заключение

Могут быть веские причины для использования запечатанных секретов. Тем не менее, я еще не видел ни одного положительного решения, кроме того, что запечатанные секреты являются «достаточно хорошими», что означает, что их развертывание дешевле, чем надлежащее решение для управления ключами. Я редко вижу, чтобы обсуждение касалось всего остального, связанного с обращением с этими секретами.

Я не сомневаюсь в инженерном мастерстве тех, кто решил имитировать службу управления ключами с помощью текстовых файлов в репозитории кода, но я сомневаюсь в экономической эффективности этих подходов. Толпа DIY должна прибегнуть к комбинации размещения файлов в репозитории git, сопоставления циклов ротации ключей с запросами на вытягивание git и оснащения конвейеров непрерывного развертывания ключами дешифрования для анализа содержимого репозитория. И если вы спрашиваете, как управлять этими главными ключами, вы можете оказаться в постоянном цикле придумывания творческих способов заставить Git действовать как сервис управления ключами.

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

Избегайте закрытых секретов, правильно начните практику GitOps и используйте службу управляемых ключей.

(Update on 5/23: If you like this topic, I wrote a new story including a couple of other things to avoid.)