Autenticazione in Kubernetes utilizzando GitHub OAuth e Dex

Vi presento un tutorial per generare accessi a un cluster Kubernetes utilizzando Dex, dex-k8s-authenticator e GitHub.

Autenticazione in Kubernetes utilizzando GitHub OAuth e Dex
Un meme locale dal chat russo di Kubernetes in Telegram

Introduzione

Utilizziamo Kubernetes per creare ambienti dinamici per il nostro team di sviluppo e QA. Vogliamo quindi fornire loro accesso al cluster sia per la dashboard che per kubectl. A differenza di OpenShift, Kubernetes vanilla non ha un'autenticazione nativa, quindi utilizziamo strumenti di terze parti per questo.

In questa configurazione utilizziamo:

  • dex-k8s-authenticator  — un'app web per generare la configurazione di kubectl
  • Dex — un provider OpenID Connect
  • GitHub — semplicemente perché utilizziamo GitHub nella nostra azienda

Abbiamo provato a usare Google OIDC, ma purtroppo non siamo riusciti a impostare gruppi, quindi l'integrazione con GitHub ci ha soddisfatti. Senza il mapping dei gruppi non si possono creare politiche RBAC basate sui gruppi.

Quindi, come funziona il nostro processo di autorizzazione in Kubernetes in un formato visivo:

Autenticazione in Kubernetes utilizzando GitHub OAuth e Dex
Il processo di autenticazione

Un po' più nel dettaglio e per punti:

  1. L'utente accede a dex-k8s-authenticator (login.k8s.example.com)
  2. ) dex-k8s-authenticator reindirizza la richiesta a Dex (dex.k8s.example.com)
  3. ) Dex reindirizza alla pagina di autorizzazione di GitHub
  4. GitHub genera le informazioni necessarie per l'autorizzazione e le restituisce a Dex
  5. Dex passa le informazioni ricevute a dex-k8s-authenticator
  6. L'utente riceve un token OIDC da GitHub
  7. dex-k8s-authenticator aggiunge il token a kubeconfig
  8. kubectl passa il token a KubeAPIServer
  9. KubeAPIServer, basandosi sul token fornito, restituisce i permessi a kubectl
  10. L'utente riceve i permessi da kubectl

Preparazioni

Naturalmente abbiamo già un cluster Kubernetes (k8s.example.com) e HELM preinstallato. Abbiamo anche un'organizzazione su GitHub (super-org).
Se non hai HELM, l'installazione è molto semplice.

Prima di tutto dobbiamo configurare GitHub.

Andiamo alla pagina delle impostazioni dell'organizzazione, (https://github.com/organizations/super-org/settings/applications) e creiamo una nuova applicazione (App OAuth autorizzata):
Autenticazione in Kubernetes utilizzando GitHub OAuth e Dex
Creazione di una nuova applicazione su GitHub

Compiliamo i campi con gli URL necessari, ad esempio:

  • Homepage URL: https://dex.k8s.example.com
  • Authorization callback URL: https://dex.k8s.example.com/callback

Fai attenzione ai link, è importante non perdere gli slash.

In risposta al modulo compilato, GitHub genererà ID del Client e Client secret, conservali in un luogo sicuro, ci serviranno (noi ad esempio utilizziamo Vault per conservare i segreti):

Client ID: 1ab2c3d4e5f6g7h8
Client secret: 98z76y54x32w1

Prepara i record DNS per i sottodomini login.k8s.example.com e dex.k8s.example.com, così come i certificati SSL per gli ingressi.

Creiamo i certificati 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

Il ClusterIssuer con il nome le-clusterissuer dovrebbe già esistere, se non c'è — creiamolo usando 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

Configurazione KubeAPIServer

Per far funzionare kubeAPIServer è necessario configurare OIDC e aggiornare il cluster:

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

Utilizziamo kops per il deployment dei cluster, ma questo funziona analogamente anche per altri gestori di cluster.

Configurazione di Dex e dex-k8s-authenticator

Per far funzionare Dex è necessario avere un certificato e una chiave dal master di Kubernetes, li estrarremo da lì:

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

Cloniamo il repository dex-k8s-authenticator:

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

Utilizzando i file values possiamo configurare in modo flessibile le variabili per i nostri chart HELM.

Descriviamo la configurazione per 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

E per 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

Installdiamo Dex e 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

Controlliamo il funzionamento dei servizi (Dex dovrebbe restituire codice 400, mentre dex-k8s-authenticator dovrebbe restituire codice 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

Configurazione RBAC

Creiamo un ClusterRole per il gruppo, nel nostro caso con accessi in sola lettura:

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

Creiamo la configurazione per 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

Ora siamo pronti per il test.

Test

Andiamo alla pagina di login (https://login.k8s.example.com) e autorizziamoci utilizzando il nostro account GitHub:

Autenticazione in Kubernetes utilizzando GitHub OAuth e Dex
Pagina di autorizzazione

Autenticazione in Kubernetes utilizzando GitHub OAuth e Dex
Pagina di autorizzazione reindirizzata a GitHub

Autenticazione in Kubernetes utilizzando GitHub OAuth e Dex
 Seguiamo le istruzioni generate per ottenere i permessi

Dopo aver copiato e incollato dal sito web, possiamo utilizzare kubectl per gestire le risorse del nostro cluster:

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"

E funziona, tutti gli utenti GitHub nella nostra organizzazione possono vedere le risorse e accedere ai pod, ma non hanno diritti per modificarle.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster