Вместо постоянного kubeconfig с широкими правами CI-задание или инженер запрашивает у Stronghold токен ServiceAccount на время работы. Stronghold создаёт в кластере ServiceAccount, роль и привязку роли с нужными правами, выпускает токен с ограниченным сроком жизни и удаляет созданные объекты по истечении аренды.

Цель
Настроить две роли механизма секретов Kubernetes:
ci-deploy— для CI-заданий: права на управление Deployment, Service и ConfigMap в неймспейсеmyapp, токен живёт 15 минут;engineer-view— для инженеров: права встроенной ClusterRoleviewв неймспейсахmyappиmyapp-stage, токен живёт 1 час, не дольше 8 часов.
Предварительные требования
Для выполнения примера нужны:
- Stronghold, развёрнутый в DP, и токен с правами на настройку механизмов секретов и политик.
- Доступ к кластеру через
d8 kс правами на создание ClusterRole и ClusterRoleBinding. - Неймспейсы
myappиmyapp-stage. - Настроенный метод аутентификации для CI (например, JWT, как в разделе «Интеграция с CI/CD») и для инженеров (например, OIDC).
Шаг 1. Выдайте Stronghold права в кластере
Stronghold создаёт объекты RBAC от имени своего ServiceAccount. Из-за защиты Kubernetes от повышения привилегий этому ServiceAccount нужны права bind и escalate на роли.
Определите имя ServiceAccount Stronghold:
d8 k -n d8-stronghold get pod stronghold-0 -o jsonpath='{.spec.serviceAccountName}'В DP это ServiceAccount
strongholdв неймспейсеd8-stronghold. Модуль выдаёт этому ServiceAccount только ClusterRolesystem:auth-delegatorи доступ к Secrets и подам в неймспейсеd8-stronghold. Модуль не выдаёт ему прав на управление ServiceAccount и объектами RBAC (Role, ClusterRole, RoleBinding, ClusterRoleBinding) в других неймспейсах, поэтому добавьте права ниже.Создайте ClusterRole и привяжите её к ServiceAccount Stronghold. Замените
strongholdвsubjectsна имя, полученное на предыдущем шаге. Сохраните манифест в файлstronghold-k8s-secrets-engine.yamlи примените его:apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: stronghold-k8s-secrets-engine rules: - apiGroups: [""] resources: ["serviceaccounts", "serviceaccounts/token"] verbs: ["create", "update", "delete"] - apiGroups: ["rbac.authorization.k8s.io"] resources: ["rolebindings", "clusterrolebindings"] verbs: ["create", "update", "delete"] - apiGroups: ["rbac.authorization.k8s.io"] resources: ["roles", "clusterroles"] verbs: ["bind", "escalate", "create", "update", "delete"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: stronghold-k8s-secrets-engine roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: stronghold-k8s-secrets-engine subjects: - kind: ServiceAccount name: stronghold namespace: d8-strongholdd8 k apply -f stronghold-k8s-secrets-engine.yaml
ServiceAccount Stronghold с такими правами фактически является администратором кластера. Ограничьте доступ к настройке механизма секретов Kubernetes политиками Stronghold.
Шаг 2. Включите механизм секретов
Включите механизм секретов Kubernetes и создайте его конфигурацию:
d8 stronghold secrets enable kubernetes
d8 stronghold write -f kubernetes/configПустая конфигурация означает, что Stronghold подключается к API текущего кластера с сертификатом CA и JWT своего пода. Для другого кластера задайте параметры kubernetes_host, kubernetes_ca_cert и service_account_jwt.
Шаг 3. Создайте роль для CI
Роль с параметром generated_role_rules создаёт на каждый запрос всю цепочку объектов: ServiceAccount, Role и RoleBinding.
d8 stronghold write kubernetes/roles/ci-deploy allowed_kubernetes_namespaces="myapp" token_default_ttl="15m" token_max_ttl="1h" generated_role_rules='{"rules":[
{"apiGroups":["apps"],"resources":["deployments"],"verbs":["get","list","watch","create","update","patch"]},
{"apiGroups":[""],"resources":["services","configmaps"],"verbs":["get","list","create","update","patch"]}
]}'allowed_kubernetes_namespaces— неймспейсы, в которых можно запросить токен. Вместо списка можно задать селектор лейбловallowed_kubernetes_namespace_selector; для этого Stronghold нужно правоgetнаnamespaces;generated_role_rules— правила Role в формате JSON или YAML;token_default_ttlиtoken_max_ttl— срок жизни токена по умолчанию и максимальный.
Шаг 4. Создайте роль для инженеров
Роль с параметром kubernetes_role_name привязывает создаваемый ServiceAccount к существующей роли, здесь — к встроенной ClusterRole view:
d8 stronghold write kubernetes/roles/engineer-view allowed_kubernetes_namespaces="myapp,myapp-stage" kubernetes_role_type="ClusterRole" kubernetes_role_name="view" token_default_ttl="1h" token_max_ttl="8h"При kubernetes_role_type="ClusterRole" Stronghold по умолчанию создаёт RoleBinding в запрошенном неймспейсе. Чтобы выдать права на весь кластер, при запросе учётных данных передайте cluster_role_binding=true — тогда будет создана ClusterRoleBinding. Разрешайте это только для отдельных ролей и политик.
Если нужно выпускать токены для существующего ServiceAccount, используйте параметр service_account_name. Он несовместим с kubernetes_role_name и generated_role_rules.
Шаг 5. Создайте политики
Эндпоинт creds вызывается методом POST, поэтому в политике нужна возможность update:
d8 stronghold policy write k8s-ci-deploy - <<'POLICY'
path "kubernetes/creds/ci-deploy" {
capabilities = ["update"]
}
POLICY
d8 stronghold policy write k8s-engineer-view - <<'POLICY'
path "kubernetes/creds/engineer-view" {
capabilities = ["update"]
}
POLICYНазначьте политику k8s-ci-deploy роли метода аутентификации CI, а k8s-engineer-view — группе инженеров в методе OIDC или в идентификационных данных (Identity).
Шаг 6. Получите токен
Запросите токены для CI и для инженера:
Запросите токен для CI:
d8 stronghold write kubernetes/creds/ci-deploy kubernetes_namespace=myappПример вывода:
Key Value --- ----- lease_id kubernetes/creds/ci-deploy/cujRLYjKZUMQk6dkHBGGWm67 lease_duration 15m lease_renewable false service_account_name v-token-ci-deplo-1653001548-5z6hrgsxnmzncxejztml4arz service_account_namespace myapp service_account_token eyJHbGci0iJSUzI1Ni...Аренда не продлевается: после её истечения запросите новый токен.
Инженер запрашивает токен на нужное время в пределах
token_max_ttl:d8 stronghold write kubernetes/creds/engineer-view kubernetes_namespace=myapp-stage ttl=2hСоздайте временный kubeconfig с полученным токеном в файле
tmp-kubeconfig:TOKEN="$(d8 stronghold write -field=service_account_token kubernetes/creds/engineer-view kubernetes_namespace=myapp-stage)" SERVER="$(d8 k config view --minify -o jsonpath='{.clusters[].cluster.server}')" d8 k config view --minify --raw -o jsonpath='{.clusters[].cluster.certificate-authority-data}' | base64 -d > ca.crt d8 k --kubeconfig=tmp-kubeconfig config set-cluster dp --server="$SERVER" --certificate-authority=ca.crt --embed-certs=true d8 k --kubeconfig=tmp-kubeconfig config set-credentials stronghold-token --token="$TOKEN" d8 k --kubeconfig=tmp-kubeconfig config set-context tmp --cluster=dp --user=stronghold-token --namespace=myapp-stage d8 k --kubeconfig=tmp-kubeconfig config use-context tmpКоманды не меняют переменную
KUBECONFIG, поэтому остальные командыd8 kпо-прежнему используют ваш kubeconfig администратора. Чтобы выполнить команду с выданным токеном, передайте параметр--kubeconfig=tmp-kubeconfig:d8 k --kubeconfig=tmp-kubeconfig get pods
В CI-задании получите токен Stronghold через метод JWT, как описано в разделе «Интеграция с CI/CD», затем запросите токен Kubernetes и передайте его в d8 k параметром --token:
deploy:
script:
- export STRONGHOLD_TOKEN="$(d8 stronghold write -field=token auth/gitlab/login role=myproject-deploy jwt=$STRONGHOLD_ID_TOKEN)"
- export K8S_TOKEN="$(d8 stronghold write -field=service_account_token kubernetes/creds/ci-deploy kubernetes_namespace=myapp)"
- d8 k --server="$K8S_SERVER" --certificate-authority="$K8S_CA_FILE" --token="$K8S_TOKEN" -n myapp apply -f deploy/Проверка
Проверьте результат:
Запросите токен CI и проверьте разрешённые действия:
TOKEN="$(d8 stronghold write -field=service_account_token kubernetes/creds/ci-deploy kubernetes_namespace=myapp)" d8 k --token="$TOKEN" auth can-i create deployments -n myapp d8 k --token="$TOKEN" auth can-i patch configmaps -n myappОбе команды должны вернуть
yes.Проверьте, что лишних прав нет:
d8 k --token="$TOKEN" auth can-i get secrets -n myapp d8 k --token="$TOKEN" auth can-i create deployments -n kube-systemОбе команды должны вернуть
no.Если в текущем kubeconfig задан другой способ аутентификации (например, клиентский сертификат), добавьте в команды параметр
--kubeconfig=tmp-kubeconfigиз шага 6. Параметр--tokenпереопределяет токен из этого kubeconfig.Убедитесь, что запрос токена для неразрешённого неймспейса отклоняется:
d8 stronghold write kubernetes/creds/ci-deploy kubernetes_namespace=defaultПросмотрите объекты, созданные Stronghold в неймспейсе:
d8 k -n myapp get serviceaccounts,roles,rolebindings | grep v-tokenОтзовите аренду досрочно и убедитесь, что токен перестал работать:
d8 stronghold lease revoke -prefix kubernetes/creds/ci-deploy/ d8 k --token="$TOKEN" auth can-i create deployments -n myappПосле удаления ServiceAccount запрос с его токеном завершается ошибкой
Unauthorized.
Для ролей с service_account_name Stronghold не создаёт ServiceAccount, поэтому отзыв аренды не делает токен недействительным до истечения его срока жизни. Для таких ролей задавайте короткий token_default_ttl.
Очистка
Удалите объекты, созданные в примере:
Отзовите все выданные токены:
d8 stronghold lease revoke -prefix kubernetes/creds/Удалите роли, политики и конфигурацию:
d8 stronghold delete kubernetes/roles/ci-deploy d8 stronghold delete kubernetes/roles/engineer-view d8 stronghold policy delete k8s-ci-deploy d8 stronghold policy delete k8s-engineer-view d8 stronghold secrets disable kubernetesУдалите права Stronghold в кластере и временные файлы:
d8 k delete -f stronghold-k8s-secrets-engine.yaml rm -f tmp-kubeconfig ca.crt