Uwierzytelnianie w Kubernetes z użyciem GitHub OAuth i Dex

Przedstawiam Państwu poradnik dotyczący generowania dostępu do klastra Kubernetes za pomocą Dex, dex-k8s-authenticator i GitHub.

Uwierzytelnianie w Kubernetes z użyciem GitHub OAuth i Dex
Lokalny mem z rosyjskojęzycznego czatu Kubernetes w Telegram

Wprowadzenie

Używamy Kubernetes do tworzenia dynamicznych środowisk dla zespołów deweloperskich i QA. W ten sposób chcemy zapewnić im dostęp do klastra zarówno do panelu kontrolnego, jak i do kubectl. W przeciwieństwie do OpenShift, standardowy Kubernetes nie ma natywnej autoryzacji, dlatego korzystamy z narzędzi zewnętrznych.

W tej konfiguracji używamy:

  • dex-k8s-authenticator  — aplikacja webowa do generowania konfiguracji kubectl
  • Dex — dostawca OpenID Connect
  • GitHub — po prostu dlatego, że używamy GitHub w naszej firmie

Próbowaliśmy używać Google OIDC, ale niestety nie udało nam się zainstalować ich z grupami, więc integracja z GitHub nas w pełni satysfakcjonuje. Bez mapowania grup nie da się stworzyć polityk RBAC opartych na grupach.

Jak zatem wygląda nasz proces autoryzacji w Kubernetes w sposób wizualny:

Uwierzytelnianie w Kubernetes z użyciem GitHub OAuth i Dex
Proces autoryzacji

Nieco więcej szczegółów i po punktach:

  1. Użytkownik loguje się do dex-k8s-authenticator (login.k8s.example.com)
  2. dex-k8s-authenticator przekierowuje żądanie do Dex (dex.k8s.example.com)
  3. Dex przekierowuje na stronę autoryzacji w GitHub
  4. GitHub generuje potrzebne informacje o autoryzacji i zwraca je do Dex
  5. Dex przekazuje otrzymane informacje do dex-k8s-authenticator
  6. Użytkownik otrzymuje token OIDC od GitHub
  7. dex-k8s-authenticator dodaje token do kubeconfig
  8. kubectl przekazuje token do KubeAPIServer
  9. KubeAPIServer na podstawie przekazanego tokena zwraca dostęp do kubectl
  10. Użytkownik otrzymuje dostęp od kubectl

Działania wstępne

Oczywiście mamy już zainstalowany klaster Kubernetes (k8s.example.com), a także preinstalowany HELM. Mamy również organizację na GitHubie (super-org).
Jeśli nie masz HELM, instalacja jest bardzo prosta.

Najpierw musimy skonfigurować GitHub.

Przechodzimy do strony ustawień organizacji, (https://github.com/organizations/super-org/settings/applications) i tworzymy nową aplikację (Aplikacja OAuth autoryzowana):
Uwierzytelnianie w Kubernetes z użyciem GitHub OAuth i Dex
Tworzenie nowej aplikacji w GitHubie

Wypełniamy pola wymaganymi URL-ami, na przykład:

  • URL strony głównej: https://dex.k8s.example.com
  • URL zwrotnego przekierowania autoryzacji: https://dex.k8s.example.com/callback

Zwróć uwagę na linki, ważne jest, aby nie zgubić slashy.

W odpowiedzi na wypełniony formularz GitHub wygeneruje ID klienta i Sekret klienta, zachowaj je w bezpiecznym miejscu, będą nam potrzebne (na przykład używamy Vault do przechowywania sekretów):

ID klienta: 1ab2c3d4e5f6g7h8
Sekret klienta: 98z76y54x32w1

Przygotuj rekordy DNS dla subdomen login.k8s.example.com i dex.k8s.example.com, a także certyfikaty SSL dla ingressów.

Stworzymy certyfikaty 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 o nazwie le-clusterissuer musi już istnieć, jeśli nie — stworzymy go za pomocą 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

Konfiguracja KubeAPIServer

Aby skonfigurować kubeAPIServer, należy skonfigurować OIDC i zaktualizować klaster:

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

Używamy kops do wdrażania klastrów, ale działa to również w przypadku innych menedżerów klastrów.

Konfiguracja Dex i dex-k8s-authenticator

Aby uruchomić Dex, potrzebujemy certyfikatu i klucza z mastera Kubernetes, wyciągnijmy je stamtąd:

sudo cat /srv/kubernetes/ca.{crt,key}
-----BEGIN CERTIFICATE-----
AAAAAAAAAAABBBBBBBBBBCCCCCC
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
DDDDDDDDDDDEEEEEEEEEEFFFFFF
-----END RSA PRIVATE KEY-----

Sklonujemy repozytorium dex-k8s-authenticator:

git clone git@github.com:mintel/dex-k8s-authenticator.git
cd dex-k8s-authenticator/

Za pomocą plików values możemy elastycznie konfigurować zmienne dla naszych HELM chartów.

Opiszemy konfigurację dla Dex:

cat < 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

I dla dex-k8s-authenticator:

cat < 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

Zainstalujemy Dex i 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

Sprawdzimy działanie usług (Dex powinien zwrócić kod 400, a dex-k8s-authenticator – kod 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

Konfiguracja RBAC

Tworzymy ClusterRole dla grupy, w naszym przypadku z dostępem tylko do odczytu:

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

Tworzymy konfigurację dla 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

Teraz jesteśmy gotowi do testowania.

Testy

Przechodzimy na stronę logowania (https://login.k8s.example.com) i logujemy się za pomocą konta GitHub:

Uwierzytelnianie w Kubernetes z użyciem GitHub OAuth i Dex
Strona autoryzacji

Uwierzytelnianie w Kubernetes z użyciem GitHub OAuth i Dex
Strona autoryzacji przekierowana na GitHub

Uwierzytelnianie w Kubernetes z użyciem GitHub OAuth i Dex
 Postępujemy zgodnie z wygenerowaną instrukcją, aby uzyskać dostęp

Po skopiowaniu z strony internetowej możemy używać kubectl do zarządzania zasobami naszego klastra:

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"

I to działa, wszyscy użytkownicy GitHub w naszej organizacji mogą widzieć zasoby i wchodzić do podów, jednak nie mają praw do ich zmiany.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster