1. 概述

在这个教程中,我们将演示如何将一个Spring Boot应用与AWS Secrets Manager集成,以便获取数据库凭据和其他类型的密钥,如API密钥。

2. AWS Secrets Manager

AWS Secrets Manager 是AWS的一项服务,用于安全地存储、轮换和管理凭据,例如数据库、API密钥、令牌或任何我们想要管理的其他密钥。

我们可以将密钥分为两类:一类是专门用于数据库凭据,另一类则更为通用,适用于任何类型的密钥。

使用AWS Secrets Manager的一个好例子是为应用程序提供一组凭据或API密钥。

推荐的密钥存储格式是JSON。此外,如果要利用密钥轮换功能,必须使用 JSON结构

3. 与AWS Secrets Manager集成

AWS Secrets Manager可以轻松地与我们的Spring Boot应用集成。我们将通过AWS CLI创建密钥,然后在Spring Boot中通过简单配置来获取它们。

3.1. 密钥创建

让我们在AWS Secrets Manager中创建一个密钥。为此,我们可以使用AWS CLIaws secretsmanager create-secret命令。

在我们的案例中,我们将密钥命名为test/secret/,并创建两对API密钥——api-key1apiKeyValue1,以及api-key2apiKeyValue2:

aws secretsmanager create-secret \ 
--name test/secret/ \ 
--secret-string "{\"api-key1\":\"apiKeyValue1\",\"api-key2\":\"apiKeyValue2\"}"

作为响应,我们应该会得到创建的密钥的ARN、名称和版本ID:

{
    "ARN": "arn:aws:secretsmanager:eu-central-1:111122223333:secret:my/secret/-gLK10U",
    "Name": "test/secret/",
    "VersionId": "a04f735e-3b5f-4194-be0d-719d5386b67b"
}

3.2. Spring Boot应用集成

为了获取新创建的密钥,我们需要添加依赖[spring-cloud-starter-aws-secrets-manager-config](https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-aws-secrets-manager-config)

<dependency>
    <groupId>io.awspring.cloud</groupId>
    <artifactId>spring-cloud-starter-aws-secrets-manager-config</artifactId>
    <version>2.4.4</version>
</dependency>

接下来,我们在application.properties文件中添加一个属性:

spring.config.import=aws-secretsmanager:test/secret/

这里提供了我们刚刚创建的密钥的名称。设置完成后,我们可以在应用中使用新的密钥并验证其值。

为了做到这一点,我们可以通过@Value注解将密钥注入到应用中。在注解中,指定我们在创建密钥过程中提供的字段名称。在本例中,这些字段是api-key1api-key2

@Value("${api-key1}")
private String apiKeyValue1;

@Value("${api-key2}")
private String apiKeyValue2;

为了在示例中验证值,我们可以在bean属性初始化后的@PostConstruct方法中打印它们:

@PostConstruct
private void postConstruct() {
    System.out.println(apiKeyValue1);
    System.out.println(apiKeyValue2);
}

需要注意的是,在控制台上输出密钥值不是一个好习惯。然而,我们可以看到,当运行应用时,我们的值已正确加载:

2023-03-26 12:40:24.376  INFO 33504 [main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
apiKeyValue1
apiKeyValue2
2023-03-26 12:40:25.306  INFO 33504 [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''

4. 数据库凭据专用密钥

在AWS Secrets Manager中,有一种特殊的密钥类型用于存储数据库凭据。我们可以选择AWS支持的数据库之一,如Amazon RDS、Amazon DocumentDB或Amazon Redshift。对于非Amazon数据库,另一种可能性是提供服务器地址、数据库名称和端口。

在Spring Boot应用中使用aws-secretsmanager-jdbc库,我们可以轻松地将这些凭据提供给数据库。此外,如果在Secrets Manager中轮换凭证,由AWS提供的库会在使用旧凭据时自动检索新的凭证,当遇到认证错误时。

4.1. 数据库类型密钥创建

要在AWS Secrets Manager中创建数据库类型的密钥,我们将再次使用AWS CLI:

$ aws secretsmanager create-secret \
    --name rds/credentials \
    --secret-string file://mycredentials.json

在上述命令中,我们使用mycredentials.json文件,其中包含了我们数据库所需的所有属性:

{
  "engine": "mysql",
  "host": "cwhgvgjbpqqa.eu-central-rds.amazonaws.com",
  "username": "admin",
  "password": "password",
  "dbname": "db-1",
  "port": "3306"
}

4.2. Spring Boot应用集成

创建了密钥后,我们就可以在Spring Boot应用中使用它了。为此,我们需要添加一些依赖,如[aws-secretsmanager-jdbc](https://mvnrepository.com/artifact/com.amazonaws.secretsmanager/aws-secretsmanager-jdbc)mysql-connector-java

<dependency>
    <groupId>com.amazonaws.secretsmanager</groupId>
    <artifactId>aws-secretsmanager-jdbc</artifactId>
    <version>1.0.11</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.32</version>
</dependency>

最后,我们还需要在application.properties文件中设置一些属性:

spring.datasource.driver-class-name=com.amazonaws.secretsmanager.sql.AWSSecretsManagerMySQLDriver
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.datasource.url=jdbc-secretsmanager:mysql://db-1.cwhqvgjbpgfw.eu-central-1.rds.amazonaws.com:3306
spring.datasource.username=rds/credentials

spring.datasource.driver-class-name中,指定我们想要使用的驱动程序名称。

下一个属性是spring.jpa.database-platform,在这里提供我们的方言。

当我们设置数据库URL时(spring.datasource.url),需要在URL前加上jdbc-secretsmanager前缀,因为我们在集成AWS Secrets Manager。在这个示例中,我们的URL指向MySQL RDS实例,但也可以指向任何MySQL数据库。

spring.datasource.username中,只需提供我们在AWS Secrets Manager中设置的用户名。基于这些属性,应用会在连接数据库之前尝试从Secrets Manager获取用户名和密码。

在应用日志中,我们可以看到已成功连接到数据库,并且EntityManager已经初始化:

2023-03-26 12:40:22.648  INFO 33504 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2023-03-26 12:40:22.697  INFO 33504 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 5.6.12.Final
2023-03-26 12:40:22.845  INFO 33504 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
2023-03-26 12:40:22.951  INFO 33504 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2023-03-26 12:40:23.752  INFO 33504 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2023-03-26 12:40:23.783  INFO 33504 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
2023-03-26 12:40:24.363  INFO 33504 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2023-03-26 12:40:24.376  INFO 33504 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'

此外,我们还创建了一个简单的UserController,用于创建、读取和删除用户。

我们可以使用curl创建用户:

$ curl --location 'localhost:8080/users/' \
--header 'Content-Type: application/json' \
--data '{
    "name": "my-user-1"
}'

并得到成功的响应:

{"id":1,"name":"my-user-1"}

5. 结论

在这篇文章中,我们学习了如何将Spring Boot应用与AWS Secrets Manager集成,以及如何获取数据库凭据和其他类型的密钥。

如往常一样,示例代码可在GitHub上找到。