Kubernetes Secrets Engine для Stronghold генерирует токены ServiceAccount Kubernetes (не путать с токенами Stronghold), а также, по желанию, сами объекты ServiceAccount, Role и RoleBinding. Созданные токены имеют настраиваемый срок жизни (TTL), а все созданные объекты автоматически удаляются по истечении срока аренды (lease) Stronghold.

На каждую аренду Stronghold создаёт токен для конкретного ServiceAccount. Токен возвращается вызывающей стороне.

Для большей информации о ресурсах Kubernetes ознакомьтесь с официальной документацией Kubernetes service account и Kubernetes RBAC.

Не используйте токены, созданные механизмом секретов Kubernetes, для аутентификации с помощью Kubernetes Auth Method. Это приведёт к созданию множества уникальных идентификаторов в Stronghold, которыми будет сложно управлять.

Настройка

Перед использованием механизма секретов Kubernetes, необходимо предварительно его настроить. Эти шаги обычно выполняются администратором Stronghold или инструментом автоматического управления конфигурацией.

По умолчанию Stronghold подключается к Kubernetes, используя собственный ServiceAccount. При использовании Helm chart этот ServiceAccount создаётся автоматически по умолчанию и называется по имени релиза Helm (по умолчанию stronghold, но это можно настроить через значение Helm server.serviceAccount.name).

Убедитесь, что ServiceAccount, который использует Stronghold, имеет права на управление токенами ServiceAccount, а при использовании соответствующих функций — и на управление ServiceAccount, ролями и привязками ролей. Этими правами можно управлять с помощью тех же ролей Kubernetes. Роль привязывается к ServiceAccount Stronghold с помощью привязки роли или привязки кластерной роли.

Например, роль кластера только для создания токенов ServiceAccount:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: k8s-minimal-secrets-abilities
rules:
- apiGroups: [""]
  resources: ["serviceaccounts/token"]
  verbs: ["create"]

Аналогичным образом можно создать кластерную роль с бóльшими правами. В данном случае установлены права на управление токенами, ServiceAccount, привязками ролей к ServiceAccount и ролями.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: k8s-full-secrets-abilities
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"]

Создайте эту роль в Kubernetes (например, с помощью d8 k apply -f).

Если вы хотите выбирать неймспейсы, в которых может действовать роль, по лейблам (label selector), предоставьте Stronghold разрешение на чтение неймспейсов.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: k8s-full-secrets-abilities-with-labels
rules:
- apiGroups: [""]
  resources: ["namespaces"]
  verbs: ["get"]
- 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"]

Получение правильных разрешений для Stronghold, скорее всего, потребует проб и ошибок, поскольку Kubernetes имеет строгую защиту от повышения привилегий. Подробнее об этом можно прочитать в документации Kubernetes RBAC

Защитите ServiceAccount Stronghold, особенно если вы выдаёте ему широкие права: по сути он является учётной записью администратора кластера.

Создайте привязку роли, чтобы связать её с ServiceAccount Stronghold и предоставить Stronghold разрешение на управление токенами.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
 name: stronghold-token-creator-binding
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: ClusterRole
 name: k8s-minimal-secrets-abilities
subjects:
- kind: ServiceAccount
  name: stronghold
  namespace: stronghold

Для получения дополнительной информации о ролях Kubernetes, ServiceAccount, привязках и токенах посетите раздел документации Kubernetes RBAC.

Если Stronghold не будет автоматически управлять ролями или ServiceAccount, настройте ServiceAccount, для которого Stronghold будет выпускать токены. Подробнее об автоматическом управлении — в разделе «Автоматическое управление ролями и ServiceAccount».

Выпускайте токены для ServiceAccount, который НЕ совпадает с ServiceAccount самого Stronghold. Иначе получатели токенов получат права, которые Stronghold использует для управления кластером.

Примеры ниже находятся в неймспейсе test, который вы можете создать, если он ещё не существует.

$ d8 k create namespace test
namespace/test created

Здесь представлена простая настройка ServiceAccount, роли и привязки роли в неймспейсе Kubernetes test с базовыми разрешениями, используемыми в примерах:

