本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
使用 IAM 进行身份验证
概述
使用 IAM 身份验证,您可以在集群配置为使用 Valkey 或 Redis OSS 版本 7 或更高版本时,使用 AWS IAM 身份对 MemoryDB 的连接进行验证。这使您可以增强安全模型并简化许多管理安全任务。通过 IAM 身份验证,您可以为每个单独的 MemoryDB 集群和 MemoryDB 用户配置精细的访问控制,并遵循最低权限权限原则。MemoryDB 的 IAM 身份验证的工作原理是在 AUTH
或 HELLO
命令中提供有效期很短的 IAM 身份验证令牌,而不是有效期很长的 MemoryDB 用户密码。有关 IAM 身份验证令牌的更多信息,请参阅《AWS 一般参考指南》中的 Signature Version 4 签名流程和下面的代码示例。
您可以使用 IAM 身份及其关联策略进一步限制 Valkey 或 Redis OSS 访问权限。您还可以直接向来自联合身份提供商的用户授予对 MemoryDB 集群的访问权限。
要将 AWS IAM 与 MemoryDB 一起使用,您首先需要创建身份验证模式设置为 IAM 的 MemoryDB 用户,然后创建或重用 IAM 身份。IAM 身份需要关联策略才能向 MemoryDB 集群和 MemoryDB 用户授予 memorydb:Connect
操作权限。配置完成后,您可以使用 IAM 用户或角色的 AWS 凭证创建 IAM 身份验证令牌。最后,在连接到 MemoryDB 集群节点时,您需要在 Valkey 或 Redis OSS 客户端中提供有效期较短的 IAM 身份验证令牌作为密码。支持凭证提供程序的客户端可以为每个新连接自动生成临时凭证。MemoryDB 将对启用 IAM 的 MemoryDB 用户的连接请求执行 IAM 身份验证,并将通过 IAM 验证连接请求。
限制
使用 IAM 身份验证时,以下限制适用:
使用 Valkey 或 Redis OSS 引擎版本 7.0 或更高版本时,IAM 身份验证可用。
IAM 身份验证令牌的有效期为 15 分钟。对于长时间的连接,建议使用支持凭证提供程序接口的 Redis OSS 客户端。
经过 IAM 身份验证的 MemoryDB 连接将在 12 小时后自动断开。通过使用新 IAM 身份验证令牌发送
AUTH
或HELLO
命令,可以将连接延长 12 小时。MULTI EXEC
命令不支持 IAM 身份验证。目前,IAM 身份验证并不支持所有的全局条件上下文键。有关全局条件上下文键的更多信息,请参阅《IAM 用户指南》中的 AWS 全局条件上下文键。
设置
要设置 IAM 身份验证,请执行以下操作:
创建集群
aws memorydb create-cluster \ --cluster-name cluster-01 \ --description "MemoryDB IAM auth application" --node-type db.r6g.large \ --engine-version 7.0 \ --acl-name open-access
为您的角色创建 IAM 信任政策文档,如下所示,允许您的账户承担新角色。将策略保存到名为 trust-policy.json 的文件中。
{ "Version": "2012-10-17", "Statement": { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::123456789012:root" }, "Action": "sts:AssumeRole" } }
创建 IAM 策略文档,如下所示。将策略保存到名为 policy.json 的文件中。
{ "Version": "2012-10-17", "Statement": [ { "Effect" : "Allow", "Action" : [ "memorydb:connect" ], "Resource" : [ "arn:aws:memorydb:us-east-1:123456789012:cluster/cluster-01", "arn:aws:memorydb:us-east-1:123456789012:user/iam-user-01" ] } ] }
创建一个 IAM 角色。
aws iam create-role \ --role-name "memorydb-iam-auth-app" \ --assume-role-policy-document file://trust-policy.json
创建 IAM 策略。
aws iam create-policy \ --policy-name "memorydb-allow-all" \ --policy-document file://policy.json
向角色附加 IAM 策略。
aws iam attach-role-policy \ --role-name "memorydb-iam-auth-app" \ --policy-arn "arn:aws:iam::123456789012:policy/memorydb-allow-all"
创建启用 IAM 的新用户。
aws memorydb create-user \ --user-name iam-user-01 \ --authentication-mode Type=iam \ --access-string "on ~* +@all"
创建 ACL 并附加用户。
aws memorydb create-acl \ --acl-name iam-acl-01 \ --user-names iam-user-01 aws memorydb update-cluster \ --cluster-name cluster-01 \ --acl-name iam-acl-01
连接
使用令牌作为密码进行连接
您首先需要使用 AWS SigV4 预签名请求生成有效期较短的 IAM 身份验证令牌。之后,您需要在连接到 MemoryDB 集群时提供 IAM 身份验证令牌作为密码,如下例所示。
String userName = "insert user name" String clusterName = "insert cluster name" String region = "insert region" // Create a default AWS Credentials provider. // This will look for AWS credentials defined in environment variables or system properties. AWSCredentialsProvider awsCredentialsProvider = new DefaultAWSCredentialsProviderChain(); // Create an IAM authentication token request and signed it using the AWS credentials. // The pre-signed request URL is used as an IAM authentication token for MemoryDB. IAMAuthTokenRequest iamAuthTokenRequest = new IAMAuthTokenRequest(userName, clusterName, region); String iamAuthToken = iamAuthTokenRequest.toSignedRequestUri(awsCredentialsProvider.getCredentials()); // Construct URL with IAM Auth credentials provider RedisURI redisURI = RedisURI.builder() .withHost(host) .withPort(port) .withSsl(ssl) .withAuthentication(userName, iamAuthToken) .build(); // Create a new Lettuce client RedisClusterClient client = RedisClusterClient.create(redisURI); client.connect();
以下为 IAMAuthTokenRequest
的定义。
public class IAMAuthTokenRequest { private static final HttpMethodName REQUEST_METHOD = HttpMethodName.GET; private static final String REQUEST_PROTOCOL = "http://"; private static final String PARAM_ACTION = "Action"; private static final String PARAM_USER = "User"; private static final String ACTION_NAME = "connect"; private static final String SERVICE_NAME = "memorydb"; private static final long TOKEN_EXPIRY_SECONDS = 900; private final String userName; private final String clusterName; private final String region; public IAMAuthTokenRequest(String userName, String clusterName, String region) { this.userName = userName; this.clusterName = clusterName; this.region = region; } public String toSignedRequestUri(AWSCredentials credentials) throws URISyntaxException { Request<Void> request = getSignableRequest(); sign(request, credentials); return new URIBuilder(request.getEndpoint()) .addParameters(toNamedValuePair(request.getParameters())) .build() .toString() .replace(REQUEST_PROTOCOL, ""); } private <T> Request<T> getSignableRequest() { Request<T> request = new DefaultRequest<>(SERVICE_NAME); request.setHttpMethod(REQUEST_METHOD); request.setEndpoint(getRequestUri()); request.addParameters(PARAM_ACTION, Collections.singletonList(ACTION_NAME)); request.addParameters(PARAM_USER, Collections.singletonList(userName)); return request; } private URI getRequestUri() { return URI.create(String.format("%s%s/", REQUEST_PROTOCOL, clusterName)); } private <T> void sign(SignableRequest<T> request, AWSCredentials credentials) { AWS4Signer signer = new AWS4Signer(); signer.setRegionName(region); signer.setServiceName(SERVICE_NAME); DateTime dateTime = DateTime.now(); dateTime = dateTime.plus(Duration.standardSeconds(TOKEN_EXPIRY_SECONDS)); signer.presignRequest(request, credentials, dateTime.toDate()); } private static List<NameValuePair> toNamedValuePair(Map<String, List<String>> in) { return in.entrySet().stream() .map(e -> new BasicNameValuePair(e.getKey(), e.getValue().get(0))) .collect(Collectors.toList()); } }
使用凭证提供程序进行连接
以下代码显示了如何使用 IAM 身份验证凭证提供程序通过 MemoryDB 进行身份验证。
String userName = "insert user name" String clusterName = "insert cluster name" String region = "insert region" // Create a default AWS Credentials provider. // This will look for AWS credentials defined in environment variables or system properties. AWSCredentialsProvider awsCredentialsProvider = new DefaultAWSCredentialsProviderChain(); // Create an IAM authentication token request. Once this request is signed it can be used as an // IAM authentication token for MemoryDB. IAMAuthTokenRequest iamAuthTokenRequest = new IAMAuthTokenRequest(userName, clusterName, region); // Create a credentials provider using IAM credentials. RedisCredentialsProvider redisCredentialsProvider = new RedisIAMAuthCredentialsProvider( userName, iamAuthTokenRequest, awsCredentialsProvider); // Construct URL with IAM Auth credentials provider RedisURI redisURI = RedisURI.builder() .withHost(host) .withPort(port) .withSsl(ssl) .withAuthentication(redisCredentialsProvider) .build(); // Create a new Lettuce cluster client RedisClusterClient client = RedisClusterClient.create(redisURI); client.connect();
以下是 Lettuce 集群客户端的示例,该客户端将 IAMAuthTokenRequest 封装在凭证提供程序中,以便在需要时自动生成临时凭证。
public class RedisIAMAuthCredentialsProvider implements RedisCredentialsProvider { private static final long TOKEN_EXPIRY_SECONDS = 900; private final AWSCredentialsProvider awsCredentialsProvider; private final String userName; private final IAMAuthTokenRequest iamAuthTokenRequest; private final Supplier<String> iamAuthTokenSupplier; public RedisIAMAuthCredentialsProvider(String userName, IAMAuthTokenRequest iamAuthTokenRequest, AWSCredentialsProvider awsCredentialsProvider) { this.userName = userName; this.awsCredentialsProvider = awsCredentialsProvider; this.iamAuthTokenRequest = iamAuthTokenRequest; this.iamAuthTokenSupplier = Suppliers.memoizeWithExpiration(this::getIamAuthToken, TOKEN_EXPIRY_SECONDS, TimeUnit.SECONDS); } @Override public Mono<RedisCredentials> resolveCredentials() { return Mono.just(RedisCredentials.just(userName, iamAuthTokenSupplier.get())); } private String getIamAuthToken() { return iamAuthTokenRequest.toSignedRequestUri(awsCredentialsProvider.getCredentials()); }