Timers Tech Blog

グローバルな家族アプリFammを運営するTimers inc (タイマーズ) の公式Tech Blogです。弊社のエンジニアリングを支える記事を随時公開。エンジニア絶賛採用中!→ https://timers-inc.com/engineering

AWS WAF + CloudFront + S3 でIP制限をかけたホスティングサイトをサーバレスで組み立てる

サーバーサイドエンジニアのいわむ(@k_iwamu)です。

AWSのサービスを組み合わせて、サーバーレスで静的サイトをホスティングするインフラを構築しました。

前回も静的サイトをホスティングする記事を書いており、 その記事中ではS3のオブジェクトを静的ウェブサイトホスティング機能を用いてホスティングし、 バケットポリシーでIP制限もする方法を紹介しておりました。

techblog.timers-inc.com

今回は、HTTPSでの通信を実現するため、 S3のオブジェクトをCloudFrontを用いてホスティングし、AWS WAFでIP制限を加える実装を行ったので紹介します。 Terraformで作成したので、サンプルコードも少し載せておきます。参考になれば嬉しいです。

構成図

f:id:kohei_iwamura:20200713181405p:plain

やったこと

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以外からアクセスすると許可されないことが確認できました。 f:id:kohei_iwamura:20200713191748p:plain

指定のIPからアクセスすると許可されることが確認することができました。 f:id:kohei_iwamura:20200713191803p:plain

まとめ

AWSのサービス組み合わせてCDN配信やWAF機能を簡単に提供できるのが嬉しいですね。 運用に手間をかけたくない方はこういったサーバーレスでの構築を取り入れてみてはいかがでしょうか。

これからもどんどんクラウドの恩恵に授かっていこうと思います!笑

積極採用中!!

子育て家族アプリFammを運営するTimers inc.では、現在エンジニアを積極採用中!
急成長中のサービスの技術の話を少しでも聞いてみたい方、スタートアップで働きたい方など、是非お気軽にご連絡ください!
採用HP: http://timers-inc.com/engineerings

Timersでは各職種を積極採用中!

急成長スタートアップで、最高のものづくりをしよう。

募集の詳細をみる