CloudFormationでAmazon MemoryDB for Redisのリソースを管理する

CloudFormationを使ってAmazon MemoryDB for Redisのリソースをコード管理できるようになりました。MemoryDB for Redisは、データの永続化をサポートしたRedis互換のマネージドデータベースサービスです。CloudFormationでリソース作成するための簡単なサンプルを記載しています。
2021.11.02

コンサル部のとばち(@toda_kk)です。

2021年8月に発表された新サービスであるAmazon MemoryDB for Redisについて、CloudFormationを使ってリソース管理できるようになりました。

Amazon MemoryDB for Redisは、高速なインメモリデータベースでありつつデータの永続化をサポートしているRedis互換のマネージドサービスです。詳細は下記ページをご参照ください。

なお、2021年10月からは東京リージョンでも利用可能になっています。

Amazon MemoryDB for RedisのCloudFormationリソースタイプ

公式ドキュメントが公開されたので、早速眺めてみます。

2021年11月2日現在、サポートされているCloudFormationのリソースタイプは下記の通りです。

  • AWS::MemoryDB::ACL
  • AWS::MemoryDB::Cluster
  • AWS::MemoryDB::ParameterGroup
  • AWS::MemoryDB::SubnetGroup
  • AWS::MemoryDB::User

Cluster、ParameterGroup、SubnetGroup

MemoryDB for Redisは、ElastiCache for Redisと同様にVPC内に配置されるリソースであり、サブネットグループによって配置するAvailability Zoneやサブネットを指定し、パラメーターグループによってRedisエンジンのパラメーターを設定します。

また、クラスターモードのみがサポートされており、シャード数(NumShards)やレプリカ数(NumReplicasPerShard)を指定する必要があります。レプリカ数を1以上で設定する場合は、指定するサブネットグループに複数のAZが含まれている必要があります。

ACL

MemoryDB for Redisではセキュリティグループをサポートしていますが、それとは別にアクセスコントロールリスト(ACL)という形でユーザー毎のアクセス制御を設定できます。

このACLは、Redisバージョン6にて標準でサポートされている機能です。Redis ACLコマンドを通じて、ユーザーやユーザーグループを作成し、実行可能なコマンドやデータのアクセス制御を設定することができます。

ただし、MemoryDB for RedisにおいてはACLコマンドの機能は一部制限されており、ユーザーの作成や権限の変更といった書き込みベースの処理がサポートされていません。そのため、ユーザー作成といった操作を実行したいときは、MemoryDB for Redisの機能としてマネジメントコンソールやCLIやCloudFormationから行う必要があります。

redis-cliでRedisに接続した後、ACL HELPを実行することでサポートされているコマンドを確認できます。まずは、Redisバージョン6のコンテナイメージを引っ張ってきてローカル環境などで起動した上で、素のRedisでサポートされているコマンドを確認してみます。

Dockerで起動したRedisでACL HELPした場合

$ sudo docker pull redis:6
$ sudo docker run -d -p 6379:6379 redis:6
$ redis-cli -h localhost
localhost:6379> ACL HELP
 1) ACL <subcommand> [<arg> [value] [opt] ...]. Subcommands are:
 2) CAT [<category>]
 3)     List all commands that belong to <category>, or all command categories
 4)     when no category is specified.
 5) DELUSER <username> [<username> ...]
 6)     Delete a list of users.
 7) GETUSER <username>
 8)     Get the user's details.
 9) GENPASS [<bits>]
10)       Generate a secure 256-bit user password. The optional `bits` argument can
11)       be used to specify a different size.
12)   LIST
13)       Show users details in config file format.
14)   LOAD
15)       Reload users from the ACL file.
16)   LOG [<count> | RESET]
17)       Show the ACL log entries.
18)   SAVE
19)     Save the current config to the ACL file.
20) SETUSER <username> <attribute> [<attribute> ...]
21)     Create or modify a user with the specified attributes.
22) USERS
23)     List all the registered usernames.
24) WHOAMI
25)     Return the current connection username.
26) HELP
27)     Prints this help.

次に、MemoryDB for Redisに接続して確認してみます。ちなみに、クラスターの設定でTLS接続を有効にしている場合は--tlsオプションが必要になります。また、クラスターモードで接続したい場合は-cオプションを付与します。

MemoryDB for Redisに接続してACL HELPした場合

$ redis-cli -h xxxxxx.cluster-name.xxxxxx.memorydb.ap-northeast-1.amazonaws.com --tls -c
xxxxxx.cluster-name.xxxxxx.memorydb.ap-northeast-1.amazonaws.com:6379> ACL HELP
 1) ACL <subcommand> [<arg> [value] [opt] ...]. Subcommands are:
 2) LIST                             -- Show user details in config file format.
 3) USERS                            -- List all the registered usernames.
 4) GETUSER <username>               -- Get the user details.
 5) CAT                              -- List available categories.
 6) CAT <category>                   -- List commands inside category.
 7) GENPASS [<bits>]                 -- Generate a secure user password.
 8) WHOAMI                           -- Return the current connection username.
 9) LOG [<count> | RESET]            -- Show the ACL log entries.
