Autenticarse en Kubernetes usando GitHub OAuth y Dex

Les presento un tutorial para generar acceso a un clúster de Kubernetes usando Dex, dex-k8s-authenticator y GitHub.

Autenticarse en Kubernetes usando GitHub OAuth y Dex
Meme local del chat de Kubernetes en ruso en Telegram

introducción

Usamos Kubernetes para crear entornos dinámicos para el equipo de desarrollo y control de calidad. Por eso queremos darles acceso al clúster tanto para el panel como para kubectl. A diferencia de OpenShift, Vanilla Kubernetes no tiene autenticación nativa, por lo que utilizamos herramientas de terceros para ello.

En esta configuración utilizamos:

  • autenticador-dex-k8s  — aplicación web para generar configuración de kubectl
  • Dex — Proveedor de conexión OpenID
  • GitHub: simplemente porque usamos GitHub en nuestra empresa

Intentamos utilizar Google OIDC, pero desafortunadamente fallado iniciarlos con grupos, por lo que la integración con GitHub nos vino bastante bien. Sin el mapeo de grupos, no será posible crear políticas RBAC basadas en grupos.

Entonces, ¿cómo funciona nuestro proceso de autorización de Kubernetes en una representación visual?

Autenticarse en Kubernetes usando GitHub OAuth y Dex
Proceso de autorización

Un poco más de detalle y punto por punto:

  1. El usuario inicia sesión en dex-k8s-authenticator (login.k8s.example.com)
  2. dex-k8s-authenticator reenvía la solicitud a Dex (dex.k8s.example.com)
  3. Dex redirige a la página de inicio de sesión de GitHub
  4. GitHub genera la información de autorización necesaria y la devuelve a Dex
  5. Dex pasa la información recibida a dex-k8s-authenticator
  6. El usuario recibe un token OIDC de GitHub
  7. dex-k8s-authenticator agrega token a kubeconfig
  8. kubectl pasa el token a KubeAPIServer
  9. KubeAPIServer devuelve accesos a kubectl según el token pasado
  10. El usuario obtiene acceso desde kubectl.

Acciones preparatorias

Por supuesto, ya tenemos instalado un clúster de Kubernetes (k8s.example.com), y también viene con HELM preinstalado. También tenemos una organización en GitHub (super-org).
Si no tienes HELM, instálalo muy simple.

Primero necesitamos configurar GitHub.

Vaya a la página de configuración de la organización, (https://github.com/organizations/super-org/settings/applications) y cree una nueva aplicación (Aplicación OAuth autorizada):
Autenticarse en Kubernetes usando GitHub OAuth y Dex
Creando una nueva aplicación en GitHub

Complete los campos con las URL necesarias, por ejemplo:

  • URL de la Pagina Principal: https://dex.k8s.example.com
  • URL de devolución de llamada de autorización: https://dex.k8s.example.com/callback

Ojo con los enlaces, es importante no perder barras.

En respuesta a un formulario completado, GitHub generará Client ID и Client secret, guárdalos en un lugar seguro, nos serán útiles (por ejemplo, usamos Bóveda para guardar secretos):

Client ID: 1ab2c3d4e5f6g7h8
Client secret: 98z76y54x32w1

Preparar registros DNS para subdominios login.k8s.example.com и dex.k8s.example.com, así como certificados SSL para ingreso.

Creemos certificados 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 con título le-clusterissuer ya debería existir, pero si no, créelo 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: [email protected]
    privateKeySecretRef:
      name: le-clusterissuer
    http01: {}
EOF

Configuración del servidor KubeAPIServer

Para que kubeAPIServer funcione, debe configurar OIDC y actualizar el clúster:

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

Usamos policías para implementar clústeres, pero esto funciona de manera similar para otros administradores de clusters.

Configuración dex y autenticador dex-k8s

Para que Dex funcione, necesitas tener un certificado y una clave del maestro de Kubernetes, comencemos desde allí:

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

Clonemos el repositorio dex-k8s-authenticator:

git clone [email protected]:mintel/dex-k8s-authenticator.git
cd dex-k8s-authenticator/

Usando archivos de valores, podemos configurar variables de manera flexible para nuestro gráficos HELM.

Describamos la configuración de 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

Y para 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

Instale Dex y 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

Comprobemos la funcionalidad de los servicios (Dex debería devolver el código 400 y dex-k8s-authenticator debería devolver el código 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

configuración RBAC

Creamos un ClusterRole para el grupo, en nuestro caso con acceso de solo lectura:

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

Creemos una configuración para 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

Ahora estamos listos para las pruebas.

Pruebas

Vaya a la página de inicio de sesión (https://login.k8s.example.com) e inicie sesión con su cuenta de GitHub:

Autenticarse en Kubernetes usando GitHub OAuth y Dex
Página de inicio de sesión

Autenticarse en Kubernetes usando GitHub OAuth y Dex
Página de inicio de sesión redirigida a GitHub

Autenticarse en Kubernetes usando GitHub OAuth y Dex
 Siga las instrucciones generadas para obtener acceso.

Después de copiar y pegar desde la página web, podemos usar kubectl para administrar los recursos de nuestro clúster:

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"

Y funciona, todos los usuarios de GitHub de nuestra organización pueden ver los recursos e iniciar sesión en los pods, pero no tienen derechos para cambiarlos.

Fuente: habr.com

Añadir un comentario