Autenticar no Kubernetes usando GitHub OAuth e Dex

Apresento a vocês um tutorial para gerar acesso a um cluster Kubernetes usando Dex, dex-k8s-authenticator e GitHub.

Autenticar no Kubernetes usando GitHub OAuth e Dex
Meme local do bate-papo do Kubernetes em russo em Telegram

Introdução

Usamos Kubernetes para criar ambientes dinâmicos para a equipe de desenvolvimento e QA. Portanto, queremos dar a eles acesso ao cluster tanto para o painel quanto para o kubectl. Ao contrário do OpenShift, o Vanilla Kubernetes não possui autenticação nativa, portanto, usamos ferramentas de terceiros para isso.

Nesta configuração usamos:

  • autenticador dex-k8s  — aplicativo web para gerar configuração do kubectl
  • Dex — Provedor OpenID Connect
  • GitHub - simplesmente porque usamos GitHub em nossa empresa

Tentamos usar o Google OIDC, mas infelizmente não conseguimos fracassado para iniciá-los com grupos, então a integração com o GitHub nos serviu muito bem. Sem mapeamento de grupos, não será possível criar políticas RBAC baseadas em grupos.

Então, como funciona nosso processo de autorização do Kubernetes em uma representação visual:

Autenticar no Kubernetes usando GitHub OAuth e Dex
Processo de autorização

Um pouco mais de detalhes e ponto por ponto:

  1. O usuário faz login no dex-k8s-authenticator (login.k8s.example.com)
  2. dex-k8s-authenticator encaminha a solicitação para Dex (dex.k8s.example.com)
  3. Dex redireciona para a página de login do GitHub
  4. GitHub gera as informações de autorização necessárias e as retorna ao Dex
  5. Dex passa as informações recebidas para dex-k8s-authenticator
  6. O usuário recebe um token OIDC do GitHub
  7. dex-k8s-authenticator adiciona token ao kubeconfig
  8. kubectl passa o token para KubeAPIServer
  9. KubeAPIServer retorna acessos ao kubectl com base no token passado
  10. O usuário obtém acesso do kubectl

Ações preparatórias

Claro, já temos um cluster Kubernetes instalado (k8s.example.com) e também vem com o HELM pré-instalado. Também temos uma organização no GitHub (super-org).
Se você não possui o HELM, instale-o muito simples.

Primeiro precisamos configurar o GitHub.

Vá para a página de configurações da organização, (https://github.com/organizations/super-org/settings/applications) e crie um novo aplicativo (aplicativo OAuth autorizado):
Autenticar no Kubernetes usando GitHub OAuth e Dex
Criando um novo aplicativo no GitHub

Preencha os campos com as URLs necessárias, por exemplo:

  • URL da Página incial: https://dex.k8s.example.com
  • URL de retorno de chamada de autorização: https://dex.k8s.example.com/callback

Cuidado com os links, é importante não perder as barras.

Em resposta a um formulário preenchido, o GitHub irá gerar Client ID и Client secret, guarde-os em um local seguro, eles serão úteis para nós (por exemplo, usamos Cofre para armazenar segredos):

Client ID: 1ab2c3d4e5f6g7h8
Client secret: 98z76y54x32w1

Prepare registros DNS para subdomínios login.k8s.example.com и dex.k8s.example.com, bem como certificados SSL para entrada.

Vamos criar 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 com título le-clusterissuer já deveria existir, mas se não, crie-o 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

Configuração do KubeAPIServer

Para que o kubeAPIServer funcione, você precisa configurar o OIDC e atualizar o 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

Nós usamos chute para implantar clusters, mas isso funciona de forma semelhante para outros gerenciadores de cluster.

Configuração Dex e dex-k8s-authenticator

Para que o Dex funcione, você precisa ter um certificado e uma chave do mestre do Kubernetes, vamos lá:

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

Vamos clonar o repositório dex-k8s-authenticator:

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

Usando arquivos de valores, podemos configurar variáveis ​​de maneira flexível para nossos Gráficos HELM.

Vamos descrever a configuração do 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

E para o autenticador dex-k8s:

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

Vamos verificar a funcionalidade dos serviços (Dex deve retornar o código 400 e dex-k8s-authenticator deve retornar o 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

Configuração RBAC

Criamos um ClusterRole para o grupo, no nosso caso com acesso somente leitura:

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

Vamos criar uma configuração 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

Agora estamos prontos para testes.

Testes

Vá para a página de login (https://login.k8s.example.com) e faça login usando sua conta GitHub:

Autenticar no Kubernetes usando GitHub OAuth e Dex
Página de login

Autenticar no Kubernetes usando GitHub OAuth e Dex
Página de login redirecionada para GitHub

Autenticar no Kubernetes usando GitHub OAuth e Dex
 Siga as instruções geradas para obter acesso

Depois de copiar e colar da página da web, podemos usar kubectl para gerenciar nossos recursos de 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 "[email protected]" cannot delete pods in the namespace "default"

E funciona, todos os usuários do GitHub em nossa organização podem ver os recursos e fazer login nos pods, mas não têm direitos para alterá-los.

Fonte: habr.com

Adicionar um comentário