FIPS 140-2 支持

如何配置 Keycloak 服务器以符合 FIPS 标准

联邦信息处理标准出版物 140-2 (FIPS 140-2) 是美国政府用于批准密码模块的计算机安全标准。Keycloak 支持在符合 FIPS 140-2 标准的模式下运行。在这种情况下,Keycloak 将仅使用 FIPS 批准的加密算法来执行其功能。

要以符合 FIPS 140-2 标准的方式运行,Keycloak 应在启用 FIPS 140-2 的系统上运行。此要求通常假定 RHEL 或 Fedora 在安装过程中启用了 FIPS。有关详细信息,请参见 RHEL 文档。当系统处于 FIPS 模式时,它会确保底层的 OpenJDK 也处于 FIPS 模式,并且将仅使用 启用 FIPS 的安全提供程序

要检查系统是否处于 FIPS 模式,您可以从命令行使用以下命令进行检查

fips-mode-setup --check

如果系统未处于 FIPS 模式,您可以使用以下命令启用它,但建议系统在安装时处于 FIPS 模式,而不是随后启用它

fips-mode-setup --enable

BouncyCastle 库

Keycloak 在内部使用 BouncyCastle 库来完成许多加密实用程序。请注意,随 Keycloak 提供的 BouncyCastle 库的默认版本不符合 FIPS 标准;但是,BouncyCastle 还提供其库的 FIPS 验证版本。由于许可限制,无法将 FIPS 验证的 BouncyCastle 库与 Keycloak 一起提供,并且 Keycloak 无法提供对其的官方支持。因此,要以符合 FIPS 标准的方式运行,您需要下载 BouncyCastle-FIPS 位并将其添加到 Keycloak 发行版中。当 Keycloak 在 fips 模式下执行时,它将使用 BCFIPS 位而不是默认的 BouncyCastle 位,从而实现 FIPS 兼容性。

BouncyCastle FIPS 位

可以从 BouncyCastle 官方页面 下载 BouncyCastle FIPS。然后,您可以将其添加到发行版目录 KEYCLOAK_HOME/providers 中。确保使用与 BouncyCastle Keycloak 依赖项兼容的适当版本。所需的受支持 BCFIPS 位是

  • bc-fips 版本 2.0.0。

  • bctls-fips 版本 2.0.19。

  • bcpkix-fips 版本 2.0.7。

  • bcutil-fips 版本 2.0.3。

生成密钥库

您可以创建 pkcs12bcfks 密钥库,用于 Keycloak 服务器 SSL。

PKCS12 密钥库

p12 (或 pkcs12) 密钥库 (和/或信任库) 在 BCFIPS 非批准模式下运行良好。

可以使用 RHEL 9 上的 OpenJDK 21 Java 以标准方式生成 PKCS12 密钥库。例如,以下命令可用于生成密钥库

keytool -genkeypair -sigalg SHA512withRSA -keyalg RSA -storepass passwordpassword \
  -keystore $KEYCLOAK_HOME/conf/server.keystore \
  -alias localhost \
  -dname CN=localhost -keypass passwordpassword

在 FIPS 模式下,pkcs12 密钥库**无法**管理秘密 (对称) 密钥。此限制是由 BCFIPS 提供程序强加的,该提供程序不允许这种类型的密钥存在于 pkcs12 密钥库类型中。

当系统处于 FIPS 模式时,默认的 java.security 文件会更改以使用启用 FIPS 的安全提供程序,因此无需额外配置。此外,在 PKCS12 密钥库中,您可以通过简单地使用 keytool 命令来存储 PBE (基于密码的加密) 密钥,这使其成为与 Keycloak 密钥库保管库一起使用或在密钥库配置源中存储配置属性的理想选择。有关更多详细信息,请参见 配置 Keycloak使用保管库

BCFKS 密钥库

BCFKS 密钥库生成需要使用 BouncyCastle FIPS 库和自定义安全文件。

