Управление секретами в конфигурации агента

Обновлено 15.10.2026
Как убрать пароли, токены и ключ API из файлов конфигурации агента ProtoOBP: ссылки ENC[] и получение значений из файлов, Kubernetes Secrets, HashiCorp Vault или собственной программы.

На этой странице:

Как это работает

Вместо значения секрета в конфигурации указывается ссылка вида ENC[<идентификатор>]. При запуске агент собирает все такие ссылки, запрашивает значения у источника секретов и подставляет их в конфигурацию в памяти. В файлах на диске секреты не появляются.

# /etc/protoobp-agent/protoobp.yaml
api_key: ENC[protoobp_api_key]

# /etc/protoobp-agent/conf.d/postgres.d/conf.yaml
instances:
  - host: localhost
    port: 5432
    username: protoobp
    password: ENC[postgres_password]

Правила использования ссылок:

  • ENC[...] должна занимать всё значение параметра. Значение "pass-ENC[x]" или "ENC[x]/path" не распознаётся.
  • Ссылки работают в protoobp.yaml, в файлах интеграций conf.d/<интеграция>.d/conf.yaml и в шаблонах автообнаружения (лейблы контейнеров и аннотации подов).
  • Идентификатор внутри скобок передаётся источнику секретов без изменений; его формат зависит от выбранного источника и описан ниже.

Выбор способа

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

ПриоритетПараметрКогда использовать
1secret_backend_commandНужен источник, которого нет среди встроенных, или уже есть собственный скрипт
2secret_backend_typeВсе секреты лежат в одном поддерживаемом хранилище
3multi_secret_backendsСекреты распределены по нескольким хранилищам

Встроенные хранилища: secret_backend_type

Для встроенных хранилищ писать программу не нужно: агент использует поставляемый в пакете исполняемый файл secret-generic-connector (Linux — /opt/protoobp-agent/embedded/bin/, Windows — каталог bin\agent установки агента). Тип хранилища задаётся в secret_backend_type, его параметры — в secret_backend_config.

Файл YAML или JSON

Секреты хранятся в одном файле в виде плоского словаря «идентификатор: значение».

# /etc/protoobp-agent/secrets.yaml — права 600, владелец pobp-agent
protoobp_api_key: "<ВАШ_API_KEY>"
postgres_password: "s3cr3t"
# protoobp.yaml
secret_backend_type: file.yaml          # для JSON-файла — file.json
secret_backend_config:
  file_path: /etc/protoobp-agent/secrets.yaml

api_key: ENC[protoobp_api_key]

Идентификатор в ENC[] — ключ верхнего уровня в файле. Вложенные структуры не поддерживаются. Размер файла ограничен параметром max_file_read_size в secret_backend_config (в байтах).

Каталог с файлами

Каждый секрет хранится в отдельном файле; идентификатор — имя файла относительно каталога. Подходит для секретов, смонтированных в контейнер как файлы.

secret_backend_type: file.text
secret_backend_config:
  secrets_path: /etc/protoobp-agent/secrets

# значение берётся из /etc/protoobp-agent/secrets/postgres_password
password: ENC[postgres_password]

Ссылки за пределы secrets_path (например, ENC[../../etc/shadow]) отклоняются.

Kubernetes Secrets

Агент читает секреты через API Kubernetes. Идентификатор имеет вид <namespace>/<имя секрета>;<ключ>:

secret_backend_type: k8s.secrets

password: ENC[monitoring/postgres-credentials;password]

По умолчанию используются токен сервисного аккаунта пода и адрес API из окружения пода. Переопределить их можно параметрами token_path, ca_path и api_server в secret_backend_config. Сервисному аккаунту агента нужны права get на соответствующие объекты Secret (Role и RoleBinding в пространстве имён секрета).

HashiCorp Vault

Идентификатор задаётся в одном из двух форматов:

  • <путь к секрету>;<ключ> — например, ENC[secret/protoobp/postgres;password];
  • vault://<путь>#<JSON-указатель> — для вложенных значений, например ENC[vault://secret/protoobp/db#/postgres/password].

Версия хранилища KV (v1 или v2) определяется автоматически.

secret_backend_type: hashicorp.vault
secret_backend_config:
  vault_address: https://vault.corp.local:8200
  vault_namespace: monitoring            # для Vault Enterprise, необязательно
  vault_tls_config:
    ca_cert: /etc/protoobp-agent/vault-ca.pem
  vault_session:
    vault_role_id: <ROLE_ID>             # аутентификация AppRole
    vault_secret_id: <SECRET_ID>
АутентификацияПараметры
Токенvault_token в secret_backend_config
AppRolevault_session.vault_role_id, vault_session.vault_secret_id
Логин и пароль (userpass)vault_session.vault_username, vault_session.vault_password
LDAPvault_session.vault_ldap_username, vault_session.vault_ldap_password
Kubernetesvault_session.vault_auth_type: kubernetes, vault_session.vault_kubernetes_role; при необходимости vault_kubernetes_jwt_path и vault_kubernetes_mount_path

Адрес Vault можно также передать стандартной переменной окружения VAULT_ADDR, она имеет приоритет над vault_address. Параметры TLS-клиента: ca_cert, ca_path, client_cert, client_key, tls_server, insecure в секции vault_tls_config.

Другие типы

secret_backend_typeИсточник
file.yaml, file.jsonОдин файл со словарём секретов
file.textКаталог, один файл на секрет
k8s.secretsОбъекты Secret через API Kubernetes
k8s.fileСекреты, смонтированные в под как файлы
docker.secretsСекреты Docker Swarm (/run/secrets)
hashicorp.vaultHashiCorp Vault
akeylessAkeyless
aws.secrets, aws.ssmОблачные хранилища секретов AWS
azure.keyvaultAzure Key Vault
gcp.secretmanagerGoogle Secret Manager

Несколько хранилищ: multi_secret_backends

Каждому хранилищу присваивается имя, которое указывается в ссылке перед точкой с запятой: ENC[<имя хранилища>;<идентификатор>].

multi_secret_backends:
  local:
    type: file.yaml
    config:
      file_path: /etc/protoobp-agent/secrets.yaml
  vault:
    type: hashicorp.vault
    config:
      vault_address: https://vault.corp.local:8200
      vault_token: <VAULT_TOKEN>

api_key: ENC[local;protoobp_api_key]
password: ENC[vault;secret/protoobp/postgres;password]

Ссылка без имени хранилища (ENC[protoobp_api_key]) при использовании только multi_secret_backends отклоняется.

Собственная программа: secret_backend_command

Если нужного хранилища нет среди встроенных, укажите путь к собственному исполняемому файлу (скрипт или программа на любом языке):

secret_backend_command: /etc/protoobp-agent/fetch-secrets.py
secret_backend_arguments:          # необязательно
  - --profile
  - monitoring
secret_backend_timeout: 30         # секунд

Протокол обмена

Агент запускает программу, передаёт ей на стандартный ввод JSON со списком нужных идентификаторов и ждёт ответ на стандартном выводе.

Запрос:

{"version": "1.1", "secrets": ["protoobp_api_key", "postgres_password"], "secret_backend_timeout": 30}

Ответ — объект, где для каждого идентификатора указано значение либо текст ошибки:

{
  "protoobp_api_key": {"value": "<ВАШ_API_KEY>"},
  "postgres_password": {"error": "секрет не найден"}
}

Требования к программе:

  • проверять старшую часть версии протокола (1) и завершаться с ошибкой при несовместимой версии;
  • уложиться в secret_backend_timeout секунд;
  • выводить не больше secret_backend_output_max_size байт (по умолчанию 1 МиБ);
  • не выводить на стандартный вывод ничего, кроме JSON-ответа; диагностические сообщения писать в stderr.

Если секрет не получен, параметр сохраняет значение ENC[...], а агент пишет ошибку в журнал. Интеграция с таким параметром обычно не сможет подключиться к сервису.

Минимальный пример на Python, читающий секреты из каталога:

#!/usr/bin/env python3
# /etc/protoobp-agent/fetch-secrets.py
import json
import os
import sys

SECRETS_DIR = "/etc/protoobp-agent/secrets"

request = json.load(sys.stdin)
if not request.get("version", "").startswith("1."):
    sys.exit("unsupported protocol version: %s" % request.get("version"))

response = {}
for handle in request["secrets"]:
    path = os.path.join(SECRETS_DIR, handle)
    if os.path.dirname(os.path.normpath(path)) != SECRETS_DIR:
        response[handle] = {"error": "invalid handle"}
        continue
    try:
        with open(path) as f:
            response[handle] = {"value": f.read().rstrip("\n")}
    except OSError as e:
        response[handle] = {"error": str(e)}

json.dump(response, sys.stdout)

Для такой задачи проще использовать встроенный тип file.text; пример показывает формат обмена.

Требования к правам на файл

Агент отказывается запускать программу, если к ней есть доступ у посторонних пользователей:

  • Linux: файл принадлежит пользователю, от которого работает агент (pobp-agent), и не имеет прав для группы и остальных:

    chown pobp-agent:pobp-agent /etc/protoobp-agent/fetch-secrets.py
    chmod 700 /etc/protoobp-agent/fetch-secrets.py
    

    Если программу нужно разделить между несколькими пользователями через группу, включите secret_backend_command_allow_group_exec_perm: true — тогда группе разрешено чтение и выполнение (chmod 750), но не запись.

  • Windows: в списке доступа файла могут быть только учётная запись службы агента (по умолчанию pobpagentuser), группа Administrators и LOCAL SYSTEM; явных запретов (Deny) для этих учётных записей быть не должно.

