3年前 (2021-09-09)  相关技术 |   抢沙发  445 
文章评分 0 次,平均分 0.0
[收起] 文章目录

基于Spring WebFlux和Vault PKI的SSL

在本文中,我们将学习如何配置Vault PKI引擎并将其与Spring WebFlux集成。使用Vault PKI,您可以轻松生成由CA签名的X.509证书。然后,您的应用程序可以通过REST API获得证书。它的TTL相对较短。每个应用程序实例都是唯一的。此外,我们还可以使用SpringVault模板简化与Vault API的集成。

让我们再多说一点关于安全库的事。它允许您使用UI、CLI或HTTP API保护、存储和控制对令牌、密码、证书和加密密钥的访问。这是一个非常强大的工具。使用Vault,而不是传统的方法,您可以以更动态、云本地的方式管理您的安全性。例如,可以将Vault与数据库后端集成,然后动态生成用户登录名和密码。此外,对于Spring Boot应用程序,您可以利用Spring Cloud Vault项目。

还不止这些。您可以将Vault与来自Hashicorp的其他工具(如Consor或Nomad)集成。换句话说,它允许我们以安全的方式构建云本地平台。

源代码

如果您想自己尝试,您可以随时查看我的源代码。为了做到这一点,您需要克隆我的存储库示例SpringCloudSecurity(https://github.com/piomin/sample-spring-cloud-security.git)。然后,您应该转到网关服务目录,并按照我在下一节中的说明进行操作。示例应用程序充当微服务的API网关。我们使用Spring Cloud Gateway。由于它是建立在Spring WebFlux之上的,所以这个例子非常适合我们当前的文章。

1. 运行Vault

我们将在开发模式下在Docker容器中运行Vault。在该模式下运行的服务器不需要任何进一步的设置,启动后即可使用。启动后,我们的Vault实例在端口8200上可用。本文中使用的Vault版本为1.7.1。

$ docker run --cap-add=IPC_LOCK -d --name vault -p 8200:8200 vault

可以使用不同的方法登录,但最适合我们的方式是通过令牌。为此,我们必须使用命令docker logs vault显示容器日志,然后复制根令牌,如下所示。

基于Spring WebFlux和Vault PKI的SSL

最后,我们可以登录到Vault web控制台。

基于Spring WebFlux和Vault PKI的SSL

2. 启用和配置Vault PKI

有两种方法可以启用和配置Vault PKI:使用CLI或通过UI。大多数文章都描述了配置PKI引擎所需的CLI命令列表。但是,我将使用Vault UI来实现这一点。首先,让我们在主站点上启用一个新引擎。

基于Spring WebFlux和Vault PKI的SSL

然后,我们需要选择一种类型的引擎来启用。在我们的例子中,它是PKI证书的选项。

基于Spring WebFlux和Vault PKI的SSL

在创建过程中,让我们保留一个默认名称pki。然后,我们需要导航到新启用的引擎并创建一个新角色。角色用于生成证书。我的角色的名称是默认的。这个名称很重要,因为我们必须使用VaultTemplate从代码中调用它。

基于Spring WebFlux和Vault PKI的SSL

我们角色中使用的密钥类型是rsa

基于Spring WebFlux和Vault PKI的SSL

在创建它之前,我们应该设置一些重要参数。其中之一是TTL,设置为3天。另外,不要忘了检查字段是否允许任何名称,以及是否需要通用名称。它们都与证书中的CN字段相关。因为我们将在CN字段中存储一个用户名,所以我们需要允许它的任何名称。

基于Spring WebFlux和Vault PKI的SSL

创建角色后,我们需要配置CA。为此,我们应该首先切换到“配置”选项卡,然后单击“配置”按钮。

基于Spring WebFlux和Vault PKI的SSL

之后,让我们选择配置CA。

基于Spring WebFlux和Vault PKI的SSL

最后,我们可以创建一个新的CA证书。我们应该将根值保留为CA类型,将内部值保留为类型。默认密钥格式为pem。我们还可以为CA证书设置一个通用名称。对于角色和CA,值得填写其他字段,例如组织或组织单位的名称。

基于Spring WebFlux和Vault PKI的SSL

3. Spring WebFlux与Vault PKI的集成

让我们从依赖性开始。我们需要包括一个用于反应式API的Spring WebFlux启动器和一个用于保护API的Spring Security启动器。spring Vault core可以提供与Vault API的集成。为了能够使用Spring Vault启动应用程序,我还必须包含Jackson库。

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-cloud-starter-webflux</artifactId>
</dependency>
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-core</artifactId>
</dependency>
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.vault</groupId>
   <artifactId>spring-vault-core</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
</dependency>

然后,让我们配置一个Vault模板bean。它应该使用http方案和从配置中注入的身份验证令牌。

@Value("vault.token")
private String vaultToken;

@Bean
VaultTemplate vaultTemplate() {
   VaultEndpoint e =  new VaultEndpoint();
   e.setScheme("http");
   VaultTemplate template = new VaultTemplate(e, new TokenAuthentication(vaultToken));
   return template;
}

Vault模板为与PKI引擎的交互提供专用支持。我们只需要调用传递PKI引擎名称的方法opsForPki来获得Vault PKI操作实例(1)。然后,我们需要使用Vault CertificateRequest构建一个证书请求。我们可以设置几个参数,但最重要的是CN和证书TTL(2)。最后,我们应该调用issueCertificate方法,传递请求和在Vault PKI上配置的角色的名称(3)。我们的证书已成功生成。现在,我们只需要从响应中获得它。生成的证书、CA证书和私钥在方法返回的CertificateBundle对象中可用。

private CertificateBundle issueCertificate() throws Exception {
   VaultPkiOperations pkiOperations = vaultTemplate.opsForPki("pki"); // (1)
   VaultCertificateRequest request = VaultCertificateRequest.builder()
        .ttl(Duration.ofHours(12))
        .commonName("localhost")
        .build(); // (2)
   VaultCertificateResponse response = pkiOperations.issueCertificate("default", request); // (3)
   CertificateBundle certificateBundle = response.getRequiredData(); // (4)

   log.info("Cert-SerialNumber: {}", certificateBundle.getSerialNumber());
   return certificateBundle;
}

4. 启用SpringWebFlux安全性

在上一节中,我们已经将SpringWebFlux与Vault PKI集成。最后,我们可以进入实现的最后一步——基于X.509证书启用安全性。为此,我们需要创建一个@Configuration类。应使用@EnableWebFluxSecurity(1)对其进行注释。我们还需要通过实现主体提取器从证书中获取用户名。我们将使用SubjectDNX509(2)和从CN字段读取数据的正确正则表达式。最终配置禁用CSRF、基本身份验证,并使用X509证书启用SSL(3)。我们还需要用一个用户名piotrm提供UserDetails接口(4)的实现。

@Configuration
@EnableWebFluxSecurity // (1)
public class SecurityConfig {

   @Bean
   public SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
      SubjectDnX509PrincipalExtractor principalExtractor =
             new SubjectDnX509PrincipalExtractor(); // (2)
      principalExtractor.setSubjectDnRegex("CN=(.*?)(?:,|$)");

      return http.csrf().disable()
             .authorizeExchange(exchanges -> 
                    exchanges.anyExchange().authenticated())
             .x509()
                .principalExtractor(principalExtractor)
             .and()
                .httpBasic().disable().build(); // (3)
   }

   @Bean
   public MapReactiveUserDetailsService users() { // (4)
      UserDetails user1 = User.builder()
             .username("piotrm")
             .password("{noop}1234")
             .roles("USER")
             .build();
      return new MapReactiveUserDetailsService(user1);
   }
}

