1Password

Получайте ключи API провайдеров из 1Password прямо при старте процесса, вместо того чтобы хранить их в открытом виде в ~/.hermes/.env. Вы держите ключи как элементы 1Password и ссылаетесь на них через op://vault/item/field; ротация учётных данных сводится к одному изменению внутри 1Password.

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

  1. Вы устанавливаете официальный 1Password CLI (op) и аутентифицируете его — либо токеном сервисного аккаунта (для headless-серверов), либо через интерактивную/десктопную сессию (на вашем ноутбуке).
  2. Вы сопоставляете имена переменных окружения со ссылками op:// в ~/.hermes/config.yaml.
  3. При каждом запуске hermes (или шлюза, или cron-задачи), уже после того как загрузился ~/.hermes/.env, Hermes выполняет op read для каждой ссылки и записывает полученные значения в os.environ.
  4. По умолчанию Hermes переопределяет значения, уже присутствующие в окружении, — так источником истины остаётся 1Password: обновили учётные данные один раз, и каждый процесс Hermes подхватит их при следующем запуске. Установите override_existing: false, если хотите, чтобы приоритет оставался за .env.

Hermes никогда не аутентифицируется от вашего имени и никогда не скачивает op — он лишь вызывает через shell уже установленный и уже доверенный вами CLI. Если op отсутствует, сессия заблокирована или ссылка указана неверно, Hermes выводит однострочное предупреждение и продолжает работать с теми учётными данными, которые уже были в .env. Запуск он не блокирует ни при каких обстоятельствах.

Аутентификация

op поддерживает два режима, дружественных к неинтерактивному запуску, и Hermes работает с обоими:

  • Сервисные аккаунты (рекомендуется для серверов/CI): создайте сервисный аккаунт в 1Password, выдайте ему доступ на чтение к нужному хранилищу и экспортируйте его токен как OP_SERVICE_ACCOUNT_TOKEN в ~/.hermes/.env. Сам токен и есть учётные данные — относитесь к нему как к любому другому bearer-токену.
  • Десктопные / интерактивные сессии (ноутбуки): выполните op signin (или включите интеграцию с CLI в приложении 1Password). Hermes передаёт ваши переменные OP_SESSION_* дочернему процессу op. Ключ кэша 1Password строится с учётом этих переменных сессии, поэтому вход в другой аккаунт никогда не отдаст значение, закэшированное под прежней учётной записью.

Токен для начальной загрузки

Когда вы аутентифицируетесь токеном сервисного аккаунта, этот токен сам по себе становится начальными учётными данными, без которых Hermes не сможет разрешить ни одной ссылки op://. Он должен присутствовать в os.environ каждого процесса, который разрешает секреты, — включая cron-задачи (kanban.dispatch_in_gateway: false), вызовы подпроцессов, запуски CLI, агенты macOS launchd и Docker-контейнеры, а не только интерактивный шлюз. Сделать его доступным можно тремя способами, в порядке приоритета:

  1. В ~/.hermes/.env (рекомендуется). Команда hermes secrets onepassword setup --token <token> записывает токен в ~/.hermes/.env — точно так же, как BWS_ACCESS_TOKEN у Bitwarden. Поскольку load_hermes_dotenv() всегда загружает .env, токен становится доступен везде без какой-либо дополнительной настройки. Это самый простой и надёжный вариант.

  2. В ~/.hermes/.op.env (в .gitignore). Если вы предпочитаете не держать токен сервисного аккаунта в .env — например, чтобы .env можно было закоммитить в приватный репозиторий с дотфайлами, а токен при этом оставался вне контроля версий, — поместите его в ~/.hermes/.op.env:

    echo 'OP_SERVICE_ACCOUNT_TOKEN=ops_...' > ~/.hermes/.op.env
    chmod 600 ~/.hermes/.op.env

    Hermes автоматически загружает .op.env при старте, после .env, и никогда не переопределяет токен, уже присутствующий в окружении. .op.env добавлен в .gitignore, так что токен никогда не попадёт в закоммиченный файл.

  3. Через EnvironmentFile в systemd (Linux-шлюз). Если шлюз запущен под systemd, токен можно внедрить прямо в окружение сервиса:

    [Service]
    EnvironmentFile=-/home/youruser/.hermes/.op.env

    Токен, внедрённый таким способом, получает приоритет — Hermes обнаруживает, что OP_SERVICE_ACCOUNT_TOKEN уже установлен, и полностью пропускает загрузку .op.env.