apiVersion: v1
kind: ServiceAccount
metadata:
 name: test-service-account-with-generated-token
 namespace: test
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
 name: test-role-list-pods
 namespace: test
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
 name: test-role-abilities
 namespace: test
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: Role
 name: test-role-list-pods
subjects:
- kind: ServiceAccount
  name: test-service-account-with-generated-token
  namespace: test

Вы можете создать эти объекты с помощью команды d8 k apply -f.

Включите механизм секретов Kubernetes:

$ stronghold secrets enable kubernetes
Success! Enabled the kubernetes Secrets Engine at: kubernetes/

По умолчанию движок секретов будет монтироваться по тому же имени, что и его название, то есть kubernetes/. Это можно изменить, передав аргумент -path при включении.

Настройте точку монтирования. Допускается пустая конфигурация.

stronghold write -f kubernetes/config
  1. Теперь можно настроить роль Stronghold в механизме секретов Kubernetes (не то же самое, что роль Kubernetes), которая сможет генерировать токены Kubernetes для созданного нами ServiceAccount:
stronghold write kubernetes/roles/my-role allowed_kubernetes_namespaces="*" service_account_name="test-service-account-with-generated-token" token_default_ttl="10m"

Создание учётных данных

После того как пользователь прошёл аутентификацию в Stronghold и получил достаточные права, запись в эндпоинт creds для роли Stronghold сгенерирует и вернёт новый токен ServiceAccount.

$ stronghold write kubernetes/creds/my-role kubernetes_namespace=test

Key                        Value
–--                        -----
lease_id                   kubernetes/creds/my-role/31d771a6-...
lease_duration             10m0s
lease_renwable             false
service_account_name       test-service-account-with-generated-token
service_account_namespace  test
service_account_token      eyJHbGci0iJSUzI1NiIsImtpZCI6ImlrUEE...

Вы можете использовать указанный выше токен ServiceAccount (eyJHbG...) для любого авторизованного запроса к Kubernetes API. Авторизацией управляют привязки ролей к ServiceAccount.

$ curl -sk $(d8 k config view --minify -o 'jsonpath={.clusters[].cluster.server}')/api/v1/namespaces/test/pods --header "Authorization: Bearer eyJHbGci0iJSUzI1Ni..."
{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "resourceVersion": "1624"
  },
  "items": []
}

После истечения срока аренды, можно удостовериться, что токен был отозван и больше не может быть использован для запросов к Kubernetes API.

$ curl -sk $(d8 k config view --minify -o 'jsonpath={.clusters[].cluster.server}')/api/v1/namespaces/test/pods --header "Authorization: Bearer eyJHbGci0iJSUzI1Ni..."
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "Unauthorized",
  "reason": "Unauthorized",
  "code": 401
}

Время жизни токена (TTL)

Токены ServiceAccount Kubernetes имеют время жизни (TTL). Когда срок действия токена истекает, токен автоматически отзывается.

Можно установить стандартное (token_default_ttl) и максимальное время жизни (token_max_ttl) при создании или настройке роли Stronghold.

stronghold write kubernetes/roles/my-role allowed_kubernetes_namespaces="*" service_account_name="new-service-account-with-generated-token" token_default_ttl="10m" token_max_ttl="2h"

Вы также можете задать время жизни (ttl) при генерации токена из эндпоинта creds. Если время жизни токена не указано, используется значение по умолчанию (и не может превышать максимальный срок (token_max_ttl) роли, если он есть).

$ stronghold write kubernetes/creds/my-role kubernetes_namespace=test ttl=20m

Key                        Value
–--                        -----
lease_id                   kubernetes/creds/my-role/31d771a6-...
lease_duration             20m0s
lease_renwable             false
service_account_name       new-service-account-with-generated-token
service_account_namespace  test
service_account_token      eyJHbGci0iJSUzI1NiIsImtpZCI6ImlrUEE...

Можно проверить время жизни токена JWT-токена. Для этого декодируем токен и конвертируем поля iat (issued at) и exp (expiration time) из формата timestamp в удобночитаемый.

$ echo 'eyJhbGc...' | cut -d'.' -f2 | base64 -d  | jq -r '.iat,.exp|todate'
2022-05-20T17:14:50Z
2022-05-20T17:34:50Z

Аудитория (aud)

