tl;dr
AWS アカウントをまたいだ S3 バケットへの書き込みが色々とアレなので Lambda で無理矢理アレした。
※1年半ぶりに追記: 解決策はあまりにも無理矢理だったが問題の知見としては有用なのでタイトルを変更しておく
背景
S3 は AWS 最古参のサービスであり、 S3 が登場した頃は IAM も存在しなかった。このため、今では AWS サービスの標準アクセス権限管理になった IAM とは異なる、独自のアクセス権限管理の仕組みが S3 にはある。
この歴史的経緯により、ある状況で非常に面倒な事態が発生する。
バケットオーナー != オブジェクトオーナー の場合に発生するつらみ
- 凡例
- つらくない現実
- つらい現実
- バケットポリシーで他アカウントへの認可を設定すると、別の AWS アカウント(と、その配下の IAM User など)がバケットへの書き込みを行えるようになる
- バケットに
PutObject
されたオブジェクトのオーナーはそのオブジェクトを PUT したユーザーになる- ここでの
ユーザー
はAWS アカウント
と読み替えても構わない - これが誰なのかを調べる API は
GetObjectACL
である
- ここでの
-
権限付与(Object ACL)を明示的に指定せず PUT されたオブジェクトへの権限は、オブジェクトオーナーのフルアクセスのみになる
- オブジェクトオーナーのフルアクセス権限は剥がすことができるが、そのようにしても依然としてオブジェクトオーナーはそのオブジェクトへのフルアクセスが可能である
- 自分がオーナーではなく、自分に対して明示的許可が与えられていないオブジェクトに対する
GetObject
、GetObjectACL
はバケットオーナーであっても不可能 - バケットオーナーは、自分に対してアクセス許可がないオブジェクトを
DeleteObject
できる - 自分がオーナーでないオブジェクトと同じキーに対して
PutObject
すること(上書き)は可能 - バケットポリシーによるアクセス許可は、オーナーがバケットオーナーであるオブジェクトのみに適用される
どうしたか
アカウント A と B があるとして、アカウント A にあるバケットに対し、アカウント B から PutObject
した場合に上のようなつらみが発生する。
そこで、まず s3:PutObject
, s3:GetObject
, s3:GetObjectAcl
が可能な Role をアカウント B に作り、さらに以下のような Lambda Function をアカウント A に配置して S3 の ObjectCreated
イベントで発火するようにした。
これは何をしているのか
前述の、アカウント B にある Role をsts:AssumeRole
する作成されたオブジェクトにバケットオーナー(アカウント A)に対する ACL が設定されていなければバケットオーナー(アカウント A)に対する ACL を明示的に指定して、PutObject
しなおす
1が必要なのは、この場合2と3がそもそもアカウント A からは操作できないから。
まとめ
ここまで全部 BK 。 S3 (Simple Storage Service) は極力シンプルに使うべき。
その他
Serverless Framework で書き直したい。