IAM を使用した認証 - Amazon MemoryDB

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

IAM を使用した認証

概要

IAM 認証では、クラスターが Redis OSS バージョン 7 以降を使用するように設定されている場合、 AWS IAM ID を使用して MemoryDB への接続を認証できます。これにより、セキュリティモデルを強化し、多くの管理セキュリティタスクを簡素化できます。IAM 認証では、個々の MemoryDB クラスターと MemoryDB ユーザーごとにきめ細かいアクセス制御を設定し、最小特権の権限の原則に従うことができます。MemoryDB の IAM 認証は、Redis OSS AUTHまたは HELLO コマンドで存続期間の長い MemoryDB ユーザーパスワードの代わりに、有効期間の短い IAM 認証トークンを提供することで機能します。IAM 認証トークンの詳細については、「 AWS 全般のリファレンスガイド」の「署名バージョン 4 の署名プロセス」および以下のコード例を参照してください。

IAM ID とそれに関連するポリシーを使用して、Redis OSS アクセスをさらに制限できます。また、フェデレーテッド ID プロバイダーのユーザーに MemoryDB クラスターへのアクセス権を直接付与することもできます。

MemoryDB で AWS IAM を使用するには、まず認証モードを IAM に設定して MemoryDB ユーザーを作成し、次に IAM ID を作成または再利用する必要があります。IAM アイデンティティには、MemoryDB クラスターと MemoryDB ユーザーに memorydb:Connect アクションを許可するための関連ポリシーが必要です。設定したら、IAM ユーザーまたはロールの AWS 認証情報を使用して IAM 認証トークンを作成できます。最後に、MemoryDB クラスターノードに接続するときに、有効期間の短い IAM 認証トークンを Redis OSS クライアントのパスワードとして指定する必要があります。認証情報プロバイダーをサポートする Redis OSS クライアントは、新しい接続ごとに一時的な認証情報を自動的に生成できます。MemoryDB for Redis は、IAM が有効な MemoryDB ユーザーの接続リクエストに対して IAM 認証を実行し、その接続リクエストを IAM で検証します。

制限事項

IAM 認証を使用する場合、以下の制限が適用されます。

  • IAM 認証は、Redis OSS エンジンバージョン 7.0 以降を使用している場合に使用できます。

  • IAM 認証トークンは 15 分間有効です。存続期間が長い接続の場合は、認証情報プロバイダーインターフェイスをサポートする Redis OSS クライアントを使用することをお勧めします。

  • MemoryDB for Redis への IAM 認証された接続は、12 時間後に自動的に切断されます。新しい IAM 認証トークンを使用してAUTH または HELLO コマンドを送信することで、接続を 12 時間延長できます。

  • IAM 認証は MULTI EXEC コマンドではサポートされていません。

  • 現在、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 for Redis で認証する方法を示しています。

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

以下は、IAM を認証情報プロバイダーAuthTokenRequest にラップして、必要に応じて一時的な認証情報を自動生成する Lettuce Redis OSS クラスタークライアントの例です。

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