Токены в Kubernetes имеют формат JWT, а значит, используют механизм «утверждений» (claims). Одним из таких является утверждение aud (аудитория) - это строка или массив строк, которые идентифицируют получателей, для которых предназначен JWT. Для более подробной информации ознакомьтесь со спецификацией JWT audience claim

Вы можете задать аудитории по умолчанию (token_default_audiences) при создании или настройке роли Stronghold. Если явно не задано, по умолчанию кластер Kubernetes будет использовать свои значения аудитории для токенов ServiceAccount.

stronghold write kubernetes/roles/my-role allowed_kubernetes_namespaces="*" service_account_name="new-service-account-with-generated-token" token_default_audiences="custom-audience"

Вы также можете задать аудитории (audiences) при генерации токена из эндпоинта creds. Если аудитории токена не заданы, то они будут заданы по умолчанию из значения поля token_default_audiences, которое мы указывали ранее.

$ stronghold write kubernetes/creds/my-role kubernetes_namespace=test audiences="another-custom-audience"

Key                        Value
–--                        -----
lease_id                   kubernetes/creds/my-role/SriWQf0bPZ...
lease_duration             768h
lease_renwable             false
service_account_name       new-service-account-with-generated-token
service_account_namespace  test
service_account_token      eyJHbGci0iJSUzI1NiIsImtpZCI6ImlrUEE...

Аудиторию токена можно проверить, расшифровав JWT.

$ echo 'eyJhbGc...' | cut -d'.' -f2 | base64 -d
{"aud":["another-custom-audience"]...

Автоматическое управление ролями и ServiceAccount

При настройке роли Stronghold вы можете передать параметры, чтобы указать, что вы хотите автоматически генерировать ServiceAccount и привязку роли, а также, по желанию, генерировать саму роль Kubernetes.

Если вы хотите настроить роль Stronghold на использование уже существующей роли Kubernetes, но при этом автоматически создать ServiceAccount и привязку роли, вы можете задать параметр kubernetes_role_name.

stronghold write kubernetes/roles/auto-managed-sa-role allowed_kubernetes_namespaces="test" kubernetes_role_name="test-role-list-pods"

ServiceAccount Stronghold также потребуется доступ к ресурсам, к которым он предоставляет доступ. Это можно сделать для приведённых выше примеров с помощью команды d8 k -n test create rolebinding --role test-role-list-pods --serviceaccount=stronghold:stronghold stronghold stronghold-test-role-abilities. Так Kubernetes предотвращает эскалацию привилегий. Более подробную информацию вы можете прочитать в документации к Kubernetes RBAC.

После чего вы можете получить учётные данные с помощью автоматически созданного ServiceAccount.

$ stronghold write kubernetes/creds/auto-managed-sa-role kubernetes_namespace=test
Key                          Value
---                          -----
lease_id                     kubernetes/creds/auto-managed-sa-role/cujRLYjKZUMQk6dkHBGGWm67
lease_duration               768h
lease_renewable              false
service_account_name         v-token-auto-man-1653001548-5z6hrgsxnmzncxejztml4arz
service_account_namespace    test
service_account_token        eyJHbGci0iJSUzI1Ni...

Кроме того, Stronghold может автоматически создать роль в дополнение к ServiceAccount и привязке роли, указав параметр generated_role_rules, в который передаётся набор правил JSON или YAML для создаваемой роли.

stronghold write kubernetes/roles/auto-managed-sa-and-role allowed_kubernetes_namespaces="test" generated_role_rules='{"rules":[{"apiGroups":[""],"resources":["pods"],"verbs":["list"]}]}'

После этого можно получить учётные данные тем же способом, что и раньше.

$ stronghold write kubernetes/creds/auto-managed-sa-and-role kubernetes_namespace=test
Key                          Value
---                          -----
lease_id                     kubernetes/creds/auto-managed-sa-and-role/pehLtegoTP8vCkcaQozUqOHf
lease_duration               768h
lease_renewable              false
service_account_name         v-token-auto-man-1653002096-4imxf3ytjh5hbyro9s1oqdo3
service_account_namespace    test
service_account_token        eyJHbGci0iJSUzI1Ni...

Дополнительные ресурсы