将应用程序与 HashiCorp Vault 在 Cloud Foundry 中通过 Spring 绑定

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

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

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

Spring Cloud Connectors 为与各种云服务集成的连接器奠定了基础。它提供了允许正确配置中间件的组件。使用 CloudFoundry 的 Java 构建包附带了“自动重新配置”功能,旨在减轻将简单应用程序迁移到云端的负担。

正确配置中间件服务(例如 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 是获取 CloudFoundry 服务配置并将其提供给实际 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 和 CloudFoundry 连接器之外,您实际上无需做其他任何事情。

Spring 连接器附带一个引导配置,该配置使用服务配置中的 token 和端点来配置 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 的 PropertySourceEnvironment 中解析属性。

  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. cloud 对象暴露了创建服务连接器的方法。将 VaultServiceConnectorConfig 以及 VaultOperations 服务类型传递给这些方法,以创建模板 API 实例。Cloud 对象还使您能够访问包含认证信息和托管 Vault 后端详细信息的服务信息。

HashiCorp 的 Vault 服务代理

HashiCorp 提供了一个服务代理,用于配置可绑定到您应用程序的 Vault 服务。它使用基于 Token 的认证并启动几个后端。具体而言,它们是

  • 应用程序实例独享的 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",
    }
]
}

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

等等,LocalConfig 怎么办?

哦,对了,谢谢提醒。您偶尔会希望在部署到云端之前在本地测试您的应用程序,或者您不想使用服务绑定。Spring Cloud Vault LocalConfig 连接器正是为此目的而设计的。它允许您指定一个由连接器获取的配置属性,并提供与 CloudFoundry 上的 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=http://localhost: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: http://localhost:8200?token=my-token
                      &backend.generic=cf/secret
                      &backend.transit=cf/transit
                      &shared_backend.space=cf/space

您可能已经注意到,这个 URL 看起来与您通常使用的 Vault 端点前缀 URL 有些不同。连接器需要额外的配置选项,这些选项表示为查询参数。连接器只使用协议、主机和端口来配置端点。额外的查询参数代表了通常通过 VCAP_SERVICES 传输的键

  • token 认证 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 和 token 认证是使 Spring Boot 与 Spring Cloud Vault 一起工作所需的仅有的两个属性。根据上面的示例,您的引导配置将如下所示

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}

您可以在没有任何额外自动配置库的情况下拥有完全控制权。使用属性可以利用 profiles 进行条件激活。

更多资源

订阅 Spring 电子报

通过 Spring 电子报保持联系

订阅

抢占先机

VMware 提供培训和认证,为您的进步加速。

了解更多

获取支持

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

了解更多

近期活动

查看 Spring 社区的所有近期活动。

查看全部