【问题标题】:Manage RDS access with AWS Secrets Manager使用 AWS Secrets Manager 管理 RDS 访问
【发布时间】:2018-11-20 18:04:09
【问题描述】:

我目前正在使用 Eclipse 和 AWS Toolkit for Eclipse。我的项目已经运行,它正在完成它的工作,即连接到 RDS 实例并将 JSON 对象返回给 API Gateway 调用。

我刚刚有一个新需求,我们要使用服务SecretsManager来自动轮换RDS配置,比如用户、密码等等。

问题是当我尝试导入 GetSecretValueResponse 等类时,我得到一个 The import com.amazonaws.services.secretsmanager cannot be resolved。当我浏览文档和 SDK 时,存在 GetSecretValueRequest 但不存在 GetSecretValueResponse,所以我无法理解我应该做什么,也没有找到与我可以研究的示例类似的任何东西。

以下代码是我正在尝试实现的,由 Amazon 自己提供(在 Secrets Manager 页面中有一个按钮,您可以单击以查看它在这种情况下如何与 Java 一起使用),并显示没有任何修改,因为正如我所说我不知道​​如何导入几个类:

// Use this code snippet in your app.
public static void getSecret() {
String secretName = "secretName";
String endpoint = "secretEndpoint";
String region = "region";

AwsClientBuilder.EndpointConfiguration config = new AwsClientBuilder.EndpointConfiguration(endpoint, region);
AWSSecretsManagerClientBuilder clientBuilder = AWSSecretsManagerClientBuilder.standard();
clientBuilder.setEndpointConfiguration(config);
AWSSecretsManager client = clientBuilder.build();

String secret;
ByteBuffer binarySecretData;
GetSecretValueRequest getSecretValueRequest = GetSecretValueRequest.builder()
        .withSecretId(secretName)
        .build();
GetSecretValueResponse getSecretValueResponse = null;
try {
    getSecretValueResponse = client.getSecretValue(getSecretValueRequest);

} catch(ResourceNotFoundException e) {
    System.out.println("The requested secret " + secretName + " was not found");
} catch (InvalidRequestException e) {
    System.out.println("The request was invalid due to: " + e.getMessage());
} catch (InvalidParameterException e) {
    System.out.println("The request had invalid params: " + e.getMessage());
}

if(getSecretValueResponse == null) {
    return;
}

// Decrypted secret using the associated KMS CMK
// Depending on whether the secret was a string or binary, one of these fields will be populated
if(getSecretValueResponse.getSecretString() != null) {
    secret = getSecretValueResponse.getSecretString();
}
else {
    binarySecretData = getSecretValueResponse.getSecretBinary();
}

// Your code goes here. 
}

