データアナリティクス事業本部の鈴木です。
最近はAmazon Redshiftのデータ共有に凝っています。前回はRedshift Serverlessで同一アカウント内のデータ共有設定を確認してみましたが、今回はクロスアカウントでのデータ共有設定について確認してみました。
確認したかったこと
異なるアカウントに一つずつRedshift Serverlessインスタンスを起動し、データ共有の設定方法を確認しました。
特に以下を確認しました。
- アカウント間のデータ共有設定を実行してみて、コンシューマーアカウントのRedshift Serverlessインスタンスからプロデューサーアカウントのインスタンスのデータをクエリできることを確認する。
- コンシューマーアカウントのRedshift Serverlessインスタンスに一般ユーザーを作成し、データ共有から作ったデータベースがクエリできるか確認する。
- プロデューサーアカウントでデータ共有を無効化した時にどうなるのか確認する。
Redshift Serverlessインスタンスの準備
以下のブログで紹介されているCloudFormationテンプレートを少し修正してデプロイし、リソースを準備しました。
修正内容は以下になります。
AWS::RedshiftServerless::Namespace
でKmsKeyId
は指定せず、Redshift Serverlessの暗号化鍵にAWS_OWNED_KMS_KEY
を使いました。- 最小ベースキャパシティは8RPUとしました。
テンプレートを、プロデューサーアカウントとコンシューマーアカウントのそれぞれのCloudFormationからデプロイしました。
テンプレートは以下としましたが、長いのでトグルメニューにして隠しておきます。
CloudFormationテンプレート
AWSTemplateFormatVersion: "2010-09-09"
Description: "Redshift Serverless and VPC"
Parameters:
Env:
Type: "String"
Default: "test"
ProjectName:
Type: "String"
CidrBlock:
Description: Please type the CidrBlock.
Type: String
Default: 192.168.0.0/22
BaseCapacity:
Type: Number
Default: 8
EnhancedVpcRouting:
Type: String
AllowedValues:
- true
- false
Default: false
PubliclyAccessible:
Type: String
AllowedValues:
- true
- false
Default: true
AdminUsername:
Type: String
Default: awsuser
AdminUserPassword:
Type: String
Description: Must be 8-64 characters long. Must contain at least one uppercase letter, one lowercase letter and one number. Can be any printable ASCII character except “/”, ““”, or “@”.
NoEcho: true
MinLength: 8
MaxLength: 64
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Sub ${CidrBlock}
EnableDnsSupport: True
EnableDnsHostnames: True
InstanceTenancy: default
Tags:
- Key: Name
Value: !Sub ${ProjectName}-redshiftserverless-${Env}-VPC
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Application
Value:
Ref: AWS::StackId
- Key: Network
Value: Public
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId:
Ref: VPC
InternetGatewayId:
Ref: InternetGateway
PublicRouteTable:
Type: AWS::EC2::RouteTable
DependsOn: AttachGateway
Properties:
VpcId:
Ref: VPC
Tags:
- Key: Name
Value: !Sub |
${ProjectName}-redshiftserverless-${Env}-public-rtb
- Key: Application
Value:
Ref: AWS::StackId
PublicRoute:
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId:
Ref: PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
Ref: InternetGateway
Subnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId:
Ref: VPC
AvailabilityZone: !Select [ 0, !GetAZs ]
CidrBlock: !Select [ 0, !Cidr [ !GetAtt VPC.CidrBlock, 4, 8 ]]
Subnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId:
Ref: VPC
AvailabilityZone: !Select [ 1, !GetAZs ]
CidrBlock: !Select [ 1, !Cidr [ !GetAtt VPC.CidrBlock, 4, 8 ]]
Subnet3:
Type: AWS::EC2::Subnet
Properties:
VpcId:
Ref: VPC
AvailabilityZone: !Select [ 2, !GetAZs ]
CidrBlock: !Select [ 2, !Cidr [ !GetAtt VPC.CidrBlock, 4, 8 ]]
Subnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId:
Ref: Subnet1
RouteTableId:
Ref: PublicRouteTable
Subnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId:
Ref: Subnet2
RouteTableId:
Ref: PublicRouteTable
Subnet3RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId:
Ref: Subnet3
RouteTableId:
Ref: PublicRouteTable
RedshiftServerlessSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId:
Ref: VPC
GroupDescription: Marker security group for Application server.
Tags:
- Key: Name
Value: !Sub |
${ProjectName}-redshiftserverless-${Env}-sg
RedshiftServerlessRole:
Type: "AWS::IAM::Role"
Properties:
Path: "/"
RoleName: !Sub "${ProjectName}-${Env}-redshift-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- redshift.amazonaws.com
Action: sts:AssumeRole
MaxSessionDuration: 3600
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/AmazonAthenaFullAccess"
- "arn:aws:iam::aws:policy/AmazonS3FullAccess"
- "arn:aws:iam::aws:policy/AWSGlueConsoleFullAccess"
- "arn:aws:iam::aws:policy/AmazonRedshiftAllCommandsFullAccess"
Description: "Allows Redshift clusters to call AWS services on your behalf."
Tags:
- Key: "Name"
Value: !Sub "${ProjectName}-redshiftserverless-${Env}-redshift-role"
RedshiftServerlessWorkGroup:
Type: AWS::RedshiftServerless::Workgroup
Properties:
WorkgroupName: !Sub "${ProjectName}-${Env}-redshift-wg"
BaseCapacity: !Ref BaseCapacity
EnhancedVpcRouting: !Ref EnhancedVpcRouting
NamespaceName: !Ref RedshiftServerlessNamespace
PubliclyAccessible: !Ref PubliclyAccessible
SecurityGroupIds:
- !Ref RedshiftServerlessSecurityGroup
SubnetIds:
- !Ref Subnet1
- !Ref Subnet2
- !Ref Subnet3
RedshiftServerlessNamespace:
Type: AWS::RedshiftServerless::Namespace
Properties:
NamespaceName: !Sub "${ProjectName}-${Env}-redshift-ns"
AdminUsername: !Ref AdminUsername
AdminUserPassword: !Ref AdminUserPassword
DbName: !Sub "${ProjectName}-db"
IamRoles:
- !GetAtt RedshiftServerlessRole.Arn
データ共有の設定
ドキュメントとしては、以下の『Amazon Redshift データベース開発者ガイド』のAWSアカウント間でのデータ共有のページを参考にしました。Redshiftのデータ共有をそのまま使って設定する方法になります。
記載の手順に従って、クロスアカウントでのデータ共有ができることを確認しました。ただし、実際やってみると、ドキュメントを読んだだけよりも、必要な操作が多い印象だった(とはいえあくまで確認手順が増えたくらいの話です)ので、後の検証内容の紹介部分で補足します。
やってみる
今回は二つのアカウントを使います。マネジメントコンソールがライトモードである方がプロデューサーアカウント、ダークモードである方がプロデューサーアカウントです。Redshift query editor v2のコンソールは両方ダークモードで作業してしまったので、どちらなのかは随時記載します。
1. CloudFormationテンプレートのデプロイ
先に紹介したCloudFormationテンプレートを、プロデューサーアカウントとコンシューマーアカウントのそれぞれでデプロイしました。
2. プロデューサー側の設定(データ共有作成)
データの準備
まず、プロデューサーのRedshift Serverlessインスタンスに、Redshift query editor v2で、awsuser
スーパーユーザーで接続し、tickit
サンプルデータベースを作成しました。
データ共有の作成
以下のSQLを実行し、tickit_datashare
データ共有を作成しました。
CREATE DATASHARE tickit_datashare;
ALTER DATASHARE tickit_datashare SET publicaccessible = TRUE;
次に、以下のSQLを実行して、tickit.users
サンプルテーブルをデータ共有に追加しました。
-- Add schema to datashare
ALTER DATASHARE tickit_datashare ADD SCHEMA PUBLIC;
-- Add table under schema to datashare
ALTER DATASHARE tickit_datashare ADD SCHEMA tickit;
ALTER DATASHARE tickit_datashare ADD TABLE tickit.users;
最後に、以下のSQLを実行して、コンシューマーアカウントにデータ共有を行うよう設定しました。
-- <コンシューマーアカウントのアカウントID>は適したものに変えてください
GRANT USAGE ON DATASHARE tickit_datashare TO ACCOUNT '<コンシューマーアカウントのアカウントID>';
ここまでで、アカウントで作成されたデータ共有
画面に、作業で作成したデータ共有ができていることを確認できました。
データ共有ステータス
が必要なアクション
になっていました。これは次で説明します。
3. プロデューサー側の設定(データコンシューマーの承認)
アカウント内のデータ共有では不要でしたが、クロスアカウントではデータコンシューマーの承認をする必要がありました。
個別のデータ共有を開きました。コンシューマーのステータス
がPending authorization
になっています。
データコンシューマーを選び、データコンシューマーID
が合っていることを確認して、承認
を押しました。
これでコンシューマーのステータス
が承認済み
になりました。
4. コンシューマー側の設定(データ共有の関連付け)
次に、コンシューマーアカウントの設定をしていきました。
データ共有で他のアカウントから
タブを開くと、tickit_datashare
があることを確認できました。ここでもデータ共有ステータス
が 必要なアクション
になっているので作業をしました。
tickit_datashare
を選択し、Associtate
を押しました。
データ共有を関連づける対象を選択しました。今回は、コンシューマーアカウントにある、今回作成したRedshift Serverlessインスタンスだけを指定しました。
データ共有ステータス
がアクティブ
になりました。
5. コンシューマー側の設定(データ共有からのデータベース作成)
まず、コンシューマー側のRedshift Serverlessインスタンスからデータ共有が確認できるか、Redshift query editor v2で確認しました。
コンシューマー側のRedshift Serverlessインスタンスの適当なデータベースにawsuser
で接続し、以下のSQLを実行しました。
SHOW DATASHARES LIKE 'tickit_%';
関連付けをしているため、データ共有が見えました。
次に、以下のSQLを実行して、データ共有からデータベースを作成しました。
-- <コンシューマーアカウントのアカウントID>は適したものに変えてください
-- <プロデューサーRedshift ServerlessのNAMESPACE>は適したものに変えてください
CREATE DATABASE consumer_tickit FROM DATASHARE tickit_datashare OF ACCOUNT '<プロデューサーアカウントのアカウントID>' NAMESPACE '<プロデューサーRedshift ServerlessのNAMESPACE>';
検索すると、確かにデータを取得できました。
そのほかに確認したこと
プロデューサーに追加したデータが反映されることの確認
改めてではありますが、プロデューサーのRedshift Serverless側で追加したデータが、コンシューマー側で取得できるのかについて確認しました。
プロデューサーアカウントで、Redshift query editor v2にてインスタンスに接続し、以下のSQLを実行してusers
テーブルにデータを追加しました。
insert into tickit.users values
('000','Samaple','Samaple','Samaple','Samaple','OK','Sample.nulla@magnisdis.ca','(295) Samaple',null,false,false,false,null,true,null,null,null,null)
コンシューマーアカウントで、Redshift query editor v2にてインスタンスに接続し、consumer_tickit.tickit.users
テーブルにデータが反映されているか確認できました。
コンシューマーアカウントの一般ユーザーで共有されたデータを確認する
コンシューマーアカウントにて、Redshift query editor v2でawsuser
スーパーユーザーを使って適当なユーザーを作成しました。このユーザーから共有されたconsumer_tickit.tickit.users
テーブルを確認できるか試しました。
コンシューマーアカウントにて、以下のSQLを実行しました。
CREATE USER testuser1 WITH PASSWORD 'testPASS111';
Redshift query editor v2で、testuser1
で接続しました。
この時点では、consumer_tickit
データベースが見られませんでした。
再びawsuser
での接続に切り替え、consumer_tickit
データベースへの権限を付与しました。
GRANT USAGE ON DATABASE consumer_tickit TO testuser1;
再度testuser1
で接続すると、利用できるようになりました。
プロデューサー側からデータ共有を無効化した場合の挙動
最後に、プロデューサー側からデータ共有を無効化した場合の挙動を確認しました。これはドキュメントにオプションとして記載されていたもので、データ共有が不要になった場合の操作になります。
まず、プロデューサー側からawsuser
で以下のSQLを実行し、tickit_datashare
データ共有を無効化しました。
-- <コンシューマーアカウントのアカウントID>は適したものに変えてください
REVOKE USAGE ON DATASHARE tickit_datashare FROM ACCOUNT '<コンシューマーアカウントのアカウントID>';
これでRedshiftのコンソールからはデータ共有が削除されました。
コンシューマー側でもRedshiftのコンソールからはデータ共有が削除されました。
ただし、コンシューマー側のインスタンスに接続すると、データベースは残っていたので、これは手動で削除する必要がありそうでした。
例えば以下のようにSQLを実行して削除できました。
DROP DATABASE consumer_tickit;
最後に
今回はAmazon Redshift Serverlessで、クロスアカウントでのデータ共有設定について確認してみました。同一アカウントのときよりも少し操作が増えていましたが、事故防止の一手間という程度で、とても簡単に設定できました。
アカウントを跨いでも、Redshift間であればETLなしでデータを連携できるのは非常に強力です。Redshiftをデータウェアハウスの選択肢に入れておられる方は、ぜひご確認頂ければと思います。