Snowflakeの署名付きURL(Pre-Signed URL)を利用してファイルをダウンロードしてみた

2021.09.28

こんにちは!DA(データアナリティクス)事業本部 サービスソリューション部の大高です。

Snowflakeに、新しいSQL関数「GET_PRESIGNED_URL」が追加され、署名付きURL(Pre-Signed URL)が利用できるようになりました。(2021年9月現在はプレビュー機能です)

今回はこの「GET_PRESIGNED_URL」を実際に試していきたいと思います。

前提

今回試すSQL関数「GET_PRESIGNED_URL」では、ステージを利用します。

今回はステージとして外部ステージCM_OOTAKA_EXTERNAL_STAGE(S3)を以下と同様の手順で、事前に作成してあります。また、この外部ステージは、S3のバケット直下をURLとして指定して作成しています。(例:s3://foo-bar/を指定)

Snowflakeの署名付きURL(Pre-Signed URL)とは?

Snowflakeの署名付きURL(Pre-Signed URL)を利用すると、URLにアクセスすることで、ステージ上のファイルを直接読み込んだり、ダウンロードすることができます。この機能は非構造化データのサポートに伴って追加された機能で、例えば非構造化データである画像ファイルなどを署名付きURL(Pre-Signed URL)経由でダウンロードしたりすることができます。

なお注意点として、ステージはサーバーサイド暗号化を有効化したステージである必要があります。

また、内部ステージですが「ユーザーステージ」と「テーブルステージ」は署名付きURL(Pre-Signed URL)を発行できるステージとしては対象外となります。実際に試すと、以下のようにエラーになります。

SELECT GET_PRESIGNED_URL(@~, 'snowflake/pre-signed-url/user-master.csv');

SQLコンパイルエラー:関数「 GET_PRESIGNED_URL 」の引数 1 は、ユーザーまたはテーブルステージを提供します。これらのステージの種類は、この関数ではサポートされていません。

署名付きURL(Pre-Signed URL)を発行して、ファイルを取得してみる

では、実際に署名付きURL(Pre-Signed URL)を発行して、ファイルを取得してみましょう。

前提として記述した通り、外部ステージCM_OOTAKA_EXTERNAL_STAGEを事前に作成しています。今回は、このS3バケットのsnowflake/pre-signed-url/user-master.csvに、以下のファイルをアップロードしておきます。

user-master.csv

id,name
1,雨宮 蓮
2,坂本 竜司
3,モルガナ
4,高巻 杏
5,喜多川 祐介
6,新島 真
7,佐倉 双葉
8,奥村 春
9,明智 吾郎

ファイルをアップロードしたら、GET_PRESIGNED_URL関数を利用して、署名付きURL(Pre-Signed URL)を発行します。第1引数にステージを、第2引数にファイルまでの相対パスを指定します。

SELECT GET_PRESIGNED_URL(@CM_OOTAKA_EXTERNAL_STAGE, 'snowflake/pre-signed-url/user-master.csv');

署名付きURL(Pre-Signed URL)が発行されたら、下記のようにcurlコマンドでファイルを取得してみます。

$ curl 'https://foo-bar.s3.ap-northeast-1.amazonaws.com/snowflake/pre-signed-url/user-master.csv?X-Amz-Security-Token=XXXXX.....'
id,name
1,雨宮 蓮
2,坂本 竜司
3,モルガナ
4,高巻 杏
5,喜多川 祐介
6,新島 真
7,佐倉 双葉
8,奥村 春
9,明智 吾郎

想定どおり、ファイルのデータが取得できました!

なお、今回は指定しませんでしたが有効期限を秒単位で指定することもできます。例えば60秒に指定する場合は、以下のようになります。(デフォルトは「3600秒 = 60分」です)

SELECT GET_PRESIGNED_URL(@CM_OOTAKA_EXTERNAL_STAGE, 'snowflake/pre-signed-url/user-master.csv', 60);

URLの有効期限が切れていると、以下のようなエラーが返ります。

<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Request has expired</Message><X-Amz-Expires>4</X-Amz-Expires><Expires>2021-09-27T12:27:45Z</Expires><ServerTime>2021-09-27T12:27:50Z</ServerTime><RequestId>N5G7XX9QT2TS8R5S</RequestId><HostId>INlNRDGyi66jrd3CvID9IYm4If9Z+IKiDtE5wVMRq7lnht2Jqc+7LpJqP9nXcHaps+tgz7o4jvQ=</HostId></Error>

おまけ

一応、アップロードしたらどうなるかも試してみました。パスはsnowflake/pre-signed-url/user-master-upload.csvに変えてみます。

SELECT GET_PRESIGNED_URL(@CM_OOTAKA_EXTERNAL_STAGE, 'snowflake/pre-signed-url/user-master-upload.csv');

署名付きURL(Pre-Signed URL)が発行されたら、下記のようにcurlコマンドでファイルをアップロードしてみます。

curl -X PUT --upload-file user-master.csv 'https://foo-bar.s3.ap-northeast-1.amazonaws.com/snowflake/pre-signed-url/user-master.csv?X-Amz-Security-Token=XXXXX.....'

<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>.....

怒られました。PUTの場合にはおとなしく別の方法でPUTすると良さそうです。

まとめ

以上、Snowflakeで署名付きURL(Pre-Signed URL)を利用してファイルをダウンロードしてみました。

これまではステージ上のファイルを取得する際には、Snowflakeアカウント上のユーザーが必要だったのですが、署名付きURL(Pre-Signed URL)の登場によって、Snowflakeアカウント上にユーザーを持たない人もファイルアクセスが出来るようになりました。

データの受け渡しの際にはとても便利な機能だと思うので、うまく利用していきたいですね。

どなたかのお役に立てば幸いです。それでは!