На встроенный secret-generic-connector эти требования не распространяются.

Готовый помощник для контейнеров

В образе агента есть скрипты для чтения секретов, смонтированных в контейнер:

СкриптПоведение
/readsecret.sh <каталог>Идентификатор — имя файла в указанном каталоге
/readsecret_multiple_providers.shИдентификатор с префиксом: file@/путь/к/файлу или k8s_secret@<namespace>/<секрет>/<ключ>

В Helm-чарте агента они подключаются параметрами protoobp.secretBackend.command и protoobp.secretBackend.arguments:

protoobp:
  secretBackend:
    command: "/readsecret_multiple_providers.sh"
  confd:
    postgres.yaml: |-
      instances:
        - host: postgres.db.svc
          username: protoobp
          password: ENC[k8s_secret@db/postgres-credentials/password]      

При /readsecret_multiple_providers.sh чарт по умолчанию выдаёт агенту права на чтение секретов во всём кластере (protoobp.secretBackend.enableGlobalPermissions: true). Чтобы ограничить доступ, отключите этот параметр и выдайте права только на нужные пространства имён, а также используйте secret_allowed_k8s_namespace или secret_scope_integration_to_their_k8s_namespace (см. справочник).

Обновление секретов без перезапуска

По умолчанию секреты запрашиваются один раз при запуске агента. Чтобы ключ API можно было сменить без перезапуска:

secret_refresh_interval: 3600                     # секунд; повторно запрашивать ключ API каждый час
secret_refresh_scatter: true                      # случайный сдвиг первого обновления
secret_refresh_on_api_key_failure_interval: 5     # минут; внеочередное обновление при отказе бэкенда в ключе
  • secret_refresh_interval — периодическое обновление ключей API; 0 отключает.
  • secret_refresh_scatter — первое обновление выполняется в случайный момент интервала, чтобы множество агентов не обращалось к хранилищу одновременно.
  • secret_refresh_on_api_key_failure_interval — если бэкенд отвечает 403 или проверка ключа не проходит, агент запрашивает секреты заново, но не чаще одного раза в указанное число минут; 0 отключает.

Обновить секреты вручную: protoobp-agent secret refresh.

Справочник параметров

Все параметры задаются в protoobp.yaml или переменными окружения с префиксом POBP_ (например, POBP_SECRET_BACKEND_TYPE). Параметры-объекты (secret_backend_config, multi_secret_backends) передаются в переменной окружения как JSON.

ПараметрПо умолчаниюНазначение
secret_backend_type—Тип встроенного хранилища
secret_backend_config{}Параметры встроенного хранилища
multi_secret_backends{}Именованные хранилища
secret_backend_command—Путь к собственной программе
secret_backend_arguments[]Аргументы программы
secret_backend_timeout30Тайм-аут запроса к источнику, секунд
secret_backend_output_max_size1048576Максимальный размер ответа программы, байт
secret_backend_remove_trailing_line_breakfalseУдалять завершающий перевод строки из значений
secret_backend_skip_checksfalseНе разрешать ENC[] в конфигурациях интеграций
secret_backend_command_allow_group_exec_permfalseРазрешить группе чтение и выполнение программы (Linux)
secret_refresh_interval0Период обновления ключей API, секунд
secret_refresh_scattertrueСлучайный сдвиг первого обновления
secret_refresh_on_api_key_failure_interval0Минимальный интервал внеочередного обновления при отказе в ключе, минут
secret_allowed_k8s_namespace[]Пространства имён, из которых разрешено читать k8s_secret@
secret_scope_integration_to_their_k8s_namespacefalseИнтеграции читают k8s_secret@ только из своего пространства имён
secret_image_to_handle{}Явный список секретов k8s_secret@, доступных каждому образу

Три последних параметра взаимоисключающие.

Проверка и диагностика

Команда protoobp-agent secret (в контейнере — agent secret) показывает:

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

Значения секретов команда не выводит. Сводка по секретам также есть в блоке Secrets вывода protoobp-agent status.

Частые ошибки:

Сообщение в журналеПричина
invalid executable ... 'group' or 'others' have rights on itПрава на программу шире допустимых — см. требования к правам
... returned invalid JSONПрограмма выводит в stdout что-то кроме JSON-ответа
... takes precedence over ...Заданы одновременно несколько способов; действует первый по приоритету
secrets path ... is not a directoryДля file.text в secrets_path указан не каталог
invalid secret format, expected 'secret_path;key' ...Для Vault идентификатор задан без ;<ключ> или #<указатель>