You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Keycloak自签名证书SSL验证失败问题排查与解决咨询

同一自签名证书在Flask验证正常,但Keycloak请求时SSL验证失败的问题及解决

场景说明

Keycloak容器配置(16.1.1版本)

keycloak-m1:
  container_name: keycloak
  image: codingpuss/keycloak-silicon:16.1.1
  restart: always
  environment:
    KEYCLOAK_USER: admin
    KEYCLOAK_PASSWORD: admin
    KEYCLOAK_EXTRA_ARGS="-Dkeycloak:profile:feature:upload_scripts=enabled":
    KC_HTTPS_CERTIFICATE_FILE: /opt/keycloak/localhostCert.pem
    KC_HTTPS_CERTIFICATE_KEY_FILE: /opt/keycloak/localhostKey.pem
  ports:
   - "8090:8080"
   - "8843:8443"
  networks:
    - myNetwork
  volumes:
    - ./keycloak-data:/tmp
    - ./certs-folder/local:/opt/keycloak

自签名证书生成命令

openssl req -x509 -out localhostCert.pem -keyout localhostKey.pem \
 -newkey rsa:2048 -nodes -sha256 \
 -subj '/CN=localhost' -extensions EXT -config <( \
  printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")

请求Keycloak时的错误信息

requests.exceptions.SSLError: HTTPSConnectionPool(host='localhost', port=8843): Max retries exceeded with url: /auth/realms/test/protocol/openid-connect/token (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1002)')))

Python请求Keycloak的代码

if __name__ == '__main__':
    data = {
        constants.GRANT_TYPE_KEY: constants.OAUTH_PASSWORD_FLOW,
        constants.USERNAME_KEY: "test",
        constants.PASSWORD_KEY: "test",
        constants.CLIENT_ID_KEY: "test-client",
        constants.CLIENT_SECRET_KEY: "QX1hsAGiQADuegPcAXOn4mlwZUfcoksH"
    }
    session = Session()
    oauth_request = Request()
    oauth_request.method = "POST"
    oauth_request.url = "https://localhost:8843/auth/realms/test/protocol/openid-connect/token"
    oauth_request.data = data
    session.verify = "<path_to_the_certs_directory>"
    response = session.send(oauth_request.prepare())
    access_token = response.json().get(constants.ACCESS_TOKEN_KEY, None)
    print(access_token)

对比:Flask使用同一证书的代码(验证正常)

from flask import Flask, request, jsonify
import ssl
app = Flask(__name__)

context = ssl.SSLContext()
context.load_cert_chain('localhostCert.pem', 'localhostKey.pem')
@app.route('/test/', methods=['GET'])
def get_test():
    return jsonify(test="test")


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5001, debug=True, ssl_context=context)

问题

为何同一证书在Flask中可正常验证,在Keycloak中却失败?如何解决该问题?

解决方案

原因分析

  1. Keycloak证书加载逻辑差异:Keycloak基于WildFly运行,对证书的存放格式、权限要求更严格,且可能未正确读取挂载的证书文件;而Flask直接加载证书文件,不存在额外的信任链配置要求。
  2. requests验证细节问题:当session.verify指向目录时,依赖c_rehash生成的哈希符号链接匹配证书,若Keycloak返回的证书链与本地存储的证书不匹配,就会验证失败。

解决步骤

1. 检查并修复容器内证书权限

进入Keycloak容器查看证书权限:

docker exec -it keycloak ls -l /opt/keycloak/localhostCert.pem /opt/keycloak/localhostKey.pem

确保文件拥有者为jboss(Keycloak默认运行用户),否则修改权限:

docker exec -it keycloak chown jboss:jboss /opt/keycloak/localhostCert.pem /opt/keycloak/localhostKey.pem

修改后重启容器:

docker restart keycloak

2. 直接指定证书文件而非目录

修改Python请求代码,将session.verify指向证书文件路径,避免目录哈希匹配问题:

session.verify = "<path_to_localhostCert.pem>"

3. 修正Keycloak的HTTPS环境变量

Keycloak 16.x版本可能不支持KC_HTTPS_*格式的环境变量,改用旧版变量配置:

KEYCLOAK_HTTPS_CERTIFICATE_FILE: /opt/keycloak/localhostCert.pem
KEYCLOAK_HTTPS_CERTIFICATE_KEY_FILE: /opt/keycloak/localhostKey.pem

更新配置后重启容器。

4. 将证书导入Keycloak的Java信任存储(可选)

若上述方法无效,将自签名证书添加到Java信任存储(Keycloak依赖Java运行):

# 进入容器
docker exec -it keycloak bash
# 导入证书,默认信任存储密码为changeit
keytool -importcert -file /opt/keycloak/localhostCert.pem -alias localhost -keystore /opt/keycloak/jre/lib/security/cacerts -storepass changeit -noprompt

完成后重启容器。


内容的提问来源于stack exchange,提问作者Abdel Ysf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 07:15:10