Привет! Меня зовут Андрей Шилов, я старший инженер по практикам DevOps в компании «Флант». Мы занимаемся консалтингом и помогаем клиентам строить информационные системы, что почти всегда означает построение CI/CD-пайплайнов, которые должны быть безопасными, масштабируемыми и функциональными. И ключевое слово здесь — «безопасными». А безопасность пайплайна во многом определяется тем, как в нём хранятся секреты.
В статье разберёмся, как с этим обстоят дела на практике. Сначала я рассмотрю подходы к хранению секретов для пайплайнов и ограничения GitLab CI/CD Variables. Затем покажу три кейса самодельной интеграции GitLab CE с HashiCorp Vault и сложности, которые остаются даже при аккуратной её реализации. А в конце настрою нативную интеграцию Deckhouse Code и Deckhouse Stronghold, которая решает проблемы хранения секретов в пайплайнах «из коробки».
Дисклеймер: Deckhouse Code и Deckhouse Stronghold — это коммерческие продукты, для их использования нужно купить лицензию, хотя базовые возможности Stronghold доступны и в Open Source-платформе Deckhouse Kubernetes Platform Community Edition. В статье я разбираю проблемы существующих подходов и показываю, как наши продукты их решают. Итоговый выбор решения, как и всегда, остаётся за вами.

