Авторизация для приложения в облаке

от автора

Начал писать свой пэт проект и дошел до момента, когда мне понадобилось авторизовывать пользователя в своем приложении. До этого был опыт использования спринга с кейклок, но поскольку сейчас развернул приложение в облаке, решил узнать, как принято использовать кейклок в облаке. Может можно использовать кейклок как авторизационную прокси?

Для начала, у меня были приложение развернутое в кубере и ingress сервис. Для начала решил использовать kubectl, а не helm, чтобы разобраться что-за что отвечает, а после по надобности перейти на helm. Собственно этой командой у меня был настроен ингрес.

kubectl --namespace default apply -f - <<< ' apiVersion: networking.k8s.io/v1 kind: Ingress metadata:   name: ingress spec:   rules:     - host: somehost.ru       http:         paths:           - path: /app             pathType: Prefix             backend:               service:                 name: app                 port:                   number: 80   ingressClassName: nginx '

Покопавшись немного в интернете нашел, что ингресс может делегировать авторизацию c помощью аннотаций, а сервис которому можно так делегировать называется oauth2-proxy.

oauth2-proxy

Сам по себе oauth2-proxy не умеет авторизовывать пользователей. Он по сути является адаптером между ingress и сервисами которые можно использовать для авторизации. В документации у них есть инструкции как использовать для авторизации гугл, гитхаб, гитлаб… Для начала решил не настраивать сервис кеклока, а поэкспериментировать с чем-то готовым, например авторизовывать через гитхаб.

По сути, действуя по инструкции настроил oauth2-proxy, добавил только две настройки:
1) —set-xauthrequest — добавляет в запрос хэдеры X-Auth-Request-User, X-Auth-Request-Groups, X-Auth-Request-Email и X-Auth-Request-Preferred-Username.
2) —set-authorization-header — добавляет хедер Authorization: Bearer…

kubectl --namespace default apply -f - <<< ' apiVersion: apps/v1 kind: Deployment metadata:   labels:     app: oauth2-proxy   name: oauth2-proxy spec:   replicas: 1   selector:     matchLabels:       app: oauth2-proxy   template:     metadata:       labels:         app: oauth2-proxy     spec:       containers:         - name: oauth2-proxy           image: quay.io/oauth2-proxy/oauth2-proxy:latest           imagePullPolicy: Always           ports:             - containerPort: 4180               protocol: TCP           args:             - --provider=github             - --email-domain=*             - --upstream=file:///dev/null             - --http-address=0.0.0.0:4180             - --scope=user:email             - --set-xauthrequest=true             - --set-authorization-header=true           env:             - name: OAUTH2_PROXY_CLIENT_ID               value: acb0636a63a40efab6d             - name: OAUTH2_PROXY_CLIENT_SECRET               value: 4076962096c9b3d1774e9cb6850b67eef23ad88e             - name: OAUTH2_PROXY_COOKIE_SECRET               value: 6Pf1nzU4nV2syd8e0JAkmw== --- apiVersion: v1 kind: Service metadata:   labels:     app: oauth2-proxy   name: oauth2-proxy spec:   ports:     - name: http       port: 4180       protocol: TCP       targetPort: 4180   selector:     app: oauth2-proxy --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata:   name: ingress-oauth2-proxy   annotations:     nginx.ingress.kubernetes.io/proxy-buffer-size: "8k"     nginx.ingress.kubernetes.io/proxy-buffers-number: "4" spec:   rules:     - host: somehost.ru       http:         paths:           - path: /oauth2             pathType: Prefix             backend:               service:                 name: oauth2-proxy                 port:                   number: 4180   ingressClassName: nginx '

Дальше надо проставить переменные окружения (в целом можно так же в аргументах передать):
OAUTH2_PROXY_CLIENT_ID — берется и приложения в git-hub
OAUTH2_PROXY_CLIENT_SECRET — так же берется из приложения, но показывается только один раз, после нужно создавать новый
OAUTH2_PROXY_COOKIE_SECRET — можно сгенерировать так python ‑c 'import os,base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())'

