Top View


Author uchida

Terraform | CloudFrontにカスタムヘッダーを追加し WAF で ALB へのアクセスを制限する

2021/11/17


ALBの前段にCloudFrontを設置している場合、ALBに直接アクセスされたくないことが多いです。 ALBにWAFを追加し、CloudFrontからALBへの通信のみを許可する設定をTerraformでやってみました。

やること

  1. CloudFrontにカスタムヘッダーを追加する
  2. WAFにルールを追加し、ALBと紐づける

CloudFrontにカスタムヘッダーを追加する

ALBの前に設置されるCloudFrontにカスタムヘッダーの設定を行います。
こちらを行うことで、CloudFrontからALBへ通信される際に任意のヘッダーと値が追加されます。
AWSで予約されているヘッダー以外から任意の値を設定してください。
CloudFront でオリジンリクエストに追加できないカスタムヘッダー

# CloudFrontの設定(中略
resource "aws_cloudfront_distribution" "cdn" {
  ......

  origin {
      ......

    custom_header {
      name  = {任意のヘッダー名}
      value = {ヘッダーに設定する値}
    }
  }
  ......
}

WAFにルールを追加し、ALBと紐づける

WAFを作成しカスタムヘッダーを判定するルールを追加し、ALBと紐づけます。

# WAFの定義
resource "aws_wafregional_web_acl" "alb_acl" {
  name        = "alb_acl"
  metric_name = "AlbAcl"

  # DefaultはDeny
  default_action {
    type = "BLOCK"
  }

  # CloudFrontからのアクセスのみを許可するルールをALLOW
  rule {
    action {
      type = "ALLOW"
    }

    priority = 1
    rule_id  = aws_wafregional_rule.get_from_cloudfront_rule.id
  }
}

# ALBとの紐づけ
resource "aws_wafregional_web_acl_association" "alb_acl_attach_alb" {
    resource_arn = {ALBのARN}
    web_acl_id   = aws_wafregional_web_acl.alb_acl.id
}

# WAFのルール
resource "aws_wafregional_rule" "get_from_cloudfront_rule" {
  name        = "get_from_cloudfront_rule"
  metric_name = "GetFromCloudFront"

  # GETのみ許可
  predicate {
    data_id = aws_wafregional_byte_match_set.http_method_get_match.id
    negated = false
    type    = "ByteMatch"
  }

  # カスタムヘッダーの判定
  predicate {
    data_id = aws_wafregional_byte_match_set.cloudfront_custom_header_match.id
    negated = false
    type    = "ByteMatch"
  }
}

# GETのみ許可
resource "aws_wafregional_byte_match_set" "http_method_get_match" {
  name = "http_method_get_match"

  byte_match_tuples {
    text_transformation   = "NONE"
    target_string         = "GET"
    positional_constraint = "EXACTLY"

    field_to_match {
      type = "METHOD"
    }
  }
}

# カスタムヘッダーの判定
resource "aws_wafregional_byte_match_set" "cloudfront_custom_header_match" {
  name = "cloudfront_custom_header_match"

  byte_match_tuples {
    text_transformation   = "NONE"
    target_string         = {CloudFrontに設定したヘッダーの値}
    positional_constraint = "CONTAINS"

    field_to_match {
      type = "HEADER"
      data  = {CloudFrontに設定した任意のヘッダー名}
    }
  }
}

uchida

uchida

福岡でWebエンジニアやってます。PHP, クラウド, インフラあたりが好き。