Способы хранения секретов для пайплайнов: от репозитория до хранилища
В CI/CD-пайплайнах секреты нужны практически на каждом этапе. Сборка и публикация образов — нужны credentials к registry. Деплой в Kubernetes-кластер — нужен kubeconfig или токен сервисного аккаунта. Интеграционные тесты — нужны реальные connection strings для подключения к базе данных. Нотификации и внешние API — токены Slack, Telegram, Kaiten, S3.
Если грубо прикинуть, способы хранения секретов для пайплайнов выстраиваются от «просто, но небезопасно» к «сложнее, но надёжнее».
Секреты в репозитории вместе с кодом. Секреты лежат в открытом виде, иногда обёрнутые в Base64, и подкладываются в переменные окружения или конфиг-файл при запуске или деплое. Плюсы очевидны: очень просто, изменения видны в коммитах. Минусы не менее очевидны: доступ к секретам есть у всех, у кого есть доступ к репозиторию. Это, конечно, антипаттерн. Но на практике он встречается чаще, чем хотелось бы, поэтому нужно его упомянуть.
CI/CD Variables. Секреты хранятся в зашифрованном виде внутри инструмента CI/CD, могут маскироваться, их видимость можно фильтровать по веткам и тегам. Звучит лучше, чем первый вариант. Правда, подводных камней, как мы разберём ниже, здесь значительно больше, чем кажется.
Сюда же примыкает промежуточный вариант: секреты лежат в репозитории, но в зашифрованном виде. Так работают SOPS, helm-secrets и werf: чувствительные значения шифруются ключом, а сам ключ передаётся в пайплайн через переменные CI/CD (реже — лежит в KMS). Прочитать секрет из репозитория без ключа нельзя, при этом история изменений сохраняется в Git. Но вся схема безопасна ровно настолько, насколько безопасен ключ в CI/CD Variables, а значит, наследует все их проблемы.
Выделенное хранилище секретов. Секреты хранятся в зашифрованном виде внутри специализированного решения и доставляются несколькими безопасными способами. Все секреты в одном месте, управление жизненным циклом и доступом строится на единых принципах, доставка безопасна на всех этапах и не требует написания каких-то особенных механизмов. Индустриальным стандартом здесь исторически является HashiCorp Vault.
Основным способом хранения секретов для CI/CD являются GitLab CI/CD Variables. Почему так? По данным нашего исследования State of DevOps Russia за 2025 год, львиная доля российского рынка пользуется GitLab и как системой хранения кода (70,2 %), и как платформой для CI/CD (64,5 % в вопросе с мультивыбором). И именно CI/CD Variables GitLab позиционирует как место для хранения секретов.
Давайте разберёмся, почему с этим есть серьёзные проблемы.
Почему GitLab CI/CD Variables — это не хранилище секретов
GitLab предоставляет три уровня хранения переменных:
Уровень инстанса — переменные доступны во всех проектах, управляются только администратором.
Уровень группы — доступны во всех проектах группы и подгрупп, наследуются автоматически.
Уровень проекта — доступны только в конкретном проекте, управляются maintainer'ом.
Каждая переменная может иметь тип Variable или File, несколько режимов видимости (Visible, Masked, Masked and hidden) и флаги Protected и Expand variable reference. Можно привязать переменную к конкретному окружению.
Звучит функционально. Но здесь кроется фундаментальная архитектурная проблема.
GitLab CI/CD Variables не разделяют «кто может запускать пайплайн» и «кто должен знать секрет».
Maintainer может добавить в Job printenv — и все секреты окажутся в логах. Но это ещё не всё. Секреты доступны через GitLab API при наличии токена. Все мы знаем привычку выдавать токенам максимально долгий lifecycle и максимально широкие скоупы, просто чтобы их не перевыпускать. Ротации нет: однажды прописанный секрет живёт годами без каких-либо алертов. Нет audit log: непонятно, кто и когда менял или читал секрет. Owner группы видит переменные всех дочерних проектов.
Кстати, ротация — это отдельная боль. Один секрет используется в 30 пайплайнах, разбросанных по разным группам, например тот же connection string к базе. При ротации нужно обновить его в каждом проекте вручную. Про часть, вероятно, забудут, что приведёт как минимум к падению пайплайна, как максимум — к инциденту на каком-то окружении.
Но самое неприятное то, что маскировка переменной не спасает. Представьте, что вы хотите дать разработчикам доступ к пайплайнам, но скрыть от них продовые секреты. С CI/CD Variables это архитектурно невозможно. Masked var не поможет, потому что любой разработчик может написать вот такое:
script: - echo ${SUPER_SECRET::1} ${SUPER_SECRET:1}
GitLab маскирует в логах только точные совпадения значения переменной. Здесь же секрет разрезан Bash-подстрокой на первый символ и хвост — ни одна из частей не совпадает с маской целиком, поэтому в логах окажется значение в открытом виде, разделённое пробелом.
Если возиться с логами не хочется, можно сохранить секрет в артефакт и скачать через UI:
script: - echo $SUPER_SECRET > secret.txt artifacts: paths: - secret.txt # Скачать через UI.
Момент с артефактами можно закрыть точечно: например, через artifacts:access: 'maintainer', который запретит скачивание артефакта не-мейнтейнерам. Но это перекрывает один способ утечки из десятков: способ компрометации вообще ничем не ограничен, кроме изобретательности злоумышленника.
Более системное решение может дать механизм general pipelines. CI-конфиг выносится в отдельный репозиторий с read-only-доступом для разработчиков, импортируется в проектные репозитории целиком, и переопределить из локального .gitlab-ci.yml ничего нельзя.
Но в нашей консалтинговой практике такое решение встречается крайне редко — оно требует очень высокой инженерной культуры. Командам почти всегда нужны «крутилки»: параметры, кастомные задачи (Jobs), переопределения под конкретный проект. Сделать общий пайплайн, который одновременно покроет все потребности и при этом не даст ничего изменить локально, сложно. Поэтому большинство команд использует более мягкие схемы — общие шаблоны через include и extends, где переопределить можно всё. А значит, на практике остаётся то же правило: если у разработчика есть возможность менять .gitlab-ci.yml, он дотянется до значений переменных окружения.
Концепция решения: пайплайн не хранит секрет
Решение через HashiCorp Vault меняет саму концепцию: пайплайн не хранит секрет — он его получает. Делается это через JWT/OIDC flow.
Схема работает так. При каждом запуске пайплайна GitLab автоматически генерирует одноразовый JWT-токен, подписанный своим приватным ключом. Внутри токена — обширный набор метаданных о контексте запуска: проект, ветка, окружение и многое другое, включая то, является ли ветка protected. Этот токен уникален для каждой задачи.
Runner передаёт JWT на эндпоинт аутентификации Vault. Никаких статичных паролей или токенов не нужно. Vault скачивает публичный ключ GitLab по OIDC Discovery URL, верифицирует подпись и проверяет bound claims — например, что запрос приходит именно из вашего проекта и с protected-ветки.
Если проверка прошла, Vault возвращает временный токен доступа с ограниченным TTL — ровно на время выполнения задачи. С этим токеном runner читает нужный секрет из Vault. После завершения задачи токен автоматически аннулируется, ничего не сохраняется.