您可以从创建辅助文件开始,例如 /tmp/kc.keystore-create.java.security。该文件的内容只需要包含以下属性

securerandom.strongAlgorithms=PKCS11:SunPKCS11-NSS-FIPS

接下来,输入以下命令来生成密钥库

keytool -keystore $KEYCLOAK_HOME/conf/server.keystore \
  -storetype bcfks \
  -providername BCFIPS \
  -providerclass org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider \
  -provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider \
  -providerpath $KEYCLOAK_HOME/providers/bc-fips-*.jar \
  -alias localhost \
  -genkeypair -sigalg SHA512withRSA -keyalg RSA -storepass passwordpassword \
  -dname CN=localhost -keypass passwordpassword \
  -J-Djava.security.properties=/tmp/kc.keystore-create.java.security
使用自签名证书仅用于演示目的,因此在迁移到生产环境时,请将这些证书替换为适当的证书。

当您对 bcfks 类型的密钥库/信任库进行任何其他操作时,需要类似的选项。

运行服务器。

要使用 BCFIPS 在非批准模式下运行服务器,请输入以下命令
bin/kc.[sh|bat] start --features=fips --hostname=localhost --https-key-store-password=passwordpassword --log-level=INFO,org.keycloak.common.crypto:TRACE,org.keycloak.crypto:TRACE
在非批准模式下,默认密钥库类型 (以及默认信任库类型) 为 PKCS12。因此,如果您如上所述生成了 BCFKS 密钥库,则还需要使用命令 --https-key-store-type=bcfks。如果要使用信任库,则可能也需要对信任库执行类似的命令。
如果一切按预期工作,您可以在生产环境中禁用日志记录。

严格模式

存在 fips-mode 选项,当启用 fips 功能时,该选项会自动设置为 non-strict。这意味着以“非批准模式”运行 BCFIPS。更安全的替代方案是使用 --features=fips --fips-mode=strict,在这种情况下,BouncyCastle FIPS 将使用“批准模式”。使用该选项会导致对加密和安全算法有更严格的安全要求。

在严格模式下,默认密钥库类型 (以及默认信任库类型) 为 BCFKS。如果要使用其他密钥库类型,则需要使用 --https-key-store-type 选项,并指定相应的类型。如果要使用信任库,则可能也需要对信任库执行类似的命令。

启动服务器时,您可以检查启动日志中是否包含 KC 提供程序,以及关于 Approved Mode 的说明,例如以下内容

KC(BCFIPS version 2.0 Approved Mode, FIPS-JVM: enabled) version 1.0 - class org.keycloak.crypto.fips.KeycloakFipsSecurityProvider,

严格模式下的加密限制

  • 如上一节所述,严格模式可能无法与 pkcs12 密钥库一起使用。如前所述,需要使用其他密钥库 (例如 bcfks)。此外,在使用严格模式时,Keycloak 中不支持 jkspkcs12 密钥库。一些示例包括在管理控制台中导入或生成 OIDC 或 SAML 客户端的密钥库,或用于域密钥的 java-keystore 提供程序。

  • 用户密码必须至少为 14 个字符。Keycloak 默认使用基于 PBKDF2 的密码编码。BCFIPS 批准模式要求密码至少为 112 位 (实际上为 14 个字符),并使用 PBKDF2 算法。如果您想允许使用更短的密码,请将 max-padding-length 属性设置为 14,该属性属于 pbkdf2-sha512 提供程序 (属于 password-hashing SPI),以便在验证此算法创建的哈希时提供额外的填充。此设置还与以前存储的密码向后兼容。例如,如果用户数据库位于非 FIPS 环境中,并且您有更短的密码,并且您现在想使用 Keycloak 中的 BCFIPS 以批准模式对其进行验证,则密码应该可以正常工作。因此,您实际上可以使用以下选项在启动服务器时使用该选项

