Представляю вашему вниманию туториал для генерации доступов к Kubernetes-кластеру с помощью Dex, dex-k8s-authenticator и GitHub.

Локальный мем из русскоязычного чата Kubernetes в Telegram
Мы используем Kubernetes для создания динамических окружений для команды разработчиков и QA. Таким образом, мы хотим предоставить им доступ к кластеру как для дашборда, так и для kubectl. В отличие от того же OpenShift, ванильный Kubernetes не имеет нативной аутентификации, поэтому мы используем для этого сторонние средства.
В данной конфигурации мы используем:
Мы пытались использовать Google OIDC, но к сожалению нам не удалось завести их с группами, поэтому интеграция с GitHub нас вполне устроила. Без маппинга групп не удасться создать RBAC-политики основанные на группах.
Итак, как же работает наш процесс авторизации в Kubernetes в визуальном представлении:

Процесс авторизации
Немного подробнее и по пунктам:
Само собой у нас уже установлен Kubernetes-кластер (
Если у вас нет HELM, устанавливается он очень просто.
Сначала нам необходимо настроить GitHub.
Переходим на страницу настроек организации, (

Создание нового приложения в GitHub
Заполняем поля необходимыми URL, например:
Будьте внимательны с ссылками, важно не потерять слеши.
В ответ на заполненную форму, GitHub сгенерирует
Подготовьте DNS-записи для субдоменов
Создадим SSL-сертификаты:
ClusterIssuer с названием
Для работы kubeAPIServer необходимо сконфигурировать OIDC и обновить кластер:
Мы используем kops для разворачивания кластеров, но это аналогично работает и для других менеджеров кластеров.
Для работы Dex необходимо иметь сертификат и ключ с Kubernetes-мастера, вытащим его оттуда:
Склонируем репозиторий dex-k8s-authenticator:
С помощью values-файлов мы можем гибко настраивать переменные для наших HELM-чартов.
Опишем конфигурацию для Dex:
И для dex-k8s-authenticator:
Установим Dex и dex-k8s-authenticator:
Проверим работоспособность сервисов (Dex должен вернуть код 400, а dex-k8s-authenticator — код 200):
Создаем ClusterRole для группы, в нашем случае с read-only доступами:
Создадим конфигурацию для ClusterRoleBinding:
Теперь мы готовы к тестированию.
Переходим на страницу логина (

Страница авторизации

Страница авторизации перенаправленная на GitHub

Следуем сгенерированной инструкции для получения доступов
После копипасты с веб-страницы мы можем использовать kubectl для управления ресурсами нашего кластера:
И это работает, все пользователи GitHub в нашей организации могут видеть ресурсы и входить в поды, однако они не имеют прав на их изменение.

Локальный мем из русскоязычного чата Kubernetes в Telegram
Введение
Мы используем Kubernetes для создания динамических окружений для команды разработчиков и QA. Таким образом, мы хотим предоставить им доступ к кластеру как для дашборда, так и для kubectl. В отличие от того же OpenShift, ванильный Kubernetes не имеет нативной аутентификации, поэтому мы используем для этого сторонние средства.
В данной конфигурации мы используем:
- dex-k8s-authenticator — веб-приложение для генерации конфига kubectl
- Dex — провайдер OpenID Connect
- GitHub — просто потому-что мы используем GitHub в нашей компании
Мы пытались использовать Google OIDC, но к сожалению нам не удалось завести их с группами, поэтому интеграция с GitHub нас вполне устроила. Без маппинга групп не удасться создать RBAC-политики основанные на группах.
Итак, как же работает наш процесс авторизации в Kubernetes в визуальном представлении:

Процесс авторизации
Немного подробнее и по пунктам:
- Пользователь входит в dex-k8s-authenticator (
login.k8s.example.com) - dex-k8s-authenticator перенаправляет запрос в Dex (
dex.k8s.example.com) - Dex перенаправляет на страницу авторизации в GitHub
- GitHub генерирует необходимую информацию об авторизации и возвращает ее в Dex
- Dex передает полученную информацию в dex-k8s-authenticator
- Пользователь получает OIDC token от GitHub
- dex-k8s-authenticator добавляет токен в kubeconfig
- kubectl передает токен в KubeAPIServer
- KubeAPIServer на основе переданного токена возвращает доступы в kubectl
- Пользователь получает доступы от kubectl
Подготовительные действия
Само собой у нас уже установлен Kubernetes-кластер (
k8s.example.com), а также предустановлен HELM. Также у нас есть организация в GitHub (super-org).Если у вас нет HELM, устанавливается он очень просто.
Сначала нам необходимо настроить GitHub.
Переходим на страницу настроек организации, (
https://github.com/organizations/super-org/settings/applications) и создаем новое приложение (Authorized OAuth App):
Создание нового приложения в GitHub
Заполняем поля необходимыми URL, например:
- Homepage URL:
https://dex.k8s.example.com - Authorization callback URL:
https://dex.k8s.example.com/callback
Будьте внимательны с ссылками, важно не потерять слеши.
В ответ на заполненную форму, GitHub сгенерирует
Client ID и Client secret, сохраните их в надежном месте, они нам пригодятся (мы например используем Vault для хранения секретов):Client ID: 1ab2c3d4e5f6g7h8 Client secret: 98z76y54x32w1
Подготовьте DNS-записи для субдоменов
login.k8s.example.com и dex.k8s.example.com, а также SSL-сертификаты для ингрессов.Создадим SSL-сертификаты:
cat <<EOF | kubectl create -f - apiVersion: certmanager.k8s.io/v1alpha1 kind: Certificate metadata: name: cert-auth-dex namespace: kube-system spec: secretName: cert-auth-dex dnsNames: - dex.k8s.example.com acme: config: - http01: ingressClass: nginx domains: - dex.k8s.example.com issuerRef: name: le-clusterissuer kind: ClusterIssuer --- apiVersion: certmanager.k8s.io/v1alpha1 kind: Certificate metadata: name: cert-auth-login namespace: kube-system spec: secretName: cert-auth-login dnsNames: - login.k8s.example.com acme: config: - http01: ingressClass: nginx domains: - login.k8s.example.com issuerRef: name: le-clusterissuer kind: ClusterIssuer EOF kubectl describe certificates cert-auth-dex -n kube-system kubectl describe certificates cert-auth-login -n kube-system
ClusterIssuer с названием
le-clusterissuer уже должен существовать, если же нет — создадим его с помощью HELM:helm install --namespace kube-system -n cert-manager stable/cert-manager cat << EOF | kubectl create -f - apiVersion: certmanager.k8s.io/v1alpha1 kind: ClusterIssuer metadata: name: le-clusterissuer namespace: kube-system spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: k8s-admin@example.com privateKeySecretRef: name: le-clusterissuer http01: {} EOF
Конфигурация KubeAPIServer
Для работы kubeAPIServer необходимо сконфигурировать OIDC и обновить кластер:
kops edit cluster ... kubeAPIServer: anonymousAuth: false authorizationMode: RBAC oidcClientID: dex-k8s-authenticator oidcGroupsClaim: groups oidcIssuerURL: https://dex.k8s.example.com/ oidcUsernameClaim: email kops update cluster --yes kops rolling-update cluster --yes
Мы используем kops для разворачивания кластеров, но это аналогично работает и для других менеджеров кластеров.
Конфигурация Dex и dex-k8s-authenticator
Для работы Dex необходимо иметь сертификат и ключ с Kubernetes-мастера, вытащим его оттуда:
sudo cat /srv/kubernetes/ca.{crt,key} -----BEGIN CERTIFICATE----- AAAAAAAAAAABBBBBBBBBBCCCCCC -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- DDDDDDDDDDDEEEEEEEEEEFFFFFF -----END RSA PRIVATE KEY-----
Склонируем репозиторий dex-k8s-authenticator:
git clone git@github.com:mintel/dex-k8s-authenticator.git cd dex-k8s-authenticator/
С помощью values-файлов мы можем гибко настраивать переменные для наших HELM-чартов.
Опишем конфигурацию для Dex:
cat << \EOF > values-dex.yml global: deployEnv: prod tls: certificate: |- -----BEGIN CERTIFICATE----- AAAAAAAAAAABBBBBBBBBBCCCCCC -----END CERTIFICATE----- key: |- -----BEGIN RSA PRIVATE KEY----- DDDDDDDDDDDEEEEEEEEEEFFFFFF -----END RSA PRIVATE KEY----- ingress: enabled: true annotations: kubernetes.io/ingress.class: nginx kubernetes.io/tls-acme: "true" path: / hosts: - dex.k8s.example.com tls: - secretName: cert-auth-dex hosts: - dex.k8s.example.com serviceAccount: create: true name: dex-auth-sa config: | issuer: https://dex.k8s.example.com/ storage: # https://github.com/dexidp/dex/issues/798 type: sqlite3 config: file: /var/dex.db web: http: 0.0.0.0:5556 frontend: theme: "coreos" issuer: "Example Co" issuerUrl: "https://example.com" logoUrl: https://example.com/images/logo-250x25.png expiry: signingKeys: "6h" idTokens: "24h" logger: level: debug format: json oauth2: responseTypes: ["code", "token", "id_token"] skipApprovalScreen: true connectors: - type: github id: github name: GitHub config: clientID: $GITHUB_CLIENT_ID clientSecret: $GITHUB_CLIENT_SECRET redirectURI: https://dex.k8s.example.com/callback orgs: - name: super-org teams: - team-red staticClients: - id: dex-k8s-authenticator name: dex-k8s-authenticator secret: generatedLongRandomPhrase redirectURIs: - https://login.k8s.example.com/callback/ envSecrets: GITHUB_CLIENT_ID: "1ab2c3d4e5f6g7h8" GITHUB_CLIENT_SECRET: "98z76y54x32w1" EOF
И для dex-k8s-authenticator:
cat << EOF > values-auth.yml global: deployEnv: prod dexK8sAuthenticator: clusters: - name: k8s.example.com short_description: "k8s cluster" description: "Kubernetes cluster" issuer: https://dex.k8s.example.com/ k8s_master_uri: https://api.k8s.example.com client_id: dex-k8s-authenticator client_secret: generatedLongRandomPhrase redirect_uri: https://login.k8s.example.com/callback/ k8s_ca_pem: | -----BEGIN CERTIFICATE----- AAAAAAAAAAABBBBBBBBBBCCCCCC -----END CERTIFICATE----- ingress: enabled: true annotations: kubernetes.io/ingress.class: nginx kubernetes.io/tls-acme: "true" path: / hosts: - login.k8s.example.com tls: - secretName: cert-auth-login hosts: - login.k8s.example.com EOF
Установим Dex и dex-k8s-authenticator:
helm install -n dex --namespace kube-system --values values-dex.yml charts/dex helm install -n dex-auth --namespace kube-system --values values-auth.yml charts/dex-k8s-authenticator
Проверим работоспособность сервисов (Dex должен вернуть код 400, а dex-k8s-authenticator — код 200):
curl -sI https://dex.k8s.example.com/callback | head -1 HTTP/2 400 curl -sI https://login.k8s.example.com/ | head -1 HTTP/2 200
RBAC-конфигурация
Создаем ClusterRole для группы, в нашем случае с read-only доступами:
cat << EOF | kubectl create -f - apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: cluster-read-all rules: - apiGroups: - "" - apps - autoscaling - batch - extensions - policy - rbac.authorization.k8s.io - storage.k8s.io resources: - componentstatuses - configmaps - cronjobs - daemonsets - deployments - events - endpoints - horizontalpodautoscalers - ingress - ingresses - jobs - limitranges - namespaces - nodes - pods - pods/log - pods/exec - persistentvolumes - persistentvolumeclaims - resourcequotas - replicasets - replicationcontrollers - serviceaccounts - services - statefulsets - storageclasses - clusterroles - roles verbs: - get - watch - list - nonResourceURLs: ["*"] verbs: - get - watch - list - apiGroups: [""] resources: ["pods/exec"] verbs: ["create"] EOF
Создадим конфигурацию для ClusterRoleBinding:
cat <<EOF | kubectl create -f - apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: dex-cluster-auth namespace: kube-system roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-read-all subjects: kind: Group name: "super-org:team-red" EOF
Теперь мы готовы к тестированию.
Тесты
Переходим на страницу логина (
https://login.k8s.example.com) и авторизуемся с помощью GitHub-аккаунта:
Страница авторизации

Страница авторизации перенаправленная на GitHub

Следуем сгенерированной инструкции для получения доступов
После копипасты с веб-страницы мы можем использовать kubectl для управления ресурсами нашего кластера:
kubectl get po NAME READY STATUS RESTARTS AGE mypod 1/1 Running 0 3d kubectl delete po mypod Error from server (Forbidden): pods "mypod" is forbidden: User "amet@example.com" cannot delete pods in the namespace "default"
И это работает, все пользователи GitHub в нашей организации могут видеть ресурсы и входить в поды, однако они не имеют прав на их изменение.
