【Snowflake】S3 Storage Integration作成時にはS3バケットポリシーにも注意する
概要
SnowflakeのS3 Storage Integrationで設定する対象のS3バケットにおいて、S3バケットポリシーにaws:PrincipalOrgID
を条件にしたPut系の権限を設定している場合は注意しよう。
比較的ニッチな話題ではあるが、なぜ注意が必要かというと以下のことが理由である。
- S3 Storage IntegrationでGet系の権限を設定したにも関わらず、SnowflakeからそのS3へUnload(Put)ができる(本来意図している挙動とは異なる)
aws:PrincipaOrgIDとは?
AWS IAMポリシーのCondition
の条件キーの一つ。(参考)
この条件を使えば、AWS Organizationに属するIdentifierのみにアクションを制御することができる。
ケースとしてはS3バケットへのアクセスをAWS Organization内に限定する場合などが挙げられる。
{ "Version": "2012-10-17", "Statement": { "Sid": "AllowPutObject", "Effect": "Allow", "Principal": "*", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::policy-ninja-dev/*", "Condition": {"StringEquals": {"aws:PrincipalOrgID":"o-xxxxxxxxxxx"} } } }
指定したorganization以外からのS3バケットへのアクセスを拒否することができる。
問題になるケース
早速、問題となるケースを手順を示しながら見ていく。
1. [AWS] S3バケットにバケットポリシーを設定
事前に作成したS3バケットにList系、Get系、Put系のアクションを許可するポリシーを設定する。
指定したPrincipalOrgIDであれば、誰でも許可されたアクションを実行できる。
2. [AWS] S3 Storage Integration用のIAMポリシーの作成
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:GetObjectVersion" ], "Resource": "arn:aws:s3:::XXXXXX/*" #自身のS3バケットパス }, { "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:GetBucketLocation" ], "Resource": "arn:aws:s3:::XXXXXX", #自身のS3バケットパス "Condition": { "StringLike": { "s3:prefix": [ "*" ] } } } ] }
このポリシーをアタッチしたIAMロールを作成する。
3. [Snowflake] S3 Storage Integrationを作成
CREATE OR REPLACE STORAGE INTEGRATION S3_INT TYPE = EXTERNAL_STAGE STORAGE_PROVIDER = 'S3' ENABLED = TRUE STORAGE_AWS_ROLE_ARN = 'arn:aws:iam::XXXXXXXX' #自身のIAMロールのARN STORAGE_ALLOWED_LOCATIONS = ('s3://XXXXXXX/') #自身のS3バケットパス ;
以下のSQLを実行し、返却された結果のSTORAGE_AWS_IAM_USER_ARN
とSTORAGE_AWS_EXTERNAL_ID
をメモしておく。
DESC INTEGRATION S3_INT;
4. [AWS] IAMロールの信頼関係の設定
先程メモしたプロパティをIAMロールの信頼関係において以下のように設定する。
PrincipalのAWS →
STORAGE_AWS_IAM_USER_ARN
ExternalId →
STORAGE_AWS_EXTERNAL_ID
5. [Snowflake] S3バケット内のフォルダにUnloadしてみる
今回作成したIntegrationはGetやList系のみのアクションのみが可能なため、本来であればSnowflakeからS3に対してPutはできないはず。
サンプルテーブルを用意し、そのテーブルをS3バケットに対してUnloadをすると、、
USE DATABASE SAMPLE_DB; USE SCHEMA SAMPLE_SCHEMA; CREATE TABLE SAMPLE_TABLE (ID INT, NAME VARCHAR) AS SELECT 1 AS ID, 'USER1' AS NAME UNION ALL SELECT 2 AS ID, 'USER2' AS NAME ; COPY INTO 's3://XXXXXXX/' #自身のS3バケットパス FROM SAMPLE_TABLE STORAGE_INTEGRATION = S3_INT FILE_FORMAT = (TYPE = CSV) ;
なんとPutができてしまう!
Snowflake側のIAMユーザーに対してAssumeRoleする際にPrincipalOrgID
の属性も持つようになるため、S3バケットに書き込みが可能となる。
Snowflake側ではこの挙動を制限できないので、S3バケットポリシーの許可範囲を絞る方法で解決できる。
まとめ
S3のバケットポリシーによってはSnowflakeのGetやList系のみ許可されたS3 Storage Integrationを用いたとしても、S3バケットへのPutが可能になるケースがあるので注意しましょう。