--spi-password-hashing-pbkdf2-sha512-max-padding-length=14
使用以上选项不会破坏 FIPS 兼容性。但是,请注意,更长的密码始终是最佳做法。例如,由现代浏览器自动生成的密码满足此要求,因为它们长于 14 个字符。如果您想省略 max-padding-length 选项,可以将密码策略设置为域,要求密码至少为 14 个字符长。
如果您从 24 版之前的 Keycloak 迁移,或者如果您显式设置密码策略以覆盖默认哈希算法,则您的某些用户可能会使用较旧的算法,例如 pbkdf2-sha256。在这种情况下,请考虑添加 --spi-password-hashing-pbkdf2-sha256-max-padding-length=14 选项,以确保使用旧的 pbkdf2-sha256 对其密码进行哈希的用户可以登录,因为他们的密码可能短于 14 个字符。
  • 1024 位的 RSA 密钥无法使用 (2048 位是最小值)。这适用于 Keycloak 域本身使用的密钥 (来自管理控制台“密钥”选项卡的域密钥),也适用于客户端密钥和 IDP 密钥

  • HMAC SHA-XXX 密钥必须至少为 112 位 (或 14 个字符长)。例如,如果您使用 OIDC 客户端,并且其客户端身份验证方法为 Signed Jwt with Client Secret (或 OIDC 表示法中的 client-secret-jwt),则您的客户端密钥必须至少为 14 个字符长。请注意,为了确保良好的安全性,建议使用 Keycloak 服务器生成的客户端密钥,因为这些密钥始终满足此要求。

  • bc-fips 版本 1.0.2.4 处理了 PKCS 1.5 RSA 加密的过渡期的结束。因此,默认情况下,严格模式不允许使用算法 RSA1_5 的 JSON Web 加密 (JWE) (BC 提供系统属性 -Dorg.bouncycastle.rsa.allow_pkcs15_enc=true 作为向后兼容选项,目前尚在使用中)。RSA-OAEPRSA-OAEP-256 仍然可用,与以前相同。

其他限制

要使 SAML 正常工作,请确保您的安全提供程序中包含 XMLDSig 安全提供程序。要使 Kerberos 正常工作,请确保您的安全提供程序中包含 SunJGSS 安全提供程序。在 OpenJDK 21 的 FIPS 启用的 RHEL 9 中,XMLDSig 安全提供程序可能已默认在 java.security 中启用,最新版本的 OpenJDK 17 也一样。但是,在较旧的 OpenJDK 17 中,它可能未默认启用,这意味着 SAML 实际上无法正常工作。

要使 SAML 正常工作,您可以手动将该提供程序添加到 JAVA_HOME/conf/security/java.security 中,添加到 fips 提供程序列表中。例如,如果您的 FIPS 安全提供程序中尚未包含以下行,则将其添加进去

fips.provider.7=XMLDSig

添加此安全提供程序应该可以正常工作。事实上,它符合 FIPS 标准,并且默认情况下已添加到 OpenJDK 21 和 OpenJDK 17 的更新版本中。有关详细信息,请参见 bugzilla

建议查看 JAVA_HOME/conf/security/java.security 并检查此处配置的所有提供程序,并确保数量匹配。换句话说,fips.provider.7 假设该文件中已配置了 6 个提供程序,并且这些提供程序的前缀为 fips.provider.N

如果您不想编辑 java 本身内部的 java.security 文件,则可以创建一个自定义 java 安全文件 (例如,命名为 kc.java.security),并将以上单个属性添加到该文件中,用于将 XMLDSig 提供程序添加到该文件中。然后,使用附加了此属性文件的属性启动 Keycloak 服务器

-Djava.security.properties=/location/to/your/file/kc.java.security

对于 Kerberos/SPNEGO,安全提供程序 SunJGSS 尚未完全符合 FIPS 标准。因此,如果您想符合 FIPS 标准,建议不要将其添加到安全提供程序列表中。当 Keycloak 在 FIPS 平台上执行且安全提供程序不可用时,KERBEROS 功能默认情况下会被禁用。有关详细信息,请参见 bugzilla

