これはなんですか
- 別アカウントからS3バケットにオブジェクトを投入し、CloudFrontで読む設定をした時に失敗したのでメモとして残しておきます。
- クロスアカウントアクセスの際にはAssumeRoleを使いましょう、という話です。
- 失敗の内容と解決策を書きます。
ざっくり構成
- アカウントAとアカウントBがあり、アカウントA側でCloudFront + S3(OAI)を設定する。
- CloudFrontの署名つきURLを発行してバケット内のオブジェクトを読み込むアプリケーションを作成していた。
- アプリケーションの要件で、アカウントBからS3バケットにオブジェクトをおく必要があり、次の設定を行った
- アカウントB側でS3バケットへのPutObjectを許可するポリシーを書き、ロールに当てる
- アカウントAのS3バケットポリシーに上記ロールからのPutObjectを許可する設定を書く
おきたことと解決策
事象1. アカウントAがオブジェクトを操作できない
上記設定でアカウントBからアカウントAにオブジェクトを配置したところ、アカウントAのユーザー、ロールからオブジェクトの操作ができなくなっていた。CloudFront経由でアクセスしても403 (AccessDenied) が返ってくる。
原因
オブジェクトのACLを確認したところ、アカウントBがオーナーとなっており、アカウントAへのアクセス権限が設定されていなかった。
解決策
原因は、アカウントBがオブジェクトへのアクセス権をアカウントAに付与しなかったこと。以下リンク (AWSのKnowledge Center) がまさにこの件を扱っている。
ざっくり言うと、「PutObjectの際にACL設定に bucket-owner-full-control
を指定すればOK」と言う内容。
事象2. CloudFrontで403エラー(AccessDenied)が返ってくる
上記問題を解決したものの、依然としてCloudFront経由のアクセスでは403となる。
原因
オブジェクトのオーナーについて調べたところ、以下の記事を見つけた。
曰く、
オブジェクトのオーナーがバケットのオーナーと異なる場合、そのオブジェクトにはバケットポリシーによるアクセス制御が効かない
とのこと。CloudfrontのOAI設定は以下のようなS3のバケットポリシーで行うため、今の構成ではCloudFront経由のアクセスは実現できない。
{
"Version": "2012-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity Exxxxxxxxxxxxxxxx"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
},
... 略 ...
]
}
解決策
クロスアカウントアクセスの方法を変えることで解決した。
- アカウントAにIAMロールを作成し、アカウントBとの信頼関係を設定する
- 作成したIAMロールにS3バケットへのPutObject権限を付与する
- アカウントBはアカウントAのロールに対して
sts:AssumeRole
を許可するポリシーをロールに当て、アプリ側で AssumeRole を行いS3バケットにオブジェクトを配置する
こうすることでアカウントBはアカウントAの権限を委任されることになり、オブジェクトのオーナーがアカウントAとなる。この設定により無事にCloudFront経由のアクセスができるようになった。 (そもそも初めからこうしておけば事象1も発生しなかった)
まとめ
- CloudFront + S3 構成で別アカウントからS3バケットにオブジェクトを投入しようとして失敗しまくった
- 素直にAssumeRole設定を書くことで解決した
感想
- すごく勉強になった。
- 横着はよくない。