在最后一步中,我们需要在运行时覆盖Netty服务器SSL配置。我们的定制者应该实现WebServerFactoryCustomizer接口,并使用NettyReactiveWebServerFactory。在customize方法中,我们首先调用负责在Vault中生成证书的方法issueCertificate(您可以参考上一节了解该方法的实现)(1)。CertificateBundle包含所有必需的数据。我们可以在其上调用createKeyStore方法来创建密钥库(2),然后将其保存在文件(3)中。

要覆盖Netty SSL设置,我们应该使用SSL对象。需要启用客户端身份验证(4)。我们还将设置当前创建的密钥库(5)的位置。之后,我们可以继续创建信任库。发卡机构证书可从CertificateBundle(6)处获得。然后我们应该创建一个新的密钥库,并将CA证书设置为其中的一个条目(7)。最后,我们将把信任库保存到文件中,并在Ssl对象中设置其位置。

@Component
@Slf4j
public class GatewayServerCustomizer implements 
         WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {

   @SneakyThrows
   @Override
   public void customize(NettyReactiveWebServerFactory factory) {
      String keyAlias = "vault";
      CertificateBundle bundle = issueCertificate(); // (1)
      KeyStore keyStore = bundle.createKeyStore(keyAlias); // (2)
      String keyStorePath = saveKeyStoreToFile("server-key.pkcs12", keyStore); // (3)

      Ssl ssl = new Ssl();
      ssl.setEnabled(true);
      ssl.setClientAuth(Ssl.ClientAuth.NEED); // (4)

      ssl.setKeyStore(keyStorePath); // (5)
      ssl.setKeyAlias(keyAlias);
      ssl.setKeyStoreType(keyStore.getType());
      ssl.setKeyPassword("");
      ssl.setKeyStorePassword("123456");

      X509Certificate caCert = bundle.getX509IssuerCertificate(); // (6)
      log.info("CA-SerialNumber: {}", caCert.getSerialNumber());
      KeyStore trustStore = KeyStore.getInstance("pkcs12");
      trustStore.load(null, null);
      trustStore.setCertificateEntry("ca", caCert); // (7)
      String trustStorePath = saveKeyStoreToFile("server-trust.pkcs12", trustStore); // (8)

      ssl.setTrustStore(trustStorePath); // (9)
      ssl.setTrustStorePassword("123456");
      ssl.setTrustStoreType(trustStore.getType());

      factory.setSsl(ssl);
      factory.setPort(8443);
   }
}

5. 使用Vault PKI测试Spring WebFlux

让我们运行示例应用程序。它在8443端口下可用。我们将使用curl工具进行测试。在这样做之前,我们需要生成一个带有私钥的客户端证书。让我们再次转到Vault UI。如果单击默认Vault UI,将重定向到负责生成证书的表单,如下所示。在CommonName字段中,我们应该提供UserDetails实现中配置的测试用户名。对我来说,这是piotrm。另外,不要忘记设置正确的TTL。

基于Spring WebFlux和Vault PKI的SSL

生成证书后,您将被重定向到带有结果的站点。首先,您应该将字符串与证书一起复制,并将其保存到文件中。对我来说,它是piotrm.crt。您还可以显示生成的私钥的内容。然后,执行与证书相同的操作。我的文件名是piotrm.key

基于Spring WebFlux和Vault PKI的SSL

最后,我们可以向示例应用程序发送一个测试请求,传递密钥和证书文件的名称:

$ curl https://localhost:8443/hello -v --key piotrm.key --cert piotrm.crt

原文地址:https://piotrminkowski.com/2021/05/24/ssl-with-spring-webflux-and-vault-pki/

 

除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/2327.html

关于

发表评论

表情 格式

暂无评论

登录

忘记密码 ?

切换登录

注册