Мне нужно сконфигурировать keycloak (версии 7.0.1), развернутый с помощью helm в кластере kubernetes, чтобы он забирал пользователей из Active Directory по протоколу LDAPS.
Проверка подключения к контроллеру домена (Test Connection) по протоколу ldaps (порт 636) проходит нормально, но тест аутентификации (Test Authentication) не проходит с ошибкой:
14:19:35,523 ERROR [org.keycloak.services] (default task-1) KC-SERVICES0055: Error when authenticating to LDAP: simple bind failed: dc.domain.local:636: javax.naming.CommunicationException: simple bind failed: dc.domain.local:636 [Root exception is javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target]
Проблема в том, что сертификат контроллера домена выдан корпоративным certification authority.
Мануалы, которые я нашел в интернете предлагают пересобрать docker image, поместив туда корневой сертификат. Но мне такой вариант не нравится. Я бы хотел, чтобы при старте pod'а keycloak импортировал корневой сертификат в keystore (jks) и использовател его.
Создаем ConfigMap с корпоративными корневыми сертификатами. Они должны быть в формате pem и оформлены стандартными разделителями - —–BEGIN CERTIFICATE—– и —–END CERTIFICATE—–.
curl -k https://nexus.rdleas.ru/repository/files/Root_CA_Certs/RDleas-SRV-DC02-CA.cer -o ./ca.cer kubectl -n keycloak create configmap ca-bundle --from-file=./ca.cer
А keycloak_values.yaml приводим к такому виду:
keycloak: replicas: 1 image: tag: 8.0.2 existingSecret: "keycloak-default-admin-password" extraVolumes: | - name: ca-bundle configMap: name: ca-bundle extraVolumeMounts: | - name: ca-bundle mountPath: /custom_certs/ extraEnv: | - name: X509_CA_BUNDLE value: "/custom_certs/ca.cer" - name: PROXY_ADDRESS_FORWARDING value: "true" - name: JAVA_OPTS value: | -server -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true -Dkeycloak.profile.feature.upload_scripts=enabled ingress: enabled: true path: / annotations: kubernetes.io/ingress.class: nginx hosts: - sso.domain.local tls: - hosts: - sso.domain.local secretName: sso-domain-local persistence: deployPostgres: false dbVendor: "postgres" existingSecret: "keycloak-db-password" dbName: keycloak dbHost: 10.10.10.10 dbPort: 5432 test: enabled: false
Некоторые пояснения.
Созданный ConfigMap с корпоративными корневыми сертификатами монтируется в директорию /custom_certs/.
Переменная X509_CA_BUNDLE указывает на путь к файлу с сертификатами и при старте контейнера используется скриптом /opt/jboss/tools/x509.sh, который импортирует сертификаты из файла в keystore.
Для этого редактируем StatefulSet keycloak:
В раздел env добавляем такое:
spec: template: spec: containers: env: - name: JAVA_OPTS value: -server -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true -Djavax.net.ssl.trustStore=/opt/jboss/keycloak/standalone/configuration/keystores/truststore.jks -Djavax.net.ssl.trustStorePassword=changeit --add-exports=java.base/sun.nio.ch=ALL-UNNAMED --add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED --add-exports=jdk.unsupported/sun.reflect=ALL-UNNAMED
А command приводим к такому виду:
spec: template: spec: containers: ... command: - /bin/bash - -c args: - mkdir -p /opt/jboss/keycloak/standalone/configuration/keystores/ && curl -k https://http.server.local/domain_ca.cer -o /opt/jboss/keycloak/standalone/configuration/ca.cer && keytool -import -noprompt -keystore /opt/jboss/keycloak/standalone/configuration/keystores/truststore.jks -file /opt/jboss/keycloak/standalone/configuration/ca.cer -storepass changeit -alias domain-local-CA && /scripts/keycloak.sh
В результате - до старта сервера Keycloak корневой сертификат забирается с http-сервера и помещается в ssl.trustStore, параметры которого (путь и пароль) передаются в виде переменных среды Java.