
# 如何使用凭据管理服务替换硬编码的数据库账号密码
华为云凭据管理服务（CSMS）提供安全、高效的凭据管理，减少硬编码凭据的风险，支持多种凭据类型，如业务账号密码和数据库信息。用户可通过API安全地创建、更新和查询凭据，示例代码展示了使用Java SDK管理凭据的方法，强调了避免在代码中直接写入认证信息的重要性，建议使用环境变量或配置文件存储敏感信息。
华为云凭据管理服务（Cloud Secret Management Service，CSMS）可以帮助您拥有以下优势：
- 通过凭据托管功能，降低通过硬编码方式带来的凭据泄露风险，提高数据及资产的安全性。
- 减少对业务的影响：当您进行[人工轮换](https://support.huaweicloud.com/bestpractice-dew/dew_06_0015.html)的方式更新凭据时，您的业务不会受到影响。
- 提供安全的SDK接入方式，动态调用您的凭据。
- 凭据存储类型多样化。您不仅可以存储业务相关的账号密码，也可以存储业务数据库详细信息，包括但不限于：数据库名称、IP地址和端口等。
#### 使用凭据登录数据库
下文为您介绍如何创建凭据，并且通过API调用凭据来登录到您的数据库。
您首先需要确保您的账号拥有KMS Administrator或者KMS CMKFullAccess权限，详情见[DEW权限管理](https://support.huaweicloud.com/productdesc-dew/dew_01_0018.html)。
图1凭据登录流程   
![](https://support.huaweicloud.com/bestpractice-dew/zh-cn_image_0000001260617431.png "点击放大")
流程说明如下：
1. 您首先需要在凭据管理服务中使用[控制台](https://support.huaweicloud.com/usermanual-dew/dew_01_9993.html)或者[API]创建一个凭据，用来存储数据库的相关信息（例如：数据库地址、端口、密码）。
2. 当您使用应用程序访问数据库时，凭据管理服务会去查询[步骤1]所创建的凭据存储的内容。
3. 凭据管理服务检索并解密凭据密文，将凭据中保存的信息通过凭据管理API安全地返回到应用程序中。
4. 应用程序获取到解密后的凭据明文信息，使用这些安全的信息访问数据库。
 
 #### 创建凭据和查询凭据API
您可以调用以下API，通过API创建凭据保存相关内容并且查询相关凭据信息。
| API名称                                                             | 说明                     |
|:---|:---|
| [创建凭据](https://support.huaweicloud.com/api-dew/CreateSecret.html) | 创建新的凭据，并且将凭据值存入凭据的初始版本 |
| [查询凭据](https://support.huaweicloud.com/api-dew/ShowSecret.html)   | 查询指定凭据的信息              |
   
 #### 通过API接口创建凭据和查询凭据
1. 请准备基础认证信息：
   - ACCESS_KEY：华为账号Access Key
   
   - SECRET_ACCESS_KEY：华为账号Secret Access Key
   
   - PROJECT_ID：华为云局点项目ID，请参见[华为云局点项目](https://support.huaweicloud.com/api-iam/iam_17_0002.html)。
   
   - CSMS_ENDPOINT：华为云CSMS服务访问终端地址。
   
   - SECURITY_TOKEN：可选，采用临时 AK\&SK 认证场景下的必选。
   
   - 认证用的AK和SK直接写到代码中有很大的安全风险，建议在配置文件或者环境变量中密文存放，使用时解密，确保安全。
   
   - 本示例以AK和SK保存在环境变量中来实现身份验证为例，运行本示例前请先在本地环境中设置环境变量HUAWEICLOUD_SDK_AK和HUAWEICLOUD_SDK_SK。
    
2. 创建和查询凭据信息： 凭据名称：secretName
   凭据值：secretString
   凭据版本值：LATEST_SECRET
   凭据版本：versionId
   ```
   import com.huaweicloud.sdk.core.auth.BasicCredentials;
   import com.huaweicloud.sdk.csms.v1.CsmsClient;
   import com.huaweicloud.sdk.csms.v1.model.CreateSecretRequest;
   import com.huaweicloud.sdk.csms.v1.model.CreateSecretRequestBody;
   import com.huaweicloud.sdk.csms.v1.model.CreateSecretResponse;
   import com.huaweicloud.sdk.csms.v1.model.ShowSecretVersionRequest;
   import com.huaweicloud.sdk.csms.v1.model.ShowSecretVersionResponse;
   public class CsmsCreateSecretExample {
       /**
        * 基础认证信息：
        * - ACCESS_KEY: 华为账号Access Key
        * - SECRET_ACCESS_KEY: 华为账号Secret Access Key
        * - PROJECT_ID: 华为云局点项目ID 详情见https://support.huaweicloud.com/productdesc-iam/iam_01_0023.html
        * - CSMS_ENDPOINT: 华为云CSMS服务访问终端地址 详情见https://support.huaweicloud.com/api-dew/dew_02_0052.html
        * - SECURITY_TOKEN: 临时token，注意临时token存在有效期，示例仅做演示使用。
        * - 认证用的ak和sk直接写到代码中有很大的安全风险，建议在配置文件或者环境变量中密文存放，使用时解密，确保安全。
        * - 本示例以ak和sk保存在环境变量中来实现身份验证为例，运行本示例前请先在本地环境中设置环境变量HUAWEICLOUD_SDK_AK和HUAWEICLOUD_SDK_SK。
        */
       private static final String ACCESS_KEY = System.getenv("HUAWEICLOUD_SDK_AK");
       private static final String SECRET_ACCESS_KEY = System.getenv("HUAWEICLOUD_SDK_SK");
       private static final String PROJECT_ID = "<ProjectID>";
       private static final String CSMS_ENDPOINT = "<CsmsEndpoint>";
       private static final String SECURITY_TOKEN = "<SecurityToken>";
       // 用来查询凭据最新版本详情的版本Id
       private static final String LATEST_SECRET = "latest";
       public static void main(String[] args) {
           String secretName = args[0];
           String secretString = args[1];
           // 创建凭据
           createSecret(secretName, secretString);
           // 通过凭据版本值“latest”或者版本值“v1"查询到新创建的凭据内容
           ShowSecretVersionResponse latestVersion = showSecretVersion(secretName, LATEST_SECRET);
           ShowSecretVersionResponse firstVersion = showSecretVersion(secretName, "v1");
           assert latestVersion.equals(firstVersion);
           assert latestVersion.getVersion().getSecretString().equalsIgnoreCase(secretString);
       }
       /**
        * 创建凭据
        * @param secretName
        * @param secretString
        */
       private static void createSecret(String secretName, String secretString) {
           CreateSecretRequest secret = new CreateSecretRequest().withBody(
                   new CreateSecretRequestBody().withName(secretName).withSecretString(secretString));
           CsmsClient csmsClient = getCsmsClient();
           CreateSecretResponse createdSecret = csmsClient.createSecret(secret);
           System.out.printf("Created secret success, secret detail:%s", createdSecret);
       }
       /**
        * 根据凭据版本id查询凭据版本详情
        * @param secretName
        * @param versionId
        * @return
        */
       private static ShowSecretVersionResponse showSecretVersion(String secretName, String versionId) {
           ShowSecretVersionRequest showSecretVersionRequest = new ShowSecretVersionRequest().withSecretName(secretName)
                   .withVersionId(versionId);
           CsmsClient csmsClient = getCsmsClient();
           ShowSecretVersionResponse version = csmsClient.showSecretVersion(showSecretVersionRequest);
           System.out.printf("Query secret success. version id:%s", version.getVersion().getVersionMetadata().getId());
           return version;
       }
       /**
        * 通过临时AK&SK获取CSMS服务客户端
        * @return
        */
       private static CsmsClient getCsmsClientWithStsToken() {
           BasicCredentials auth = new BasicCredentials()
                   .withAk(ACCESS_KEY)
                   .withSk(SECRET_ACCESS_KEY)
                   .withSecurityToken(SECURITY_TOKEN)
                   .withProjectId(PROJECT_ID);
           return CsmsClient.newBuilder().withCredential(auth).withEndpoint(CSMS_ENDPOINT).build();
       }
       /**
        * 通过永久AK&SK获取CSMS服务客户端
        * @return
        */
       private static CsmsClient getCsmsClient() {
           BasicCredentials auth = new BasicCredentials()
                   .withAk(ACCESS_KEY)
                   .withSk(SECRET_ACCESS_KEY)
                   .withProjectId(PROJECT_ID);
           return CsmsClient.newBuilder().withCredential(auth).withEndpoint(CSMS_ENDPOINT).build();
       }
   }
   ```
   
 
#### 使用应用程序获取数据库账号和密码
1. 获取凭据管理服务的CSMS SDK的依赖声明。 示例如下：
   ```
   <dependency>
               <groupId>mysql</groupId>
               <artifactId>mysql-connector-java</artifactId>
               <version>XXX</version>
           </dependency>
           <dependency>
               <groupId>com.google.code.gson</groupId>
               <artifactId>gson</artifactId>
               <version>2.8.9</version>
           </dependency>
           <dependency>
               <groupId>com.huaweicloud.sdk</groupId>
               <artifactId>huaweicloud-sdk-csms</artifactId>
               <version>3.0.79</version>
           </dependency>
   ```
   
2. 建立数据库链接并且获取账号密码：
   示例代码如下
   ```
   import com.google.gson.Gson;
   import com.google.gson.JsonObject;
   import com.huaweicloud.sdk.csms.v1.model.ShowSecretVersionRequest;
   import com.huaweicloud.sdk.csms.v1.model.ShowSecretVersionResponse;
   import java.sql.Connection;
   import java.sql.DriverManager;
   import java.sql.SQLException;
    // 通过凭据信息获取指定的数据库账号和口令
       public static Connection getMySQLConnectionBySecret(String secretName, String jdbcUrl) throws ClassNotFoundException, SQLException{
           Class.forName(MYSQL_JDBC_DRIVER);
           ShowSecretVersionResponse latestVersionValue = getCsmsClient().showSecretVersion(new ShowSecretVersionRequest().withSecretName(secretName).withVersionId("latest"));
           String secretString = latestVersionValue.getVersion().getSecretString();
           JsonObject jsonObject = new Gson().fromJson(secretString, JsonObject.class);
           return DriverManager.getConnection(jdbcUrl, jsonObject.get("username").getAsString(), jsonObject.get("password").getAsString());
       }
   ```
   
 
