Keycloak

若要使用`Keycloak<https://www.keycloak.org/>`__ 配合 NetHSM,既能在 NetHSM 中安全地存储私钥,又能让 Keycloak 签署访问令牌并解密 JWE,您需要按照以下步骤安装并配置`此密钥提供程序<https://github.com/Nitrokey/nethsm-keycloak>`__:

AI 披露

该服务提供商是在人工智能的大力协助下开发和审核的。

Prepare the NetHSM

请按以下步骤准备 NetHSM。有关详细说明,请参阅`管理部分<../administration.html>`__。

  • 如果 NetHSM 使用的是自签名证书,请记录其指纹:

    echo | openssl s_client -connect $NETHSM_HOST 2>/dev/null \
      | openssl x509 -fingerprint -sha256 -noout
    
  • `创建一个专门用于 Keycloak 的“操作员”用户<../administration.html#user-management>`__。

  • Keycloak 扩展*会发现* 中的密钥,但不会创建这些密钥。`请手动创建所需的密钥<../operation.html#key-management>`__:

    • 密钥 ID 必须以该领域将声明的前缀开头。请选择合适的命名方案,例如``kc-<realm>-<purpose>-<year>``(例如``kc-staff-sig-rs256-2026``、kc-partners-sig-es256-2026、kc-customers-enc-oaep-2026)。该 ID 将作为``kid`` 由 Keycloak 发布。未来的密钥轮换是通过添加新 ID 来实现的,因此我们建议将年份作为密钥 ID 的一部分。

    • 机制 决定了该密钥可用于哪些 JOSE 算法:

      NetHSM key type and mechanism

      JOSE algorithms served

      RSA + RSA_Signature_PKCS1

      RS256、RS384、RS512——不依赖哈希算法,因此一个密钥即可覆盖这三种算法

      RSA +``RSA_Signature_PSS_SHA256`` /_SHA384 /_SHA512

      PS256 / PS384 / PS512 —— 这些名称仅指算法

      EC_P256 /EC_P384 /EC_P521 +``ECDSA_Signature``

      ES256 / ES384 / ES512 — 曲线决定了算法

      Curve25519 + EdDSA_Signature

      EdDSA

      RSA +``RSA_Decryption_OAEP_SHA1`` /_SHA256

      RSA-OAEP / RSA-OAEP-256,用于解密传入的 JWE

安装

下载 Keycloak NetHSM 提供程序`的 JAR 文件<https://github.com/Nitrokey/nethsm-keycloak/releases>`__,将其保存到 Keycloak 的提供程序文件夹中,例如``/opt/keycloak/providers/``

重建提供商注册表:/opt/keycloak/bin/kc.sh build

配置

设置既可以通过``conf/keycloak.conf`` 指定,也可以通过环境变量指定。这两种形式表示相同的设置;环境变量具有优先级,因此非机密值可以保存在文件中,仅在运行时注入密码短语。

使用``conf/keycloak.conf``

spi-keys--nethsm--url=https://nethsm.internal:8443/api/v1
spi-keys--nethsm--username=keycloak
spi-keys--nethsm--passphrase=<passphrase>
spi-keys--nethsm--tls-fingerprints=aabbcc...

Using environment variables

在容器部署中更推荐这种方式,因为密码短语可以从 Docker 或 Kubernetes 密钥中获取,而无需写入文件。

KC_SPI_KEYS__NETHSM__URL=https://nethsm.internal:8443/api/v1
KC_SPI_KEYS__NETHSM__USERNAME=keycloak
KC_SPI_KEYS__NETHSM__PASSPHRASE="<passphrase>"
KC_SPI_KEYS__NETHSM__TLS_FINGERPRINTS=aabbcc...

备注

环境变量名称是根据配置键机械生成的:在键名前添加`KC_` ,转换为大写,并将所有`-` 替换为`_` 。双下划线源自键的结构`spi-<spi-name>--<provider-id>--<option>` ,其中对于此扩展而言,SPI为`keys` ,提供者为`nethsm` ,以及选项名称。