算法 EdDSA 无法在 FIPS 模式下使用。尽管当前的 BCFIPS 提供程序支持 Ed25519Ed448 曲线,但生成的密钥未实现标准 JDK 接口来管理它们 (EdECKeyEdECPublicKeyEdECPrivateKey 等),因此 Keycloak 无法将其用于签名。

在 FIPS 主机上运行 CLI

如果您想运行客户端注册 CLI ( `kcreg.sh|bat` 脚本) 或管理员 CLI ( `kcadm.sh|bat` 脚本),CLI 也必须使用 BouncyCastle FIPS 依赖项而不是普通 BouncyCastle 依赖项。为了实现这一点,您可以将 jar 文件复制到 CLI 库文件夹,这样就足够了。当 CLI 检测到相应的 BCFIPS jar 文件存在时,CLI 工具会自动使用 BCFIPS 依赖项而不是普通 BC(有关使用版本的详细信息,请参见上面)。例如,在运行 CLI 之前,请使用以下命令:

cp $KEYCLOAK_HOME/providers/bc-fips-*.jar $KEYCLOAK_HOME/bin/client/lib/
cp $KEYCLOAK_HOME/providers/bctls-fips-*.jar $KEYCLOAK_HOME/bin/client/lib/
cp $KEYCLOAK_HOME/providers/bcutil-fips-*.jar $KEYCLOAK_HOME/bin/client/lib/
当尝试使用 BCFKS 信任库/密钥库与 CLI 结合使用时,您可能会遇到问题,因为此信任库不是默认的 Java 密钥库类型。将其指定为 Java 安全属性中的默认值可能会有所帮助。例如,在基于 Unix 的系统上执行此命令,然后再执行任何与 kcadm|kcreg 客户端相关的操作:
echo "keystore.type=bcfks
fips.keystore.type=bcfks" > /tmp/kcadm.java.security
export KC_OPTS="-Djava.security.properties=/tmp/kcadm.java.security"

容器中的 Keycloak 服务器 FIPS 模式

