Интеграция kubernetes и keycloak

5
(1)

Как известно в kubernetes нет нормального механизма для управления аутентификацией и авторизацией пользователей, как правило это все отдается на откуп отдельным системам и настраивают интеграцию с ними. Сегодня рассмотрим самый популярный вариант — это интеграция с keycloak. Цель будет следующая — keycloak развернем в k8s кластере, так как у меня нет AD сервера, то создадим пользователей там руками, заведем две группы admins и viewers, пользователи, добавленные в эти группы получат права в k8s либо как cluster-admin, либо как cluster-view. Это можно будет легко изменять, добавляя другие группы, меняя логику, например выдавая права на определенные нс и так далее. Но в качестве стартового базового примера, должно быть вполне достаточно и этого.

Установка keycloak

Добавляем репозиторий с чартом

Bash
helm repo add codecentric https://codecentric.github.io/helm-charts

Я заберу чарт локально, чтобы сразу настроить values под себя. Ищем добавленный чарт

Bash
helm search repo keycloak

Как видим доступно несколько версия. Я буду ставить обычный «legacy» keycloak, второй keycloakx больше предназначен для облачной архитектуры.

Забираем чарт локально:

Bash
helm pull codecentric/keycloak
tar xvf keycloak-18.4.4.tgz
rm -f keycloak-18.4.4.tgz

В values нужно добавить ингресс, сикрет с кредами для админки, а также добавить переменные
PROXY_ADDRESS_FORWARDING и KEYCLOAK_ENABLE_HTTPS, если этого не сделать, то при переходе на админ панель, будет циклическое перенаправление.

YAML
ingress:
  # If `true`, an Ingress is created
  enabled: true
  # The name of the Ingress Class associated with this ingress
  ingressClassName: nginx
  # The Service port targeted by the Ingress
  servicePort: http
  # Ingress annotations
  annotations:
    ## Resolve HTTP 502 error using ingress-nginx:
    ## See https://www.ibm.com/support/pages/502-error-ingress-keycloak-response
    nginx.ingress.kubernetes.io/proxy-buffer-size: 128k

  # Additional Ingress labels
  labels: {}
   # List of rules for the Ingress
  rules:
    -
      # Ingress host
      host: '{{ .Release.Name }}.dev.local'
      # Paths for the host
      paths:
        - path: /
          pathType: Prefix
# Example TLS configuration
  tls:
    - hosts:
        - '{{ .Release.Name }}.dev.local'
      secretName: "keycloak-tls"
      
extraEnv: |
  - name: PROXY_ADDRESS_FORWARDING
    value: "true"
  - name: KEYCLOAK_ENABLE_HTTPS
    value: "true"
    
secrets:
  adminsecret:
    type: Opaque
    annotations: {}
    labels: {}
    stringData: {}
    data:
      KEYCLOAK_USER: YWRtaW4=
      KEYCLOAK_PASSWORD: YWRtaW4=
      
extraEnvFrom: |
  - secretRef:
      name: keycloak-adminsecret

В base64 скрывается дефолтный admin/admin.

Для keycloak нужно завести свой сертификат, который будет подписан нашим самопальным CA. Это понадобится в будущем, для передачи этого сертификата в api-server, чтобы избежать ошибки x509.

Создание CA и сертификатов keycloak:

Bash
openssl req -x509 -nodes -days 365 -newkey rsa:2048   -keyout ca.key -out ca.crt   -subj "/CN=DevLocal"
openssl genrsa -out keycloak.key 2048
openssl req -new -key keycloak.key -out keycloak.csr   -subj "/CN=keycloak.dev.local"
openssl x509 -req -in keycloak.csr -CA ca.crt -CAkey ca.key -CAcreateserial   -out keycloak.crt -days 365   -extfile <(printf "subjectAltName=DNS:keycloak.dev.local")
kubectl create ns keycloak
kubectl create secret tls keycloak-tls --cert=keycloak.crt --key=keycloak.key -n keycloak

Устанавливаем helm релиз.

Bash
helm --kubeconfig ~/local_k8s.conf install keycloak -n keycloak -f values.yaml .


Создадим новый realm в UI.

