はじめに
S3へのアクセスを制御するために様々な機能がありますが、これらはIAMのアクセス制御と混同して考えられることが多く、両方の機能の関連について、質問を非常に多く受けています。
以前に S3のアクセス制御はまずシンプルに捉えて対応すべき という記事を書きましたが、この記事に書いたように、S3バケットポリシーとIAMポリシーには以下のような違いがあります。
- S3バケットポリシーは、S3側で、エンティティから行われるアクセスの制御
- IAMポリシーの場合、エンティティ側で、S3に対して行うアクセスの制御
このように、両者では設定箇所および制御する操作の矢印の方向が異なります。
基本はこの2つでS3バケットやオブジェクトに対するアクセス制御を行いますが、この2つに加えて、全く異なるアクセス制御の要素が加わることがあります。
その代表例と言える 「Presigned URL」 を今回は取り上げます。
Presigned URLとは
誰でも一時的にS3オブジェクトの操作を可能にするためのURLです。
URLを知っていれば、誰でも、インターネット経由でS3オブジェクトの操作が可能となります。
最も基本的な使い方として、クラウドストレージのBoxのように、URLを知っている人に期限付きでファイルをダウンロード(s3:GetObject)させることができます。
さらに、URLの発行の仕方によっては、ダウンロード以外の操作も可能にします。
Presigned URLは、オブジェクトの一時ダウンロードURLを発行する用途として広く認識されていますが、その本質は 「URLを発行するIAMユーザーまたはロールで可能なS3に対する操作を、URLを介して、期限付きでできるようにする」 です。(詳細は後述)
コマンドの発行方法は2通りあり、AWS CLIの「aws s3 presign」を実行するか、AWS SDKで各言語のコマンド(Pythonの場合「generate_presigned_url」)を実行します。
コマンドを実行する時に、操作名、バケット名、オブジェクトキー、HTTPメソッド (GET または PUT)、および有効期限の日時を指定します。
記事執筆時点でCLIには操作名を指定するオプションがありませんので、「s3:GetObject」以外の操作をできるようにしたい場合はSDK一択となります。
Presigned URLの発行とアクセス許可
AWS CLIでURLを発行する場合、暗黙的に「s3:GetObject」の操作が指定されます。
AWS SDKでURLを発行する場合、クエリの記述方法は以下の通りで、1つの任意の操作をClientMethod
パラメータで指定できます。
ここに ClientMethod='put_object'
と書けば「s3:PutObject」の操作を指定できます。
url = s3_client.generate_presigned_url(
ClientMethod=client_method,
Params=method_parameters,
ExpiresIn=expires_in
)
s3_client = boto3.client('s3')
client_action = 'put_object'
url = s3_client.generate_presigned_url(
s3_client, client_action, {'Bucket': args.bucket, 'Key': args.key}, 86400)
IAMポリシー/S3バケットポリシーと「Presigned URL」の関係
前述の方法でURLを発行できますが、このURLを介して何でも操作が可能になるわけではなく、「URLを発行したIAMユーザーが可能なS3の操作」が「URLにつき1つ」発行されたURLを介してできるようになります。
ここで「URLを発行したIAMユーザーが可能なS3の操作」とは、冒頭に紹介した記事でも取り上げている、以下のフローで評価されて決まります。
引用: IAM Policies and Bucket Policies and ACLs! Oh, My! (Controlling Access to S3 Resources)
また、URLを介して実行可能なコマンドには、Presigned URLの仕様上の制限があり、全てのコマンドが実行できるわけではありません。
参考: Presigned URLs
URLを介したコマンド実行までの間にAWS側でアクセス制御の変更が行われる場合
通常「IAMユーザーがURLを発行」することと「誰かがURLを介してコマンドを実行」することは連続しておらず、必ず両方の操作の間にいくらか時間があります。
URL発行当時のアクセス制御が、コマンドが実行されるまでの間に変更された場合、コマンド実行時点の(変更された)アクセス制御が有効となります。
例えば、URLを発行する時にIAMユーザーが「s3:PutObject」の権限を持っていたとしても、誰かがURLを介してコマンドを実行するまでの間に「s3:PutObject」がIAMポリシーまたはS3バケットポリシーでDenyされた場合、URLを介して「s3:PutObject」を実行できなくなります。
見方を変えれば、IAMユーザーは自身の権限を超えた操作を可能とするURLを発行できないと言えますし、自身の権限を(Presigned URLの仕様上の制限内で)誰にでも渡すことができるとも言えます。
まとめ
以上の内容をまとめると、以下の図のようになります。
Presigned URLを知る者なら誰でもS3オブジェクトに対する操作が可能となりますが、その操作はURLを発行したIAMユーザーの権限で可能な操作の中から、暗黙または明示的に指定された1つの操作となります。
「一時ダウンロード用途」として良く使われるPresigned URLですが、このアクセス制御の仕組みが分かると、開発の幅が広がりますし、トラブルシューティングにも役立つと思われます。
一つ不便な点として、現状はAWS SDKを使用しない限り「s3:GetObject」以外の操作を許可できない点がありますが、Presigned URLでは誰にでもアクセス権限を渡すことができますから、発行できる前提条件が限られているほうが、セキュリティの観点で良いとも言えます。