Если токен доступен только через интерактивную оболочку (op signin, экспорт OP_SESSION_* в .bashrc и тому подобное), он не унаследуется cron-задачами или заново созданными подпроцессами: в таких контекстах будет записано предупреждение, а Hermes откатится к тем учётным данным, что уже были в .env. Для любой неинтерактивной нагрузки используйте один из трёх способов выше.

Настройка

1. Установите op и войдите в аккаунт

Следуйте руководству по началу работы с 1Password CLI. Проверьте, что всё работает:

op whoami

2. Включите интеграцию

hermes secrets onepassword setup

Эта команда проверяет, что op доступен в PATH (либо используйте --binary-path), сохраняет настройки аккаунта/токена, проверяет наличие активной сессии и переключает secrets.onepassword.enabled в true. Флаги для неинтерактивного режима:

hermes secrets onepassword setup \
  --account my.1password.com \
  --token-env OP_SERVICE_ACCOUNT_TOKEN \
  --token "$OP_SERVICE_ACCOUNT_TOKEN"

3. Сопоставьте учётные данные

Формат ссылки — op://<vault>/<item>/<field>:

hermes secrets onepassword set OPENAI_API_KEY    "op://Private/OpenAI/api key"
hermes secrets onepassword set ANTHROPIC_API_KEY "op://Private/Anthropic/credential"

4. Проверьте и подтвердите

hermes secrets onepassword sync     # пробный запуск: разрешает ссылки сейчас и показывает, что было бы применено
hermes secrets onepassword status   # конфигурация + бинарник + ссылки + аутентификация

С этого момента каждый вызов hermes разрешает ссылки при старте. При первом применении секретов в рамках процесса вы увидите однострочную сводку в stderr.

CLI

КомандаЧто делает
hermes secrets onepassword setupПроверяет op, задаёт аккаунт / переменную окружения токена, включает интеграцию
hermes secrets onepassword statusПоказывает конфигурацию, бинарник, аутентификацию и настроенные ссылки
hermes secrets onepassword tokenРотация токена сервисного аккаунта: проверяет его через op whoami, затем сохраняет в .env
hermes secrets onepassword set ENV_VAR "op://…"Сопоставляет переменную окружения со ссылкой (сохраняется в очищенном и провалидированном виде)
hermes secrets onepassword remove ENV_VARУдаляет сопоставление
hermes secrets onepassword syncПробный запуск: разрешает ссылки сейчас и показывает, что было бы применено
hermes secrets onepassword sync --applyРазрешает ссылки и экспортирует их в окружение текущей оболочки
hermes secrets onepassword disableПереключает enabled: false; сопоставления остаются на месте

op и 1password принимаются как псевдонимы для onepassword.

Конфигурация

Значения по умолчанию в ~/.hermes/config.yaml:

secrets:
  onepassword:
    enabled: false
    env:
      OPENAI_API_KEY: "op://Private/OpenAI/api key"
      ANTHROPIC_API_KEY: "op://Private/Anthropic/credential"
    account: ""
    service_account_token_env: OP_SERVICE_ACCOUNT_TOKEN
    binary_path: ""
    cache_ttl_seconds: 300
    override_existing: true
КлючПо умолчаниюЧто делает
enabledfalseГлавный переключатель. Пока false, op вообще не вызывается.
env{}Сопоставление имени переменной окружения со ссылкой op://vault/item/field. Записи, у которых имя не является допустимым именем переменной окружения либо значение не является ссылкой op://, пропускаются с предупреждением.
account""Сокращённое имя аккаунта / адрес для входа, передаётся как op read --account. Пустое значение означает использование аккаунта op по умолчанию.
service_account_token_envOP_SERVICE_ACCOUNT_TOKENПеременная окружения, из которой Hermes считывает токен сервисного аккаунта. Её значение экспортируется дочернему процессу op под именем OP_SERVICE_ACCOUNT_TOKEN (именно такого имени ожидает op). Оставьте переменную неустановленной, чтобы использовать десктопную/интерактивную сессию.
binary_path""Абсолютный путь к op. Если задан, используется как есть, а PATH не учитывается вовсе — закрепите это значение, чтобы не полагаться на первый попавшийся op в PATH.
cache_ttl_seconds300Как долго переиспользуются разрешённые значения (в процессе и на диске). Установите 0, чтобы отключить оба слоя кэша — тогда значения вообще не будут записываться на диск.
override_existingtrueКогда true, разрешённые значения перезаписывают всё, что уже есть в окружении (так ротация вступает в силу). Переключите на false, чтобы приоритет оставался за .env / экспортами оболочки; такие ссылки в этом случае пропускаются ещё до вызова op.

