はじめに
S3の静的ウェブサイトホスティングは便利。
でもエンドポイントがhttp://バケット名.s3-website-ap-northeast-1.amazonaws.com
になってしまったりhttps://s3-ap-northeast-1.amazonaws.com/バケット名.com
になってしまってイケてない。内部通信くらいはちゃんとしたサービス名をつけてあげたいけど内部通信にドメイン使用量は払いたくない。
そんなワガママなあなたに、良い感じの名前でアクセスするコツを書いておく。
さらに、今回の記事では、作った静的ウェブサイトホスティングに対してクロスアカウントでセキュアにアクセスする方法まで書いておく。
Route53のプライベートホストゾーンを使おう
良い感じの名前を付けるのであれば、Route53のプライベートホストゾーンを使えば良い。
プライベートホストゾーンを設定する方法は以前の記事に書いている。
一つ注意しなければいけないのは、S3のエイリアスを作る場合は、「ホスト名=バケット名」になっている必要があるということだ。これをやっておかないと、Route53のホストゾーンでAレコードをS3に紐付けることができない。
Terraformで格納であればこんな感じになる。name = aws_s3_bucket.my.id
としているのがキモだ。
lifecycle
については後述する。
resource "aws_route53_zone" "s3" {
provider = aws.to_account
name = local.zone_name
vpc {
vpc_id = data.aws_vpc.to.id
}
}
resource "aws_route53_record" "s3" {
provider = aws.to_account
zone_id = aws_route53_zone.s3.zone_id
name = aws_s3_bucket.my.id
type = "A"
alias {
name = aws_s3_bucket.my.website_domain
zone_id = aws_s3_bucket.my.hosted_zone_id
evaluate_target_health = true
}
}
作ったエイリアスレコードを他のAWSアカウントと共有してクロスアカウントアクセスを可能にする
さて、せっかく作ったエイリアスレコードなのだから、複数のサービスで共通で使用したくなることがあるかもしれない。ないかもしれないしその可能性が高い。
だが、もしそういう事態が訪れた時には、AWS公式がやり方を紹介してくれている。
このリンクお貼っておくだけでは芸がないので、Terraformで書くとこうなる、を置いておく。
resource "aws_route53_vpc_association_authorization" "s3" {
provider = aws.to_account
vpc_id = data.aws_vpc.from.id
zone_id = aws_route53_zone.s3.id
}
resource "aws_route53_zone_association" "s3" {
provider = aws.from_account
vpc_id = aws_route53_vpc_association_authorization.s3.vpc_id
zone_id = aws_route53_vpc_association_authorization.s3.zone_id
}
これでterraform applyすると、aws_route53_zoneに指定したVPCが追加される。
しかし、VPCが追加されるということは、aws_route53_zone.s3
の.tfファイルとプロパティが合わなくなってしまうということだ。
すると、何が起こるかと言うと、次にapplyするタイミングで、実際のリソースとの差分を検知して、せっかく設定したVPCの設定が削除されてしまう。
これを避けるために、aws_route53_zone_association でクロスアカウント設定する場合は、aws_route53_zone に以下の設定を追加する。
resource "aws_route53_zone" "s3" {
provider = aws.to_account
name = local.zone_name
vpc {
vpc_id = data.aws_vpc.to.id
}
lifecycle { ★追加
ignore_changes = [ ★追加
vpc, ★追加
] ★追加
} ★追加
}
これにより、vpcの変更は無視されるようになるため、次に関係のないリソースをapplyする際に差文検知しなくなる。
クロスアカウントアクセスをセキュアにする
さて、静的Webサイトホスティングの用途は千差万別だが、内部のためにクロスアカウントアクセスを設定したのであれば、以下のようにVPCエンドポイント経由のアクセスにして、該当VPCエンドポイント以外からのアクセスを制限をしよう。バケットポリシーでAllowするのであれば、バケット全体のACL自体はprivate
でも問題ない。
resource "aws_vpc_endpoint" "s3" {
provider = aws.from_account
vpc_id = data.aws_vpc.from.id
service_name = "com.amazonaws.ap-northeast-1.s3"
}
resource "aws_vpc_endpoint_route_table_association" "s3" {
provider = aws.from_account
route_table_id = data.aws_route_table.from.id
vpc_endpoint_id = aws_vpc_endpoint.s3.id
}
resource "aws_s3_bucket_policy" "my" {
provider = aws.to_account
bucket = aws_s3_bucket.my.id
policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowVPCEndPointRead",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::${local.bucket_name}",
"arn:aws:s3:::${local.bucket_name}/*"
],
"Condition": {
"StringEquals": {
"aws:sourceVpce": "${aws_vpc_endpoint.s3.id}"
}
}
}
]
}
POLICY
}