Amazon S3へのセキュアなファイルアップロード方法まとめ
連休はAWSでセキュアにサーバーレスする方法勉強するぞー!と思い、 手始めにセキュアにS3へファイルをアップロードする方法を整理したかったのでまとめた。 サーバーレスとそうでない場合の比較である。
次の3種類を紹介する。
- アプリケーションサーバー経由
- アプリケーションサーバー + 署名付きURL
- サーバーレス(API Gateway + カスタムオーソライザ)
1. アプリケーションサーバ経由
非常に一般的な方法。画像には分かりやすさのためにRailsを載せているが、 RailsでなくてLaravelでもDjangoでも同様だしそもそもフレームワークを使わなくても良い。
認証はセッション認証やトークン認証をアプリケーションサーバで解決し、 サーバーが保有するS3のアクセスキーを使ってアップロードを行う。 アクセスキーはユーザーには露出していない。シンプル。
2. アプリケーションサーバー + 署名付きURL
署名付き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)
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