See also all available configuration options.

Restart Keycloak

连接配置文件仅在提供商工厂初始化时被读取。请重启 Keycloak。

Confirm the server configuration

在配置任何领域之前,请检查启动日志。这样可以区分连接或凭据问题与领域配置问题。

成功时:

NetHSM key provider ready: 1 instance(s), user 'keycloak',
discovery cache PT5M, on-unavailable fail

Otherwise:

Log message

Cause

没有提示信息,或者出现一条调试信息,指出提供程序处于非活动状态

url is not set

NetHSM is not reachable or not Operational at startup

地址错误、被防火墙阻止、证书 PIN 不匹配,或者 NetHSM 处于锁定状态或未配置状态

NetHSM rejected the configured credential with HTTP 401

Wrong username or passphrase

将提供商添加到领域中

在管理控制台中,进入*领域设置 → 密钥 → 提供商* ,选择**添加提供商** ,并选择``nethsm``。

Field

含义

Key use

sig 用于签名令牌,enc 用于解密传入的 JWE

Key ID prefix

ID 以该字符串开头的每个 NetHSM 密钥均由该领域发布

Algorithm

发布这些密钥所依据的算法

Priority

参见`将优先级设置为大于 100`_

Enabled / Active

若要使密钥生效,这两项都必须开启

一个组件发布一种算法,这与 Keycloak 的内置密钥提供程序相类似。因此,需要同时支持 RS256 和 ES256 的领域将包含两个组件。对于前缀下无法支持所选算法的密钥,系统会将其跳过,因此一个前缀可以安全地匹配一组混合的密钥。

小心

请勿将两个组件使用不同的算法指向同一个密钥。否则,两者都会在相同的``kid`` 下发布一个 JWKS 条目。

将优先级设置为大于 100

重要

一个新创建的域包含四个生成的密钥提供者——rsa-generated、rsa-enc-generated、hmac-generated 以及``aes-generated``——它们的优先级均为**100** 。NetHSM 组件的优先级必须更高,否则 Keycloak 将继续使用生成的软件密钥进行签名,且配置看似正常。

NetHSM 的默认值为``200``,这是一个合理的设置。

为该领域选择算法

将*中的“领域设置”→“令牌”→“默认签名算法”* 设置为组件上配置的算法。如果领域请求的算法是组件未发布的,Keycloak 将回退到使用生成的密钥,且不会报告错误。

验证

List the published keys:

curl -s https://<keycloak-host>/realms/<realm>/protocol/openid-connect/certs

kid 的值应为 NetHSM 密钥 ID。

最终的验证依据是生成的令牌。请求一个令牌并解析其头部信息:

curl -s \
  -d "client_id=<client>" \
  -d "client_secret=<secret>" \
  -d "grant_type=client_credentials" \
  https://$NETHSM_HOST/realms/<realm>/protocol/openid-connect/token \
| python3 -c 'import sys, json, base64
header = json.load(sys.stdin)["access_token"].split(".")[0]
print(json.loads(base64.urlsafe_b64decode(header + "==")))'

如果``kid`` 是 NetHSM 的密钥 ID,则该签名是在 HSM 内部生成的。您还可以同时查看 NetHSM 的日志,其中应会显示相应的调用记录。

NetHSM 无法使用时的应对方案

如果无法连接到 NetHSM 且未缓存任何密钥元数据,则该域中将没有可用的密钥,令牌签发将失败,而非回退到使用生成的软件密钥。

警告

如果某个域的默认签名算法由 NetHSM 密钥提供,而 NetHSM 无法访问,则也无法为该域签发管理令牌。此时,无法使用管理 API 来解决该问题。

恢复操作需通过服务器配置而非管理控制台进行:将`` 设置为 spi-keys--nethsm--on-unavailable=degrade` 并重启,或者禁用该组件。

因此,请先配置一个测试域,并将``master`` 域保留为 Keycloak 自身生成的密钥,以确保管理控制台仍可访问。

Further Details

You find further details here.