こんにちは、エクスチュアの黒岩と申します。
つい最近、AWSアカウントを保持していないメンバーより、S3に日次で配置されるファイルをメールで送ってほしいという要望をいただくことがありました。
by 読者の皆様
「…ん?IAMユーザーを発行して、該当のファイルが配置されたS3バケットへのアクセス権を付与してあげればいいんじゃない?」
はい、これだけ聞くとそう思いますよね。ある程度自動化ができる人且つ、メンバーが1人ならまだそれでいいんです。なんと今回は数十名が同じようにメールでファイルを受け取りたいとのことなんです。。(よくあるパターンな気がする)
ということで今回の記事では、複数人の非AWSユーザーが、S3に日次で配置されるファイルをメールで受け取りたいという要望を満たすための1つの選択肢とその注意点を紹介する記事となります。
実装はMatillionを使用して行うため、Matillionってこんなことまでできるんだ!という発見と、是非同じようなリクエストを受け取った方の参考になると嬉しいです!
※Matillionでなくても、pythonの実行環境さえ存在すれば参考になるかと思います
署名付きURLとは
S3では、オブジェクトに対して署名付きURLというものが発行できることをご存知でしょうか。
S3のオブジェクトへの一時的なアクセスを提供するためのURLで、有効期間と署名(アクセスを許可する証明)が含まれています。これにより、データの所有者はS3に保存されたファイルを安全に共有することができる且つ、アクセスを許可する期間もコントロールすることができるのです。
この署名付きURL自体をメールで送信する形で実装してみましょう!
実装手順
前提:ファイルはExcel形式であり、他の処理でS3に日次で配置されていると仮定
1. Matillionから、対象のS3オブジェクトへ署名付きURLを発行する
①MatillionのPython Scriptコンポーネントを配置し、「publish_presigned_url」という名前に設定
②Python Scriptを記述
import boto3
import os
from dotenv import load_dotenv
from botocore.client import Config
import pyshorteners
# 環境変数の読み込み
load_dotenv()
ACCESS_KEY = os.getenv('ACCESS_KEY')
SECRET_KEY = os.getenv('SECRET_KEY')
def generate_presigned_url(bucket_name, object_key, expiration=86400, region='ap-northeast-1'):
s3_client = boto3.client('s3', config=Config(signature_version='s3v4'), region_name=region, aws_access_key_id=ACCESS_KEY,
aws_secret_access_key=SECRET_KEY)
url = s3_client.generate_presigned_url(
'get_object',
Params={'Bucket': bucket_name, 'Key': object_key},
ExpiresIn=expiration
)
return url
if __name__ == '__main__':
# S3バケットとオブジェクトキーを指定
bucket_name = 'test_bucket'
object_key = 'test_folder/test.xlsx'
# 署名付きURLの生成とURL短縮化
presigned_url = generate_presigned_url(bucket_name, object_key)
shortener = pyshorteners.Shortener()
presigned_short_url = shortener.tinyurl.short(presigned_url)
print("署名付きURL: {}".format(presigned_short_url))
# Matillionのジョブ変数へ値を設定
context.updateVariable('presigned_short_url', presigned_short_url)
2. SNS Messageコンポーネントを使用して、ダウンロードURLをメールで通知する
注意点
今回注意点として注目いただきたい点は、boto3.clientの引数に指定している認証情報の部分になります。
s3_client = boto3.client('s3', config=Config(signature_version='s3v4'), region_name=region, aws_access_key_id=ACCESS_KEY, aws_secret_access_key=SECRET_KEY)
pythonファイルの実行環境がAWS上のリソースだった場合、boto3.clientの引数にはIAMユーザーのアクセスキー及びシークレットキーを指定しなくてもエラーになることはありません。ではどの認証情報を元にするかというと、実行するサービスに紐づいたIAMロールの認証情報を使用することになるのです。
よって今回の場合、実行環境はMatillionですが、そのMatillionはEC2上で稼働しているツールであるため、EC2に紐づけられたIAMロールが認証情報となります。
ではこの認証情報の指定有無がどんな影響を及ぼすのかについて着目していきましょう。
URLの有効期限
署名付きURLは、発行する際にURLの有効期限を指定することができます。
以下のexpirationで指定している数字が有効期限にあたり、秒単位の記載が可能です。(86400=24時間)
def generate_presigned_url(bucket_name, object_key, expiration=86400, region='ap-northeast-1'):
....
....
url = s3_client.generate_presigned_url(
'get_object',
Params={'Bucket': bucket_name, 'Key': object_key},
ExpiresIn=expiration
)
return url
実はこの有効期限の指定、boto3.clientで使用する認証情報次第では無効となってしまうのです。。
AWS公式の情報センターに投稿された以下の記事を見てみましょう。
https://repost.aws/ja/knowledge-center/presigned-url-s3-bucket-expiration
記事に記載の通り、IAMロールでは最長6時間の設定しかできず、それ以上の期限の指定を行いたい場合はIAMユーザーの認証情報、いわゆるアクセスキーとシークレットキーを使用する必要があるというわけです。
よって解決策としては、例えばこの署名付きURLを発行するためのIAMユーザーを新規に作成し必要なポリシーを付与した上で、アクセスキー及びシークレットキーを生成して認証情報としてboto3.clientの引数に指定することで有効期限の指定が可能になります。くれぐれもキーの指定方法や管理にはお気をつけください!
おまけ
発行したURL文字列には、S3バケットやオブジェクト名、署名やクエリパラメータ等の情報が含まれるため非常に長くなります。短いURLとして簡潔に共有するためにも、以下のようにpyshortenersというライブラリを用いてURLの短縮化をコードで行うことができますので是非使用してみてください!
import pyshorteners
shortener = pyshorteners.Shortener()
presigned_short_url = shortener.tinyurl.short(presigned_url)
おわりに
本記事では、AWS S3に存在するオブジェクトに対して署名付きURLを発行する方法や、その注意点等を紹介させていただきました。実際には単一のファイル名だけでなく、複数のファイルや日付のプレフィックスがついたファイル名に対して日次で署名付きURLを発行するといった処理をMatillion上で実装したため、より詳しいMatillionの扱い方なども紹介していければと考えています!是非そちらも楽しみにお待ちください。
ここまで読んでくださった方、どうもありがとうございました!
エクスチュアはAdobe Experience Cloud、Tableau、Lookerなどに精通したスタッフによるデータ活用サポート、各マーケティングツールの導入実装・活用支援のコンサルティングサービスや、GCP/AWSなどのパブリッククラウドを使ったデータ分析基盤構築コンサルティングサービスを提供しております。
デジタルマーケティングやデータ分析基盤構築に関するお悩みや活用支援、他分析ツールなどについてお困りの方はお気軽にご質問・ご相談ください。