在 Cloud Foundry 中使用 Spring 将应用程序绑定到 HashiCorp 的 Vault

工程 | Mark Paluch | 2017年11月28日 | ...

在本文中,我们将深入探讨如何在 Cloud Foundry 上将 Spring 应用程序绑定到HashiCorp 的 Vault 服务代理

Spring Boot 提供了许多自动配置和外部绑定功能,其中一些与 Cloud Foundry 相关,许多则无关。Spring Cloud Connectors 是一个库,如果您想以编程方式创建自己的组件,可以在应用程序中使用它,但它本身不会做任何“神奇”的事情。

Spring Cloud Connectors 为与各种云服务集成的连接器奠定了基础。它自带组件,允许正确的中间件配置。使用 Cloud Foundry 的 Java buildpack 带有“自动重新配置”功能,试图减轻将简单应用程序迁移到云的负担。

正确配置中间件服务(如 HashiCorp 的 Vault)的关键在于了解每个工具提供的功能以及它们在运行时如何相互影响。目标应该是应用程序在开发人员桌面上进行本地执行到 Cloud Foundry 中的测试环境,以及最终在 Cloud Foundry(或其他环境)中进行生产的平滑过渡,而无需更改源代码或打包,符合十二要素应用程序指南。

Spring Cloud Vault 连接器附带四个库

  • spring-cloud-vault-connector-core 提供其他三个库使用的公共部分。

  • spring-cloud-vault-spring-connector 使用 Vault 连接器配置基于 Spring Framework 和 Spring Boot(Spring Cloud)的应用程序。

  • spring-cloud-vault-cloudfoundry-connector 需要获取 Cloud Foundry 的服务配置并将服务配置提供给实际的 Spring 连接器。

  • spring-cloud-vault-localconfig-connector 允许您提供基于属性的配置,如果您想自己配置服务,例如在 CI 或本地运行时环境中,而无需提供额外的代码来区分云和非云运行时。

    io.pivotal.spring.cloud spring-cloud-vault-connector-core 1.0.0.RELEASE io.pivotal.spring.cloud spring-cloud-vault-spring-connector 1.0.0.RELEASE io.pivotal.spring.cloud spring-cloud-vault-cloudfoundry-connector 1.0.0.RELEASE io.pivotal.spring.cloud spring-cloud-vault-localconfig-connector 1.0.0.RELEASE

您的应用程序

如果您使用的是 Spring Boot 和 Spring Cloud Vault,那么实际上除了引入 Spring 和 Cloud Foundry 连接器之外,您什么都不需要做。

Spring 连接器附带一个引导配置,它使用服务配置中的令牌和端点来配置 Spring 的 Vault 客户端。Spring Cloud Vault 默认配置一个属性源,指向${spring.application.name}/${profile-name}。HashiCorp 的服务代理在应用程序、空间和组织命名空间中配置通用后端。连接器按顺序拾取后端和共享后端(按上述顺序)以从这些后端获取其配置属性。

@SpringBootApplication
public class HelloWorldApplication {

  public static void main(String[] args) {
    SpringApplication.run(HelloWorldApplication.class, args);
  }

  static class MyComponent {

    public MyComponent(@Value("${some-property}") String someProperty, (1)
                        VaultOperations vaultOperations) {             (2)
      // …
    }
  }
}
  1. 直接注入配置属性。Spring 尝试从其使用 Vault 的PropertySource配置的Environment中解析属性。

  2. 注入配置为使用已连接 Vault 服务的VaultOperations

如果您的应用程序纯粹是基于 Spring Framework 的,或者是一个没有 Spring Cloud Vault 的 Spring Boot 应用程序,那么在您的一个配置类上启用@ServiceScan就足以获取身份验证和端点。

public class CloudFoundryApplication {

  @Configuration
  @ServiceScan                                                            (1)
  static class VaultConfig {
  }

  public static void main(String[] args) {

    GenericApplicationContext ctx =
                    new AnnotationConfigApplicationContext(VaultConnectorsConfig.class,
                                            VaultConfig.class);

    ctx.start();

    VaultOperations vaultOperations = ctx.getBean(VaultOperations.class); (2)

    ctx.stop();
  }
}
  1. @ServiceScan启用扫描绑定到您的应用程序的服务。它为所有找到的服务创建 bean。

  2. VaultOperations是由服务扫描创建的,因此您可以直接在应用程序中使用它。

您是否更希望自己配置 bean 而无需激活@ServiceScan,或者您想提供自定义客户端配置?然后直接使用CloudCloud对象允许您访问服务信息,并允许您创建VaultTemplate

@Configuration
class VaultConfig {

  @Bean
  public Cloud cloud() {                                                  (1)
    return new CloudFactory().getCloud();
  }

  @Bean
  public SslConfiguration sslConfiguration() {                            (2)
    return SslConfiguration.forTrustStore(…);
  }

  @Bean
  VaultOperations vaultOperations() {                                     (3)

    VaultServiceInfo vaultServiceInfo = (VaultServiceInfo) cloud()
          .getServiceInfos(VaultOperations.class).get(0);

    VaultServiceConnectorConfig config = VaultServiceConnectorConfig.builder()
                .sslConfiguration(sslConfiguration())
                .build();

    return cloud().getSingletonServiceConnector(VaultOperations.class, config);
  }
}
  1. Cloud对象解析绑定的服务。将其注册为 bean 只需要解析一次,而无需每次需要Cloud对象时都重新解析服务。

  2. 在继续您的配置时,可能需要自定义 SSL 或客户端配置选项。以下是如何为 Spring 的 Vault 客户端提供信任存储的示例。

  3. 云对象公开了创建服务连接器的方法。将VaultServiceConnectorConfigVaultOperations服务类型一起传递给这些方法以创建模板 API 实例。Cloud对象还允许您访问服务信息,其中包含有关身份验证和托管 Vault 后端的详细信息。

