#Redshift 別アカウントのS3バケットにUnloadする際にオブジェクト所有者を出力先アカウントにする

別アカウントにUnloadする時は実質必須の設定だと思います。
2020.11.24

先日DataAPIを使って別アカウントのRedshiftにクエリを投げるという方法を行ってみました。

DataAPIで楽々、Lambda関数から別アカウントのRedshiftにクエリを投げてみた。

私がその時やりたかった内容は、S3にファイルをUnloadするというものでした。 しかも、この出力先のバケットはLambda実行側のアカウント(Redshiftとは別のアカウント)という状況でした。

RedshiftからのファイルのUnloadはRedshiftクラスタにアタッチしたIAMロールを通じて行われるため、 そのIAMロールからの書き込みを許可してあげれば別アカウントのバケットであっても問題なくファイル出力ができます。 しかしこの場合、Unloadで出力されたオブジェクトの所有者は出力元のRedshiftのアカウントとなります。

S3ではバケットとオブジェクトの所有アカウントが異なると色々面倒なことが多いです。 そのため、例えばAWS CLIで別アカウントのS3へファイルをアップロードする際には、 別アカウント側での操作を可能にするオプション-acl bucket-owner-full-controlなどが用意されています。 しかしRedshiftのUnloadではそのような設定がまだできないようです。

解決策を調べてみた所、出力先のアカウントのIAMロールを経由するようにすれば解決できることがわかりましたので、 実際にやってみました。 最終的に出来上がる構成は以下のようになります。

便宜上、Redshiftがあるアカウントを「Redshiftアカウント」、 出力先のS3バケットがあるアカウントを「S3アカウント」と称します。

やってみた

以下の手順でやっていきます。

  • Redshiftアカウント側: IAMロールの作成
  • S3アカウント側: IAMロールの作成
  • UNLOADの実行

Redshiftアカウント側: IAMロールの作成

「AWSサービスの作成」

「Redshift - Customizable」を選択

このロールに必要なものは後ほど作るIAMロールへのAssumeRoleだけなので、今回は飛ばしてあとで設定します。

タグは適当に。

ロール名を設定して、一旦ロール作成は完了。

次に今作ったIAMロールにAssumeRoleの権限を付与します。 「インラインポリシーの追加」

JSONに直書きで以下のように書きます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "RedshiftAssumeCrossAccountRole",
      "Effect": "Allow",
      "Action": [
        "sts:AssumeRole"
      ],
      "Resource": "arn:aws:iam::(S3アカウントID):role/RedshiftUnloadToCrossAccountS3"
    }
  ]
}

ここでResourceに設定したIAMロールは未作成です。 ここで指定する名前と次で作るIAMロールの名前は一致するようにしてください。

IAMロールの作成は完了です。 Redshiftのマネジメントコンソール画面に戻って、クラスタにIAMロールをセットします。

これでRedshiftアカウント側は完了です。

S3アカウント側: IAMロールの作成

次にS3アカウントにIAMロールを作成して行きます。

「別のAWSアカウント」でRedshiftアカウントのアカウントIDを入力。

このロールはS3へのファイル出力をするので、今回はAmazonS3FullAccessを選択。

タグは適当に。

ロール名を入力して「ロールの作成」。ここは上記で信頼関係に記述したARMと合致するロール名を指定します。

RedshiftにアタッチしたロールだけがAssumeできるように、信頼関係の編集を行います。

以上でIAM関係の設定は完了となります。

UNLOADの実行

早速RedshiftからのUnloadを実行してみます。 以下のような感じです。

UNLOAD ('
    SELECT * FROM public.sample_table
')
TO 's3://s3-account-bucket/redshift-unload-from-redshift-account/sample_table/'
IAM_ROLE 'arn:aws:iam::arn:aws:iam::10XXXXXXXXXX:role/XXXX-Redshift-XXXX,arn:aws:iam::59XXXXXXXXXX:role/RedshiftUnloadToCrossAccountS3'
HEADER
DELIMITER '\t'
PARALLEL OFF
GZIP

ポイントはIAM_ROLEの指定です。 ここに「RedshiftにアタッチしたIAMロール」と、そこからAssumeする「S3アカウント側のIAMロール」をカンマ区切りで2つ並べます。

実際に実行してみると、想定通りファイルが出力され、 ファイルの所有者はS3アカウントとなっており、ファイルのダウンロードなどが問題なくできることが確認できました。

S3アカウントのIAMロールを経由しているので、 そのロールがファイルを置いたことになるためバケットポリシーでの明示的な許可も不要です。

まとめ

RedshiftのUnloadでは、別アカウントのバケットに出力した場合も、 オブジェクトの所有者はRedshiftのアカウントになってしまいます。 そこで、出力先のアカウントにIAMロールを作成してそれを経由することで ファイルの所有者を吐き出す先のアカウントとしてファイル出力することができました。 これによってRedshiftからUnloadしたファイルを使っての分析などが別アカウントでも非常にやりやすくなります。 Redshiftから別アカウントへUnloadする際には、実質的に必須な設定になるかなと思います。

参考リンク

Chaining IAM roles in Amazon Redshift - Amazon Redshift クラスター管理ガイド Unload with Grant or Canned ACL - Discussion Forums