Аутентификация с использованием сертификатов x.509 в Keycloak

Вопрос или проблема

Я пытаюсь настроить следующую архитектуру, но у меня возникают трудности:

  • Контейнер Keycloak с этим образом jboss/keycloak:7.0.0

  • Apache с mod_auth_openidc

  • У Apache есть защищенная директория

  • Apache выполняет аутентификацию клиента SSL

Я хочу настроить следующий сценарий:

  • Пользователь посещает mywebsite/demo

  • Apache предлагает ему аутентифицироваться с помощью его сертификата

  • Apache передает информацию в Keycloak

  • Keycloak использует X509/Validate Username для проверки сертификата (CN)

  • Возвращает ресурс пользователю после успешной аутентификации

У меня есть следующая конфигурация для vhost Apache :

Listen 8081 https
<VirtualHost *:8081>

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html/

        SSLEngine on
        SSLCipherSuite HIGH
        SSLProtocol all -SSLv3 -TLSv1.3


        SSLCertificateFile /etc/apache2/ssl/serv.crt
        SSLCertificateKeyFile /etc/apache2/ssl/serv.key
        SSLCACertificateFile /etc/apache2/ssl/ca.crt

        <Location /pdf >
                ProxyPass http://mywebsite:5001/pdf
                ProxyPassReverse http://mywebsite:5001/pdf
        </Location>
        #RequestHeader set CERT_CHAIN ""
        RequestHeader set  SSL_CLIENT_CERT ""


        OIDCCryptoPassphrase passphrase
        OIDCProviderMetadataURL https://mywebsite:9004/auth/realms/demorealm/.well-known/openid-configuration
        OIDCClientID demo2
        OIDCClientSecret e6dc781f-49c0-4cfa-9cde-411f9d8bc2cb
        OIDCSSLValidateServer Off
        OIDCRedirectURI https://mywebsite:9998/demo2/redirect
        OIDCRemoteUserClaim preferred_username
        OIDCInfoHook access_token id_token userinfo session


        <Location /demo2 >

                SSLVerifyClient require
                SSLVerifyDepth 2
                #RequestHeader set SSL_CLIENT_CERT_CHAIN_0 "%{{CERT_CHAIN}}s"
                RequestHeader set SSL_CLIENT_CERT "%{SSL_CLIENT_CERT}s"
                #Require ssl


                AuthType openid-connect
                Require valid-user
                Loglevel debug
        </Location>

</VirtualHost>

Для контейнера Keycloak я не уверен, учитывает ли контейнер мой standalone.xml, если я монтирую его вместо стандартного, поэтому я выполнил следующие команды jboss:

   /subsystem=keycloak-server/spi=x509cert-lookup:write-attribute(name=default-provider, value="apache")
   /subsystem=keycloak-server/spi=x509cert-lookup/provider=apache:write-attribute(name=properties.sslClientCert,value="SSL_CLIENT_CERT")
   /subsystem=keycloak-server/spi=x509cert-lookup/provider=apache:write-attribute(name=properties.sslCertChainPrefix,value="CERT_CHAIN")
   /subsystem=keycloak-server/spi=x509cert-lookup/provider=apache:write-attribute(name=properties.certificateChainLength,value="10")
   :reload

Мой Keycloak настроен следующим образом :
Перенаправление клиента :

перенаправление клиента

И поток аутентификации :

Исполнение

Конфигурация исполнителя аутентификации

Но когда я посещаю веб-сайт, я получаю эту ошибку как пользователь “Team XYZ” с сертификатом CN “Team XYZ” :
{"error_description":"X509 client certificate is missing.","error":"invalid_request"}

Логи Keycloak :

21:10:24,178 WARN  [org.keycloak.services.x509.AbstractClientCertificateFromHttpHeadersLookup] (default task-49) HTTP header "SSL_CLIENT_CERT" is empty

20:09:48,062 WARN  [org.keycloak.events] (default task-9) type=LOGIN_ERROR, realmId=5c005f6f-a912-4788-bf53-345551eb0e01, clientId=demo2, userId=null, ipAddress=Dummy, error=user_not_found, auth_method=openid-connect, auth_type=code, response_type=code, redirect_uri=https://mywebsite:9998/demo2/redirect, code_id=d2b3aecf-0a53-4d3a-85fd-3433aee61d61, response_mode=query, authSessionParentId=d2b3aecf-0a53-4d3a-85fd-3433aee61d61, authSessionTabId=FqOsf6BrEBk

Может кто-то помочь мне, я застрял с этим уже несколько дней.

В окружении Kubernetes следующее решение работает

      nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
      nginx.ingress.kubernetes.io/proxy-ssl-secret: "mynamespace/backend-x509-secret"
      nginx.ingress.kubernetes.io/proxy-ssl-verify: "on"
      nginx.ingress.kubernetes.io/proxy-ssl-verify-depth: "2"

      nginx.ingress.kubernetes.io/auth-tls-secret: "mynamespace/backend-x509-secret"
      nginx.ingress.kubernetes.io/auth-tls-verify-client: "optional"
      nginx.ingress.kubernetes.io/auth-tls-verify-depth: "2"
      nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "true"

где
mynamespace/backend-x509-secret генерируется из kustomization.yaml

secretGenerator:
- name: backend-x509-secret
  files:
  - tls.crt
  - tls.key
  - ca.crt

где tls.crt, tls.key, ca.crt – это мои собственные самоподписанные и CA сертификаты, используемые для авторизации X509 в Keycloak, в то время как мой nginx использует сертификат от Let’s Encrypt.
Затем конфигурационный файл Keycloak standalone.xml или standalone-ha.xml обновляется с помощью следующего командного файла во время запуска