HashiCorp 的 Vault 服务代理

HashiCorp 提供了一个服务代理来配置 Vault 服务,这些服务可以绑定到您的应用程序。它使用基于令牌的身份验证并启动几个后端。特别是:

  • 一个专用于应用程序实例的generic 密钥后端

  • 一个专用于应用程序实例的transit 后端

  • 一个位于您的空间范围内的共享generic 密钥后端

  • 一个位于您的组织范围内的共享generic 密钥后端

  • 每个应用程序的一组策略,例如将共享组织后端限制为应用程序的只读。

服务实例的详细信息通过VCAP_SERVICES提供,这是一个您的应用程序可见的环境变量。通常,它看起来像这样:

{
"hashicorp-vault": [
    {
    "credentials": {
      "address": "https://your-server:8200/",
      "auth": {
          "token": "00000000-0000-0000-0000-000000000000"
      },
      "backends": {
          "generic": "cf/20fffe9d-d8d1-4825-9977-1426840a13db/secret",
          "transit": "cf/20fffe9d-d8d1-4825-9977-1426840a13db/transit"
      },
      "backends_shared": {
          "organization": "cf/1a558498-59ad-488c-b395-8b983aacb7da/secret",
          "space": "cf/d007583f-5617-4b02-a5a7-550648827cfa/secret"
      }
    },
    "label": "hashicorp-vault",
    "name": "hashicorp-vault",
    }
]
}

令牌由服务代理管理和刷新,应用程序不应接触它。撤销令牌将关闭绑定应用程序中所有应用程序实例的访问权限。

等等,LocalConfig 怎么办?

哦,对了,谢谢提醒。有时您想在将应用程序部署到云之前在本地测试它,或者您不想使用服务绑定。Spring Cloud Vault LocalConfig 连接器完全适合此目的。它允许您指定一个连接器拾取的配置属性,并提供与 Cloud Foundry 上的VCAP_SERVICES相同的配置密钥集。

引导配置至少需要设置两个密钥

  • spring.cloud.appId:应用程序标识符名称。任何描述性应用程序名称(甚至可能是${spring.application.name})都可以完成这项工作。

  • spring.cloud.命名空间下设置为 HTTP/HTTPS url 的密钥。

    spring.application.name=…

    spring.cloud.appId=your-app-id spring.cloud.my-vault-service=https://127.0.0.1:8200?token=my-token &backend.generic=cf/secret &backend.transit=cf/transit &shared_backend.space=cf/space

或写成 YAML

spring.application.name: …

spring.cloud:
    appId: your-app-id
    my-vault-service: https://127.0.0.1:8200?token=my-token
                      &backend.generic=cf/secret
                      &backend.transit=cf/transit
                      &shared_backend.space=cf/space

您可能已经注意到,该 URL 看起来与您通常的 Vault 端点前缀 URL 略有不同。连接器需要额外的配置选项,这些选项以查询参数的形式表示。连接器仅使用方案、主机和端口来配置端点。附加的查询参数表示通常通过VCAP_SERVICES传输的密钥。

  • token 身份验证令牌(必需)

  • backend.(.*) 专用后端的上下文路径。backend.后的属性键表示专用后端名称。

  • shared_backend.(.*) 共享后端的上下文路径。shared_backend.后的属性键表示共享后端名称。

您可以配置多个后端和共享后端。

我可以无需连接器库连接到 HashiCorp 的 Vault 吗?

是的,可以!在您希望更好地控制正在发生的事情,或者想要省略额外依赖项的情况下,还有另一种连接到 Vault 的方法。Spring Boot 自带 CloudFoundryVcapEnvironmentPostProcessor,它通过属性源将 CloudFoundry 的 VCAP 变量导出到您的应用程序。这些属性以 vcap.application(用于 VCAP_APPLICATION)和 vcap.services(用于 VCAP_SERVICES)为前缀。您可以像引用任何其他属性一样引用 VCAP 属性。

通过 VCAP_SERVICES 配置 Vault 连接需要了解 VCAP_SERVICES 的实际结构。配置 URL 和令牌身份验证是使 Spring Boot 与 Spring Cloud Vault 协同工作的唯一两个必需属性。根据上面的 示例,您的 bootstrap 配置如下所示:

spring.application.name=…

spring.cloud.vault.url=${vcap.services.hashicorp-vault.credentials.address}
spring.cloud.vault.token=${vcap.services.hashicorp-vault.auth.token}
spring.cloud.vault.generic.backend=${vcap.services.hashicorp-vault.credentials.backend.generic}

或写成 YAML

spring.application.name: …

spring.cloud.vault:
    url: ${vcap.services.hashicorp-vault.credentials.address}
    token: ${vcap.services.hashicorp-vault.auth.token}
    generic.backend: ${vcap.services.hashicorp-vault.credentials.backend.generic}

您可以完全控制,无需任何额外的自动配置库。使用属性允许您利用配置文件进行条件激活。

更多资源

获取 Spring 新闻通讯

关注 Spring 新闻通讯

订阅

领先一步

VMware 提供培训和认证,助您快速提升技能。

了解更多

获取支持

Tanzu Spring 通过一个简单的订阅提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看全部