🐷

terraformを使ってAWS WAFだけでBasic認証を設定する

2022/04/23に公開1

Basic認証を導入する方法はCloudFront + Lambda Edge、CloudFront Function、
ALB + Lambdaなど、色々あるかと思います。

WAFのルールでも設定が可能なようで、コードを書く必要がある上記と比べると
設定が楽&管理がしやすいかと思い選択、こちらをterraformで実装したので記事にします。

参考記事はこちら、これをterraformで書いたものです。
https://dev.classmethod.jp/articles/aws-waf-basic-auth/

早速ですがコードはこちら

resource "aws_wafv2_web_acl" "waf" {
  provider = aws.virginia
  name     = "waf"
  scope    = "CLOUDFRONT"

  default_action {
    allow {}
  }

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = "waf"
    sampled_requests_enabled   = true
  }

  rule {
    name     = "basic-auth"
    priority = 0

    action {
      block {
        custom_response {
          response_code = 401
          response_header {
            name  = "www-authenticate"
            value = "Basic"
          }
        }
      }
    }

    statement {
      not_statement {
        statement {
          byte_match_statement {
            positional_constraint = "EXACTLY"
            search_string         = "Basic xxxxxxxxxxxxxxxxxxxxxx"
            field_to_match {
              single_header {
                name = "authorization"
              }
            }
            text_transformation {
              priority = 0
              type     = "NONE"
            }
          }
        }
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "basic-auth"
      sampled_requests_enabled   = true
    }
  }
}

これをCloudFrontに割り当てればOK
(設定内容は参考サイトが詳しいのでそちらを参照ください)

ユーザ名/パスワードの入力欄も表示され、認証も問題なくできます

search_stringに指定するBasic xxxxxxxxは以下コマンドでさくっと作成

]# echo -n basic-user:basic-password | base64 | xargs -I{} echo Basic {}
Basic YmFzaWMtdXNlcjpiYXNpYy1wYXNzd29yZA==
]#

null_resourceを使ってterraform上でエンコードすることもできます。
provisioner "local-exec"の出力結果を他リソースで参照させることができないようなので、
テキストに出力した後にdata "local_file"で読み込みます。

resource "aws_wafv2_web_acl" "waf" {
(省略)
            - search_string = "Basic xxxxxxxxxxxxxxxxxxxxxx"
            + search_string = data.local_file.base64_encode.content
(省略)
}

resource "null_resource" "base64_encode" {
  provisioner "local-exec" {
    command = "echo -n $USERNAME:$PASSWORD | base64 | xargs -I{} echo Basic {} > basicauth.txt"

    environment  = {
      USERNAME = "basic-user"
      PASSWORD = "basic-password"
    }
  }
}

data "local_file" "base64_encode" {
  filename   = "${path.module}/basicauth.txt"
  depends_on = [null_resource.base64_encode]
}

ALBでBasic認証を入れる場合、ほぼ同じ方法で設定できるのも利点
WAFをREGIONALで作成してALBに適用しましょう

resource "aws_wafv2_web_acl" "waf" {
  name     = "waf"
  scope    = "REGIONAL"

...以下同じ

IP制限などと併用する場合も、同じWAFにルールを追加することで実装できます。
複数のアクセス制限をWAFだけで実装できるというのが運用的な観点でより管理しやすい!はず

Discussion