/subsystem=keycloak-server/spi=x509cert-lookup:write-attribute(name=default-provider, value="nginx")            
/subsystem=keycloak-server/spi=x509cert-lookup/provider=default:remove
/subsystem=keycloak-server/spi=x509cert-lookup/provider=nginx:add(enabled=true,properties={sslClientCert => "ssl-client-cert", sslCertChainPrefix => "USELESS",     certificateChainLength => "2"})            

вы также можете динамически изменить конфигурацию Keycloak, используя

$JBOSS_HOME/bin/jboss-cli.sh --connect --command='/subsystem=keycloak-server/spi=x509cert-lookup:write-attribute(name=default-provider, value="nginx")'            
$JBOSS_HOME/bin/jboss-cli.sh --connect --command='/subsystem=keycloak-server/spi=x509cert-lookup/provider=default:remove'
$JBOSS_HOME/bin/jboss-cli.sh --connect --command='/subsystem=keycloak-server/spi=x509cert-lookup/provider=nginx:add(enabled=true,properties={ sslClientCert => "ssl-client-cert", sslCertChainPrefix => "USELESS", certificateChainLength => "2"})'           
$JBOSS_HOME/bin/jboss-cli.sh --connect --command=':reload'

Ответ или решение

Настройка аутентификации X.509 с использованием Keycloak, Apache и SSL

В данной статье мы рассмотрим решение для настройки аутентификации X.509 с использованием Keycloak в контейнере, Apache с модулем mod_auth_openidc для аутентификации и защищенной директории.

Архитектура

У вас уже есть следующая архитектура:

  • Keycloak (контейнер на образе jboss/keycloak:7.0.0)
  • Apache с модулем mod_auth_openidc
  • Защищенная директория на Apache
  • Аутентификация клиента по SSL

Шаги по настройке

1. Конфигурация Apache

Ваш текущий виртуальный хост на Apache содержит правильные настройки SSL и mod_auth_openidc. Однако необходимо обратить внимание на следующие параметры:

  1. SSL Client Certificate:
    Убедитесь, что Apache правильно показывает клиентские сертификаты, используя SSLVerifyClient. Ваша конфигурация выглядит нормально, однако убедитесь, что заголовок SSL_CLIENT_CERT правильно заполняется.

    В конфигурации, у вас есть такие строки:

    SSLVerifyClient require
    SSLVerifyDepth 2
    RequestHeader set SSL_CLIENT_CERT "%{SSL_CLIENT_CERT}s"

    Убедитесь, что клиентский сертификат действительно передается и заголовок устанавливается в правильное значение.

  2. Проверка конфигурации клиентского сертификата:
    Чтобы убедиться, что клиентский сертификат правильно передается, рассмотрите возможность включения логирования для отладки:

    LogLevel debug

    Теперь вы сможете проверить, какие заголовки передаются в Keycloak.

2. Настройка Keycloak для поддержки X.509

В Keycloak необходимо настроить провайдер для кодирования X.509 сертификатов. Вы выполнили необходимые команды через JBoss CLI:

/subsystem=keycloak-server/spi=x509cert-lookup:write-attribute(name=default-provider, value="apache")
/subsystem=keycloak-server/spi=x509cert-lookup/provider=apache:write-attribute(name=properties.sslClientCert,value="SSL_CLIENT_CERT")

Убедитесь, что Keycloak взаимодействует с Apache, и что он получит заголовок SSL_CLIENT_CERT из Apache. Также стоит проверить, правильно ли настроены параметры для обработки цепочки сертификатов:

/subsystem=keycloak-server/spi=x509cert-lookup/provider=apache:write-attribute(name=properties.sslCertChainPrefix,value="CERT_CHAIN")

3. Проблемы и их диагностика

Ошибка, с которой вы столкнулись:

{"error_description":"X509 client certificate is missing.","error":"invalid_request"}

показывает, что Keycloak не получает заголовок с клиентским сертификатом. Это может быть вызвано неправильной передачей заголовка из Apache в Keycloak.

  1. Проверка логов Apache:
    Проверьте логи Apache для подтверждения, что клиентский сертификат действительно заполнен и передается в заголовках.

  2. Тестирование с помощью cURL:
    Используйте cURL, чтобы протестировать, отправляет ли Apache заголовки, когда вы обращаетесь к защищенному ресурсу, например:

    curl -v --cacert ca.crt --cert client.crt --key client.key https://mywebsite:8081/demo2

    Это поможет вам увидеть, какие заголовки отправляются.

  3. Тестирование с заголовками:
    Вы можете попробовать временно изменить конфигурацию Apache, чтобы передавать только SSL_CLIENT_CERT, без SSL_CLIENT_CERT_CHAIN, чтобы упростить проверку.

4. Альтернативные решения

Если по какой-то причине Apache не может передать клиентский сертификат или если вы ищете более устойчивое решение, можно рассмотреть использование Nginx с настройками, которые вы упомянули в вашей Kubernetes среде. Модуль Nginx также поддерживает аутентификацию по сертификатам и может облегчить процесс интеграции с Keycloak.

Заключение

Настройка аутентификации X.509 с использованием Keycloak и Apache требует внимательного подхода к настройкам SSL и правильному управлению заголовками. Следуя вышеописанным шагам, вы сможете успешно решить проблему с отсутствующим клиентским сертификатом. Убедитесь в том, что логирование активировано для диагностики, а также протестируйте разные конфигурации, чтобы найти идеальное решение для вашей архитектуры.

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

Капча загружается...