Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
devops:deploy_keycloak_using_helm [2020/02/27 07:00] – [keycloak_values.yaml] admin | devops:deploy_keycloak_using_helm [2020/06/10 18:59] (current) – [Ошибки при обновлении] admin | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Установка keycloak с помощью helm-чарта ====== | ||
+ | Клонируем репозиторий с чартом: | ||
+ | mkdir ~/keycloak && cd ~/keycloak | ||
+ | git clone https:// | ||
+ | echo '' | ||
+ | ===== Cоздание базы на сервере postgres ===== | ||
+ | < | ||
+ | postgres@postgres: | ||
+ | postgres=# create database keycloak; | ||
+ | CREATE DATABASE | ||
+ | postgres=# create user keycloak with encrypted password ' | ||
+ | CREATE ROLE | ||
+ | postgres=# grant all privileges on database keycloak to keycloak; | ||
+ | GRANT</ | ||
+ | |||
+ | ===== Создание неймспейса и секретов (паролей и сертов) ===== | ||
+ | Создаем неймспейс | ||
+ | kubectl create ns keycloak | ||
+ | Создаем секреты с дефолтным паролем админской учетки **keycloak** и паролем пользователя базы данных: | ||
+ | kubectl create secret generic keycloak-default-admin-password -n keycloak --from-literal=password=keycloak_console_password | ||
+ | kubectl create secret generic keycloak-db-password -n keycloak --from-literal=password=keycloak_db_password --from-literal=username=keycloak | ||
+ | |||
+ | Создаем секрет с **ssl**-сертификатом **web**-интерфейса: | ||
+ | < | ||
+ | openssl rsa -in sso.domain.local.key -out sso.domain.local.key.pem | ||
+ | openssl pkcs12 -in sso.domain.local.pfx -clcerts -nokeys -out sso.domain.local.cert.crt | ||
+ | kubectl create secret generic -n keycloak sso-domain-local --from-file=tls.crt=./ | ||
+ | |||
+ | Создаем **ConfigMap** с корпоративными корневыми сертификатами. Они должны быть в формате **pem** и оформлены стандартными разделителями - **-----BEGIN CERTIFICATE-----** и **-----END CERTIFICATE-----**. | ||
+ | kubectl -n keycloak create configmap ca-bundle --from-file=./ | ||
+ | |||
+ | ===== keycloak_values.yaml ===== | ||
+ | < | ||
+ | keycloak: | ||
+ | replicas: 1 | ||
+ | image: | ||
+ | tag: 8.0.2 | ||
+ | existingSecret: | ||
+ | |||
+ | extraVolumes: | ||
+ | - name: ca-bundle | ||
+ | configMap: | ||
+ | name: ca-bundle | ||
+ | extraVolumeMounts: | ||
+ | - name: ca-bundle | ||
+ | mountPath: / | ||
+ | |||
+ | extraEnv: | | ||
+ | - name: X509_CA_BUNDLE | ||
+ | value: "/ | ||
+ | - name: PROXY_ADDRESS_FORWARDING | ||
+ | value: " | ||
+ | - name: JAVA_OPTS | ||
+ | value: | | ||
+ | -server -Xms64m -Xmx512m -XX: | ||
+ | |||
+ | ingress: | ||
+ | enabled: true | ||
+ | path: / | ||
+ | annotations: | ||
+ | kubernetes.io/ | ||
+ | hosts: | ||
+ | - sso.domain.local | ||
+ | tls: | ||
+ | - hosts: | ||
+ | - sso.domain.local | ||
+ | secretName: sso-domain-local | ||
+ | |||
+ | persistence: | ||
+ | deployPostgres: | ||
+ | dbVendor: " | ||
+ | existingSecret: | ||
+ | dbName: keycloak | ||
+ | dbHost: 10.10.10.10 | ||
+ | dbPort: 5432 | ||
+ | |||
+ | test: | ||
+ | enabled: false | ||
+ | </ | ||
+ | |||
+ | * Созданный **ConfigMap** с корпоративными корневыми сертификатами монтируется в директорию | ||
+ | * Переменная **X509_CA_BUNDLE** указывает на путь к файлу с сертификатами и при старте контейнера используется скриптом **/ | ||
+ | * Переменная **PROXY_ADDRESS_FORWARDING** нужна для нормального проксирования заголовков **X-Forwarded-For**. Если ёе не задать, | ||
+ | * Переменная **JAVA_OPTS** переопределяется для того, чтобы добавить **-Dkeycloak.profile.feature.upload_scripts=enabled**. Это нужно для того, чтобы нормально работал импорт ранее забекапленных (экспортированных) реалмов. Без этого параметра, | ||
+ | |||
+ | ===== Ошибки при обновлении ===== | ||
+ | При обновлении с версии **8.0.2** до версии **9.0.3** в логах возникла ошибка: | ||
+ | < | ||
+ | 16: | ||
+ | Detail: Key (realm_id, parent_group, | ||
+ | 16: | ||
+ | |||
+ | Судя по всему - в базе две записи о группе **1_SrvDocs_DocumentationAIB_Owner**. \\ | ||
+ | Сначала - останавливаем **keycloak**. для этого редактируем **statefullSet** и ставим **replicas: 0** \\ | ||
+ | Идем на сервер **postgres**, | ||
+ | sudo su - postgres | ||
+ | и лечим. Для начала - восстановим базу из бекапа в исходное состояние: | ||
+ | dropdb keycloak | ||
+ | createdb keycloak | ||
+ | psql -d keycloak -f ./ | ||
+ | Дальше запускаем **psql** и смотрим список баз: | ||
+ | \l | ||
+ | Переключаемся на базу **keycloak**: | ||
+ | \c keycloak | ||
+ | Убеждаемся, | ||
+ | SELECT * FROM public.KEYCLOAK_GROUP WHERE name = ' | ||
+ | Непонятно, | ||
+ | DELETE FROM public.KEYCLOAK_GROUP WHERE name = ' | ||
+ | |||
+ | ====== Приложение для тестирования KeyCloak (python Flask) ====== | ||
+ | Протестировать **keycloak** и убедиться, | ||
+ | ===== flask_oidc ===== | ||
+ | https:// | ||
+ | https:// | ||
+ | \\ | ||
+ | Ставим то что нужно: | ||
+ | sudo pip3 --trusted-host pypi.org --trusted-host files.pythonhosted.org --proxy=http:// | ||
+ | Тестовое приложение на фреймворке **flask** - **app.py**. \\ | ||
+ | < | ||
+ | import json | ||
+ | import logging | ||
+ | |||
+ | from flask import Flask, g | ||
+ | from flask_oidc import OpenIDConnect | ||
+ | import requests | ||
+ | |||
+ | logging.basicConfig(level=logging.DEBUG) | ||
+ | |||
+ | app = Flask(__name__) | ||
+ | app.config.update({ | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }) | ||
+ | |||
+ | oidc = OpenIDConnect(app) | ||
+ | |||
+ | @app.route('/' | ||
+ | def hello_world(): | ||
+ | if oidc.user_loggedin: | ||
+ | return (' | ||
+ | '<a href="/ | ||
+ | oidc.user_getfield(' | ||
+ | else: | ||
+ | return ' | ||
+ | |||
+ | @app.route('/ | ||
+ | @oidc.require_login | ||
+ | def hello_me(): | ||
+ | """ | ||
+ | Uses the accompanied access_token to access a backend service. | ||
+ | """ | ||
+ | |||
+ | info = oidc.user_getinfo([' | ||
+ | |||
+ | username = info.get(' | ||
+ | email = info.get(' | ||
+ | user_id = info.get(' | ||
+ | groups = info.get(' | ||
+ | greeting = ' | ||
+ | """ | ||
+ | try: | ||
+ | from oauth2client.client import OAuth2Credentials | ||
+ | access_token = OAuth2Credentials.from_json(oidc.credentials_store[user_id]).access_token | ||
+ | print (' | ||
+ | headers = {' | ||
+ | # YOLO | ||
+ | # greeting = requests.get(' | ||
+ | except: | ||
+ | print (" | ||
+ | greeting = "Hello %s" % username | ||
+ | """ | ||
+ | return (""" | ||
+ | Your email is %s </br> | ||
+ | Your user_id is %s! </br> | ||
+ | Your Groups - %s </br> | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | (greeting, email, user_id, groups)) | ||
+ | |||
+ | @app.route('/ | ||
+ | @oidc.accept_token(require_token=True, | ||
+ | def hello_api(): | ||
+ | """ | ||
+ | |||
+ | return json.dumps({' | ||
+ | |||
+ | @app.route('/ | ||
+ | def logout(): | ||
+ | """ | ||
+ | |||
+ | oidc.logout() | ||
+ | return 'Hi, you have been logged out! <a href="/"> | ||
+ | |||
+ | if __name__ == ' | ||
+ | | ||
+ | # app.run() | ||
+ | </ | ||
+ | И конфигурационный файл для него - **client_secrets.json** | ||
+ | < | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ], | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | } | ||
+ | }</ | ||
+ | Запускаем так: | ||
+ | ./app.py | ||
+ | ===== JWTConnect-Python-OidcRP ===== | ||
+ | Вот еще один ваиант тестового приложения. Но его запуск я не осилил. | ||
+ | git clone https:// | ||
+ | cd ./ | ||
+ | cp ./ | ||
+ | ./ | ||
+ | sudo pip3 --trusted-host pypi.org --trusted-host files.pythonhosted.org --proxy=http:// |