Сценарии сбоев

1Password никогда не блокирует запуск Hermes. Если что-то пошло не так, вы увидите однострочное предупреждение в stderr, а Hermes продолжит работу:

СимптомПричинаКак исправить
the op CLI was not found on PATHop не установлен / отсутствует в PATHУстановите CLI либо задайте secrets.onepassword.binary_path
op read failed for 'op://…': …Сессия заблокирована, токен истёк, либо нет доступа к хранилищуВыполните op signin, запустите hermes secrets onepassword token для ротации токена сервисного аккаунта или откройте сервисному аккаунту доступ
op read returned an empty value for 'op://…'Указанное поле существует, но пустоеИсправьте элемент/поле в 1Password (пустое значение никогда не применяется — уже существующая переменная окружения остаётся нетронутой)
… is not an op:// secret referenceЗначение сопоставления не является ссылкой op://Переустановите его в правильном формате op://vault/item/field
op read timed outЗаблокирована сеть либо 1Password отвечает медленноПроверьте соединение / интеграцию с десктопным приложением

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

Кэширование

Успешные полные выгрузки кэшируются в процессе и на диске, в <hermes_home>/cache/op_cache.json (запись атомарная, права доступа 0600), так что идущие подряд короткоживущие вызовы hermes не запускают op заново для каждой ссылки. Кэш:

  • хранит только разрешённые значения секретов — никогда токен сервисного аккаунта или любые сырые данные аутентификации (данные аутентификации превращаются в отпечаток и попадают в ключ кэша);
  • инвалидируется при изменении токена, аккаунта, переменных OP_SESSION_* или набора ссылок;
  • не записывается, если при выгрузке возникла ошибка хотя бы по одной ссылке, — так временный сбой аутентификации не «замораживается» на весь срок жизни TTL;
  • полностью отключается — и чтение, и запись — при cache_ttl_seconds: 0.

Замечания по безопасности

  • Токен сервисного аккаунта 1Password способен прочитать любой секрет, к которому у аккаунта есть доступ. Храните его в ~/.hermes/.env (не в config.yaml), а при утечке немедленно отзовите и перевыпустите его в 1Password.
  • Hermes не даёт разрешённому значению перезаписать саму переменную окружения токена, даже при override_existing: true.
  • Дочерний процесс op получает минимальное окружение из белого списка (переменные аутентификации/сессии плюс PATH/HOME и переменные расположения конфига op — OP_CONFIG_DIR/XDG_CONFIG_HOME), а не копию полного os.environ, поэтому учётные данные провайдеров, загруженные после dotenv, дочернему процессу целиком не достаются. Задайте OP_CONFIG_DIR, если ~/.config недоступен для записи пользователю Hermes (обычное дело в контейнерах).
  • Ссылки проверяются на то, что начинаются с op://, и передаются после разделителя опций --, так что специально сконструированное значение нельзя выдать за флаг op.

Когда этим НЕ стоит пользоваться

  • Личные однокомпьютерные настройки, где ~/.hermes/.env вполне достаточно.
  • Изолированные (air-gapped) среды, у которых нет доступа к 1Password.
  • CI/CD, где уже настроен собственный механизм внедрения секретов — выбирайте один путь, а не оба сразу.

Хороший сценарий для этой интеграции — парк из нескольких машин, общие dev-серверы, шлюзовые VPS или любой случай, когда нужна централизованная ротация и отзыв секретов сразу для нескольких инсталляций Hermes.

перевод и редактура:

обновлено

⌕ ESC