Настройки приложения в гитхаб

Настройки приложения в гитхаб

Остается только добавить аннотации в ingress сервис и авторизация заработает.

1) nginx.ingress.kubernetes.io/auth-url — судя по инструкция в интернетах обычно можно указать через https://$host… но у меня не получалось ни в какую. Появлялась проблема ssl сертификата, возможно он не совсем правильно настроен был. Поэтому я этот url прописываю внутрекуберовский.
2 nginx.ingress.kubernetes.io/auth-signin: — этот url вернется пользователю, на неудачную авторизацию.
3) nginx.ingress.kubernetes.io/auth-response-headers: — здесь ингрес добавляет указанные хэдеры из ответа oauth2-proxy в запрос
4) nginx.ingress.kubernetes.io/proxy-buffer-size: — размер кэша, нужен, чтобы на каждый запрос не ходить за авторизацией.

kubectl --namespace default apply -f - <<< ' apiVersion: networking.k8s.io/v1 kind: Ingress metadata:   name: ingress   annotations:     nginx.ingress.kubernetes.io/auth-url: "http://oauth2-proxy.default.svc.cluster.local:4180/oauth2/auth"     nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"     nginx.ingress.kubernetes.io/auth-response-headers: "x-auth-request-user, x-auth-request-email, authorization"     nginx.ingress.kubernetes.io/proxy-buffer-size: "16k" spec:   rules:     - host: somehost.ru       http:         paths:           - path: /app             pathType: Prefix             backend:               service:                 name: app                 port:                   number: 80   ingressClassName: nginx '

Заходим теперь в https://somehost.ru/app и нас перенаправляет на страничку авторизации в git-hub.

Keycloak

Так, теперь у меня есть какая-никакая авторизация, но хочется ее самому контролировать. Пришло время перевести oauth2-proxy на кейклок. И сначала я чуть-чуть ошибся. Очень много инструкций в интернете рассказывают, как настраивать кейклок до 16й версии. Я его настроил, посмотрел как подключить русских провайдеров типа вк яндекс итд и понял, что нужно настроить 19ю версию. В общем обратите на это внимание, 19 версия лучше, легче быстрее и всякое такое. По крайней мере в документации так написано.

Собственно настройка кейклок у меня выглядит так:

kubectl --namespace default apply -f - <<< ' apiVersion: v1 kind: Service metadata:   name: keycloak   labels:     app: keycloak spec:   type: LoadBalancer   ports:     - name: http       port: 80       targetPort: 8080   selector:     app: keycloak --- apiVersion: apps/v1 kind: Deployment metadata:   name: keycloak   namespace: default   labels:     app: keycloak spec:   replicas: 1   selector:     matchLabels:       app: keycloak   template:     metadata:       labels:         app: keycloak     spec:       containers:         - name: keycloak           image: playaru/keycloak-russian           args: [ "start" ]           env:             - name: KC_HOSTNAME_URL               value: "https://somehost.ru"             - name: KC_HOSTNAME_ADMIN_URL               value: "https://somehost.ru"             - name: KC_HOSTNAME_STRICT               value: "false"             - name: KC_HTTP_ENABLED               value: "true"             - name: KEYCLOAK_ADMIN               value: "keycloak"             - name: KEYCLOAK_ADMIN_PASSWORD               value: "keycloak"             - name: KC_PROXY               value: "edge"             - name: KC_HEALTH_ENABLED               value: "true"             - name: KC_DB               value: "postgres"             - name: KC_DB_URL               value: ""             - name: KC_DB_URL_DATABASE               value: "keycloak"             - name: KC_DB_USERNAME               value: ""             - name: KC_DB_PASSWORD               value: ""           ports:             - name: http               containerPort: 8080           readinessProbe:             httpGet:               path: /realms/master               port: 8080 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata:   name: nginx-test   namespace: default spec:   tls:     - hosts:         - somehost.ru       secretName: k8s-secret   ingressClassName: nginx   rules:     - host: somehost.ru       http:         paths:           - path: /admin             pathType: Prefix             backend:               service:                 name: keycloak                 port:                   number: 80           - path: /realms/             pathType: Prefix             backend:               service:                 name: keycloak                 port:                   number: 80           - path: /resources/             pathType: Prefix             backend:               service:                 name: keycloak                 port:                   number: 80           - path: /robots.txt             pathType: ImplementationSpecific             backend:               service:                 name: keycloak                 port:                   number: 80           - path: /js/             pathType: Prefix             backend:               service:                 name: keycloak                 port:                   number: 80   '

Если не указывать настройки базы данных, то кейклок создаст базу сам, а мне нужно было подключиться к своей. И image я взял playaru/keycloak-russian, чтобы у меня сразу были русские провайдеры и не мучиться с их подключением.

Помимо настроек сервиса надо прокинуть через ингрес путь в keycloak, поскольку теперь страничку авторизации будет возвращать он. Путь /admin лучше не пробрасывать, можно например добавить vpn чтобы подключаться к сервисам внутри кубера, но я так не научился еще.

Теперь нужно поменять настройки oauth2-proxy.

kubectl --namespace default apply -f - <<< ' apiVersion: apps/v1 kind: Deployment metadata:   labels:     app: oauth2-proxy   name: oauth2-proxy spec:   replicas: 1   selector:     matchLabels:       app: oauth2-proxy   template:     metadata:       labels:         app: oauth2-proxy     spec:       containers:         - name: oauth2-proxy           image: quay.io/oauth2-proxy/oauth2-proxy:latest           imagePullPolicy: Always           ports:             - containerPort: 4180               protocol: TCP           args:             - --provider=keycloak-oidc             - --upstream=file:///dev/null             - --http-address=0.0.0.0:4180             - --whitelist-domain=somehost.ru             - --cookie-domain=somehost.ru             - --set-xauthrequest=true             - --reverse-proxy=true             - --set-authorization-header=true             - --oidc-issuer-url=https://somehost.ru/realms/master             - --ssl-insecure-skip-verify=true             - --silence-ping-logging=true             - --email-domain=*           env:             - name: OAUTH2_PROXY_CLIENT_ID               value: ingress             - name: OAUTH2_PROXY_CLIENT_SECRET               value: <client-secret>             - name: OAUTH2_PROXY_COOKIE_SECRET               value: zTBum01F+fZmVntQutehXw== --- apiVersion: v1 kind: Service metadata:   labels:     app: oauth2-proxy   name: oauth2-proxy spec:   ports:     - name: http       port: 4180       protocol: TCP       targetPort: 4180   selector:     app: oauth2-proxy --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata:   name: ingress-oauth2-proxy   annotations:     nginx.ingress.kubernetes.io/proxy-buffer-size: "8k"     nginx.ingress.kubernetes.io/proxy-buffers-number: "4" spec:   rules:     - host: somehost.ru       http:         paths:           - path: /oauth2             pathType: Prefix             backend:               service:                 name: oauth2-proxy                 port:                   number: 4180   ingressClassName: nginx '

Здесь настройки такие добавились:
1) —oidc-issuer-url — url по которому кейклок вернет настройки для авторизации, регистрации и подобное.
2) —ssl-insecure-skip-verify — как раз здесь я выключаю проверку сертификата, потому что не получалось настроить удачный поход внутри кубера. С моим сертификатом явно что-то не так.
3) —silence-ping-logging — буквально «не пиши в логи пинг кубера»

Как настроить кейклок и где взять client-secret хорошо описано тут.

Теперь при входе на страницу https://somehost.ru/app нам откроется авторизация в кейклоке.

Выводы

В целом, получилось сделать то что хотелось, авторизация работает. Но нужно еще разобраться с сертификатом да и наверняка много с чем еще.

Ну и как всегда телега, хотя в прошлые разы подписываться на нее не было никакого смысла, но я стараюсь)


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