Облегчаем боль от перехода с Openshift на ванильный kubernetes. Настройка openshift-console с поддержкой SSO

от автора

Мы в нашей организации, как и многие, переходим на отечественные продукты, коснулось это и среды контейнеризации. За годы эксплуатации мы нежно полюбили OKD (Openshift) и очень расстраивались в ванильном kubernetes, подмечая отсутствие ставших уже привычными вещей. Однако OKD состоит из свободно распространяемых компонентов, а значит что-то да можно переиспользовать, например, web-консоль. Ее то мы и решили перенести в насколько это возможной полноте функционала. Существующие гайды обычно покрывают лишь установку самой консоли, нам же хотелось использовать и SSO и дополнительные элементы консоли — каталог ссылок и объявления в заголовке.

Итак, нам потребуется:

  • Сертификаты для обслуживания web-console

  • OIDC провайдер. В нашем случае Keycloak

  • Кластер kubernetes

  • Образ openshift-console из quay.io

  • Репозитарий с CRD для web-консоли

  • cli от openshift (опционально, но команды cli придется адаптировать самостоятельно)

1. Настраиваем клиент в OIDC провайдере

Создаем клиент keycloak. Все изображения с примерами настройки спрячу под спойлер.

  1. client ID: kubernetes

  2. root url: <url консоли>

  3. valid redirect urls: /*

  4. Client authentication: on

  5. Сохраняем клиент

  6. Внутри клиента, во вкладке client scopes добавляем audience

    1. переходим в scope kubernetes-dedicated (либо <cliendID>-dedicated если ID другой)

    2. Жмем Configure a new mapper

    3. Выбираем тип: Audience

    4. прописываем имя и выбираем included client audience: kubernetes (cliendID)

    5. Add to ID token: on

    6. Остальные параметры оставляем по умолчанию, жмем save

  7. В глобальной вкладке client scopes (слева) добавляем Groups:

    1. name: groups

    2. Type: Default

    3. Переходим во вкладку Mappers, жмем Configure a new mapper

      1. выбираем Group Membership

      2. name: groups

      3. Token Claim Name: groups

      4. Full group path: off

    4. Сохраняем изменения

Скрытый текст

Важно: Это рабочий конфиг, однако после необходимо захарденить клиент согласно политикам безопасности в вашей организации.

Сохраняем конфиг, сохраняем себе Client ID и Client Secret (вкладка Credentials). Также нам потребуется Issuer, взять его можно из раздела realm settings -> OpenID Endpoint Configuration.

Пример настройки:
Настройка client

Настройка client
6. Настройка Audience

6. Настройка Audience
7. Настройка глобального Client scope

7. Настройка глобального Client scope

2. Настройка kubernetes

Для того, чтобы консоль могла выполнять действия от имени пользователя, необходимо чтобы кластер kuebrentes мог аутентифицировать запросы с использование вашего jwt-токена. Наш кластер разворачивался через kubeadm, для других инсталляций локации конфигов могут отличаться

  1. На ВМ с kubernetes apiserver необходимо добавить сертификат, который используется в keycloak по пути: /etc/kubernetes/pki/oidc-ca.crt

  2. Добавляем конфиг oidc в kubernetes apiserver:

/etc/kubernetes/manifests/kube-apiserver.yaml
... spec:   containers:   - command:     - kube-apiserver     ...     - --oidc-issuer-url=https://auth.keycloak.myinfra.zone/auth/realms/myrealm     - --oidc-client-id=kubernetes     - --oidc-username-claim=preferred_username     - --oidc-groups-claim=groups     - --oidc-ca-file=/etc/kubernetes/pki/oidc-ca.crt     - --oidc-username-prefix=- ...
  • oidc-issuer-url — урл из OpenID Endpoint Configuration

  • oidc-client-id — client id

  • oidc-username-claim — атрибут из jwt по которому определяется логин пользователя

  • oidc-groups-claim — claim, в котором содержится список групп

  • oidc-ca-file — путь до файла с сертификатом keycloak

  • oidc-username-prefix — префикс, который добавляется к логину пользователя внутри kubernetes (например, для rolebinding)

После перезапуска подов должны подтянуться новые настройки, проверить доступ можно сгенерировав access токен и обратившись с ним в kube-api

Скрытый текст
curl -k -L -X POST 'https://auth.keycloak.myinfra.zone/auth/realms/myrealm/protocol/openid-connect/token' \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id=kubernetes' \ --data-urlencode 'grant_type=password' \ --data-urlencode 'client_secret=<KUBERNETES_CLIENT_ID_TOKEN>' \ --data-urlencode 'scope=openid' \ --data-urlencode 'username=<KEYCLOAK_USER>' \ --data-urlencode 'password=<KEYCLOAK_USER_PASSWORD>'
oc login --token=ACCESS_TOKEN_HERE --server=https://apiserver_url:6443

3. Настройка openshift-console в кластере

Нам остается только грамотно настроить манифесты:

Скрытый текст

Вспомогательные манифесты, namespaces, serviceaccouns, clusterrolebindings:

--- kind: Namespace apiVersion: v1 metadata:   name: openshift-console --- kind: Namespace apiVersion: v1 metadata:   name: openshift-console-user-settings --- kind: ServiceAccount apiVersion: v1 metadata:   name: console   namespace: openshift-console --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata:   name: okd-console-role subjects:   - kind: ServiceAccount     name: console     namespace: openshift-console roleRef:   apiGroup: rbac.authorization.k8s.io   kind: ClusterRole   name: cluster-admin ---

Сертификаты для https консоли и ca для доверия к keycloak:

kind: Secret apiVersion: v1 metadata:   name: console-serving-cert   namespace: openshift-console data:   ca.crt: >-     ca_cert_base_64   tls.crt: >-     public_cert_base_64   tls.key: >-     private_cert_base_64 type: kubernetes.io/tls

Deployment:

Скрытый текст
--- kind: Deployment apiVersion: apps/v1 metadata:   name: console   namespace: openshift-console   labels:     app: console     component: ui spec:   replicas: 1   selector:     matchLabels:       app: console       component: ui   template:     metadata:       name: console       creationTimestamp: null       labels:         app: console         component: ui     spec:       nodeSelector:         node-role.kubernetes.io/control-plane: ''       restartPolicy: Always       serviceAccountName: console       schedulerName: default-scheduler       affinity:         podAntiAffinity:           requiredDuringSchedulingIgnoredDuringExecution:             - labelSelector:                 matchExpressions:                   - key: component                     operator: In                     values:                       - ui               topologyKey: kubernetes.io/hostname       terminationGracePeriodSeconds: 30       securityContext: {}       containers:         - name: console           image: quay.io/openshift/origin-console:4.12.0           command:             - /opt/bridge/bin/bridge             - '--public-dir=/opt/bridge/static'             - '--control-plane-topology-mode=HighlyAvailable'             - '--k8s-public-endpoint=https://kubernetes_apserver:6443'             - '--listen=http://[::]:8080'             - '--k8s-auth=oidc'             - '--k8s-mode=in-cluster'             - '--tls-cert-file=/var/serving-cert/tls.crt'             - '--tls-key-file=/var/serving-cert/tls.key'             - '--base-address=https://console.apps.myinfra.zone'             - '--user-auth=oidc'             - '--user-auth-oidc-ca-file=/var/serving-cert/ca.crt'             - '--user-auth-oidc-client-id=kubernetes' # the same as for kubernetes apiserver client             - '--user-auth-oidc-client-secret=oidc_client_from_keycloak'             - '--user-auth-logout-redirect=https://console.apps.myinfra.zone'             - >-               -user-auth-oidc-issuer-url=https://auth.keycloak.myinfra.zone/auth/realms/myrealm           resources: {}           volumeMounts:             - name: console-serving-cert               readOnly: true               mountPath: /var/serving-cert           terminationMessagePath: /dev/termination-log           terminationMessagePolicy: File           readinessProbe:             httpGet:               path: /health               port: 8080               scheme: HTTP             timeoutSeconds: 1             periodSeconds: 10             successThreshold: 1             failureThreshold: 3           livenessProbe:             httpGet:               path: /health               port: 8080               scheme: HTTP             initialDelaySeconds: 150             timeoutSeconds: 1             periodSeconds: 10             successThreshold: 1             failureThreshold: 3           ports:             - name: https               containerPort: 8443               protocol: TCP             - name: http               containerPort: 8080               protocol: TCP           imagePullPolicy: IfNotPresent       serviceAccount: console       volumes:         - name: console-serving-cert           secret:             secretName: console-serving-cert             defaultMode: 420       dnsPolicy: ClusterFirst   strategy:     type: RollingUpdate     rollingUpdate:       maxUnavailable: 1       maxSurge: 3   revisionHistoryLimit: 10   progressDeadlineSeconds: 600

Сервис и ingress:

--- kind: Service apiVersion: v1 metadata:   name: console   namespace: openshift-console spec:   ports:     - name: https       protocol: TCP       port: 443       targetPort: 8443     - name: http       protocol: TCP       port: 80       targetPort: 8080   internalTrafficPolicy: Cluster   type: ClusterIP   selector:     app: console     component: ui --- kind: Ingress apiVersion: networking.k8s.io/v1 metadata:   name: okd-console   namespace: openshift-console   annotations:     nginx.ingress.kubernetes.io/affinity: cookie     nginx.ingress.kubernetes.io/force-ssl-redirect: 'true'     nginx.ingress.kubernetes.io/ssl-passthrough: 'false' spec:   ingressClassName: nginx   tls:     - secretName: console-serving-cert   rules:     - host: console.apps.myinfra.zone       http:         paths:           - path: /             pathType: Prefix             backend:               service:                 name: console                 port:                   number: 80

В зависимости от ваших требований можно включить ssl-passthrough, не забыв при этом поменять listen port в приложении и поправить раздел rules у ingress, однако я столкнулся с проблемой, что при такой конфигурации не работает > 1 пода — трафик round-robin отправляется на поды и возможны потери сессии.

На этом этапе у вас должна запуститься веб-консоль, при входе должно произойти перенаправление в SSO. После входа запросы будут выполняться от аутентифицированного пользователя.

4. Включаем console links, ConsoleNotification, ConsoleCLIDownload

Все что нам надо, это взять из репозитария манифесты CRD и применить их в кластере:

Скрытый текст
oc apply -f https://raw.githubusercontent.com/openshift/api/refs/heads/release-4.12/console/v1/0000_10_consolelink.crd.yaml oc apply -f https://raw.githubusercontent.com/openshift/api/refs/heads/release-4.12/console/v1/0000_10_consoleclidownload.crd.yaml oc apply -f https://raw.githubusercontent.com/openshift/api/refs/heads/release-4.12/console/v1/0000_10_consolenotification.crd.yaml

При желании можно применить и другие CRD console<type> из репозитория. Консоль подхватит и их.

После чего можно создавать соответствующие объекты (API Explorer -> group: console.openshift.io) и наблюдать эффект:

Вот и все, вы запустили web-консоль OKD с авторизацией, оповещениями и настраиваемыми ссылками!


ссылка на оригинал статьи https://habr.com/ru/articles/850864/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *