🦉

AmplifyとWAFを連携しアクセスコントロールする方法

2024/12/17に公開

この記事は LCL Advent Calendar 2024 の 17日目の記事です。
https://qiita.com/advent-calendar/2024
12/16 の記事は @takara の S3+CloudFrontでの配信基盤の構築で詰まったポイント でした。
https://zenn.dev/lclco/articles/c8b5e6424cd8c7
S3のアクセスコントロール周り複雑な分、ソリューション記事は助かりますね🙏
本日も同じくAWSアクセスコントロール関連の紹介をいたします!

はじめに

弊社のHPをリニューアルするにあたり、ECS(WordPress)で動いていたインフラ環境を、Amplify(Next.jsアプリ)+microCMSに移行することになりました。
https://www.lclco.com/

新HPには、アクセス制限・ブラックリスト機能などのアクセスコントロール全般機能を付与したかったのですが、Amplifyだけだとそのような機能は付与できないようでした。
今回はCloudFront+WAFを紐付けたことで、アクセスコントロール機能を付与できたので、その方法をご紹介します!

結論


Amplifyの前段にCloudFrontを配置し、WAFを連携させることで、アクセスコントロールを可能にしました。

経緯

先述の通り、Amplifyでのアクセスコントロールは不可だったので、WAFを用いてアクセスコントロールを行おうと思いました。
WAFの連携にはCloudFrontが必要だったので、Amplify内部のCloudFrontに連携できないか、サポートセンターに問い合わせたところ、それは不可とのことだったので、Amplifyの前段にCloudFrontを配置して、そこにWAFを連携させました。

実装詳細

Terraformで実装したので、CloudFrontのコードの一部を紹介します。
Amplify, WAF, ACMとの連携箇所はコードのコメントをご参照ください。
実装意図等もコメントしてあります。
また、今回の記事では触れていませんが、AmplifyのBasic認証突破にはLambda@Edgeを使用しています。

resource "aws_cloudfront_distribution" "app" {
  origin {
    domain_name = var.origin_domain_name # Amplifyのエンドポイントを設定
    origin_id   = local.name_prefix # 任意の識別子

    # 以下の数値の設定はお好みで
    custom_origin_config {
      http_port                = 80
      https_port               = 443
      origin_protocol_policy   = "https-only"
      origin_ssl_protocols     = ["TLSv1.2"]
      origin_keepalive_timeout = 60
      origin_read_timeout      = 60
    }
  }

  # Route53に登録してあるAレコード
  aliases = [var.domain_name]

  enabled         = true
  is_ipv6_enabled = true
  comment         = "コメント"
  # 以下でWAFと連携
  web_acl_id = var.web_acl_id

  viewer_certificate {
    cloudfront_default_certificate = false
    # 以下でACMと連携
    acm_certificate_arn      = var.acm_certificate_arn
    minimum_protocol_version = "TLSv1.2_2021"
    ssl_support_method       = "sni-only"
  }

  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD", "OPTIONS"]
    cached_methods   = ["GET", "HEAD", "OPTIONS"]
    target_origin_id = local.name_prefix
    # Amplify内部のCloudFrontにキャッシュの設定があるので、前段のCloudFrontにはキャッシュをさせないよう設定してあります。
    cache_policy_id  = aws_cloudfront_cache_policy.no_cache_policy.id

    # CloudFrontにBasic認証を設定しています。
    function_association {
      event_type   = "viewer-request"
      function_arn = aws_cloudfront_function.basic_auth.arn
    }

    # CloudFrontからのアクセスの場合、AmplifyのBasic認証を突破するLambdaです。
    lambda_function_association {
      event_type = "origin-request"
      lambda_arn = aws_lambda_function.basic_auth_lambda.qualified_arn
    }

    viewer_protocol_policy = "redirect-to-https"
    min_ttl                = 0
    default_ttl            = 0
    max_ttl                = 0
    compress               = false
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }
}

参考記事

https://tech.nri-net.com/entry/add_cloudfront_waf_edge_and_acm_to_custom_origin_like_aws_amplify_hosting

おわりに

Amplifyでデプロイしたアプリにも、開発者がハンドリング可能なアクセスコントロール機能があった方が便利だと思います。
前例が少なめだったので、今回の記事を執筆しました。
この記事が誰かのお役に立つことを願います🌱

LCL Engineers

Discussion