Описание Secret Manager
Введение
Secret Manager в Altflow отвечает за безопасное хранение и выдачу секретов: паролей, токенов, ключей доступа к реестрам, ключей подписи и других чувствительных данных. В качестве Secret Manager используется OpenBao (форк HashiCorp Vault).
OpenBao используется в двух сценариях:
- хранение системных секретов Altflow, которые нужны helm-чартам и компонентам в Kubernetes;
- хранение пользовательских секретов сборок: данных доступа к git-репозиторию и OCI registry для конкретного
TaskID.
В проекте используется KV-хранилище версии 1 без версионирования. При обновлении секрета старое значение перезаписывается, поэтому перед изменениями нужно сохранять резервную копию.
Цели
- Обеспечить безопасное хранение секретов приложений.
- Обеспечить безопасное хранение данных аутентификации в git-репозиториях и OCI-реестрах пользователей системы сборки.
- Упростить доступ к секретам для компонентов системы.
- Поддержать аудит и контроль доступа к секретам.
Архитектура
Система состоит из следующих частей:
- OpenBao: основное хранилище секретов.
- External Secrets Operator: синхронизирует системные секреты из OpenBao в Kubernetes Secrets.
- Kubernetes Secrets: источник секретов для компонентов Altflow внутри кластера.
- Клиенты OpenBao: компоненты, которые напрямую читают или записывают секреты сборок.
Компоненты Altflow в Kubernetes обычно не обращаются напрямую к OpenBao за системными секретами. Эти секреты синхронизируются External Secrets Operator и затем монтируются в pod как переменные окружения или файлы.
Общие принципы работы с OpenBao
- Mount point:
kv. - Тип хранилища: KV v1.
- Путь системных секретов:
kv/altflow-system-helm-secrets/. - Путь секретов сборок:
kv/altflow-builds/. - Секреты хранятся как JSON-объекты.
- Доступ ограничивается policies OpenBao.
- Для доступа из Kubernetes используется AppRole или Kubernetes auth.
- Для подключений к OpenBao должен использоваться TLS.
Структура секретов в OpenBao
Системные helm-секреты
Системные секреты лежат по пути:
kv/altflow-system-helm-secrets/<имя_ключа>
Актуальные шаблоны находятся по ссылке.
| Ключ | Поля | Назначение |
|---|---|---|
api-lite-secrets | amqp_password, amqp_username, metrics_token, trackdb_password, trackdb_username, loki_login, loki_passwd, auth_token | Упрощённый набор секретов API. |
api-secrets | amqp_password, amqp_username, trackdb_password, trackdb_username, metrics_token, sysdb_password, sysdb_user, loki_passwd, loki_login, keycloak_client_id, keycloak_client_secret, token_secret | Основной набор секретов API. |
distributor-secrets | HARBOR_NAME, HARBOR_TOKEN, OPENBAO_TOKEN, PASSWORD, POSTGRES_PASSWORD, POSTGRES_USER, RABBITMQ_PASSWORD, RABBITMQ_USER, USERNAME | Секреты Distributor для Harbor, OpenBao, TrackDB, PostgreSQL и RabbitMQ. |
internal-registry | dockerconfig | Docker config для доступа к внутреннему registry. |
oci-registry | dockerconfig | Docker config для доступа к внешнему OCI registry. |
rabbitmq-secrets | password, erlangCookie | Пароль RabbitMQ и Erlang cookie. |
saver-secrets | amqp_password, amqp_username, open_bao_token, trackdb_password, trackdb_username | Секреты Saver для RabbitMQ, OpenBao и TrackDB. |
sign-job-creds | VAULT_TOKEN | Токен OpenBao для задач подписи. |
stager-secrets | PASSWORD, RABBITMQ_PASSWORD, RABBITMQ_USER, USERNAME | Секреты Stager для TrackDB и RabbitMQ. |
tracker-secrets | TRACKDB_PASSWORD, TRACKDB_USER | Секреты Tracker для TrackDB. |
Пример загрузки системного секрета:
bao kv put kv/altflow-system-helm-secrets/api-secrets @api-secrets.json
Секреты сборок
Пользователи системы сборки образов при обращении к API передают информацию о расположении git-репозитория и данные для доступа к нему и к OCI registry назначения. Эта информация хранится по схеме:
kv/altflow-builds/<buildID>/git
kv/altflow-builds/<buildID>/registry
Пример структуры данных:
altflow-builds/
└── <buildID>/
├── git/
│ ├── username: gituser
│ └── password: gitpassword
└── registry/
├── username: registryuser
└── password: registrypassword
Получение секретов git:
curl -s \
--header "X-Vault-Token: <token>" \
--header "Content-Type: application/json" \
https://<vault_address>/v1/kv/altflow-builds/<buildID>/git | jq -r '.data'
Запись секретов git:
curl -s \
--request POST \
--header "X-Vault-Token: <token>" \
--header "Content-Type: application/json" \
--data '{"username": "<gituser>", "password": "<gitpassword>"}' \
https://<vault_address>/v1/kv/altflow-builds/<buildID>/git
Для registry используется тот же формат:
curl -s \
--request POST \
--header "X-Vault-Token: <token>" \
--header "Content-Type: application/json" \
--data '{"username": "<registryuser>", "password": "<registrypassword>"}' \
https://<vault_address>/v1/kv/altflow-builds/<buildID>/registry
Аутентификация
Для прямого доступа к OpenBao приложения используют токен из переменной среды SM_BAO_TOKEN. Запрос должен передавать токен в заголовке X-Vault-Token.
curl -s \
--header "X-Vault-Token: ${SM_BAO_TOKEN}" \
--header "Content-Type: application/json" \
https://<vault_address>/v1/kv/<path>
Для доступа из Kubernetes используется AppRole или Kubernetes auth. Роль должна выдавать токен с минимально необходимыми правами на чтение системных секретов и создание/обновление секретов сборок.
Пример policy:
path "kv/altflow-system-helm-secrets/*" {
capabilities = ["read", "list"]
}
path "kv/altflow-builds" {
capabilities = ["create", "update", "read", "list"]
}
path "kv/altflow-builds/*" {
capabilities = ["create", "update", "read", "list"]
}
Интеграция с Kubernetes
В Kubernetes системные секреты синхронизируются через External Secrets Operator. Для каждого компонента создаётся ExternalSecret, который читает поля из OpenBao и создаёт или обновляет обычный Kubernetes Secret.
Пример:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: altflow-api-secrets
spec:
refreshInterval: 1m
secretStoreRef:
name: openbao-store
kind: SecretStore
target:
name: altflow-api-secrets
data:
- secretKey: amqp_password
remoteRef:
key: kv/altflow-system-helm-secrets/api-secrets
property: amqp_password
После синхронизации компонент использует Kubernetes Secret:
env:
- name: amqp_password
valueFrom:
secretKeyRef:
name: altflow-api-secrets
key: amqp_password
Этапы создания SecretStore и ExternalSecret выполняются helm-чартами. Вручную нужно подготовить значения секретов в OpenBao и учётные данные для доступа Kubernetes к OpenBao.
Ключ подписи OCI-образов
Для создания ключа подписи используется transit engine:
bao secrets enable -description='key for sign oci-images altflow test env' transit
bao write transit/keys/altflow-test-key \
derived=false \
exportable=true \
allow_plaintext_backup=true \
type=ecdsa-p256 \
auto_rotate_period=0s
Создание и обновление секретов
При первоначальной загрузке администратор:
- Получает root-токен или другой административный токен OpenBao.
- Включает KV v1 на mount point
kv. - Загружает JSON-шаблоны в
kv/altflow-system-helm-secrets/. - Создаёт policies и настраивает AppRole или Kubernetes auth.
- Передаёт данные доступа helm-чартам, которые создают
SecretStoreиExternalSecret.
При регулярном обновлении нужно заменить соответствующий JSON целиком. Так как используется KV v1, частичное обновление без сохранения остальных полей может привести к потере данных. Перед изменением секрета нужно сохранить текущую версию.
Требования к секретам
- Пароли и токены должны генерироваться CSPRNG, например
openssl rand -base64 18. - JWT/HMAC-секреты должны быть не короче 32 байт, рекомендуется 64 байта.
- Docker config в полях
dockerconfigдолжен быть валидным JSON, сохранённым как строка. - Секреты не должны попадать в Git в заполненном виде; в репозитории допустимы только пустые шаблоны.
- Ротация паролей, токенов и JWT-секретов должна выполняться регулярно, рекомендуемый интервал — не реже одного раза в 90 дней.
Мониторинг и аудит
- В OpenBao должен быть включён audit log.
- Нужно отслеживать неуспешные попытки аутентификации и подозрительные обращения к секретам.
- В Kubernetes нужно контролировать состояние
ExternalSecretи ошибки синхронизации.