使用 AWS 秘密管理員來管理登入 - AWS 方案指引

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

使用 AWS 秘密管理員來管理登入

創建者杜爾加普拉薩德奇普里(AWS)

創建者:AWS

環境:PoC 或試點

技術:資料庫;安全性、身分識別、合規性

AWS 服務:AWS Secrets Manager

Summary

此模式會引導您完成使用 AWS Secrets Manager 動態擷取 Java Spring 應用程式的資料庫登入資料。

以往當您建立從資料庫擷取資訊的自訂應用程式時,通常必須內嵌登入資料 (秘密),才可直接存取應用程式中的資料庫。輪換憑證的時候,您必須投入時間來更新應用程式以使用新的認證,然後散發更新的應用程式。如果您有多個共享憑據的應用程序,並且錯過了更新其中一個應用程序,則該應用程序將失敗。由於這種風險,許多使用者選擇不定期輪換其憑證,這有效地取代了另一種風險。

Secrets Manager 可讓您以 API 呼叫取代程式碼中的硬式編碼認證 (包括密碼),以程式設計方式擷取密碼。這有助於確保秘密不會被正在檢查您的代碼的人入侵,因為秘密根本不存在。您也可以將 Secret Manager 設定為根據您指定的排程自動輪換密碼。這可讓您以短期密碼取代長期機密,這有助於大幅降低入侵的風險。如需詳細資訊,請參閱 AWS Secrets Manager 文件

先決條件和限制

先決條件

  • 可存取 Secrets Manager 的 AWS 帳戶

  • 一個 Java 春季應用程序

架構

源, 技術, 堆棧

  • 一個 Java Spring 應用程序與訪問數據庫的代碼,從應用程序 .properties 文件管理數據庫憑據。

目標技術堆疊

  • 一個 Java Spring 應用程序與訪問數據庫的代碼,在秘密管理器管理數據庫憑據管理。應用程式 .properties 檔案會保存秘密 Secrets Manager 碼。

Secrets Manager 與應用程序集成

工具

  • Secrets ManagerAWS Secrets Manager 是一項 AWS 服務,可讓您更輕鬆地管理機密。秘密可能是資料庫憑證、密碼、第三方 API 金鑰,甚至是任意文字。您可以使用秘密管理員主控台、秘密管 Secrets Manager 命令列介面 (CLI) 或機 Secrets Manager API 和 SDK,集中儲存和控制這些機 Secrets Manager 的存取。

史诗

任務描述所需技能
將數據庫憑據存儲為秘密管理器中的秘密。

按照秘密管理員文件中的建立密碼中的步驟,在 Secrets Manager 中將 Amazon Relational Database Service 服務 (Amazon RDS) 或其他資料庫登入資料存放為秘 Secrets Manager。

系統管理員
設置 Spring 應用程序訪問 Secrets Manager 的權限。

根據 Java Spring 應用程序使用 Secrets Manager 的方式設置適當的權限。若要控制密碼的存取權,請根據 Secrets Manager 文件中提供的資訊建立政策,請參閱 < 針對秘密管理員使用身分型政策 (IAM 政策) 和 ABAC 以及針對 Secrets Manager 使用以資源為基礎的政策 > 一節中所提供的資訊建立政策。請依照秘密管理員說明文件中擷取密碼值一節中的步驟進行。

系統管理員
任務描述所需技能
新增 JAR 相依性以使用 Secrets Manager。

如需詳細資訊,請參閱其他資訊一節。

Java 開發人員
將秘密的詳細信息添加到 Spring 應用程序中。

使用密碼名稱、端點和 AWS 區域更新應用程式 .properties 檔案。如需範例,請參閱其他資訊一節。

Java 開發人員
在 Java 中更新數據庫憑據檢索代碼。

在應用程式中,更新擷取資料庫認證的 Java 程式碼,以便從 Secrets Manager 擷取這些詳細資料。如需範例程式碼,請參閱「其他資訊」一節。

Java 開發人員

相關資源

其他資訊

新增 JAR 相依性以使用 Secrets Manager

釋界:

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

搖籃:

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

使用密碼的詳細信息更新應用程序 .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(); }