【问题讨论】:

    标签: java amazon-web-services aws-lambda aws-sdk aws-secrets-manager


    【解决方案1】:

    我遇到了同样的问题,AWS 页面上的代码无法直接使用。您正在寻找的课程是GetSecretValueResult 这是最新的 java 文档

    https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/secretsmanager/model/GetSecretValueResult.html

    这是一个可以工作的部分:

    public void printRdsSecret() throws IOException {
        String secretName = "mySecretName";
    
        System.out.println("Requesting secret...");
        AWSSecretsManager client = AWSSecretsManagerClientBuilder.standard().build();
    
        GetSecretValueRequest getSecretValueRequest = new GetSecretValueRequest().withSecretId(secretName);
    
        GetSecretValueResult getSecretValueResult = client.getSecretValue(getSecretValueRequest);
    
        System.out.println("secret retrieved ");
        final String secretBinaryString = getSecretValueResult.getSecretString();
        final ObjectMapper objectMapper = new ObjectMapper();
    
        final HashMap<String, String> secretMap = objectMapper.readValue(secretBinaryString, HashMap.class);
    
        String url = String.format("jdbc:postgresql://%s:%s/dbName", secretMap.get("host"), secretMap.get("port"));
        System.out.println("Secret url = "+url);
        System.out.println("Secret username = "+secretMap.get("username"));
        System.out.println("Secret password = "+secretMap.get("password"));
     }
    

    这是使用 aws-java-sdk-secretsmanager 的版本 1.11.337 测试的

    【讨论】:

    • 非常感谢您的帮助@Nune Isabekyan,我昨天才发现,我不知道为什么我绊倒了这么多,但我无法解决这个问题!您的解决方案完全相同,我很高兴我并不孤单并且您分享了!
    • 我发现你对 ObjectMapper 的使用非常有趣,但不知道这个类。我使用 JSONObject 来解析它,但你的似乎更干净......
    • 很高兴它有帮助!理想情况下,您将有一个自定义类型 - 一个 Java 对象,保存您的配置,然后您会将您的配置/秘密读入对象而不是“通用”哈希图... SecretConfig user = mapper.readValue(jsonInString, SecretConfig.class );
    • 他们更新了控制台以在 SampleCode 中也显示 GetSecretValueResult
    • @committedandroider - 但它仍然将结果作为完整的 json。您仍然必须解析 json 才能获得安全字符串值。没有任何方法可以直接将秘密值提供给您。
    【解决方案2】:

    我认为主要问题是缺乏对 AWS SDK v2 的依赖。

    在此处添加使用 AWS SDK v2 的代码 sn-p。以防万一有人在寻找这个。

    package com.may.util;
    
    import software.amazon.awssdk.regions.Region;
    import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
    import software.amazon.awssdk.services.secretsmanager.model.DecryptionFailureException;
    import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest;
    import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse;
    import software.amazon.awssdk.services.secretsmanager.model.InternalServiceErrorException;
    import software.amazon.awssdk.services.secretsmanager.model.InvalidParameterException;
    import software.amazon.awssdk.services.secretsmanager.model.InvalidRequestException;
    import software.amazon.awssdk.services.secretsmanager.model.ResourceNotFoundException;
    
    public class SecretsManagerUtil {
    
        public static String obtainSecret() {
            String secretName = "db_secret_name";
            String region = "us-east-1";
    
            SecretsManagerClient client = SecretsManagerClient.builder().region(Region.of(region)).build();
            GetSecretValueResponse response = null;
    
            try {
                response = client.getSecretValue(GetSecretValueRequest.builder().secretId(secretName).build());
            } catch (DecryptionFailureException e) {
                // Secrets Manager can't decrypt the protected secret text using the provided KMS key.
                // Deal with the exception here, and/or rethrow at your discretion.
                throw e;
            } catch (InternalServiceErrorException e) {
                // An error occurred on the server side.
                // Deal with the exception here, and/or rethrow at your discretion.
                throw e;
            } catch (InvalidParameterException e) {
                // You provided an invalid value for a parameter.
                // Deal with the exception here, and/or rethrow at your discretion.
                throw e;
            } catch (InvalidRequestException e) {
                // You provided a parameter value that is not valid for the current state of the resource.
                // Deal with the exception here, and/or rethrow at your discretion.
                throw e;
            } catch (ResourceNotFoundException e) {
                // We can't find the resource that you asked for.
                // Deal with the exception here, and/or rethrow at your discretion.
                throw e;
            }
    
            return response.secretString();
        }
    }
    

    反序列化并打印秘密:

    public class SecretPrinter {
    
    private static final Logger logger = LoggerFactory.getLogger(SecretPrinter.class);
    
    public void printSecret() {
        String json = SecretsManagerUtil.obtainSecret(); // secret in json format
    
        RdsSecret secret;
        try {
            secret = new ObjectMapper().disable(FAIL_ON_UNKNOWN_PROPERTIES).readValue(json, RdsSecret.class);
        } catch (IOException e) {
            logger.error("Couldn't parse secret obtained from AWS Secrets Manager!");
            throw new RuntimeException(e);
        }
    
        System.out.println("username: " + secret.getUsername());
        System.out.println("password: " + secret.getPassword());
    }
    
    static class RdsSecret {
        private String username;
        private String password;
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    }
    

    }

    马文:

    <dependencyManagement>
      <dependencies>
        <dependency>
          <groupId>software.amazon.awssdk</groupId>
          <artifactId>bom</artifactId>
          <version>2.6.3</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>
      </dependencies>
    </dependencyManagement>
    
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>secretsmanager</artifactId>
    </dependency>
    

    分级:

    implementation platform('software.amazon.awssdk:bom:2.6.3')
    implementation 'software.amazon.awssdk:secretsmanager'
    

    【讨论】:

    • 开发者在本地运行时,代码失败是正常的,因为机器没有访问密钥所需的权限,对吧?那将是云中部署实例的生产就绪代码,它本身可以访问机密,因为链接到实例的 CodeCommit 具有必要的权限? (我目前的问题是我试图阻止开发人员在本地访问机密,但仍然能够在本地运行代码......建议的方法是什么?)
    • 在本地,GetSecretValueRequest.builder().secretId(secretName).build()software.amazon.awssdk.services.secretsmanager.model.SecretsManagerException: The security token included in the request is invalid.. 发生崩溃,但我使用的是在 AWS Secrets Manager 中创建 Secret 时给我的 code-sn-p 提供的值。
    • @payne 此代码已准备好用于生产。据我了解(我可能在某处读到过这个)AWS SDK 使用附加到每个物理实例(机器)的元数据来检查特定机器是否可以访问 SecretsManager(和特定秘密)。本地机器没有此元数据,这就是本地代码无法访问 AWS SecretsManager 的原因。这可能可以配置,但老实说我不知道​​如何配置。如果您发现这方面的一些有用信息,请在此处发表评论。
    • @payne,回复评论一。如果开发人员能够在本地运行代码,他们很可能能够在本地调试代码并在从 SecretsManager 检索后评估纯密码。
    • 刚刚在部署环境中进行了测试:正如预期的那样,它通过了我之前提到的异常,现在我们正在访问not authorized to perform: secretsmanager:GetSecretValue。谢谢你的帮助!我们将通过添加适当的权限来解决此问题。
    【解决方案3】:

    aws-secretsmanager-jdbc 可用于通过 AWS secret manager 访问 AWS RDS。 https://github.com/aws/aws-secretsmanager-jdbc

    下面是我的application.properties的内容

    spring.datasource.url=jdbc-secretsmanager:mysql://dev-xxxx-database.cluster-xxxxxxxxx.ap-southeast-1.rds.amazonaws.com:3306/dev_xxxxxx
    
    spring.datasource.username=/secret/application
    spring.datasource.driver-class-name=com.amazonaws.secretsmanager.sql.AWSSecretsManagerMySQLDriver
    
    spring.jpa.database-platform = org.hibernate.dialect.MySQL5Dialect
    

    以下是 AWS 秘密管理器中的秘密。

    使用此方法,您无需手动获取用户名和密码,无需创建数据源。

    【讨论】:

    • documentdb非sql数据库呢? aws 是否也为 documentdb 提供了类似的功能?
    【解决方案4】:

    【讨论】:

      【解决方案5】:

      我建议使用 aws secret manager jdbc wrapper 来访问 RDS (https://github.com/aws/aws-secretsmanager-jdbc)。在传递给 RDS 客户端之前,您无需处理获取秘密、解码和使用文本中的密码移动。

      只需将秘密 id 传递给 RDS 客户端,jdbc 包装器将处理其余部分。

      【讨论】:

        【解决方案6】:

        您缺少“aws-java-sdk-secretsmanager”依赖项,您必须将其添加到您的 pom.xml 中,然后导入您的 java 类。

        来自 Maven:

            <dependency>
                <groupId>com.amazonaws</groupId>
                <artifactId>aws-java-sdk-secretsmanager</artifactId>
                <version>1.11.355 </version>
            </dependency>
        

        AWS Reference

        如果你没有使用maven,你有add AWS SDK to your existing project.

        【讨论】:

          猜你喜欢
          • 2022-09-23
          • 1970-01-01
          • 2020-10-26
          • 2020-09-28
          • 2021-01-19
          • 2023-01-01
          • 2020-04-24
          • 2020-06-16
          • 2021-10-03
          相关资源
          最近更新 更多