使用 S AWS ecrets Manager 管理证书 - AWS Prescriptive Guidance

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

使用 S AWS ecrets Manager 管理证书

由 Durga Prasad Cheepuri 创作 () AWS

创建者:AWS

环境:PoC 或试点

技术:数据库;安全、身份、合规性

AWS服务:S AWS ecr ets Manager

Summary

此模式将引导你使用 S AWS ecrets Manager 动态获取 Java Spring 应用程序的数据库凭据。

过去,当您创建自定义应用程序以从数据库中检索信息时,通常必须在应用程序中直接嵌入访问数据库所需凭证(密钥)。当需要轮换凭证时,您必须投入时间更新应用程序以使用新的凭证,然后分配更新后的应用程序。如果您有多个应用程序共享凭证,而您错过更新其中一个,则该应用程序将会失效。为应对此类风险,许多用户选择不定期轮换凭证,然而,这种行为实际上会带来新的风险。

Secrets Manager 允许您将代码中的硬编码凭据(包括密码)替换为以编程方式检索密钥的API调用。这有助于确保检查者不会泄露密钥,因为代码中根本不包含密钥。此外,您还可以配置 Secrets Manager 根据您指定的计划自动轮换密钥。这样,您就可以将长期密钥替换为短期密钥,从而显著降低泄露风险。有关更多信息,请参阅 S AWSecrets Manager 文档

先决条件和限制

先决条件

  • 有权访问 Secrets Manager 的AWS账户

  • Java Spring 应用程序

架构

源技术堆栈

  • Java Spring 应用程序,其中包含访问数据库的代码,其数据库凭证由 application.properties 文件管理。

目标技术堆栈

  • Java Spring 应用程序,其中包含访问数据库的代码,其数据库凭证在 Secrets Manager 中管理。application.properties 文件负责保存 Secrets Manager 的密钥。

Secrets Manager 与应用程序集成

Diagram showing AWS Secrets Manager interaction with admin, custom app, and personnel database.

工具

  • S@@ ecrets M anager — S AWS ecrets Manager 是一项可以让你更轻松地管理密钥的AWS服务。密钥可以是数据库凭证、密码、第三方API密钥,甚至是任意文本。你可以使用 Secrets Manager 控制台、Secrets Manager 命令行界面 (CLI) 或 Secrets Manager 和,集中存储和控制对这些密钥的访问。API SDKs

操作说明

任务描述所需技能
将数据库凭证作为密钥存储在 Secrets Manager 中。

按照 Secrets Manager 文档中创建密钥中的步骤将亚马逊关系数据库服务 (AmazonRDS) 或其他数据库凭证作为密钥存储在 Secrets Manager 中。

系统管理员
为 Spring 应用程序设置访问 Secrets Manager 的权限。

根据 Java Spring 应用程序使用 Secrets Manager 的方式设置相应权限。要控制对密钥的访问,请根据 Secrets Manager 文档中提供的信息,在 “使用基于身份的策略(IAM策略)”、“ABAC适用于 Secrets Manager” 和 “为 Secrets Manager 使用基于资源的策略” 部分中提供的信息创建策略。按照 Secrets Manager 文档中检索密钥值部分所述的步骤进行操作。

系统管理员
任务描述所需技能
添加JAR依赖项以使用 Secrets Manager。

有关详细信息,请参阅其他信息部分。

Java 开发人员
将密钥的详细信息添加到 Spring 应用程序。

使用密钥名称、端点和AWS区域更新应用程序.properties 文件。有关示例,请参阅其他信息部分。

Java 开发人员
在 Java 中更新数据库凭证检索代码。

在应用程序中,更新获取数据库凭证的 Java 代码,以从 Secrets Manager 获取这些详细信息。有关示例代码,请参阅其他信息部分。

Java 开发人员

相关资源

其他信息

为使用 Secrets Manager 添加JAR依赖项

Maven:

<groupId>com.amazonaws</groupId>     <artifactId>aws-java-sdk-secretsmanager</artifactId>     <version>1.11. 355 </version>

Gradle:

compile group: 'com.amazonaws', name: 'aws-java-sdk-secretsmanager', version: '1.11.355'

使用密钥的详细信息更新 application.properties 文件

spring.aws.secretsmanager.secretName=postgres-local spring.aws.secretsmanager.endpoint=secretsmanager.us-east-1.amazonaws.com spring.aws.secretsmanager.region=us-east-1

在 Java 中更新数据库凭证检索代码

String  secretName  =  env.getProperty("spring.aws.secretsmanager.secretName"); String  endpoints  =  env.getProperty("spring.aws.secretsmanager.endpoint"); String  AWS Region  =  env.getProperty("spring.aws.secretsmanager.region"); AwsClientBuilder.EndpointConfiguration  config  =  new  AwsClientBuilder.EndpointConfiguration(endpoints, AWS Region); AWSSecretsManagerClientBuilder  clientBuilder  =  AWSSecretsManagerClientBuilder.standard(); clientBuilder.setEndpointConfiguration(config); AWSSecretsManager  client  =  clientBuilder.build();        ObjectMapper  objectMapper  =  new  ObjectMapper();   JsonNode  secretsJson  =  null;   ByteBuffer  binarySecretData;   GetSecretValueRequest  getSecretValueRequest  =  new  GetSecretValueRequest().withSecretId(secretName);    GetSecretValueResult  getSecretValueResponse  =  null;   try  {      getSecretValueResponse  =  client.getSecretValue(getSecretValueRequest);     }   catch  (ResourceNotFoundException  e)  {      log.error("The requested secret "  +  secretName  +  " was not found");     }      catch  (InvalidRequestException  e)  {          log.error("The request was invalid due to: "  +  e.getMessage());      }      catch  (InvalidParameterException  e)  {          log.error("The request had invalid params: "  +  e.getMessage());      } if  (getSecretValueResponse  ==  null)  {          return  null;      }  // Decrypted secret using the associated KMS key // Depending on whether the secret was a string or binary, one of these fields will be populated               String secret = getSecretValueResponse.getSecretString();     if (secret != null) {        try {                         secretsJson  =  objectMapper.readTree(secret);                }           catch  (IOException  e)  {                         log.error("Exception while retrieving secret values: "  +  e.getMessage());                } }      else  {          log.error("The Secret String returned is null");          return null;              }      String  host  =  secretsJson.get("host").textValue();      String  port  =  secretsJson.get("port").textValue();      String  dbname  =  secretsJson.get("dbname").textValue();      String  username  =  secretsJson.get("username").textValue();      String  password  =  secretsJson.get("password").textValue(); }