以 IAM 進行身分驗證 - Amazon MemoryDB

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

以 IAM 進行身分驗證

概觀

當您的叢集設定為使用 Redis OSS 版本 7 或更新版本時,您可以使用 AWS IAM 身分驗證與 MemoryDB 的連線來驗證與 MemoryDB 的連線。這可讓您強化安全模型,並簡化許多管理安全任務。使用 IAM 身份驗證,您可以為每個單獨的 MemoryDB 叢集和 MemoryDB 使用者設定精細的存取控制,並遵循最低權限許可原則。MemoryDB 的 IAM 身份驗證的運作方式是在 Redis OSS 或命令中提供短期的 IAM 身份驗證令牌,而不是長壽命的 MemoryDB 使用者密碼。AUTH HELLO有關 IAM 身份驗證令牌的更多信息,請參閱《 AWS 一般參考指南》中的簽名版本 4 簽名過程和下面的代碼示例。

您可以使用 IAM 身分及其相關政策來進一步限制 Redis OSS 存取。您也可以從其聯合身分識別提供者直接將存取權授與使用者至 MemoryDB 叢集。

若要將 AWS IAM 與 MemoryDB 搭配使用,您首先需要建立將身份驗證模式設定為 IAM 的 MemoryDB 使用者,然後才能建立或重複使用 IAM 身分。IAM 身分識別需要關聯的政策,才能將memorydb:Connect動作授與 MemoryDB 叢集和 MemoryDB 使用者。設定完成後,您可以使用 IAM 使用者或角色的 AWS 登入資料建立 IAM 身份驗證權杖。最後,當您連線至 MemoryDB 叢集節點時,您需要在 Redis OSS 用戶端中提供短期的 IAM 身份驗證權杖做為密碼。支援憑證提供者的 Redis OSS 用戶端可以為每個新連線自動產生臨時登入資料。MemoryDB 會針對已啟用 IAM 的記憶體資料庫使用者的連線要求執行 IAM 身分驗證,並驗證與 IAM 的連線要求。

限制

使用 IAM 身分驗證,會套用以下限制:

  • 使用 Redis OSS 引擎 7.0 版或更新版本時,可以使用 IAM 身份驗證。

  • IAM 身分驗證字符的有效期限為 15 分鐘。對於長期連線,我們建議使用支援憑證提供者介面的 Redis OSS 用戶端。

  • 與 MemoryDB 的 IAM 驗證連線會在 12 小時後自動中斷連線。可以傳送包含新 IAM 身分驗證字符的 AUTHHELLO 命令,將連線再延長 12 小時。

  • MULTI EXEC 命令不支援 IAM 身分驗證。

  • 目前,IAM 驗證不支援所有全域條件內容金鑰。如需有關全域條件內容索引鍵的詳細資訊,請參閱《IAM 使用者指南》中的 AWS 全域條件內容索引鍵

設定

設定 IAM 身分驗證:

  1. 建立叢集

    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
  2. 為您的角色建立如下所示的 IAM 信任政策文件,讓您的帳戶擔任新角色。將政策儲存到名為 trust-policy.json 的檔案。

    { "Version": "2012-10-17", "Statement": { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::123456789012:root" }, "Action": "sts:AssumeRole" } }
  3. 建立 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" ] } ] }
  4. 建立 IAM 角色。

    aws iam create-role \ --role-name "memorydb-iam-auth-app" \ --assume-role-policy-document file://trust-policy.json
  5. 建立 IAM 政策。

    aws iam create-policy \ --policy-name "memorydb-allow-all" \ --policy-document file://policy.json
  6. 將 IAM 政策連接至角色。

    aws iam attach-role-policy \ --role-name "memorydb-iam-auth-app" \ --policy-arn "arn:aws:iam::123456789012:policy/memorydb-allow-all"
  7. 建立已啟用 IAM 的新使用者。

    aws memorydb create-user \ --user-name iam-user-01 \ --authentication-mode Type=iam \ --access-string "on ~* +@all"
  8. 建立 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 Redis OSS URL with IAM Auth credentials provider RedisURI redisURI = RedisURI.builder() .withHost(host) .withPort(port) .withSsl(ssl) .withAuthentication(userName, iamAuthToken) .build(); // Create a new Lettuce Redis OSS 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 Redis OSS credentials provider using IAM credentials. RedisCredentialsProvider redisCredentialsProvider = new RedisIAMAuthCredentialsProvider( userName, iamAuthTokenRequest, awsCredentialsProvider); // Construct Redis OSS URL with IAM Auth credentials provider RedisURI redisURI = RedisURI.builder() .withHost(host) .withPort(port) .withSsl(ssl) .withAuthentication(redisCredentialsProvider) .build(); // Create a new Lettuce Redis OSS cluster client RedisClusterClient client = RedisClusterClient.create(redisURI); client.connect();

以下是一個萵苣 Redis OSS 叢集用戶端的範例,該用戶端會將 IAM 封裝在登入資料提供者AuthTokenRequest 中,以便在需要時自動產生臨時登入資料。

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()); }