Создадим две группы, admins и viewers.

Создадим пользователей в нужных группах. Я создам своего пользователя в группе admins и тестового в группе viewers.

И зададим пользователям пароль в их настройках.

Далее нужно настроить клиента.

После сохранения в расширенных настройках клиента:

Обязательно нужно выставить access type: confidential и прописать valid redirect url: http://localhost:8000/. Мы будем использовать плагин oidc-login для kubernetes, он поднимает веб-сервер на этом порту, соответственно после аутентификации в кейлок, он отдаст нам токен на этот адрес.

Также нам нужно добавить Client Scops — groups:

Затем в настройках клиента kubernetes указать этот скоп в Assigned Default Client Scopes.

И в Mappers, который идет следущим пунктом настроек создать маппер groups.

На этом с кейлок пока все. Переходим к настройкам api server.

На мастер ноде api server будет в виде static pod в директории /etc/kubernetes/manifest. По крайне мерее при развертывании куба с помощью kubeadm обычно это так, если не определен другой путь в вашей конфигурации kubelet. Я использую vagrant и чтобы не было заморочек с резолвингом моего DNS адреса из контейнера api server я добавлю опцию для использования кастомного DNS.

YAML
spec:
  dnsPolicy: "None"
  dnsConfig:
    nameservers:
      - 192.168.10.100
- --oidc-issuer-url=https://keycloak.dev.local/auth/realms/kubernetes
- --oidc-client-id=kubernetes
- --oidc-username-claim=preferred_username
- --oidc-groups-claim=groups
- --oidc-ca-file=/etc/kubernetes/pki/ca.keycloak.crt
- --oidc-username-prefix=-

Также в аргументы команды запуска api server добавляем нужные опции.

—oidc-issuer-url — адрес для аутентификации.

—oidc-client-id — клиент для kubernetes, который мы создавали выше в кейлок.

—oidc-username-claim — это указывает на то, какой именно claim из токена OIDC следует использовать в качестве имени пользователя. У нас это будет поле username, которое мы добавляли пользователю в кейлок.

—oidc-groups-claim — то, какой именно claim следует использовать при извлечении информации из токена о группах пользователя.

—oidc-ca-file — собственно путь до CA файла, который создавали ранее для keycloak.

—oidc-username-prefix — отключаем использование prefix в имени пользователя. По дефолту там будет прописан путь до кейклок, это нам не нужно.

Сохраняем файл, контейнер с api-server будет перезапущен kubelet автоматически.

Далее нужно установить oidc-login плагин для kubectl. Официальный github. Там есть инструкции по установке, которые я тут приводить не буду.

Теперь нужно сделать kubeconfig следующего вида:

YAML
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCVENDQWUyZ0F3SUJBZ0lJZGhnenJlTFg3Z0l3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TkRFd01UUXhNelU1TkRWYUZ3MHpOREV3TVRJeE5EQTBORFZhTUJVeApFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLCkFvSUJBUUN2RmZYR1JsL05aUVRBQ0JxV1R5MG91SHFLNUlVRUZvRkNKeVlCM2dvbkJFMGZzZG1hWXJMWUZWSlMKRHdETW52TUNvcWtmZXlURXZmNGRMaHNjUjN2UVpVNmI4eXAxUENiWUNMUm8xdk9lZm1ibFlsOTA5VE5LU1EzSgpwQzhSTEpFdFd5ckVCekFEcHRBZW13YlBJclBnRjRXZVNHYkRIT0xFS1l4ZXMrY2RBdFNENkd2VE41NG1vVXRxClAxSXpFV0U0T2ZDRUd6Rjh5c2xiMjh0cktDVkx4alp6UFE4L3hRa1RQN1hrb3IzaEF3dS85YWxqdmdPWlo4NEwKejlCTDRCZ0g3UXVaOVcvYzNPeDhVTzVFaHY2a0NvcEhDS1VEOXNDTmZYVDIxSWZRR1g2dTBuWVR4OGZGeVlYaQpXWUFhL0RFYkNqUzRJVml3MUJLYmhodGV4SUNwQWdNQkFBR2pXVEJYTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJRRGQ3TUppaGY1MlhkWDdrQkxxYWhqQ2hpZXREQVYKQmdOVkhSRUVEakFNZ2dwcmRXSmxjbTVsZEdWek1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQVNKeUdKZVJMQwpqVEswczdlWFgzanRTSEJmRzUvcU9Uc1Nia1Yzbm0zWjc5VUpoNjRqZGE4cUFBbHF3WFFkN1lPZDRGYWtENjFtCk9VVVZSUURUUFlEL3BGYVhkLzA1N1RsdnY4RjUwREdPYnZiaDF3V0kzQ0xkVzBuTHkwNnNURExsaW8xOTZ4eHoKd2NVL29FZGM2WjRqU2hneWNGQVM0S3pSNDJlb2FmcDZScW9CeWdRc3N6V3FXTHNvY1FzZkhGdjlSUWYzZVpWUAp6eTBKeDF0ZHZMOFVrdmpyaTl6d3pHb2JTTExLRlZMOHdkS1BkLy9HdFdPN3Z6a1JKSkplRjVMN0p3eHkwQXpXCkREZ0t4R1JaR0N4Z1g0VVZ1YnBuTlowbkl2N2NTeVBRWVI0c0ZzVWdCMm5QREZjMTZnSitxTG9FaTg2aElNTHIKeG9EV3NRWjd1aU8rCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
    server: https://192.168.10.10:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: oidc-user
  name: oidc@kubernetes
