【微服务安全】使用 Spring Boot、Kafka、Vault 和 Kubernetes 保护微服务间通信——第 4 部分:构建微服务

Chinese, Simplified
  • 第 1 部分:简介和架构
  • 第 2 部分:设置 Kubernetes 和 Kafka
  • 第 3 部分:设置保险柜
  • Part 4: 构建微服务 <--本文
  • 第 5 部分:部署和测试

创建微服务

 

  • 我们将创建 2 个微服务:Transaction 和 DepositAccount。我们将为此使用 JHipster。
  • 首先,我们需要安装 JHipster。请按照此处的教程安装 JHipster [https://www.jhipster.tech/installation/]



准备信任库(truststore)

 

  • 如果您从 Java 程序调用自签名受保护端点(例如本教程中的 Vault),则需要首先信任自签名证书
  • 通常这是通过将自签名证书注册到 JVM 的信任库中来完成的。
  • 我们将面临的问题是:当我们创建 docker 镜像并在其中运行我们的微服务时,我们不会使用我们机器的 JVM。我们将改为使用图像的 JVM。我们如何将我们的证书注册到镜像的 JVM 信任库中?
  • 当我们进入本教程的部署部分时,我们将解决这个问题。同时,让我们将 Vault 的根证书注册到信任库中。请记住证书 TMPDIR/vault.crt。我们将使用此证书。
  • 我们需要找到 JVM cacerts 在哪里。在 Mac 机器上,它位于文件夹中的某个位置:$(/usr/libexec/java_home)/lib/security.你可以参考这个关于堆栈溢出的讨论:https://stackoverflow.com/questions/11936685/how-to-obtain-the-location…
  • 运行以下命令。当提示输入密码时,请指定插入符号密码。默认情况下是 changeit
> sudo keytool -import -file "/tmp/vault.crt" -keystore "$(/usr/libexec/java_home)/lib/security/cacerts" -alias "vault certificate"

 

  • 您可能需要更改生产环境的 cacerts 密码
  • 我们现在已经将 Vault 的证书注册为可信证书。

设置 JHipster 注册表

 

  • 将 JHipster Registry https://www.jhipster.tech/jhipster-registry/ 下载为 jar 文件并放入 $PROJECTS/Registry 文件夹
  • 创建另一个文件夹:$PROJECTS/Registry/central-config。在 central-config 中,创建一个名为 application.yml 的文件并在下面插入内容。请确保将 my-secret-key-which-should-be-changed-in-production-and-be-base64-encoded 替换为您自己的生产机密:
# ===================================================================
# JHipster Sample Spring Cloud Config.
# ===================================================================

# Property used on app startup to check the config server status
configserver:
    name: JHipster Registry config server
    status: Connected to the JHipster Registry config server!

# Default JWT secret token (to be changed in production!)
jhipster:
    security:
        authentication:
            jwt:
                # It is recommended to encrypt the secret key in Base64, using the `base64-secret` property.
                # For compabitibily issues with applications generated with older JHipster releases,
                # we use the non Base64-encoded `secret` property here.
                secret: my-secret-key-which-should-be-changed-in-production-and-be-base64-encoded
                # The `base64-secret` property is recommended if you use JHipster v5.3.0+
                # (you can type `echo 'secret-key'|base64` on your command line)
                # base64-secret: bXktc2VjcmV0LWtleS13aGljaC1zaG91bGQtYmUtY2hhbmdlZC1pbi1wcm9kdWN0aW9uLWFuZC1iZS1iYXNlNjQtZW5jb2RlZAo=
   
# Enable /management/logfile endpoint for all apps
logging:
    path: /tmp
    file: ${spring.application.name}.log
  • 您已成功设置 JHipster Registry



设置 API 网关



启动命令行控制台并将其指向 $PROJECTS/GatewayKafka 文件夹。跑:

> jhipster



将提出一系列问题。回答他们如下。请注意,当被问及您还想使用哪些其他技术?不要选择 Kafka。我们将单独处理 Kafka,而不是通过 JHipster:

? Which *type* of application would you like to create? Microservice gateway
? [Beta] Do you want to make it reactive with Spring WebFlux? No
? What is the base name of your application? GatewayKafka
? As you are running in a microservice architecture, on which port would like yo
ur server to run? It should be unique to avoid port conflicts. 8080
? What is your default Java package name? com.azrul.ebanking.gatewaykafka
? Which service discovery server do you want to use? JHipster Registry (uses Eur
eka, provides Spring Cloud Config support and monitoring dashboards)
? Which *type* of authentication would you like to use? JWT authentication (stat
eless, with a token)
? Which *type* of database would you like to use? SQL (H2, MySQL, MariaDB, Postg
reSQL, Oracle, MSSQL)
? Which *production* database would you like to use? PostgreSQL
? Which *development* database would you like to use? H2 with disk-based persist
ence
? Do you want to use the Spring cache abstraction? No - Warning, when using an S
QL database, this will disable the Hibernate 2nd level cache!
? Do you want to use Hibernate 2nd level cache? No
? Would you like to use Maven or Gradle for building the backend? Maven
? Which other technologies would you like to use? 
? Which *Framework* would you like to use for the client? Angular
? Would you like to use a Bootswatch theme (https://bootswatch.com/)? Default JH
ipster
? Would you like to enable internationalization support? No
? Besides JUnit and Jest, which testing frameworks would you like to use? 
? Would you like to install other generators from the JHipster Marketplace? (y/N
) No

 

  • 您现在已成功设置 API 网关

设置交易微服务



启动命令行控制台并将其指向 $PROJECTS/Transaction 文件夹。跑:

> jhipster



将提出一系列问题。回答他们如下。请注意,当被问及您还想使用哪些其他技术时?不要选择卡夫卡。我们将单独处理 Kafka,而不是通过 JHipster:

? Which *type* of application would you like to create? Microservice application
? [Beta] Do you want to make it reactive with Spring WebFlux? No
? What is the base name of your application? Transaction
? As you are running in a microservice architecture, on which port would like yo
ur server to run? It should be unique to avoid port conflicts. 8081
? What is your default Java package name? com.azrul.ebanking.transaction
? Which service discovery server do you want to use? JHipster Registry (uses Eur
eka, provides Spring Cloud Config support and monitoring dashboards)
? Which *type* of authentication would you like to use? JWT authentication (stat
eless, with a token)
? Which *type* of database would you like to use? SQL (H2, MySQL, MariaDB, Postg
reSQL, Oracle, MSSQL)
? Which *production* database would you like to use? PostgreSQL
? Which *development* database would you like to use? H2 with disk-based persist
ence
? Do you want to use the Spring cache abstraction? No - Warning, when using an S
QL database, this will disable the Hibernate 2nd level cache!
? Would you like to use Maven or Gradle for building the backend? Maven
? Which other technologies would you like to use? 
? Would you like to enable internationalization support? No
? Besides JUnit and Jest, which testing frameworks would you like to use? 
? Would you like to install other generators from the JHipster Marketplace? No

指定对 Kafka 和 Vault 的依赖关系

 

  • 首先,让我们处理依赖关系。在文件 $PROJECTS/Transaction/pom.xml 中,在 <dependencies> </dependencies> 标记中添加以下依赖项。

   

  <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
            <version>2.4.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-clients</artifactId>
            <version>2.4.1</version>
        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka_2.13</artifactId>
            <version>2.4.1</version>
        </dependency>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-vault-config</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>

 

  • 在同一个 pom.xml 文件下,我们还需要在 <dependencyManagement><dependencies> ... </dependencies></dependencyManagement> 下添加一个条目

 

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>



需要 spring-cloud-starter-vault-config 和 spring-cloud-dependencies 以允许 Vault 集成



编写事务微服务

 

  • 让我们创建一种将数据从发布者传输到消费者并再次返回的方法。为此,我们在名为 com.azrul.ebanking.common.dto 的包中创建了一个“数据传输对象”(DTO)。这将是生产者和消费者的通用包。在那里,让我们按照下面的方式创建一个 Transaction 类。请注意,为了使 Transaction 类可序列化,它必须实现 Serializable 接口,必须有一个默认构造函数,toString 和 equals 方法:

No alt text provided for this image

No alt text provided for this image

  • [完整来源:https://raw.githubusercontent.com/azrulhasni/Ebanking-JHipster-Kafka-Va…]
  • Kafka配置
  • Spring 使用 spring-kafka 库对 Kafka 提供了广泛的支持。这包括序列化器和反序列化器 - 这将使消息传递类型安全。另一方面,我们不会使用这些序列化器/反序列化器,因为我们将在消息到达我们自己的 Kafka 之前对其进行加密。我们将选择一个基本的字符串序列化器/反序列化器。
  • 这是我们将用来连接到 Kafka 的 KafkaTemplate。请注意,我们使用的是一种特殊的 KafkaTemplate,称为 ReplyingKafkaTemplate。这个类将允许我们发送请求并获得响应,而无需我们自己做太多的管道
  • 我们还需要一个配置文件。在 $PROJECTS/Transaction/src/main/resources/config 文件夹下,在 application.yml 文件中添加:
kafka:
  bootstrap-servers: kafka-headless.default.svc.cluster.local:9092
  deposit-debit-request-topic: deposit-debit-request
  deposit-debit-response-topic: deposit-debit-response
  consumer:
    group.id: transaction
    auto.offset.reset: earliest
  producer:

 

  • 在 $PROJECTS/Transaction/src/main/resources/config 文件夹下,在文件 bootstrap.yml 中,在 spring.cloud 下添加以下属性。
  • 在方案中,确保我们把 https
  • 在主机中,确保我们放置自己的 Vault Kubernetes 服务的完全限定域名。回想上面的 Vault Kubernetes Service 段落
  • 在连接超时和读取超时中,设置一个合理的超时时间。我们放了一个大的进行测试。放一个小的(比如几秒钟)用于生产
  • 在认证中,输入TOKEN,表示我们将通过安全令牌登录
  • 在令牌中,确保您在之前的“为加密和解密创建令牌”段落中输入了 client_token 值。
    vault:
      scheme: https
      host: vault.default.svc
      port: 8200
      connection-timeout: 3600000
      read-timeout: 3600000
      authentication: TOKEN
      token: s.WuTNTDpBqsspinc6dlDN0cbz
      kv:
        enabled=true:

 

  • 接下来,在 com.azrul.ebanking.transaction.web.rest 包中,创建一个名为 TransactionKafkaResource 的控制器

No alt text provided for this image

  1. 首先,我们需要获取请求和响应主题。回想一下我们的架构。另外,我们还在我们的KafkaTemplate中进行了wire,方便我们调用Kafka
  2. 我们还在 VaultTemplate 中进行接线以方便我们调用 Vault
  3. 这是我们将收到一个宁静的电话的地方。我们将加密该调用中的数据,创建 ProducerRecord 并将消息发送到 deposit-debit-request 主题。然后,我们将等待来自 deposit-debit-response 主题的回复。回复将包含我们得到的余额。一旦我们有了这些数据,我们就会解密它并返回给调用者。
  4. 这是我们加密数据的地方。最初,我们的数据是对象(Transaction 类型)的形式。然后我们将其转换为一系列字节。然后将一系列字节转换为 Base64 字符串。接下来,我们使用 Vault Transit 引擎加密 Base64 字符串。
  5. 这是我们解密数据的地方。最初,我们会得到一个加密的 Base64 字符串。我们需要使用 Vault Transit 引擎解密这个字符串。这将产生一个解密的 Base64 字符串。接下来,我们将 Base64 解密后的字符串解码为一系列字节。最后,我们将一系列字节转换回一个对象。

使用 Transaction 微服务的自签名证书处理 SSL

  • 请回想一下我们关于从微服务调用自签名保护端点的困难的讨论(准备信任库段落)。我们将利用 Jib 来帮助我们解决这个问题并部署到 Kubernetes。
  • 如果您注意到,JHipster 创建的文件夹之一称为 Jib ($PROJECTS/Transaction/src/main/jib)。此文件夹中的任何内容都将复制到根级别的 Docker 映像。
  • 例如。如果我们有 $PROJECTS/Transaction/src/main/jib/myfolder/myfile.txt,当我们创建 Docker 镜像时,Jib 会将 myfolder 和 myfile.txt 复制到 Docker 镜像中。这会在图像中创建 /myfolder/myfile.txt
  • 我们将创建一个名为 truststore 的文件夹,并在其中复制我们的主机/本地信任库(cacerts)。这会将 cacerts 复制到 /truststore/cacerts 的映像中。回想一下,我们可以找到信任库作为 JDK 的一部分。请在此处查看堆栈溢出讨论:https://stackoverflow.com/questions/11936685/how-to-obtain-the-location…

No alt text provided for this image

  • 接下来,我们需要告诉 Java 使用 /truststore/cacerts 中的 cacerts。在我们的 TransactionApp.java 文件的 main 方法中,添加以下行。确保我们使用正确的 cacerts 密码(默认为 changeit):
 System.setProperty("javax.net.ssl.trustStore","/truststore/cacerts");
 System.setProperty("javax.net.ssl.trustStorePassword","changeit");



No alt text provided for this image

设置 DepositAccount 微服务



启动命令行控制台并将其指向 $PROJECTS/DepositAccount 文件夹。跑:

> jhipster



将提出一系列问题。回答他们如下。请注意,当被问及您还想使用哪些其他技术时?不要选择卡夫卡。我们将单独处理 Kafka,而不是通过 JHipster:

? Which *type* of application would you like to create? Microservice application
? [Beta] Do you want to make it reactive with Spring WebFlux? No
? What is the base name of your application? DepositAccount
? As you are running in a microservice architecture, on which port would like yo
ur server to run? It should be unique to avoid port conflicts. 8082
? What is your default Java package name? com.azrul.ebanking.depositaccount
? Which service discovery server do you want to use? JHipster Registry (uses Eur
eka, provides Spring Cloud Config support and monitoring dashboards)
? Which *type* of authentication would you like to use? JWT authentication (stat
eless, with a token)
? Which *type* of database would you like to use? SQL (H2, MySQL, MariaDB, Postg
reSQL, Oracle, MSSQL)
? Which *production* database would you like to use? PostgreSQL
? Which *development* database would you like to use? H2 with disk-based persist
ence
? Do you want to use the Spring cache abstraction? No - Warning, when using an S
QL database, this will disable the Hibernate 2nd level cache!
? Would you like to use Maven or Gradle for building the backend? Maven
? Which other technologies would you like to use? 
? Would you like to enable internationalization support? No
? Besides JUnit and Jest, which testing frameworks would you like to use? 
? Would you like to install other generators from the JHipster Marketplace? (y/N
) No



指定对 Kafka 和 Vault 的依赖关系

 

  • DepositAccount 微服务的依赖与 Transaction 微服务相同。无论如何,我们将在这里重复以完成目的
  • 首先,让我们处理依赖关系。在文件 $PROJECTS/DepositAccount/pom.xml 中,在 <dependencies> </dependencies> 标记中添加以下依赖项。
       <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
            <version>2.4.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-clients</artifactId>
            <version>2.4.1</version>
        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka_2.13</artifactId>
            <version>2.4.1</version>
        </dependency>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-vault-config</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>

 

  • 在同一个 pom.xml 文件下,我们还需要在 <dependencyManagement><dependencies> ... </dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

 

  • 需要 spring-cloud-starter-vault-config 和 spring-cloud-dependencies 以允许 Vault 集成

为 DespositAccount 创建数据模型和存储库

 

  • 我们现在将为 DepositAccount 创建一个数据模型。
  • 在文件夹 $PROJECTS/DepositAccount/ 中创建一个名为 banking.jh 的文件。在那里,将数据模型放在下面
entity DepositAccount{  
    accountNumber String,  
    productId String,  
    openingDate ZonedDateTime,  
    status Integer,  
    balance BigDecimal  
}  

  
// Set service options to all except few  
service all with serviceClass
  • // 将服务选项设置为除少数之外的所有选项

使用 serviceClass 服务所有

然后,启动命令行控制台并将其指向文件夹 $PROJECTS/DepositAccount。 运行以下命令:

> jhipster import-jdl ./banking.jh



这将创建诸如 DepositAccountService 等可用于查询和保存存款账户数据的类。



编码 DespositAccount 微服务

 

  • 首先,我们需要与事务微服务相同的 DTO
  • 创建名为 com.azrul.ebanking.common.dto 的包,并在其中创建一个名为 Transaction 的类。回想一下,Transaction 类需要实现 Serialisable 接口,需要有一个默认构造函数,并且需要有 equals、hashCode 和 toString 方法:

No alt text provided for this image

No alt text provided for this image

  1. 卡夫卡配置
  2. Spring 使用 spring-kafka 库对 Kafka 提供了广泛的支持。这包括序列化器和反序列化器 - 这将使消息传递类型安全。另一方面,我们不会使用这些序列化器/反序列化器,因为我们将在消息到达我们自己的 Kafka 之前对其进行加密。我们将选择一个基本的字符串序列化器/反序列化器。
  3. 这是我们将用来连接到 Kafka 的 KafkaTemplate。请注意,我们使用的是一种特殊的 KafkaTemplate,称为 ReplyingKafkaTemplate。这个类将允许我们发送请求并获得响应,而无需我们自己做太多的管道
  • 我们还需要一个配置文件。在 $PROJECTS/DepositAccount/src/main/resources/config 文件夹下,在 application.yml 文件中添加:
kafka:
  bootstrap-servers: kafka-headless.default.svc.cluster.local:9092
  deposit-debit-request-topic: deposit-debit-request
  deposit-debit-response-topic: deposit-debit-response
  consumer:
    group.id: transaction
    auto.offset.reset: earliest
  producer:

 

  • 在 $PROJECTS/DepositAccount/src/main/resources/config 文件夹下,在文件 bootstrap.yml 中,在 spring.cloud 下添加以下属性。
  • 在方案中,确保我们把 https
  • 在主机中,确保我们放置自己的 Vault Kubernetes 服务的完全限定域名。回想上面的 Vault Kubernetes Service 段落
  • 在连接超时和读取超时中,设置一个合理的超时时间。我们放了一个大的进行测试。放一个小的(比如几秒钟)用于生产
  • 在认证中,输入TOKEN,表示我们将通过安全令牌登录
  • 在令牌中,确保您在之前的“为加密和解密创建令牌”段落中输入了 client_token 值。

 

    vault:
      scheme: https
      host: vault.default.svc
      port: 8200
      connection-timeout: 3600000
      read-timeout: 3600000
      authentication: TOKEN
      token: s.WuTNTDpBqsspinc6dlDN0cbz
      kv:
        enabled=true:

 

  • 接下来我们将创建一个监听器。在 com.azrul.ebanking.depositaccount.service 包中,创建一个名为 Transfer 的类,如下所示:

No alt text provided for this image

  • [完整源代码:https://github.com/azrulhasni/Ebanking-JHipster-Kafka-Vault/blob/master…]
  • 注入 VaultTemplate 允许我们解密进来的数据并加密返回的数据。
  • 注入 DespositAccountService 让我们可以查询和保存存款账户数据
  • 这是真正的听众。我们将通过输入参数从请求主题中获取我们的加密数据。我们十继续将这些数据解密到 Transaction 对象中。该对象将告诉我们要借记的源账户、要贷记的目标账户和金额。我们将继续执行该交易并计算借方和贷方账户中的结果余额。然后,我们将借记帐户余额放回消息中,并使用此编辑对象回复发布者。
  • 该方法与 Transaction 微服务中的方法相同,用于加密和对象
  • 该方法与 Transaction 微服务中的方法相同,用于解密和对象

使用 DepositAccount 微服务的自签名证书处理 SSL

 

  • 就像事务微服务一样,我们需要在这里做同样的事情
  • 我们将复制 cacerts(回想一下关于 stackoverflow 上关于 cacerts 在您的系统堆栈溢出中可用位置的讨论:https://stackoverflow.com/questions/11936685/how-to-obtain-the-location…- the-default-java-installation) 到 $PROJECTS/DepositAccounts/src/main/jib/truststore
  • 然后,我们需要通过添加以下代码来修改 main 方法(在文件 $PROJECTS/DepositAccounts/src/main/java/com/azrul/ebanking/depositaccount/DepositAccountApp.java 中):
System.setProperty("javax.net.ssl.trustStore","/truststore/cacerts");
System.setProperty("javax.net.ssl.trustStorePassword","changeit");

No alt text provided for this image

SEO Title
Secure inter-micro-service communication with Spring Boot, Kafka, Vault and Kubernetes -- Part 4 : Building micro-services