10)   HELP
11)       Prints this help.

素のRedisと比べて、MemoryDB for Redisではサポートされているコマンドが少ないことがわかります。

これはElastiCache for Redisでも同様です。Redis標準ではAUTHコマンドによるユーザー認証がサポートされていますが、より柔軟な権限制御の方法としてRBAC(Role-Based Access Control)という形でRedis ACLをサポートしています。

Redisでは当初からAUTHコマンドによる認証がサポートされていたのですが、バージョン6からAUTHの拡張と共にACLが追加され、より柔軟な権限制御を実現できるようになったという背景があります。ElastiCache for RedisではRedisエンジンのバージョン6をサポートするにあたり、RBACという形でRedis ACLを提供するようになりました。

これを受けて、MemoryDB for RedisではCloudFormationのリソースタイプにもあるようにACLUserをAWSリソースとして管理できるようにサポートしているようです。デフォルトではopen-accessという名前のACLが作成されており、defaultユーザーが登録されています。

User

上述のACLで管理するユーザーを作成するリソースタイプです。形式は下記のようになっています。

AWS::MemoryDB::User

Type: AWS::MemoryDB::User
Properties: 
  AccessString: 
    String
  AuthenticationMode: Json
  Tags: 
    - Tag
  UserName: String

AccessStringは、ユーザーに許可する操作権限を指定するパラメーターです。on ~* &* +@allといった形式で記述します。詳細は前掲の MemoryDB for Redisのドキュメント もしくは Redisの公式ドキュメント をご参照ください。

AuthenticationModeはJSON形式で指定します。MemoryDBにおけるアクションCreateUserのAPIリファレンスによると、TypePasswordsを指定する必要がありそうです。

ここで、上述のdefaultユーザーの設定値をAWS CLIから確認してみます。すると、Authentication.Typeno-passwordとなっていることがわかります。

これはつまり、パスワードなしでRedisに接続できるユーザーということになります。ElastiCache for Redisの場合でも、AUTH認証やRBACのことを特に意識していない状態で利用していれば、このdefaultユーザーを使ってアクセスしていることになります。

$ aws memorydb describe-users
{
    "Users": [
        {
            "Name": "default",
            "Status": "active",
            "AccessString": "on ~* &* +@all",
            "ACLNames": [
                "open-access"
            ],
            "MinimumEngineVersion": "6.0",
            "Authentication": {
                "Type": "no-password"
            },
            "ARN": "arn:aws:memorydb:ap-northeast-1:123456789012:user/default"
        }
    ]
}

しかし、データタイプAuthenticationModeのリファレンスを参照すると、次のような記載があります。

Indicates whether the user requires a password to authenticate. All newly-created users require a password.

つまり、新たにユーザーを作成する場合はパスワードが必要になり、no-passwordは実態としてはdefaultユーザーでしか利用できないようです。

CloudFormationからリソース作成してみる

必要なリソースタイプがわかったので、CloudFormationを使って一通りのリソースを作成してみます。以下は、簡単なサンプルとしてご利用いただければと思います。

template.yml

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  SampleCluster:
    Type: AWS::MemoryDB::Cluster
    Properties:
      ClusterName: sample-cluster
      ACLName: !Ref SampleACL
      NodeType: db.r6g.large
      NumReplicasPerShard: 1
      NumShards: 1
      ParameterGroupName: !Ref SampleParameterGroup
      SecurityGroupIds:
        - sg-xxxxxxxxxxxxxxxxx
        - sg-yyyyyyyyyyyyyyyyy
      SubnetGroupName: !Ref SampleSubnetGroup
      TLSEnabled: true
  SampleSubnetGroup:
    Type: AWS::MemoryDB::SubnetGroup
    Properties:
      SubnetGroupName: sample-subnet-group
      SubnetIds:
        - subnet-xxxxxxxxxxxxxxxxx
        - subnet-yyyyyyyyyyyyyyyyy
        - subnet-zzzzzzzzzzzzzzzzz
  SampleParameterGroup:
    Type: AWS::MemoryDB::ParameterGroup
    Properties:
      ParameterGroupName: sample-parameter-group
      Family: memorydb_redis6
  SampleACL:
    Type: AWS::MemoryDB::ACL
    Properties:
      ACLName: sample-acl
      UserNames:
        - !Ref SampleUser
  SampleUser:
    Type: AWS::MemoryDB::User
    Properties:
      UserName: sample-user
      AccessString:
        on ~* &* +@all
      AuthenticationMode: {
        Type: password,
        Passwords: [xxxxxxxxxxXXXXX!]
      }

意図した通りにリソースが作成されていました。

以上、コンサル部のとばち(@toda_kk)でした。