アクセス権限
バケットの所有者とオブジェクトの所有者が違う場合に、オブジェクトの権限をバケットポリシーに合わせたい
やりたいこと
- AWSアカウントA(以降A)が作成したバケットに、AWSアカウントB(以降B)がオブジェクトのPUTをする
- オブジェクトの閲覧は、Aが所有するCloudFrontからのみ許可したい
バケットポリシーはこんな感じでやろうとした(これは正しく動かない)
data "aws_iam_policy_document" "this" {
statement {
effect = "Allow"
principals {
type = "AWS"
// AWSアカウントBのfargateのロールに書き込みを許可する
identifiers = [
"arn:aws:iam::${var.AWS_ACCOUNT_B}:role/fargate-test-rails-app",
]
}
actions = [
"s3:PutObject",
]
resources = [
"arn:aws:s3:::<TEST_BUCKET>/*"
]
}
// cloudfrontのOAIにGetを許可する
// これだけでは実際にアクセスしてもAccess Denyになる!!!!
statement {
effect = "Allow"
principals {
type = "AWS"
identifiers = [
aws_cloudfront_origin_access_identity.this.iam_arn
]
}
actions = [
"s3:GetObject",
]
resources = [
"arn:aws:s3:::<TEST_BUCKET>/*"
]
}
}
色んな情報
バケットポリシーがアクセスを許可する場合、S3 バケットを所有する AWS アカウントもオブジェクトを所有する必要がある
https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-rest-api-cloudfront-error-403/
今回はオブジェクトの所有者がBだからこの問題が発生していた。
- オブジェクトにバケットオーナーへのフルアクセス権限を付与する
- オブジェクトを同名でcpする
- cpしたアカウントが所有者になるため、Aが所有者となる
これで所有者を変更すれば解決するが、都度cpが発生するので毎回変更するのはつらくないか‥?
バケットポリシーでBにPutObjectを許可する際に、bucket-owner-full-control
が設定されている場合にのみ許可することができる
https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-require-object-ownership/
これでは所有者は変わらず、CloudFrontからのアクセスはできなかった。
今回はRails(Carrierwave/fog)からのアクセスを想定しているため、アップロード時にaclの設定ができるのかが気になっている(まだ調べきれていない)
AssumeRoleを付与する
これで解決した。よくあることだったらしい…
https://dev.classmethod.jp/etc/sugano-005-s3/
解決方法
バケットポリシーではCloudFrontからのアクセス権限のみ残し、Put権限は剥がす
data "aws_iam_policy_document" "this" {
// put権限はバケットポリシーから削除し、Get権限だけ残す
// cloudfrontのOAIにGetを許可する
statement {
effect = "Allow"
principals {
type = "AWS"
identifiers = [
aws_cloudfront_origin_access_identity.this.iam_arn
]
}
actions = [
"s3:GetObject",
]
resources = [
"arn:aws:s3:::<TEST_BUCKET>/*"
]
}
}
iam roleを作成し、AssumeRoleを付与する
今回はECSからのassumeを許可する
resource "aws_iam_role" "put-bucket" {
name = "put-bucket"
assume_role_policy = data.aws_iam_policy_document.put-bucket-assume-.json
}
data "aws_iam_policy_document" "put-bucket-assume" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}
iamポリシーをアタッチする
アカウントBのfargateに対しての許可と明示する
resource "aws_iam_role_policy" "put-bucket" {
policy = data.aws_iam_policy_document.put-bucket.json
role = aws_iam_role.put-residency-certificates.id
}
data "aws_iam_policy_document" "put-bucket" {
// fargate-test-rails-appからのassumeを許可
statement {
actions = [
"sts:AssumeRole",
]
resources = [
"arn:aws:iam::${var.AWS_ACCOUNT_B}:role/fargate-test-rails-app",
]
}
statement {
effect = "Allow"
actions = [
"s3:PutObject",
]
resources = [
"arn:aws:s3:::<TEST_BUCKET>/*"
]
}
}
アカウントBのfargateに付与しているiam roleに対してiamポリシーをアタッチする アカウントAで作ったroleを指定する
resource "aws_iam_role_policy" "put-account-a-bucket" {
name = "put-account-a-bucket"
role = module.fargate-test-rails-app.iam_role_name
policy = data.aws_iam_policy_document.put-account-a-bucket.json
}
data "aws_iam_policy_document" "put-account-a-bucket" {
statement {
effect = "Allow"
actions = [
"sts:AssumeRole",
]
resources = [
"arn:aws:iam::${var.AWS_ACCOUNT_A}:role/put-bucket",
]
}
}
これで終了。誰しもが通る道っぽいので、いい経験だった、、、