使用 AWS Secrets Manager 管理登入資料 - AWS Prescriptive Guidance

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

使用 AWS Secrets Manager 管理登入資料

由杜爾加·普拉薩德·奇普里創作 (AWS)

建立者:AWS

環境:PoC 或試驗

技術:資料庫;安全、身份、合規

AWS 服務:AWS Secrets Manager

Summary

這種模式會引導您使用 AWS Secrets Manager 來動態獲取 Java Spring 應用程序的數據庫憑據。

以往當您建立從資料庫擷取資訊的自訂應用程式時,通常必須內嵌登入資料 (秘密),才可直接存取應用程式中的資料庫。到了輪換登入資料的時間時,您必須花時間將應用程式更新為使用新的登入資料,然後散發更新的應用程式。如果您有多個共用登入資料的應用程式,而您遺漏其中一個的更新,則該應用程式會失敗。因為有此風險,許多使用者選擇不要定期輪換登入資料,但這實際上只是換湯不換藥,風險仍在。

Secrets Manager 可讓您將程式碼中硬式編碼的登入資料 (包括密碼),改成以程式設計方法擷取秘密。這有助於確保您的秘密不會因檢查您的程式碼的人而洩漏,因為秘密根本不在程式碼中。您也可以設定 Secrets Manager,根據您指定的排程自動輪換秘密。這可讓您以短期秘密取代長期秘密,有助於大幅降低洩漏風險。如需詳細資訊,請參閲 。AWS Secrets Manager 文件

先決條件和限制

先決條件

  • 可存取 Secrets Manager 的 AWS 帳戶

  • 一個 Java 彈簧應用程序

Architecture

來源技術堆疊

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

目標技術堆疊

  • Java Spring 應用程序與訪問數據庫的代碼,並在秘密管理器中管理數據庫憑據。應用程序 .properties 文件保存秘密管理器的秘密。

Secrets Manager 與應用程序集成

Tools

  • Secrets ManagerAWS Secrets Manager是可讓您輕鬆管理秘密的 AWS 服務。秘密可能是資料庫登入資料、密碼、第三方 API 金鑰,甚至是任意文字。您可以使用 Secrets Manager 主控台、Secrets Manager 命令列界面 (CLI) 或 Secrets Manager API 和軟體開發套件,以集中存放和控管對這些秘密的存取權。

Epics

任務描述所需技能
將 DB 登入資料存放為 Secrets Manager 中的秘密。

將 Amazon Secrets Manager 中的秘密存放為 Secrets Manager 中的秘密,請遵循建立私密在 Secrets Manager 文檔中。

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

根據 Java Spring 應用程序如何使用 Secrets Manager 設置適當的權限。若要控制密碼的存取權,請根據「Secrets Manager」文件中提供的資訊建立原則,針對 Secrets Manager 使用以身分為基礎的政策 (IAM 政策) 和 ABAC對 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'

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