サーバーサイドエンジニアのいわむ(@k_iwamu)です。
AWSのサービスを組み合わせて、サーバーレスで静的サイトをホスティングするインフラを構築しました。
前回書いた記事中ではS3のオブジェクトを静的ウェブサイトホスティング機能を用いてホスティングし、 IP制限はバケットポリシーで行う方法を紹介しておりました。
今回は、HTTPSでの通信を実現するため、 S3のオブジェクトをCloudFrontを用いてホスティングし、IP制限はAWS WAFで行う実装を行ったので紹介します。 Terraformで作成したので、サンプルコードも少し載せておきます。参考になれば嬉しいです。
構成図
やったこと
CloudFrontでホスティング
CloudFront + S3 はサーバーレスで静的サイトをホスティングし、CDN配信ができる強力な組み合わせですね。
今回のポイントは、S3のアクセスをCloudFrontからに限定することです。
Terraformのaws_cloudfront_origin_access_identityで設定することができます。
cloudfront.tf※ ポイントだけ抽出してます。
resource "aws_cloudfront_origin_access_identity" "blog_sample" { } resource "aws_cloudfront_distribution" "blog_sample" { enabled = true // AWS WAFのルールを適用させる web_acl_id = "${aws_waf_web_acl.allow_only_timers_vpn.id}" origin { domain_name = "${var.s3_blog_sample_bucket_domain_name}" origin_id = "S3-${var.s3_blog_sample_bucket}" s3_origin_config { // CloudFrontからのアクセスのみ許可するようにする origin_access_identity = "${aws_cloudfront_origin_access_identity.blog_sample.cloudfront_access_identity_path}" } } }
s3.tf
resource "aws_s3_bucket" "blog_sample" { bucket = "blog_sample" acl = "private" } // アクセスをブロックしておく resource "aws_s3_bucket_public_access_block" "blog_sample" { bucket = "${aws_s3_bucket.blog_sample.id}" block_public_acls = true block_public_policy = true restrict_public_buckets = true ignore_public_acls = true } // CloudFrontからのアクセスを許可するポリシー作成 data "aws_iam_policy_document" "blog_sample" { statement { actions = ["s3:GetObject"] resources = ["${aws_s3_bucket.blog_sample.arn}/*"] principals { type = "AWS" identifiers = ["${var.cloudfront_blog_sample_origin_access_identity_iam_arn}"] } } } // ポリシー適用 resource "aws_s3_bucket_policy" "blog_sample" { bucket = "${aws_s3_bucket.blog_sample.id}" policy = "${data.aws_iam_policy_document.blog_sample.json}" }
これで、S3のオブジェクトを、CloudFrontからのみアクセスできるように設定できます。
AWS WAFを使ってIP制限
AWS WAFは特定の条件の通信(IPアドレス、HTTPヘッダー、URI文字列、SQLインジェクション...)を検知し遮断することができ、様々な攻撃からリソースを保護するために用いられるサービスです。
CloudFrontだけでなく、API Gatewayや ALBに対してもルールを適用できます。
指定のIP(会社のVPN)からのアクセスのみを許可するルールをCloudFrontに適用させるTerraformのサンプルコードです。
waf.tf
resource "aws_waf_ipset" "company_vpn" { name = "CompanyVpn" ip_set_descriptors { type = "IPV4" value = "xxx.xxx.xx.xx/xx" // 許可するIPを記入 } } resource "aws_waf_rule" "match_company_vpn" { depends_on = ["aws_waf_ipset.company_vpn"] name = "matchCompanyVpn" metric_name = "matchCompanyVpn" predicates { data_id = "${aws_waf_ipset.company_vpn.id}" negated = false type = "IPMatch" } } resource "aws_waf_web_acl" "allow_only_company_vpn" { depends_on = ["aws_waf_ipset.company_vpn", "aws_waf_rule.match_company_vpn"] name = "allowOnlyCompanyVpn" metric_name = "allowOnlyCompanyVpn" default_action { type = "BLOCK" } rules { action { type = "ALLOW" } priority = 1 rule_id = "${aws_waf_rule.match_company_vpn.id}" type = "REGULAR" } }
CloudFrontのディストリビューションの設定に追記します。そうすることで、CloudFrontにWAFのルールを適用させることができます。
cloudfront.tf
resource "aws_cloudfront_distribution" "blog_sample" { // AWS WAFのルールを適用させる web_acl_id = "${aws_waf_web_acl.allow_only_company_vpn.id}" }
指定のIP以外からアクセスすると許可されないことが確認できました。
指定のIPからアクセスすると許可されることが確認することができました。
まとめ
AWSのサービス組み合わせてCDN配信やWAF機能を簡単に提供できるのが嬉しいですね。 運用に手間をかけたくない方はこういったサーバーレスでの構築を取り入れてみてはいかがでしょうか。
これからもどんどんクラウドの恩恵に授かっていこうと思います!笑
積極採用中!!
子育て家族アプリFammを運営するTimers inc.では、現在エンジニアを積極採用中!
急成長中のサービスの技術の話を少しでも聞いてみたい方、スタートアップで働きたい方など、是非お気軽にご連絡ください!
採用HP: http://timers-inc.com/engineerings