当您希望在容器内执行 FIPS 模式的 Keycloak 时,您的“主机”也必须使用 FIPS 模式。然后,容器将从父主机“继承”FIPS 模式。有关详细信息,请参见 RHEL 文档中的 [本节](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/security_hardening/using-the-system-wide-cryptographic-policies_security-hardening#enabling-fips-mode-in-a-container_using-the-system-wide-cryptographic-policies)。

当从 FIPS 模式的主机执行时,Keycloak 容器映像将自动处于 FIPS 模式。但是,请确保 Keycloak 容器也使用 BCFIPS jar 文件(而不是 BC jar 文件)并在启动时使用正确的选项。

关于这一点,最好像 [在容器中运行 Keycloak](http://keycloak.java.net.cn/server/containers) 中所述的那样构建自己的容器映像,并对其进行调整以使用 BCFIPS 等。

例如,在当前目录中,您可以创建子目录 `files` 并添加以下内容:

  • 如上所述的 BC FIPS jar 文件

  • 自定义密钥库文件 - 例如名为 `keycloak-fips.keystore.bcfks`

  • 安全文件 `kc.java.security`,其中添加了 SAML 提供程序(对于 OpenJDK 21 或更新的 OpenJDK 17 不需要)

然后在当前目录中创建一个类似于此的 `Containerfile`:

Containerfile
FROM quay.io/keycloak/keycloak:latest as builder

ADD files /tmp/files/

WORKDIR /opt/keycloak
RUN cp /tmp/files/*.jar /opt/keycloak/providers/
RUN cp /tmp/files/keycloak-fips.keystore.* /opt/keycloak/conf/server.keystore
RUN cp /tmp/files/kc.java.security /opt/keycloak/conf/

RUN /opt/keycloak/bin/kc.sh build --features=fips --fips-mode=strict

FROM quay.io/keycloak/keycloak:latest
COPY --from=builder /opt/keycloak/ /opt/keycloak/

ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]

然后,按照 [在容器中运行 Keycloak](http://keycloak.java.net.cn/server/containers) 中的说明,将 FIPS 构建为优化的 Docker 映像并启动它。这些步骤要求您在启动映像时使用上述参数。

从非 FIPS 环境迁移

如果您之前在非 FIPS 环境中使用过 Keycloak,则可以将其迁移到 FIPS 环境,包括其数据。但是,如前几节所述,存在限制和注意事项,即

  • 从 Keycloak 25 开始,密码哈希的默认算法是 `argon2`。但是,此算法不支持 FIPS 140-2。这意味着,如果您的用户使用 `argon2` 对其密码进行哈希处理,他们将无法在切换到 FIPS 环境后登录。如果您计划迁移到 FIPS 环境,请考虑从一开始(在创建任何用户之前)为您的领域设置密码策略,并覆盖默认算法,例如使用 `pbkdf2-sha512`,它是符合 FIPS 的。此策略有助于使迁移到 FIPS 环境变得顺利。否则,如果您的用户已经在使用 `argon2` 密码,只需在迁移到 FIPS 环境后让用户重置密码即可。例如,让用户使用“忘记密码”或向所有用户发送重置密码的电子邮件。

  • 确保所有依赖密钥库的 Keycloak 功能仅使用支持的密钥库类型。这取决于使用严格模式还是非严格模式。

  • Kerberos 身份验证可能无法正常工作。如果您的身份验证流程使用 `Kerberos` 身份验证器,则此身份验证器在迁移到 FIPS 环境后将自动切换为 `DISABLED`。建议在切换到 FIPS 环境之前,从您的领域中删除任何 `Kerberos` 用户存储提供程序,并在 LDAP 提供程序中禁用与 `Kerberos` 相关的功能。

除了上述要求外,请确保在切换到 FIPS 严格模式之前仔细检查以下内容:

  • 确保所有依赖于密钥的 Keycloak 功能(例如,领域或客户端密钥)都使用至少 2048 位的 RSA 密钥。

  • 确保依赖于 `Signed JWT with Client Secret` 的客户端使用至少 14 个字符长的密钥(理想情况下是生成的密钥)。

  • 如前所述的密码长度限制。如果您的用户有较短的密码,请确保以最大填充长度设置为 PBKDF2 提供程序的 14 的方式启动服务器,如前所述。如果您希望避免此选项,您可以例如让所有用户在新的环境中进行首次身份验证时重置密码(例如通过 `Forgot password` 链接)。

非 FIPS 系统上的 Keycloak FIPS 模式

Keycloak 在支持 FIPS 的 RHEL 8 系统和 `ubi8` 映像上受支持并经过测试。它也支持 RHEL 9(以及 `ubi9` 映像)。在非 RHEL 兼容平台或不支持 FIPS 的平台上运行,无法严格保证 FIPS 兼容性,也无法获得官方支持。

如果您仍然需要在这样的系统上运行 Keycloak,您至少可以更新在 `java.security` 文件中配置的安全提供程序。此更新并不等同于 FIPS 兼容性,但至少设置更接近它。可以通过提供仅包含覆盖的安全提供程序列表的自定义安全文件来完成此操作,如前所述。有关推荐提供程序的列表,请参见 [OpenJDK 21 文档](https://access.redhat.com/documentation/en-us/red_hat_build_of_openjdk/21/html/configuring_red_hat_build_of_openjdk_21_on_rhel_with_fips)。

您可以在启动时检查 Keycloak 服务器日志,以查看是否使用了正确的安全提供程序。如前所述的 Keycloak 启动命令中所述,应为与加密相关的 Keycloak 包启用 TRACE 日志记录。

在本页上