Перейти к основному содержимому

Ключи из переменных окружения и файлов

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

  • SSH-ключ, смонтированный в контейнер Semaphore как секрет Docker или Kubernetes;
  • токен, записываемый на диск агентом (HashiCorp Vault Agent, cert-manager и т. п.) и регулярно ротируемый;
  • пароль, внедрённый в окружение контейнера вашим оркестратором.

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

к сведению

Файл или переменную читает сервер Semaphore, а не раннер. Если вы используете удалённые раннеры, монтируйте файл на хосте сервера; сервер получает секрет и передаёт его раннеру.

Выбор источника

При создании или редактировании ключа (Хранилище ключей → Новый ключ) в верхней части формы находятся вкладки источника:

ВкладкаОткуда берётся значениеЧто вводить
LocalБаза данных Semaphore (в зашифрованном виде)Логин, пароль или приватный ключ в форме
Storage ProВнешнее хранилище секретов, например HashiCorp VaultХранилище и путь к секрету
EnvПеременная окружения процесса сервера SemaphoreИмя переменной, например PROD_SSH_KEY
FileФайл на сервере SemaphoreАбсолютный путь к файлу, например /var/lib/semaphore/secrets/prod.json

При выборе Env или File поля логина, пароля и приватного ключа исчезают. Все учётные данные целиком, включая логин для ключей типа SSH и «Логин с паролем», должны находиться в файле или переменной.

1. Разрешите каталог

В целях безопасности Semaphore читает файлы ключей только из своего каталога секретов. Любой другой путь отклоняется при запуске задачи:

Failed to install inventory: file path must be inside secrets path

Каталог секретов по умолчанию — /tmp/semaphore. Укажите каталог, в котором находятся ваши файлы ключей, с помощью dirs.secrets в config.json или переменной окружения SEMAPHORE_SECRETS_PATH. Правила приоритета описаны в разделе Каталог секретов.

Пример Docker Compose, который монтирует каталог хоста и разрешает его:

services:
semaphore:
image: semaphoreui/semaphore:latest
environment:
SEMAPHORE_SECRETS_PATH: /var/lib/semaphore/secrets
volumes:
- /srv/semaphore/secrets:/var/lib/semaphore/secrets:ro

Эквивалентный фрагмент config.json:

{
"dirs": {
"secrets": "/var/lib/semaphore/secrets"
}
}

Правила для пути, вводимого на вкладке File:

  • путь должен быть абсолютным (/var/lib/semaphore/secrets/prod.json, а не prod.json);
  • путь не должен содержать сегменты ..;
  • путь должен указывать на расположение внутри каталога секретов (подкаталоги допускаются);
  • файл должен быть доступен для чтения пользователю, от имени которого работает Semaphore (в официальном Docker-образе это semaphore, UID 1001).

Для переменных окружения такого ограничения нет: сервер просто читает переменную с указанным именем из собственного окружения.

2. Подготовьте значение

Содержимое файла (или значение переменной) зависит от типа ключа. Один завершающий перевод строки в конце файла игнорируется; всё остальное используется как есть.

SSH-ключ

Semaphore ожидает JSON-документ, а не «сырой» файл приватного ключа в формате PEM или OpenSSH:

{
"login": "deploy",
"passphrase": "",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----\n"
}
  • login — имя пользователя SSH, передаётся в Ansible как --user. Оставьте пустым, чтобы решение принимал инвентарь (ansible_user). Для Git-репозиториев пустой логин по умолчанию означает git.
  • passphrase — парольная фраза приватного ключа или пустая строка.
  • private_key — приватный ключ, в котором переводы строк закодированы как \n.

Сформируйте обёртку из существующего ключа с помощью jq, который сам позаботится об экранировании:

jq -n --arg login deploy --rawfile key ~/.ssh/id_ed25519 \
'{login: $login, passphrase: "", private_key: $key}' \
> /srv/semaphore/secrets/prod_ssh.json
chmod 0400 /srv/semaphore/secrets/prod_ssh.json

Затем создайте ключ типа SSH, откройте вкладку File и введите /var/lib/semaphore/secrets/prod_ssh.json (путь таким, каким он виден внутри контейнера).

внимание

Указывать на вкладке File «сырой» приватный ключ, например ~/.ssh/id_ed25519, нельзя. Файл разбирается как JSON, и задача не сможет загрузить инвентарь.

Логин с паролем

Тоже JSON-документ:

{
"login": "svc-ansible",
"password": "s3cr3t"
}

Оставьте login пустым, чтобы использовать ключ как обычный токен или пароль, например как пароль Ansible Vault.

Пример с переменной окружения

Тот же формат JSON применяется и для вкладки Env. В Docker Compose:

services:
semaphore:
image: semaphoreui/semaphore:latest
environment:
PROD_SSH_KEY: '{"login":"deploy","passphrase":"","private_key":"-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----\n"}'

Создайте ключ типа SSH, выберите вкладку Env и введите PROD_SSH_KEY в качестве имени переменной.

подсказка

Переменные окружения видны каждому процессу в контейнере и часто попадают в метаданные и логи оркестратора. По возможности предпочитайте вкладку File со смонтированным секретом.

Устранение неполадок

ОшибкаПричинаРешение
file path must be absoluteВведён относительный путьВведите полный путь, начинающийся с /
file path must not contain traversal segmentsПуть содержит ..Введите путь без таких сегментов
file path must be inside secrets pathФайл находится вне dirs.secretsУкажите в SEMAPHORE_SECRETS_PATH каталог файла или переместите файл
no such file or directoryПуть неверен или не смонтирован в контейнерПроверьте монтирование тома и используйте путь внутри контейнера
permission deniedПроцесс Semaphore не может прочитать файлИсправьте владельца или права доступа файла
invalid character '-' looking for beginning of valueВместо JSON-обёртки указан «сырой» приватный ключОберните ключ в JSON, как показано выше