Приложение, которое читает пароли из конфигурационного файла и не умеет обращаться к API Stronghold, можно подключить без изменения кода. Stronghold Agent аутентифицируется в Stronghold, рендерит конфигурационный файл по шаблону и перезагружает приложение при изменении секретов.
Цель
Настроить на виртуальной машине Stronghold Agent под управлением systemd, который входит по AppRole с одноразовым обёрнутым secret_id, формирует файл application.properties и выполняет systemctl reload myapp при изменении секретов.
Предварительные требования
Перед началом подготовьте:
- Виртуальная машина Linux с systemd и приложением
myapp, запущенным как сервисmyapp.service. - Исполняемый файл Stronghold на ВМ (в примерах
/usr/local/bin/stronghold) и сетевой доступ к Stronghold. - Токен Stronghold с правами на настройку AppRole, политик и KV.
- Механизм секретов KV версии 2, включённый по пути
secret.
Шаг 1. Сохраните секрет и создайте политику
Запишите учётные данные базы данных в KV и создайте политику, которая разрешает их чтение:
d8 stronghold kv put -mount=secret myapp/config db_user=app_user db_password='S3cure-P@ss'
d8 stronghold policy write myapp-vm - <<'POLICY'
path "secret/data/myapp/config" {
capabilities = ["read"]
}
POLICYШаг 2. Создайте роль AppRole
Включите метод аутентификации AppRole и создайте роль для ВМ:
d8 stronghold auth enable approle
d8 stronghold write auth/approle/role/myapp-vm token_policies=myapp-vm token_ttl=1h token_max_ttl=24h secret_id_ttl=720h secret_id_bound_cidrs="10.0.10.15/32"Параметр secret_id_bound_cidrs разрешает вход только с адреса ВМ. secret_id_ttl ограничивает срок, в течение которого Agent может повторно входить с одним secret_id.
Шаг 3. Доставьте role_id и обёрнутый secret_id на ВМ
Agent входит по role_id и одноразовому обёрнутому secret_id. Подготовьте оба файла и скопируйте их на ВМ.
Получите
role_id— он не является секретом и может распространяться системой управления конфигурацией:d8 stronghold read -field=role_id auth/approle/role/myapp-vm/role-id > role-idВыпустите
secret_idв обёрнутом виде. Вместо самогоsecret_idвозвращается одноразовый токен с TTL 10 минут:d8 stronghold write -wrap-ttl=10m -field=wrapping_token -f auth/approle/role/myapp-vm/secret-id > secret-idСкопируйте оба файла на ВМ в директорию
/etc/stronghold-agent/и ограничьте доступ. Владельцем директории должен быть пользовательstronghold-agent: Agent удаляет файлsecret_idпосле чтения.sudo install -d -o stronghold-agent -g stronghold-agent -m 0750 /etc/stronghold-agent sudo install -o stronghold-agent -g stronghold-agent -m 0640 role-id /etc/stronghold-agent/role-id sudo install -o stronghold-agent -g stronghold-agent -m 0600 secret-id /etc/stronghold-agent/secret-id
Если токен обёртывания перехвачен и развёрнут кем-то другим, Agent не сможет его развернуть — это признак инцидента. Порядок проверки описан в разделе «Обёртывание ответа».
Шаг 4. Создайте шаблон
Создайте файл /etc/myapp/templates/application.properties.ctmpl:
{{ with secret "secret/data/myapp/config" }}
spring.datasource.username={{ .Data.data.db_user }}
spring.datasource.password={{ .Data.data.db_password }}
{{ end }}Шаг 5. Настройте Agent
Создайте файл /etc/stronghold-agent/agent.hcl:
stronghold {
address = "https://stronghold.example.com"
}
auto_auth {
method "approle" {
mount_path = "auth/approle"
config = {
role_id_file_path = "/etc/stronghold-agent/role-id"
secret_id_file_path = "/etc/stronghold-agent/secret-id"
secret_id_response_wrapping_path = "auth/approle/role/myapp-vm/secret-id"
remove_secret_id_file_after_reading = true
}
}
sink "file" {
config = {
path = "/var/run/stronghold-agent/token"
mode = 0600
}
}
}
template_config {
static_secret_render_interval = "5m"
}
template {
source = "/etc/myapp/templates/application.properties.ctmpl"
destination = "/etc/myapp/application.properties"
perms = "0640"
group = "myapp"
command = "/usr/bin/systemctl reload myapp"
command_timeout = "30s"
error_on_missing_key = true
}secret_id_response_wrapping_path— Agent распознаёт обёрнутыйsecret_id, проверяет путь его создания и разворачивает его;remove_secret_id_file_after_reading = true— файл сsecret_idудаляется после чтения;static_secret_render_interval— как часто Agent перечитывает статические секреты KV;permsиgroup— владельцем файла становится пользовательstronghold-agentи группаmyapp, поэтому приложение может его прочитать. Agent может назначить только группу, в которую входит пользовательstronghold-agent. Добавьте пользователя в группу командойsudo usermod -aG myapp stronghold-agent;command— выполняется после каждой записи файла. Команда выполняется безsudo: unit Agent запускается сNoNewPrivileges=true, поэтомуsudoне работает. Право на перезагрузку приложения выдаёт правило polkit из шага 6.
Развёрнутый secret_id хранится только в памяти Agent. После перезапуска Agent или ВМ, а также по истечении secret_id_ttl ему потребуется новый обёрнутый secret_id. Встройте выпуск и доставку secret_id в процесс развёртывания, например в CI/CD.
Шаг 6. Запустите Agent под systemd
Настройте unit Agent, разрешите Agent перезагружать приложение и запустите сервис.
Создайте unit-файл
/etc/systemd/system/stronghold-agent.serviceпо примеру из раздела «Запуск и управление». ВReadWritePathsукажите директории/var/run/stronghold-agentи/etc/myapp.Разрешите Agent удалять файл
secret_id. Unit используетProtectSystem=strict, поэтому добавьте директорию/etc/stronghold-agentвReadWritePathsв drop-in-файле. Выполнитеsudo systemctl edit stronghold-agentи добавьте строки:[Service] ReadWritePaths=/etc/stronghold-agentРазрешите пользователю
stronghold-agentвыполнять только перезагрузкуmyapp.service. Создайте файл/etc/polkit-1/rules.d/50-stronghold-agent-myapp.rules:polkit.addRule(function(action, subject) { if (action.id == "org.freedesktop.systemd1.manage-units" && subject.user == "stronghold-agent" && action.lookup("unit") == "myapp.service" && action.lookup("verb") == "reload") { return polkit.Result.YES; } });polkit читает файлы правил автоматически. Параметры
unitиverbпередаёт systemd версии 226 и выше. Если приложение не поддерживает перезагрузку, замените в правиле"reload"на"restart", а вcommand—reloadнаrestart.Запустите сервис:
sudo systemctl daemon-reload sudo systemctl enable --now stronghold-agent
Проверка
Проверьте, что Agent вошёл в Stronghold, сформировал файл и реагирует на изменение секрета.
Проверьте журнал Agent — должны быть сообщения об успешной аутентификации и рендеринге:
sudo journalctl -u stronghold-agent -n 50Убедитесь, что файл секрета удалён, а конфигурация сформирована:
ls -la /etc/stronghold-agent/secret-id /etc/myapp/application.propertiesИзмените секрет и дождитесь перерисовки файла и перезагрузки приложения (не дольше
static_secret_render_interval):d8 stronghold kv patch -mount=secret myapp/config db_password='N3w-P@ss' sudo journalctl -u myapp -f
Очистка
Чтобы удалить конфигурацию примера, выполните следующие действия:
Остановите и отключите Agent:
sudo systemctl disable --now stronghold-agent.Удалите файлы
/etc/stronghold-agent/role-id,/etc/myapp/application.propertiesи файл токена в/var/run/stronghold-agent/.Удалите файл
/etc/polkit-1/rules.d/50-stronghold-agent-myapp.rulesи drop-in-файл Agent:sudo systemctl revert stronghold-agent.Удалите роль и политику:
d8 stronghold delete auth/approle/role/myapp-vm d8 stronghold policy delete myapp-vm