current-context: oidc@kubernetes
kind: Config
preferences: {}
users:
- name: oidc-user
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      args:
      - oidc-login
      - get-token
      - --oidc-issuer-url=https://keycloak.dev.local/auth/realms/kubernetes
      - --oidc-client-id=kubernetes
      - --oidc-client-secret=h1HIQWMRv2ZkTc1nHk6pviFWnTJ4txts
      - --oidc-extra-scope=profile
      - --oidc-extra-scope=groups
      - --authentication-timeout-sec=43200
      command: kubectl
      env: null
      interactiveMode: IfAvailable
      provideClusterInfo: false

—oidc-client-secret — это сикрет нашего клиента, который можно получить в настройках клиента на вкладке Credentials.

Пробуем запустить kubectl

YAML
kubectl --kubeconfig ~/keycloak_k8s.conf get pod

Нас автоматически перебросит на аутентификацию в keycloak и после ее прохождения мы получим ошибку о том, что у нас нет прав смотреть поды в ns default. Это хорошо, нас узнали, мы прошли аутентификацию, но не прошли авторизацию. Чтобы это сделать, создадим clusterrolebinding для группы admins.

YAML
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: keycloak-admins
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: Group
  name: /admins
  apiGroup: rbac.authorization.k8s.io

Группа начинается со слеша. Так она создалась в кейлок, хотя явно я это не указывал. Это можно узнать если по дебажить полученный токен.

YAML
cat ~/.kube/cache/oidc-login/5811f7149864a900a0fb23dd6f7b49a4a102d476bb017289855ed82f0f6049a1

Увидим что-то вроде:

id_token можно вставить например в jwt.io и посмотреть payload. Там должно быть имя группы.

Создаем clusterrolebinding:

YAML
kubectl apply -f rbac-admin-kl.yaml   

И проверяем заново любую команду с этим kubeconfig. Если что-то не работает, можно удалить кэш oidc-login или выбить пользователя из сессии в кейлоке.

Аналогично сделаем для viewes:

YAML
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: keycloak-viewers
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: view
subjects:
- kind: Group
  name: /viewers
  apiGroup: rbac.authorization.k8s.io

Внутри пользователя в Sessions можно закрыть сессию.

И очистим кэш oidc-login:

Bash
rm -rf ~/.kube/cache/oidc-login

Выполняем любую команду с тем же конфигом.

Видим что смотреть можем то, что разрешено кластерной роли view.

Таким образом можно базово настроить аутентификацию, авторизацию с помощью keycloak в kubernetes, адаптировать это под своей проект, CI/CD и так далее.

Насколько статья полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 5 / 5. Количество оценок: 1

Оценок пока нет. Поставьте оценку первым.

Оставить комментарий