如何将信任库和密钥库添加到 PCF(Pivotal Cloud Foundry)中的 springboot 应用程序

Avi*_*thy 1 java cloud-foundry pcf spring-boot

有没有办法在 PCF 中添加信任库和密钥库:

部署到 unix box 的应用程序可以拥有信任库,并且可以通过将它们保存在单独的位置并将该位置添加为 vm 参数来外部化密钥库。

但是如何在 PCF 中外部化密钥库和信任库。

我遇到的选项 1 是将密钥库和信任库保存在 spring-boot 应用程序的 /resource 中,并在 manifest.yml 中给出路径: JAVA_OPTS arguments 。但是如果我们有 5 个不同的环境,有 5 个不同的信任库和密钥库呢?

由于这个原因,我们需要将 . 请建议是否有任何方法可以在 PCF 中做到这一点。

提前致谢 !

Dan*_*usa 7

正如您所提到的,有多种方法可以做到这一点,这取决于您的具体需求,哪种方法最有效。我将尝试概述尽可能多的选项以及每个选项的优缺点。

  1. 如果您只需要分发证书以信任,那么添加 Bosh Trusted 证书并允许 Bosh 将它们分发到 CF 中的所有 VM 和容器是一个不错的方法。在 Ops Manager 的 Bosh 磁贴下,转到安全性,您可以添加任意数量的受信任证书。

    当多个应用程序需要信任证书时,这是一种很好的方法,例如企业/私有 CA。它也适用于不同的环境/基础,因为您有不同的 Ops Manager,它可以维护不同的受信任证书列表。如果您有许多需要信任的证书和/或证书仅由一个或少数应用程序使用,则可能难以管理。它还需要对 CF 的管理权限,并且可能需要一段时间才能在整个基础上部署更新。

  2. 这是您在问题中提到的选项。将证书导入 Java 信任库文件,将该文件打包到 Java 应用程序中并通过JAVA_OPTS环境变量指定其路径。信任库文件可以放在resource目录下。

    前任: cf set-env <app> JAVA_OPTS '-Djavax.net.ssl.trustStore=/home/vcap/app/BOOT-INF/classes/jssecacerts'

    此选项对于上述选项 #1 未涵盖的场景很有用,例如单个或小型应用程序,其中有该应用程序独有的证书。例如,您有一个必须信任的数据库服务器,并且只有一个应用程序使用该数据库服务器。

    它具有您提到的缺点,信任库必须嵌入到应用程序中,因此要处理多个环境,您需要执行一些操作,例如将所有环境的证书打包到一个信任库中,然后将其打包到一个 JAR/WAR 中供所有人使用环境或构建多个 JAR/WAR 文件,每个环境一个。

    它还有一个缺点,即您完全覆盖了默认信任库。默认信任库中填充了许多众所周知的 CA 证书,因此您必须从默认信任库的副本开始,并附加要添加的证书。否则,您将丢失受信任 CA 的默认列表,并且验证将中断到 Google 或 Yahoo 等站点。默认 CA 证书随每个 JRE 一起提供,但它可能因版本而异,因此您应该保持最新状态。

  3. 这是#2 的一个细微变化。在应用程序根目录下创建一个名为 的脚本文件.profile。在其中,运行keytool并导入与您的应用程序一起打包的所有证书。

    前任:

    #!/bin/bash 
    $HOME/.java-buildpack/open_jdk_jre/bin/keytool \
        -keystore $HOME/.java-buildpack/open_jdk_jre/lib/security/cacerts \
        -storepass changeit \
        -importcert \
        -noprompt \
        -alias MyCert \
        -file $HOME/BOOT-INF/classes/ssl/MyCert.crt
    # TODO: repeat this command for all the certs you need to import
    
    Run Code Online (Sandbox Code Playgroud)

    然后运行jar uf target/your-app.jar .profile以将脚本添加到应用程序 JAR/WAR 的根目录中。该脚本必须存在于 JAR/WAR 文件的根目录中,Cloud Foundry 会选取并执行该脚本。您可以运行jar tf target/your-app.jar | grep profile以确认这一点。输出应指示.profile没有前导路径。如果有前导路径,则该文件添加到了错误的位置。

    这种方法的好处是您不需要提供完整的信任存储。这是 #2 的一大缺点,在这种情况下,您将巧妙地使用 Java buildpack 提供的 JRE 打包的默认信任库。该脚本将在您的应用程序启动之前附加额外的证书。

    这种方法的缺点是添加证书很麻烦,很容易被跳过/忘记,导致您的应用程序中断。它还需要在一个非常特定的地方,以便 Cloud Foundry 找到它并执行它。此选项也存在需要将证书打包到 JAR/WAR 中的缺点。

  4. 下一个选项是对#3 的迭代。在这种情况下,您包含.profile脚本但不将证书打包到 JAR/WAR 中。相反,您通过环境变量或绑定服务提供证书(这与 CredHub 服务代理配合得很好)。

    要使此工作正常进行,您需要调整脚本,使其从环境变量中取出证书,制作一个临时文件,然后将其导入到默认的信任库中keytool。以下示例显示将其从环境变量中取出,但您可以使用jq它并将其取出VCAP_SERVICES用于绑定服务。

    前任:

    #!/bin/bash 
    $HOME/.java-buildpack/open_jdk_jre/bin/keytool \
        -keystore $HOME/.java-buildpack/open_jdk_jre/lib/security/cacerts \
        -storepass changeit \
        -importcert \
        -noprompt \
        -alias MyCert \
        -file <(echo $CERT_1)
    # TODO: repeat this command for all the certs you need to import
    
    Run Code Online (Sandbox Code Playgroud)

    这种方法的好处与#3 相同,只是您不再需要将证书与您的应用程序捆绑在一起。它们可以从外部喂食。缺点是相同的,.profile脚本很难使用并且可能会被遗忘。

  5. #2 的一个变体是在你的代码中设置系统属性。您只需要在 JVM 初始化 TLS 之前在应用程序启动的早期发生这种情况。如果它发生在之后,则不会发生任何事情,也不会找到您的证书。

    文章解释了不同的地方,你可以把初始化代码在Spring启动应用程序。基本上,您只是使用它来调用System.setProperty("javax.net.ssl.trustStore", "path/to/custom/truststore"),如果您更改密码,System.setProperty("javax.net.ssl.trustStorePassword", "newpassword").

    我不喜欢这种方法,因为如果在代码运行之前初始化 TLS,事情可能会意外中断。恕我直言,控制这一点很棘手,尤其是在 Spring Boot 及其所有自动配置中(并不是说这些不好,只是您必须非常小心订单)。我发现在配置文件脚本中执行此操作更容易,该脚本保证在您的应用程序启动之前运行。

  6. 另一种变体是手动配置您的 WebClient,完全不依赖于默认信任库。您可以创建自己的信任库,这为您提供了最大的灵活性。

    前任:

    @Bean
    public WebClient createWebClient() throws SSLException {
        SslContext sslContext = SslContextBuilder
                .forClient()
                .trustManager( /* TODO */ )
                .build();
        ClientHttpConnector httpConnector = HttpClient.create().secure(t -> t.sslContext(sslContext) )
        return WebClient.builder().clientConnector(httpConnector).build();
    }
    
    Run Code Online (Sandbox Code Playgroud)

    上面的代码中有一个 TODO 标记,您需要在其中添加您的信任管理器。这篇SO 帖子对如何做到这一点有一些很好的想法,但总体而言,您创建的内容和加载证书的位置非常灵活。

    这种方法的结果是它是完全可定制的。您可以从任何地方、环境变量、VCAP_SERVICES甚至从 Spring Cloud Config 中提取您的证书。您只需要在初始化WebClient. 缺点可能很明显,需要编写更多代码。


可能还有其他选择,但希望这能让您思考什么是可能的。以上信息也涉及信任库的主题。如果您需要为 Keystore 提供私钥,上面的一些选项会略有不同。

  1. 不会工作。
  2. 它会工作,但有一个不同的 JVM 参数:javax.net.ssl.keyStore. 3 和 4. 可以工作,但不是附加到默认密钥库,您必须在脚本中创建一个新密钥并设置javax.net.ssl.keyStore. 这是更多的工作,而不是比 #2 更有帮助。
  3. 它将使用相同的警告,但具有不同的 JVM 参数:javax.net.ssl.keyStore.
  4. 它会起作用,您只需要对其进行编码。

您还需要对密钥更加小心,因为它们是高度敏感的信息。恕我直言,确保它们没有存储在 JAR/WAR 中并像在 CredHub 或 Spring Cloud Config Server 中一样保持安全是值得的。