

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

# 使用 AWS Secrets Manager 管理登入資料
<a name="manage-credentials-using-aws-secrets-manager"></a>

*Durga Prasad Cheepuri，Amazon Web Services*

## 總結
<a name="manage-credentials-using-aws-secrets-manager-summary"></a>

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

以往當您建立從資料庫擷取資訊的自訂應用程式時，通常必須內嵌登入資料 (秘密)，才可直接存取應用程式中的資料庫。輪換登入資料時，您必須花時間更新應用程式以使用新的登入資料，然後分發更新的應用程式。如果您有多個共用登入資料的應用程式，且您遺漏更新其中一個，則應用程式會失敗。由於這種風險，許多使用者選擇不定期輪換其登入資料，這實際上取代了另一個登入資料的風險。

Secrets Manager 可讓您將程式碼中的硬式編碼登入資料 （包括密碼） 取代為 API 呼叫，以程式設計方式擷取秘密。這有助於確保檢查程式碼的人員不會洩露秘密，因為秘密根本不存在。您也可以設定 Secrets Manager 根據您指定的排程自動輪換秘密。這可讓您將長期秘密取代為短期秘密，這有助於大幅降低入侵的風險。如需詳細資訊，請參閱 [AWS Secrets Manager 文件](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html)。

## 先決條件和限制
<a name="manage-credentials-using-aws-secrets-manager-prereqs"></a>

**先決條件**
+ 可存取 Secrets Manager 的 AWS 帳戶
+ Java Spring 應用程式

## Architecture
<a name="manage-credentials-using-aws-secrets-manager-architecture"></a>

**來源技術堆疊**
+ 具有存取資料庫之程式碼的 Java Spring 應用程式，具有從 application.properties 檔案管理的資料庫登入資料。

**目標技術堆疊 **
+ Java Spring 應用程式具有存取資料庫的程式碼，並在 Secrets Manager 中管理資料庫登入資料。application.properties 檔案會將秘密保留給 Secrets Manager。

**Secrets Manager 與應用程式的整合**

![Diagram showing AWS Secrets Manager interaction with an admin, custom app, and personnel database.](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/patterns/images/pattern-img/44d359f5-47d9-4228-ac14-a64b5dfa7972/images/fc4b44fd-d1bd-4564-9bc1-c42c896e305b.png)


## 工具
<a name="manage-credentials-using-aws-secrets-manager-tools"></a>
+ **Secrets Manager** – [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) 是一種 AWS 服務，可讓您更輕鬆地管理秘密。秘密可能是資料庫憑證、密碼、第三方 API 金鑰，甚至是任意文字。您可以使用 Secrets Manager 主控台、Secrets Manager 命令列界面 (CLI) 或 Secrets Manager API 和 SDKs存取。

## 史詩
<a name="manage-credentials-using-aws-secrets-manager-epics"></a>

### 在 Secrets Manager 中存放秘密
<a name="store-secret-in-secrets-manager"></a>


| 任務 | Description | 所需的技能 | 
| --- | --- | --- | 
| 將資料庫登入資料儲存為 Secrets Manager 中的秘密。 | 遵循 Secrets Manager 文件中建立秘密的步驟，將 Amazon Relational Database Service (Amazon RDS) 或其他資料庫憑證儲存為 Secrets Manager 中的秘密。 [https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_create-basic-secret.html](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_create-basic-secret.html) | 系統管理員 | 
| 設定 Spring 應用程式存取 Secrets Manager 的許可。 | 根據 Java Spring 應用程式如何使用 Secrets Manager 來設定適當的許可。若要控制對秘密的存取，請根據 Secrets Manager 文件所提供的資訊建立政策，請參閱[使用身分型政策 (IAM 政策） 和 ABAC for Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/auth-and-access_identity-based-policies.html) 和[使用資源型政策 for Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/auth-and-access_resource-based-policies.html) 一節。請遵循 Secrets Manager 文件中[擷取秘密值](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_retrieve-secret.html)一節中的步驟。 | 系統管理員 | 

### 更新 Spring 應用程式
<a name="update-the-spring-application"></a>


| 任務 | Description | 所需的技能 | 
| --- | --- | --- | 
| 新增 JAR 相依性以使用 Secrets Manager。 | 如需詳細資訊，請參閱*其他資訊*一節。 | Java 開發人員 | 
| 將秘密的詳細資訊新增至 Spring 應用程式。 | 使用秘密名稱、端點和 AWS 區域更新 application.properties 檔案。如需範例，請參閱*其他資訊*一節。 | Java 開發人員 | 
| 在 Java 中更新資料庫登入資料擷取程式碼。 | 在應用程式中，更新擷取資料庫登入資料的 Java 程式碼，以從 Secrets Manager 擷取這些詳細資訊。如需範例程式碼，請參閱*其他資訊*一節。 | Java 開發人員 | 

## 相關資源
<a name="manage-credentials-using-aws-secrets-manager-resources"></a>
+ [AWS Secrets Manager 文件](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html)
+ [針對 Secrets Manager 使用身分型政策 (IAM 政策） 和 ABAC](https://docs.aws.amazon.com/secretsmanager/latest/userguide/auth-and-access_identity-based-policies.html)
+ [針對 Secrets Manager 使用資源型政策](https://docs.aws.amazon.com/secretsmanager/latest/userguide/auth-and-access_resource-based-policies.html)
+ [範例程式碼](https://github.com/durgachamz/Spring-secrets-manager) 

## 其他資訊
<a name="manage-credentials-using-aws-secrets-manager-additional"></a>

**新增使用 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();
}
```