Xác thực trong Kubernetes bằng GitHub OAuth và Dex

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

Xác thực trong Kubernetes bằng GitHub OAuth và Dex
Локальный мем из русскоязычного чата Kubernetes в Telegram

Giới thiệu

Мы используем Kubernetes для создания динамических окружений для команды разработчиков и QA. Таким образом, мы хотим предоставить им доступ к кластеру как для дашборда, так и для kubectl. В отличие от того же OpenShift, ванильный Kubernetes не имеет нативной аутентификации, поэтому мы используем для этого сторонние средства.

В данной конфигурации мы используем:

  • dex-k8s-authenticator  — веб-приложение для генерации конфига kubectl
  • Dex — провайдер OpenID Connect
  • GitHub — просто потому-что мы используем GitHub в нашей компании

Мы пытались использовать Google OIDC, но к сожалению нам thất bại завести их с группами, поэтому интеграция с GitHub нас вполне устроила. Без маппинга групп не удасться создать RBAC-политики основанные на группах.

Итак, как же работает наш процесс авторизации в Kubernetes в визуальном представлении:

Xác thực trong Kubernetes bằng GitHub OAuth và Dex
quy trình ủy quyền

Немного подробнее и по пунктам:

  1. Пользователь входит в dex-k8s-authenticator (login.k8s.example.com)
  2. dex-k8s-authenticator перенаправляет запрос в Dex (dex.k8s.example.com)
  3. Dex перенаправляет на страницу авторизации в GitHub
  4. GitHub генерирует необходимую информацию об авторизации и возвращает ее в Dex
  5. Dex передает полученную информацию в dex-k8s-authenticator
  6. Пользователь получает OIDC token от GitHub
  7. dex-k8s-authenticator добавляет токен в kubeconfig
  8. kubectl передает токен в KubeAPIServer
  9. KubeAPIServer на основе переданного токена возвращает доступы в kubectl
  10. Пользователь получает доступы от kubectl

Các hành động chuẩn bị

Само собой у нас уже установлен Kubernetes-кластер (k8s.example.com), а также предустановлен HELM. Также у нас есть организация в GitHub (super-org).
Если у вас нет HELM, устанавливается он rất đơn giản.

Сначала нам необходимо настроить GitHub.

Переходим на страницу настроек организации, (https://github.com/organizations/super-org/settings/applications) и создаем новое приложение (Authorized OAuth App):
Xác thực trong Kubernetes bằng GitHub OAuth và Dex
Создание нового приложения в 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: [email protected]
    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

Chúng tôi sử dụng đá для разворачивания кластеров, но это аналогично работает и для других менеджеров кластеров.

Конфигурация 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 [email protected]: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

Теперь мы готовы к тестированию.

Kiểm tra

Переходим на страницу логина (https://login.k8s.example.com) и авторизуемся с помощью GitHub-аккаунта:

Xác thực trong Kubernetes bằng GitHub OAuth và Dex
Страница авторизации

Xác thực trong Kubernetes bằng GitHub OAuth và Dex
Страница авторизации перенаправленная на GitHub

Xác thực trong Kubernetes bằng GitHub OAuth và Dex
 Следуем сгенерированной инструкции для получения доступов

После копипасты с веб-страницы мы можем использовать 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 "[email protected]" cannot delete pods in the namespace "default"

И это работает, все пользователи GitHub в нашей организации могут видеть ресурсы и входить в поды, однако они не имеют прав на их изменение.

Nguồn: www.habr.com

Thêm một lời nhận xét