今日のつちや

田舎から元気に技術ネタと雑記を投稿します

Amazon S3へのセキュアなファイルアップロード方法まとめ

連休はAWSでセキュアにサーバーレスする方法勉強するぞー!と思い、 手始めにセキュアにS3へファイルをアップロードする方法を整理したかったのでまとめた。 サーバーレスとそうでない場合の比較である。

次の3種類を紹介する。

  1. アプリケーションサーバー経由
  2. アプリケーションサーバー + 署名付きURL
  3. サーバーレス(API Gateway + カスタムオーソライザ)

1. アプリケーションサーバ経由

f:id:corocn:20180428215902p:plain

非常に一般的な方法。画像には分かりやすさのためにRailsを載せているが、 RailsでなくてLaravelでもDjangoでも同様だしそもそもフレームワークを使わなくても良い。

認証はセッション認証やトークン認証をアプリケーションサーバで解決し、 サーバーが保有するS3のアクセスキーを使ってアップロードを行う。 アクセスキーはユーザーには露出していない。シンプル。

2. アプリケーションサーバー + 署名付きURL

f:id:corocn:20180428220354p:plain

署名付きURLは、S3へ期限付きでアップロードやダウンロードを可能にする仕組み。 S3だけでなくてGoogle Cloud StorageやAzure Storageにも同様の機能は存在するようだ。

署名付き URL を使用したオブジェクトのアップロード - Amazon Simple Storage Service

1.同様に認証はアプリケーションサーバで解決した上で、アップロード要求に対して、署名付きURLを返す。 クライアントは署名付きURLに対してファイルをアップロードする。

この方法の利点は、ファイルが直接S3に投げ込まれるため、アプリケーションサーバー側での負荷が減る。 フロー見ると分かるけど、そこまで複雑な仕組みではないはず。

Rails 5.2で導入されたActiveStorageのDirect Uploadsがこの仕組みを採用している。 Active Storage Overview — Ruby on Rails Guides

3. サーバーレス(API Gateway + Custom Authorizer)

f:id:corocn:20180428221400p:plain

API Gatewayにはカスタムオーソライザーという機能が存在し、APIに認証機能を組み込むことができる。 カスタムオーソライザーの中で、CognitoやAuth0のような外部IdP(Identity Provider)から発行されたTokenの検証を行えば良い。 カスタムオーソライザーって言ってるけど実態はLambda Functionなので、サービスロジックの前段でLambdaでTokenの検証を行うような感じ。

API Gatewayの認証さえ潜り抜けてしまえば、後はLambdaを経由してS3に保存するなり、S3プロキシとして直接アップロードするなりなんでもできる。 また、これはファイルのアップロードに限定する話ではなく、API Gatewayを使う場合の一般的な認証の仕組み・・のはず。

その他

API Gateway + Lambdaで署名付きURLを発行する方法を思いついたが、 署名付きURLを発行するAPIに対する認証を考慮すると、回りくどいし先ほど紹介した3でいいのでは?という気持ちになった。 この方法をやろうとしている人を見かけるけど、何か利点があるんだろうか?良くわからない。

感想

図だけ見るとサーバーレスが過度に複雑のように見えるが、 認証の仕組みがAWSに寄ってるだけで、基本を理解すればそう難しくないと思った。 (モノリシックフレームワークの認証機能をそのまま使うのは、それはそれで楽なんだけど)

AWS強い人間違ってたら指摘下さい!

by @corocn