Приложение получает от Stronghold уникальную пару «логин — пароль» к PostgreSQL с ограниченным сроком действия. Stronghold создаёт пользователя в базе данных при запросе и удаляет его по истечении аренды. Пароль не хранится в манифестах и в объектах Secret.
Цель
Настроить выдачу динамических учётных данных PostgreSQL приложению myapp, которое работает в неймспейсе myapp кластера Deckhouse Platform, и доставить их в под с автоматическим продлением.
Предварительные требования
Для выполнения примера нужны:
- Stronghold, развёрнутый в DP, и токен с правами на настройку механизмов секретов, политик и методов аутентификации.
- Сервер PostgreSQL, доступный из подов Stronghold, и учётная запись с правом создавать роли (
CREATEROLE), напримерstronghold. - Доступ к кластеру через
d8 k.
В DP метод аутентификации Kubernetes для текущего кластера создаётся автоматически по пути kubernetes_local. Если вы используете другой путь, замените kubernetes_local в командах ниже.
Шаг 1. Настройте механизм секретов database
Включите механизм секретов database и подключите его к PostgreSQL:
Включите механизм секретов:
d8 stronghold secrets enable databaseНастройте подключение к PostgreSQL:
d8 stronghold write database/config/myapp-postgres plugin_name="postgresql-database-plugin" allowed_roles="myapp" connection_url="postgresql://{{username}}:{{password}}@postgres.db.svc:5432/myapp?sslmode=require" username="stronghold" password="<INITIAL_PASSWORD>" password_authentication="scram-sha-256"<INITIAL_PASSWORD>— текущий пароль учётной записиstronghold. На следующем шаге Stronghold заменит его сгенерированным.Смените пароль служебной учётной записи, чтобы он был известен только Stronghold:
d8 stronghold write -force database/rotate-root/myapp-postgres
Шаг 2. Создайте роль базы данных
Роль задаёт SQL-запросы для создания пользователя и срок жизни учётных данных:
d8 stronghold write database/roles/myapp db_name="myapp-postgres" creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" revocation_statements="REVOKE ALL ON ALL TABLES IN SCHEMA public FROM \"{{name}}\"; DROP ROLE IF EXISTS \"{{name}}\";" default_ttl="1h" max_ttl="24h"default_ttl— срок аренды при выдаче и при каждом продлении;max_ttl— максимальный срок жизни учётных данных; после него приложению нужны новые учётные данные.
Шаг 3. Создайте политику
Создайте политику, которая разрешает читать учётные данные роли myapp:
d8 stronghold policy write myapp-db - <<'POLICY'
path "database/creds/myapp" {
capabilities = ["read"]
}
POLICYПродление и отзыв собственных аренд и токена разрешены встроенной политикой default.
Шаг 4. Создайте роль метода Kubernetes
Создайте ServiceAccount для приложения и свяжите его с политикой через роль метода Kubernetes:
Создайте неймспейс и ServiceAccount:
d8 k create namespace myapp d8 k -n myapp create serviceaccount myappСвяжите ServiceAccount с политикой:
d8 stronghold write auth/kubernetes_local/role/myapp bound_service_account_names=myapp bound_service_account_namespaces=myapp policies=myapp-db ttl=1h
Шаг 5. Доставьте учётные данные в под
Для динамических учётных данных используйте Stronghold Agent в режиме sidecar: он продлевает аренду и перерисовывает файл, когда учётные данные меняются. Способы, которые подставляют значения только при старте пода (env-injector, init-контейнер), подходят, только если под перезапускается чаще, чем истекает max_ttl.
Конфигурация Agent для этого сценария:
stronghold {
address = "https://stronghold.example.com"
}
auto_auth {
method "kubernetes" {
mount_path = "auth/kubernetes_local"
config = {
role = "myapp"
}
}
}
template {
destination = "/secrets/db.env"
contents = <<-EOT
{{ with secret "database/creds/myapp" }}
DB_USER={{ .Data.username }}
DB_PASSWORD={{ .Data.password }}
{{ end }}
EOT
}Манифест пода с Agent в режиме sidecar, томом emptyDir в памяти и ConfigMap с конфигурацией приведён в разделе «Доставка секретов в поды Kubernetes».
Шаг 6. Настройте реакцию приложения на смену учётных данных
Agent продлевает аренду каждые default_ttl, пока не будет достигнут max_ttl. После этого Agent запрашивает новые учётные данные и перезаписывает файл /secrets/db.env. Старый пользователь удаляется при отзыве аренды.
Приложение должно:
- перечитывать файл при изменении и переподключаться к базе данных;
- либо завершаться при ошибке аутентификации, чтобы Kubernetes перезапустил контейнер с новыми учётными данными.
Выберите max_ttl так, чтобы смена учётных данных происходила не чаще, чем приложение способно корректно переподключиться.
Проверка
Проверьте результат:
Запросите учётные данные вручную с токеном администратора:
d8 stronghold read database/creds/myappВ ответе должны быть поля
lease_id,lease_duration,usernameиpassword.Проверьте, что пользователь создан в PostgreSQL:
SELECT rolname, rolvaliduntil FROM pg_roles WHERE rolname LIKE 'v-%';Убедитесь, что в поде появился файл с учётными данными:
d8 k -n myapp exec deploy/myapp -c app -- cat /secrets/db.envПросмотрите активные аренды роли:
d8 stronghold list sys/leases/lookup/database/creds/myapp/
Очистка
Удалите объекты, созданные в примере:
Удалите тестовый неймспейс в кластере:
d8 k delete namespace myapp.Отзовите все выданные учётные данные роли:
d8 stronghold lease revoke -prefix database/creds/myapp/Удалите роль, политику и конфигурацию:
d8 stronghold delete auth/kubernetes_local/role/myapp d8 stronghold policy delete myapp-db d8 stronghold delete database/roles/myapp d8 stronghold delete database/config/myapp-postgres