Kubernetes
Kubernetes может выступать в качестве провайдера OIDC, чтобы Stronghold мог подтверждать токены сервисных учетных записей с помощью JWT/OIDC auth.
Механизм JWT-аутентификации не использует при аутентификации API Kubernetes TokenReview
, а вместо этого используется криптография с открытым ключом для проверки содержимого JWT. Это означает, что токены, которые были отозваны Kubernetes, будут считаться действительными до истечения срока их действия. Чтобы снизить этот риск, используйте короткие TTL для токенов сервисных учетных записей или используйте Kubernetes auth, который использует API TokenReview
.
Использование адреса автонастройки
При использовании автонастройки вам нужно указать только OIDC discovery URL. В случае, если OIDC URL использует кастомный сертификат, так же понадобится CA, которому можно доверять. Это режимн наиболее простой в настройке, если ваш кластер Kubernetes соответствует требованиям.
Требования к кластеру Kubernetes:
- Включенная опция
ServiceAccountIssuerDiscovery
.- Доступна с версии 1.18, включена по умолчанию с версии 1.20.
- Значение URL в параметре kube-apiserver-а
--service-account-issuer
должно содержать адрес, доступный из Stronghold. Для большинства managed сервисов Kubernetes этот адрес публичный. - Должны использоваться коротроживущие токены для сервисных аккаунтов Kubernetes.
- По умолчанию такое поведение включено для токенов, подключаемых в поды, начиная с Kubernetes 1.21.
Шаги по настройке:
Убедитесь, что URL адреса обнаружения OIDC не требует аутентификации, как описано тут:
kubectl create clusterrolebinding oidc-reviewer \
--clusterrole=system:service-account-issuer-discovery \
--group=system:unauthenticated
Определите адрес issuer URL для вашего кластера.
ISSUER="$(kubectl get --raw /.well-known/openid-configuration | jq -r '.issuer')"
Включите и настройте аутентификацию JWT в Stronghold.
d8 stronghold auth enable jwt
d8 stronghold write auth/jwt/config oidc_discovery_url="${ISSUER}"
Настройте необходимые роли, как описано ниже.
Использование публичных ключей для проверки JWT
Этот метод может быть полезен, если API Kubernetes недоступен из Stronghold или если вы хотите, чтобы один эндпоинт JWT auth обслуживал несколько кластеров Kubernetes, используя цепочку публичных ключей.
Требования к кластеру Kubernetes:
- Включенная опция
ServiceAccountIssuerDiscovery
.- Доступна с версии 1.18, включена по умолчанию с версии 1.20.
- Этого требование не обязательно, если вы имеете доступ файлу
/etc/kubernetes/pki/sa.pub
на к мастер-ноде кластера. В этом случае вы можете пропустить шаги по получению ключа и конвертации его в формат PEM, так как ключ уже находится в файле в нужном формате.
- Должны использоваться коротроживущие токены для сервисных аккаунтов Kubernetes.
- По умолчанию такое поведение включено для токенов, подключаемых в поды, начиная с Kubernetes 1.21.
Шаги по настройке:
Получите открытый ключ подписи токенов сервис-аккаунтов из JWKS URI вашего кластера.
# jwks_uri доступен в /.well-known/openid-configuration
kubectl get --raw "$(kubectl get --raw /.well-known/openid-configuration | jq -r '.jwks_uri' | sed -r 's/.*\.[^/]+(.*)/\1/')"
Преобразуйте ключи из формата JWK в формат PEM. Вы можете сделать это с помощью консолькой утилиты, или любого онлайн-сервиса, например этого.
Настройте эндпоинт JWT auth на использование полученных ключей.
d8 stronghold write auth/jwt/config \
jwt_validation_pubkeys="-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9...
-----END PUBLIC KEY-----","-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9...
-----END PUBLIC KEY-----"
Настройте необходимые роли, как описано ниже.
Создание ролей и аутентификация
После того как эндпоинт JWT-auth настроен, вы можете настроить роль и пройти аутентификацию. Далее предполагается, что вы используете токен учетной записи сервиса, доступный по умолчанию во всех подах. Если вы хотите контролировать целевую группу (audience) или TTL, смотрите раздел Указание TTL и целевой группы.
Выберите любое значение из набора стандартных целевых групп по умолчанию. В этих примерах в массиве aud
есть только одна целевая группа, https://kubernetes.default.svc.cluster.local
.
Чтобы найти целевую группу по умолчанию, вы можете создать новый токен (требуется kubectl
v1.24.0+):
$ kubectl create token default | cut -f2 -d. | base64 --decode
{"aud":["https://kubernetes.default.svc.cluster.local"], ... "sub":"system:serviceaccount:default:default"}
Или прочитать токен из запущенного пода:
$ kubectl exec my-pod -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -f2 -d. | base64 --decode
{"aud":["https://kubernetes.default.svc.cluster.local"], ... "sub":"system:serviceaccount:default:default"}
Создайте роль для JWT-auth, которую сможет использовать сервис-аккаунт default
в неймспейсе default
.
d8 stronghold write auth/jwt/role/my-role \
role_type="jwt" \
bound_audiences="<AUDIENCE-FROM-PREVIOUS-STEP>" \
user_claim="sub" \
bound_subject="system:serviceaccount:default:default" \
policies="default" \
ttl="1h"
Теперь с помошьэ этого токена проды, или кличенты, имеюшие доступ к JWT сервис-аккаунта, смогут аутентифицироваться.
d8 stronghold write auth/jwt/login \
role=my-role \
jwt=@/var/run/secrets/kubernetes.io/serviceaccount/token
# OR equivalent to:
curl \
--fail \
--request POST \
--data '{"jwt":"<JWT-TOKEN-HERE>","role":"my-role"}' \
"${STRONGHOLD_ADDR}/v1/auth/jwt/login"
Указание TTL и целевых групп
Если вы хотите указать пользовательский TTL или целевую группу для токенов сервисных учетных записей, в следующем манифесте пода показано монтирование тома, которое переопределяет инжектируемый токен по умолчанию. Это особенно актуально, если вы не можете отключить флаг –service-account-extend-token-expiration для kube-apiserver
и хотите использовать короткие TTL.
При использовании полученного токена вам нужно будет установить bound_audiences=stronghold
при создании ролей в JWT auth.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
# automountServiceAccountToken является лишним в этом примере, поскольку используемый
# используемый mountPath совпадает с путем по умолчанию. Это перекрытие предотвращает
# создание токена по умолчению. Однако вы можете использовать этот параметр, чтобы
# обеспечить монтирование только одного токена, если вы выберете другой путь монтирования.
automountServiceAccountToken: false
containers:
- name: nginx
image: nginx
volumeMounts:
- name: custom-token
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
volumes:
- name: custom-token
projected:
defaultMode: 420
sources:
- serviceAccountToken:
path: token
expirationSeconds: 600 # Минимальный TTL 10 минут
audience: stronghold # Должен совпадать с параметром `bound_audiences` вашей роли
# Остальные параметры добавлены для имитации обычного поведения при создании токена,
# и создают объекты, которые создаются при включенном параметре automountServiceAccountToken
- configMap:
name: kube-root-ca.crt
items:
- key: ca.crt
path: ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace