

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

# IAM を使用した認証
<a name="auth-iam"></a>

**Topics**
+ [概要](#auth-iam-overview)
+ [制限事項](#auth-iam-limits)
+ [セットアップ](#auth-iam-setup)
+ [接続中](#auth-iam-Connecting)

## 概要
<a name="auth-iam-overview"></a>

IAM 認証では、キャッシュが Valkey または Redis OSS バージョン 7 以降を使用するように設定されている場合、IAM ID AWS を使用して ElastiCache for Valkey または Redis OSS への接続を認証できます。これにより、セキュリティモデルを強化し、多くの管理セキュリティタスクを簡素化できます。また、IAM 認証を使用すると、個々の ElastiCache キャッシュと ElastiCache ユーザーごとにきめ細かいアクセス制御を設定し、最小特権の権限の原則に従うことができます。ElastiCache の IAM 認証は、Valkey または Redis OSS の `AUTH` または `HELLO` コマンドで、有効期間の長い ElastiCache ユーザーパスワードの代わりに、有効期間の短い IAM 認証トークンを提供することによって機能します。IAM 認証トークンの詳細については、 AWS 全般のリファレンスガイドの署名[バージョン 4 の署名プロセス](https://docs.aws.amazon.com//general/latest/gr/signature-version-4.html)と、以下のコード例を参照してください。

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

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

## 制限事項
<a name="auth-iam-limits"></a>

IAM 認証を使用する場合、以下の制限が適用されます。
+ Valkey 7.2 以降または Redis OSS バージョン 7.0 以降に対応した ElastiCache を使用している場合、IAM 認証が利用可能です。
+ IAM 認証では、キャッシュで転送時の暗号化 (TLS) を有効にする必要があります。詳細については、「[ElastiCache の転送時の暗号化 (TLS)](in-transit-encryption.md)」を参照してください。
+ IAM が有効な ElastiCache ユーザーの場合、ユーザー名とユーザー ID のプロパティは同じである必要があります。
+ IAM 認証トークンは 15 分間有効です。長時間接続する場合は、認証情報プロバイダーインターフェイスをサポートする Valkey または Redis OSS クライアントを使用することをお勧めします。
+ Valkey または Redis OSS に対応した ElastiCache への IAM 認証済み接続は、12 時間後に自動的に切断されます。新しい IAM 認証トークンを使用して`AUTH` または `HELLO` コマンドを送信することで、接続を 12 時間延長できます。
+ IAM 認証は `MULTI`/`EXEC` ブロック内ではサポートされていません。
+ 現在、IAM 認証は以下のグローバル条件コンテキストキーをサポートしています。
  + サーバーレスキャッシュで IAM 認証を使用する場合、`aws:VpcSourceIp`、`aws:SourceVpc`、`aws:SourceVpce`、`aws:CurrentTime`、`aws:EpochTime`、`aws:ResourceTag/%s` (関連するサーバーレスキャッシュとユーザーから) がサポートされます。
  + レプリケーショングループで IAM 認証を使用する場合、`aws:SourceIp` および `aws:ResourceTag/%s` (関連するレプリケーショングループとユーザーから) がサポートされます。

  グローバル条件コンテキストキーの詳細については、「IAM ユーザーガイド」の「[AWS グローバル条件コンテキストキー](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html)」を参照してください。

**注記**  
キャッシュ名は、キャッシュ作成時に小文字に変換されます。認証エラーを避けるため、認証コードでキャッシュ名を小文字で指定してください。

## セットアップ
<a name="auth-iam-setup"></a>

IAM 認証をセットアップするには:

1. キャッシュを作成します。

   ```
   aws elasticache create-serverless-cache \
     --serverless-cache-name cache-01  \
     --description "ElastiCache IAM auth application" \
     --engine redis
   ```

1. アカウントが新しいロールを引き継ぐことを許可するロール用の IAM 信頼ポリシードキュメントを以下に示すように作成します。ポリシーを *trust-policy.json* というファイルに保存します。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": {
           "Effect": "Allow",
           "Principal": { "AWS": "arn:aws:iam::123456789012:root" },
           "Action": "sts:AssumeRole"
       }
   }
   ```

------

1. 以下に示すように、IAM ポリシードキュメントを作成します。ポリシーを *policy.json* というファイルに保存します。

------
#### [ JSON ]

****  

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": [
       {
         "Effect" : "Allow",
         "Action" : [
           "elasticache:Connect"
         ],
         "Resource" : [
           "arn:aws:elasticache:us-east-1:123456789012:serverlesscache:cache-01",
           "arn:aws:elasticache:us-east-1:123456789012:user:iam-user-01"
         ]
       }
     ]
   }
   ```

------

1. IAM ロールを作成します。

   ```
   aws iam create-role \
   --role-name "elasticache-iam-auth-app" \
   --assume-role-policy-document file://trust-policy.json
   ```

1. IAM ポリシーを作成します。

   ```
   aws iam create-policy \
     --policy-name "elasticache-allow-all" \
     --policy-document file://policy.json
   ```

1. IAM ポリシーをロールにアタッチします。

   ```
   aws iam attach-role-policy \
    --role-name "elasticache-iam-auth-app" \
    --policy-arn "arn:aws:iam::123456789012:policy/elasticache-allow-all"
   ```

1. IAM を有効にしている新しいユーザーを作成します。

   ```
   aws elasticache create-user \
     --user-name iam-user-01 \
     --user-id iam-user-01 \
     --authentication-mode Type=iam \
     --engine redis \
     --access-string "on ~* +@all"
   ```

1. ユーザーグループを作成し、ユーザーをアタッチします。

   ```
   aws elasticache create-user-group \
     --user-group-id iam-user-group-01 \
     --engine redis \
     --user-ids default iam-user-01
   
   aws elasticache modify-serverless-cache \
     --serverless-cache-name cache-01  \
     --user-group-id iam-user-group-01
   ```

## 接続中
<a name="auth-iam-Connecting"></a>

**トークンをパスワードとして接続**

最初に、[AWS SigV4 の署名済みリクエスト](https://docs.aws.amazon.com//general/latest/gr/sigv4-signed-request-examples.html)を使用して、有効期間が短い IAM 認証トークンを生成する必要があります。その後、以下の例に示すように、Valkey または Redis OSS キャッシュに接続するときに IAM 認証トークンをパスワードとして指定します。

```
String userId = "{{insert user id}}";
String cacheName = "{{insert cache name}}";
boolean isServerless = {{true}};
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 ElastiCache with Redis OSS.
IAMAuthTokenRequest iamAuthTokenRequest = new IAMAuthTokenRequest(userId, cacheName, region, isServerless);
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(userId, iamAuthToken)
    .build();

// Create a new Lettuce Redis OSS client
RedisClient client = RedisClient.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 PARAM_RESOURCE_TYPE = "ResourceType";
    private static final String RESOURCE_TYPE_SERVERLESS_CACHE = "ServerlessCache";
    private static final String ACTION_NAME = "connect";
    private static final String SERVICE_NAME = "elasticache";
    private static final long TOKEN_EXPIRY_SECONDS = 900;

    private final String userId;
    private final String cacheName;
    private final String region;
    private final boolean isServerless;

    public IAMAuthTokenRequest(String userId, String cacheName, String region, boolean isServerless) {
        this.userId = userId;
        this.cacheName = cacheName;
        this.region = region;
        this.isServerless = isServerless;
    }

    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(userId));
        if (isServerless) {
            request.addParameters(PARAM_RESOURCE_TYPE, Collections.singletonList(RESOURCE_TYPE_SERVERLESS_CACHE));
        }
        return request;
    }

    private URI getRequestUri() {
        return URI.create(String.format("%s%s/", REQUEST_PROTOCOL, cacheName));
    }

    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 認証情報プロバイダーを使用して ElastiCache で認証する方法を示しています。

```
String userId = "{{insert user id}}";
String cacheName = "{{insert cache name}}";
boolean isServerless = {{true}};
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 ElastiCache with Redis OSS.
IAMAuthTokenRequest iamAuthTokenRequest = new IAMAuthTokenRequest(userId, cacheName, region, isServerless);

// Create a Redis OSS credentials provider using IAM credentials.
RedisCredentialsProvider redisCredentialsProvider = new RedisIAMAuthCredentialsProvider(
    userId, 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 client
RedisClient client = RedisClient.create(redisURI);
client.connect();
```

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

```
public class RedisIAMAuthCredentialsProvider implements RedisCredentialsProvider {
    private static final long TOKEN_EXPIRY_SECONDS = 900;

    private final AWSCredentialsProvider awsCredentialsProvider;
    private final String userId;
    private final IAMAuthTokenRequest iamAuthTokenRequest;
    private final Supplier<String> iamAuthTokenSupplier;

    public RedisIAMAuthCredentialsProvider(String userId,
        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(userId, iamAuthTokenSupplier.get()));
    }

    private String getIamAuthToken() {
        return iamAuthTokenRequest.toSignedRequestUri(awsCredentialsProvider.getCredentials());
    }
}
```