Элегантная схема. Но здесь начинаются практические сложности.
Три варианта самодельной интеграции GitLab CE и HashiCorp Vault
Большинство наших клиентов и респондентов State of DevOps Russia пользуются GitLab в Community Edition и «ванильным» HashiCorp Vault. Проблема в том, что в GitLab CE нет keyword secrets:, оно доступно только в Premium/Ultimate. Всё, что остаётся, — писать самодельную интеграцию. На примере трёх реальных кейсов разберём, как это выглядит на практике.
Вариант 1: Python hvac + AppRole
В GitLab CI/CD Variables хранятся AppRole Credentials — VAULT_ROLE_ID (логин роли) и VAULT_SECRET_ID (пароль роли). Это не ссылки на секреты, а учётные данные для входа в Vault.
Внимательный читатель заметит: это снова секреты, к которым должны предъявляться требования безопасного хранения. Клиент хранил их в GitLab CI Variables — а значит, просто добавил ещё один «хоп» на пути к компрометации.
Python-скрипт через библиотеку hvac авторизуется в Vault по AppRole, обходит все переменные с префиксом V_, читает для них значения из Vault и инжектит их в окружение задачи:
# .gitlab-ci.yml variables: V_TRIVY_REGISTRY_PASSWORD: projects/project/TRIVY_REGISTRY_PASSWORD script: - source <(get-vault-secrets-by-approle) - echo $TRIVY_REGISTRY_PASSWORD
# Ключевые функции скрипта. def get_vault_vars(self): for k, v in os.environ.items(): if k.startswith(self.var_prefix): # var_prefix = 'V_' self.vault_vars[k] = v def login_to_vault_using_approle(self): self.client = hvac.Client(namespace=os.environ.get("VAULT_NAMESPACE")) self.client.auth.approle.login( os.environ.get('VAULT_ROLE_ID'), os.environ.get('VAULT_SECRET_ID')) def get_vault_secrets(self): for k, v in self.vault_vars.items(): secret_var_name = re.sub(r'^V_', '', k) vault_path = re.fullmatch( r'^(?P<mount_point>[^/]+)/(?P<path>.+)/(?P<key>[^/]+)$', v ).groupdict() vault_secret = self.client.secrets.kv.v2.read_secret_version( vault_path['path'], 0, vault_path['mount_point']) self.secret_vars[secret_var_name] = \ vault_secret['data']['data'][vault_path['key']] for k, v in self.secret_vars.items(): print("export {}=\"{}\"".format(k, v))
Вариант 2: Bash-скрипт с префиксом vault:
Этот вариант уже использует JWT-аутентификацию и концептуально ближе к тому, что предлагает GitLab EE. Переменная с префиксом vault: содержит путь к секрету. before_script обходит env и подставляет значения из Vault через API:
variables: VAULT_ADDR: https://vault.example.com VAULT_ROLE: project_role job_with_secrets: id_tokens: VAULT_ID_TOKEN: aud: vault variables: TRIVY_REGISTRY_PASSWORD: vault:projects/project#TRIVY_REGISTRY_PASSWORD before_script: - export VAULT_TOKEN=$(vault write -field=token \ auth/jwt/login role=$VAULT_ROLE jwt=$VAULT_ID_TOKEN) - | while IFS='=' read -r name value; do if [[ $value == vault:* ]]; then stripped=${value#vault:} export "$name=$(vault kv get \ -field=${stripped#*#} ${stripped%%#*})" fi done < <(env) script: - echo $TRIVY_REGISTRY_PASSWORD
before_script обычно выносится в отдельный шаблон и подключается через extends — чтобы не копировать «портянку» в каждую задачу. Фактически это аналог keyword secrets: из GitLab EE, но работающий в CE.
Вариант 3: Bash-скрипт в сборочном образе
Этот вариант появился у клиента с жёсткой ролевой моделью: у него есть множество собственных заказчиков, для каждого из которых разрабатывается ПО, при этом каждый заказчик имеет набор проектов, а каждый проект работает в нескольких окружениях.
Скрипт зашит в каждый сборочный образ. Роль и путь строятся строго по маске CLIENT-PROJECT-ENV — произвольный путь задать нельзя. Достаточно указать три параметра, и скрипт сам знает, куда идти в Vault:
deploy: variables: CI_VAULT_CLIENT: mycompany CI_VAULT_PROJECT: backend CI_ENV: production before_script: - source ExportVaultVars script: - echo $TRIVY_REGISTRY_PASSWORD
# Построение роли и пути. VAULT_ROLE="$VAULT_CLIENT-${VAULT_PROJECT/./-}-$ENV" # mycompany-backend-production VAULT_PATH="$VAULT_CLIENT/data/$VAULT_PROJECT/$ENV" # mycompany/data/backend/production # Двойная аутентификация: JWT в CI, LDAP локально. if [[ $CI_JOB_JWT != "" ]]; then VAULT_TOKEN=$(curl -s -X POST "$VAULT_URL/v1/auth/jwt/login" \ --data "{\"jwt\":\"$CI_JOB_JWT\",\"role\":\"$VAULT_ROLE\"}" | jq -r .auth.client_token) else VAULT_TOKEN=$(curl -s -X POST "$VAULT_URL/v1/auth/ldap/login/$username" \ --data "{\"password\":\"$password\"}" | jq -r .auth.client_token) fi # Cleanup unset VAULT_TOKEN VAULT_ROLE VAULT_PATH VAULT_CLIENT VAULT_PROJECT ENV
Интересная особенность этого варианта в том, что поддерживается двойная аутентификация — JWT в CI и LDAP локально. Разработчик может запустить скрипт руками с теми же правами. Есть три режима вывода: export в env, JSON-файл или .env-файл — это способы сохранения полученных секретов.
Но у этого клиента случился неприятный инцидент. Переменная CI_JOB_JWT в GitLab помечена как deprecated, и в один момент при обновлении до мажорной версии она просто перестала работать. Все автоматизации и деплои встали, пока не нашли выход из ситуации.
Проблемы самодельной интеграции и общие проблемы с HashiCorp Vault
Подведём итог по самодельным интеграциям:
Нет нативного keyword
secrets:, эта возможность доступна только в GitLab Premium/Ultimate.Нет единого стандарта: кто-то пишет Bash, кто-то — Python, кто-то тащит Vault Agent.
В ряде случаев приходится настраивать политики для «распечатывания» секретов. Каждый новый проект начинает с нуля.
При любом обновлении GitLab или Vault — риск полной поломки.
Но на этом список сложностей не ограничивается. Существуют проблемы любой интеграции с Vault, и они актуальны вне зависимости от того, CE или Premium у вас GitLab.
Во-первых, printenv внутри Job работает при любом подходе — выше я упоминал про это. Если секрет доставлен в env, процесс может его прочитать. Это фундаментальное ограничение доставки секретов через переменные окружения.
Во-вторых, дрифт конфигурации Vault. Роли и политики создаются руками. Есть риск, что через полгода никто не вспомнит, зачем нужна каждая роль. Даже если они создаются через Terraform, рано или поздно HCL-код может превратиться в нечитаемую портянку, внутри которой легко затеряется роль с wildcard-доступом.
В-третьих, операционная нагрузка. Vault как отдельный production-сервис требует HA, unseal, ротации сертификатов, мониторинга.
И наконец, HashiCorp Vault с 2023 года перешёл на лицензию BUSL 1.1 — коммерческое использование требует покупки лицензии. Существует альтернатива в виде OpenBao, но это молодой проект без enterprise-поддержки. Плюс оба продукта сложно использовать в серьёзных российских компаниях по довольно очевидным причинам.
Эти проблемы можно решить выбором продуктов, где интеграция уже сделана за вас и нет сложностей с покупкой лицензий.
Deckhouse Code + Deckhouse Stronghold: нативная интеграция для безопасных пайплайнов
Давайте познакомимся с действующими лицами.
Deckhouse Code — это полностью совместимая с GitLab CE и расширяющая его возможности платформа для хранения кода и CI/CD. И keyword secrets: в ней доступен.
Deckhouse Stronghold — это Vault-совместимое решение для централизованного управления жизненным циклом секретов. Deckhouse Code умеет работать с ним нативно через JWT/OIDC flow.
А поподробнее?
Deckhouse Code — это решение для непрерывной разработки и управления жизненным циклом ПО с enterprise-возможностями. Позволяет безопасно хранить исходный код и автоматизировать CI/CD-конвейеры любой сложности. На Deckhouse Code просто мигрировать с любой версии GitLab благодаря полной совместимости.
Из ключевых возможностей: создание кастомных правил code review, зеркалирование репозиториев из внешних источников и стабильный CI/CD-конвейер, который обеспечивает предсказуемую работу пайплайнов, а также высокая доступность и автомасштабирование.
Deckhouse Stronghold — это решение для централизованного управления жизненным циклом секретов с сертификатом ФСТЭК России. Он защищает пароли, ключи API, сертификаты, SSH-ключи, токены и другие конфиденциальные данные от утечек, обеспечивая при этом безопасную доставку секретов в приложения.
Мы не копируем HashiCorp Vault, а переосмысливаем хранилище секретов и создаём стандарт для российского рынка. При этом Deckhouse Stronghold полностью API-совместим с HashiCorp Vault — и через CLI, и через API.
Из ключевых возможностей: механизм namespaces для создания пространств имён и делегирования прав, auto unseal без использования внешних KMS, автоматическое резервное копирование, репликация KV1/KV2 на архитектуре master-slave, удобный веб-интерфейс, модуль secrets-store-integration для безопасной автоматизированной доставки секретов в приложения. И всё это — в единственном бинарном файле, что минимизирует векторы атаки.
Работает Deckhouse Stronghold по знакомой схеме: клиент подтверждает свою идентичность, Stronghold проверяет, есть ли у него доступ к запрошенному секрету, и либо разрешает операцию чтения/записи, либо отклоняет. Всё просто — и все ваши секреты под защитой.
Настройка интеграции состоит из трёх шагов на стороне Deckhouse Stronghold и минимального конфига на стороне Deckhouse Code.
Настройка интеграции шаг за шагом
Команды ниже работают через стандартный vault CLI — Deckhouse Stronghold с ним API-совместим. Те же команды можно выполнить через d8 stronghold — это часть d8, нашего «швейцарского ножа» для работы со всеми компонентами экосистемы Deckhouse. Например, вместо vault write auth/jwt/config будет d8 stronghold write auth/jwt/config. Для краткости в примерах оставлю vault.
Шаг 1: включить JWT-аутентификацию в Deckhouse Stronghold
Deckhouse Stronghold принимает ID-токены через метод JWT. Указываются OIDC Discovery URL и issuer — это URL вашего Deckhouse Code:
vault auth enable jwt vault write auth/jwt/config \ oidc_discovery_url="https://code.example.com" \ bound_issuer="https://code.example.com"
Шаг 2: создать роль с bound_claims
bound_claims ограничивает доступ — только токены с указанными значениями смогут аутентифицироваться. Без этого доступ получит любой CI-токен.
vault write auth/jwt/role/gitlab-role - <<EOF { "role_type": "jwt", "user_claim": "sub", "bound_audiences": ["vault"], "bound_claims": { "project_id": "23" }, "policies": ["gitlab-policy"], "ttl": "1h" } EOF
В bound_claims можно использовать project_id, project_path, ref, ref_protected, environment, namespace_path. Подберите нужную комбинацию под конкретный сценарий, например разрешите доступ только с protected-веток конкретного проекта.
Шаг 3: написать ACL-политику
Политика задаёт конкретные пути в Deckhouse Stronghold, к которым разрешено обращаться. Здесь работает принцип минимальных прав: только read к нужным секретам.
vault policy write gitlab-policy - <<EOF path "kv/data/code/vault-demo" { capabilities = ["read"] } EOF
Шаг 4. Конфигурация на стороне Deckhouse Code
В CI нужно указать обязательную переменную VAULT_SERVER_URL (URL Stronghold-сервера). Опционально — VAULT_AUTH_ROLE (название роли, по умолчанию берётся из конфигурации JWT auth), VAULT_AUTH_PATH (путь до метода аутентификации, по умолчанию jwt) и VAULT_NAMESPACE (для многоуровневой иерархии).
Использование в .gitlab-ci.yml:
stages: - test vault-demo: stage: test image: alpine # 1. Запрашиваем JWT-токен с audience = наш Vault. id_tokens: VAULT_ID_TOKEN: aud: https://vault.example.com # 2. Объявляем секрет: путь@движок. secrets: DATABASE_PASSWORD: vault: code/vault-demo/DATABASE_PASSWORD@kv token: $VAULT_ID_TOKEN file: false script: - echo $DATABASE_PASSWORD
Разберём анатомию пути к секрету в строке code/vault-demo/DATABASE_PASSWORD@kv:
code/vault-demo— путь до секрета в Vault;DATABASE_PASSWORD— имя поля внутри секрета;kv— точка монтирования Secret Engine (по умолчанию kv-v2).
Всё. Никакого before_script с Bash-портянкой, никакого Python-скрипта в образе. Просто декларативное описание того, какой секрет нужен и откуда его брать.
Что даёт связка Deckhouse Code и Deckhouse Stronghold
Помимо самой интеграции, у этой связки есть несколько приятных свойств, которые стоит упомянуть.
Один вендор — одна зона ответственности. Оба продукта разрабатываются «Флантом». Если возникает проблема на стыке Deckhouse Code и Deckhouse Stronghold — это один тикет и один инженер, который разберётся. Никаких «это не наша проблема» между двумя вендорами.
Защита самого пайплайна. Однострочник с маскировкой — частный случай. Пока кто-то может вписать в .gitlab-ci.yml произвольный код, никакое хранилище секретов не спасёт от компрометации. Безопасность пайплайна упирается в контроль над CI-конфигом — кто и при каких условиях может его менять.
В чистом GitLab CE такого контроля нет: обязательный апрув от владельца файла перед слиянием — функциональность платных редакций, Premium и Ultimate. В CE можно ограничить слияние в защищённую ветку только maintainer’ами или вынесением CI-конфига в отдельный репозиторий через general pipelines (что мы разобрали выше).
В Deckhouse Code такая защита есть и она работает так же, как в GitLab Premium, — через файл CODEOWNERS. В нём указываются люди или группы, отвечающие за .gitlab-ci.yml, а ветка, в которую идёт слияние, защищается через protected branches. После этого merge request с изменениями в .gitlab-ci.yml нельзя смержить, пока его не одобрит хотя бы один из указанных владельцев. Maintainer репозитория здесь не имеет приоритета: если он не в списке владельцев .gitlab-ci.yml, его апрува недостаточно.
Deckhouse Stronghold и CODEOWNERS закрывают разные части задачи. Stronghold отвечает за то, кому и когда отдавать секрет — через JWT-аутентификацию, bound claims и ACL-политики. CODEOWNERS отвечает за то, какой код вообще может оказаться в пайплайне, читающем этот секрет.
Получается двойная защита: Deckhouse Stronghold гарантирует, кто получит секрет, а CODEOWNERS — что в пайплайне не появится код для его компрометации.
Механизм CODEOWNERS в Deckhouse Code входит в стандартную поставку.
Единая Ops-модель в Deckhouse Kubernetes Platform. Если вы уже используете DKP, то и Deckhouse Code и Stronghold подключаются как модули — через ModuleConfig или d8 CLI. Оба модуля интегрированы с мониторингом, логированием и сетевыми политиками платформы.
Регуляторика и юридические вопросы. «Флант» — российский вендор, а это значит, что все контракты будут в рамках российского права, да и общение с поддержкой будет на русском языке. Кроме того Deckhouse Code и Deckhouse Stronghold входят в реестр российского ПО, а Stronghold недавно ещё и получил сертификат ФСТЭК России. Для компаний, которым важны такие моменты, это снимает отдельный пласт вопросов.
Итог: сравнение подходов
Давайте сравним четыре подхода к хранению секретов для пайплайнов по ключевым критериям. Для полноты картины к упомянутым в статье добавим вариант с коммерческой лицензией GItLab.
Критерий | GitLab CI/CD Variables | CE GitLab + HashiCorp Vault | EE GitLab + HashiCorp Vault | Deckhouse Code + Deckhouse Stronghold |
Нативный | ✗ | ✗ | ✓ | ✓ |
Короткоживущие токены | ✗ | ✗ | ✓ | ✓ |
Audit log | ✗ | ✗ | ✓ | ✓ |
Единая точка ротации секрета | ✗ | ✗ | ✓ | ✓ |
Prod-секреты недоступны разработчику | ✗ | ✗ | ✓ | ✓ |
Нет лицензионных рисков | ✓ | ✓ | ✗ | ✓ |
Один вендор / служба поддержки | — | ✗ | ✗ | ✓ |
CODEOWNERS: защита | ✗ | ✗ | ✓ | ✓ |
Реестр российского ПО | — | ✗ | ✗ | ✓ |
GitLab CI/CD Variables — нет разделения на «кто запускает пайплайн» и «кто знает секрет». Maintainer всегда потенциально имеет доступ ко всей чувствительной информации.
GitLab CE + Vault — концепция правильная, но с интеграцией придётся повозиться самостоятельно. При любом обновлении одного из решений интеграция может сломаться.
GitLab EE + Vault — всё работает нативно, но в случае проблем нужно будет общаться сразу с двумя вендорами. Ну и важно помнить про BUSL-лицензию, так что покупать нужно оба продукта.
Deckhouse Code + Deckhouse Stronghold — нативная интеграция, один вендор, без лицензионных рисков.
Узнать больше про наши продукты можно на их страницах — Deckhouse Code, Deckhouse Stronghold. Мы готовы помочь с пилотом: развернуть стенд и провалидировать решение под вашу инфраструктуру. Ну и, конечно, «Флант» проектирует и внедряет безопасные CI/CD-платформы — обращайтесь.
P. S.
Читайте также в нашем блоге:
