10分以内に Fastly Next-Gen WAF のデプロイを完了する方法
まずはじめに
Web や API のエンドポイントを保護しようとする際に組織が直面する主な問題として、セキュリティソリューションの複雑さや管理の難しさと、デプロイに時間と手間がかかるという2つが挙げられます。
脅威の状況がダイナミックに発展する中、DevOps チームは素早くポリシーやルール (カスタムシグナルやレート制限ルールなど) を変更してアプリケーションに対するセキュリティ脅威に対応できる必要があります。
深刻化が進む Web の脅威に対抗するには、強力なセキュリティポリシーが必要ですが、それにはスピードと自動化が欠かせません。攻撃を防ぐためには、人によるミスを回避しながら迅速にルールを更新して脅威の状況にすぐに適応できることが重要です。このブログ記事では、IaC (Infrastructure-as-Code) を含む、効果的な統合型のアプローチをご紹介します。
次世代ソリューションの Fastly Next-Gen WAF (NGWAF) は、上記の2つの問題を解決できます。NGWAF では、セットアップ後すぐに誤検知を排除しながら脅威の検出を開始でき、ルールや正規表現パターンなどの設定や調整、管理は不要です。NGWAF が Gartner によって5年連続で「Customers’ Choice」で選ばれている</u>背景には理由があるのです。また、NGWAF はすぐに簡単にデプロイできます。以下では、Terraform を使って素早く簡単に NGWAF のエッジデプロイを作成する方法をご紹介します。
Terraform は、IT インフラのデプロイと管理を行うツールとして、ますます人気が高まっています。Terraform を使用することで、NGWAF をエッジにデプロイしてこれまで以上に簡単に Web や API のエンドポイントを保護することが可能になります。ただし、この記事では、Terraform よりも、インフラストラクチャのプロビジョニングを簡単に行うステップを紹介することを主な目的としています。
用語についての簡単な説明
ここでは、以下で使用されるいくつかの用語について、簡単にご説明します。詳細については、Fastly のオンラインドキュメント (https://docs.fastly.com/signalsciences/using-signal-sciences/corp-management/</u>) をご覧ください。
「Site」は「Corp」に属し、リクエストと設定のセットで構成されます。リクエストは、Site のアクセスキーと秘密鍵を使用して設定されたエージェントを通じて受信されます。設定には、エージェントルール (例 : リクエストに XSS のタグを付ける、ブロックリストと許可リストのルール、ブロックルール)、メンバーリスト、統合機能、その他の設定オプションが含まれます。理論的には、特定のアプリケーションまたはドメインのマッピング (例 : app1.example.com と app2.example.com) として Site を考えることができますが、複数のアプリケーションが同じサイトキーを共有したり、ひとつのアプリケーションを複数の Site に分割したりすることも可能です (例 : example.com と example.com/admin)。
「Corp」は「Corporation」の意味で、サイトとユーザーのセットで構成されています。ユーザーは、Corp レベルで認証され、同一 Corp に属するそれぞれの Site のメンバーが含まれます。
エッジデプロイ - https://docs.fastly.com/signalsciences/install-guides/edge/edge-deployment/</u>
エッジデプロイのメソッドによって、Signal Sciences をエッジセキュリティサービスとして Fastly のエッジクラウドプラットフォームに追加できます。自社のホスト環境に変更を加える必要は一切ありません。
デプロイの構造を決定する
お客様から「どの NGWAF Site をエッジ統合にリンクすべきか」、「エッジ統合のために新しい NGWAF Site を作成する必要があるか」と、よく聞かれます。NGWAF では、お客様の組織に最適な構造をお選びいただけます。既存の Site を簡単に使用することもできますし、この特定のデプロイオプションのために、新しい Site を作成することも可能です。これらのオプションの詳細については、エッジにデプロイする NGWAF の Corp と Site の構成を設計する方法を詳しく記したこちらの記事</u>をご覧ください。NGWAF の使用を開始する最もシンプルな方法は、既存の NGWAF Site を使用することです。
Fastly は、このプロセスに必要なものをすべて提供しています。
サービスの作成と管理の権限を持つ Fastly Edge API キー https://docs.fastly.com/ja/guides/using-api-tokens#creating-api-tokens</u>
Corp Admin の権限を持つ</u> NextGen WAF API キー
NextGen WAF の Corp と Site https://docs.fastly.com/signalsciences/using-signal-sciences/corp-management/</u>
Next-Gen WAF をエッジにデプロイする
以下の Terraform 設定を使用してエッジに NGWAF をデプロイできます。
# Terraform 0.13+ requires providers to be declared in a "required_providers" block
# https://registry.terraform.io/providers/fastly/fastly/latest/docs
terraform {
required_providers {
fastly = {
source = "fastly/fastly"
version = ">= 3.0.4"
}
sigsci = {
source = "signalsciences/sigsci"
version = ">= 1.2.18"
}
}
}
# Fastly Edge VCL configuration
variable "FASTLY_API_KEY" {
type = string
description = "This is API key for the Fastly VCL edge configuration."
}
#### VCL Service variables - Start
variable "USER_VCL_SERVICE_DOMAIN_NAME" {
type = string
description = "Frontend domain for your service. Try 'YOURNAME.global.ssl.fastly.net' to get up and running quickly."
default = "brooks-ngwaf-tf-demo.global.ssl.fastly.net"
}
variable "USER_VCL_SERVICE_BACKEND_HOSTNAME" {
type = string
description = "hostname used for backend."
default = "http-me.glitch.me"
}
# Controls the percentage of traffic sent to NGWAF
variable "Edge_Security_dictionary" {
type = string
default = "Edge_Security"
}
variable "NGWAF_CORP" {
type = string
description = "Corp name for NGWAF"
}
variable "NGWAF_SITE" {
type = string
description = "Site name for NGWAF"
}
#### VCL Service variables - End
#### NGWAF variables - Start
variable "NGWAF_EMAIL" {
type = string
description = "Email address associated with the token for the NGWAF API."
}
variable "NGWAF_TOKEN" {
type = string
description = "Secret token for the NGWAF API."
sensitive = true
}
#### NGWAF variables - End
# Configure the Fastly Provider
provider "fastly" {
api_key = var.FASTLY_API_KEY
}
#### Fastly VCL Service - Start
resource "fastly_service_vcl" "frontend-vcl-service" {
name = "Frontend VCL Service - NGWAF edge deploy"
domain {
name = var.USER_VCL_SERVICE_DOMAIN_NAME
comment = "Frontend VCL Service - NGWAF edge deploy"
}
backend {
address = var.USER_VCL_SERVICE_BACKEND_HOSTNAME
name = "vcl_service_origin_1"
port = 443
use_ssl = true
ssl_cert_hostname = var.USER_VCL_SERVICE_BACKEND_HOSTNAME
ssl_sni_hostname = var.USER_VCL_SERVICE_BACKEND_HOSTNAME
override_host = var.USER_VCL_SERVICE_BACKEND_HOSTNAME
}
#### NGWAF Dynamic Snippets - MANAGED BY FASTLY - Start
dynamicsnippet {
name = "ngwaf_config_init"
type = "init"
priority = 0
}
dynamicsnippet {
name = "ngwaf_config_miss"
type = "miss"
priority = 9000
}
dynamicsnippet {
name = "ngwaf_config_pass"
type = "pass"
priority = 9000
}
dynamicsnippet {
name = "ngwaf_config_deliver"
type = "deliver"
priority = 9000
}
#### NGWAF Dynamic Snippets - MANAGED BY FASTLY - End
dictionary {
name = var.Edge_Security_dictionary
}
lifecycle {
ignore_changes = [
product_enablement,
]
}
force_destroy = true
}
resource "fastly_service_dictionary_items" "edge_security_dictionary_items" {
for_each = {
for d in fastly_service_vcl.frontend-vcl-service.dictionary : d.name => d if d.name == var.Edge_Security_dictionary
}
service_id = fastly_service_vcl.frontend-vcl-service.id
dictionary_id = each.value.dictionary_id
items = {
Enabled: "100"
}
}
resource "fastly_service_dynamic_snippet_content" "ngwaf_config_init" {
for_each = {
for d in fastly_service_vcl.frontend-vcl-service.dynamicsnippet : d.name => d if d.name == "ngwaf_config_init"
}
service_id = fastly_service_vcl.frontend-vcl-service.id
snippet_id = each.value.snippet_id
content = "### Fastly managed ngwaf_config_init"
manage_snippets = false
}
resource "fastly_service_dynamic_snippet_content" "ngwaf_config_miss" {
for_each = {
for d in fastly_service_vcl.frontend-vcl-service.dynamicsnippet : d.name => d if d.name == "ngwaf_config_miss"
}
service_id = fastly_service_vcl.frontend-vcl-service.id
snippet_id = each.value.snippet_id
content = "### Fastly managed ngwaf_config_miss"
manage_snippets = false
}
resource "fastly_service_dynamic_snippet_content" "ngwaf_config_pass" {
for_each = {
for d in fastly_service_vcl.frontend-vcl-service.dynamicsnippet : d.name => d if d.name == "ngwaf_config_pass"
}
service_id = fastly_service_vcl.frontend-vcl-service.id
snippet_id = each.value.snippet_id
content = "### Fastly managed ngwaf_config_pass"
manage_snippets = false
}
resource "fastly_service_dynamic_snippet_content" "ngwaf_config_deliver" {
for_each = {
for d in fastly_service_vcl.frontend-vcl-service.dynamicsnippet : d.name => d if d.name == "ngwaf_config_deliver"
}
service_id = fastly_service_vcl.frontend-vcl-service.id
snippet_id = each.value.snippet_id
content = "### Fastly managed ngwaf_config_deliver"
manage_snippets = false
}
#### Fastly VCL Service - End
#### NGWAF Edge deploy - Start
provider "sigsci" {
corp = var.NGWAF_CORP
email = var.NGWAF_EMAIL
auth_token = var.NGWAF_TOKEN
fastly_api_key = var.FASTLY_API_KEY
}
resource "sigsci_edge_deployment" "ngwaf_edge_site_service" {
# https://registry.terraform.io/providers/signalsciences/sigsci/latest/docs/resources/edge_deployment
site_short_name = var.NGWAF_SITE
}
resource "sigsci_edge_deployment_service" "ngwaf_edge_service_link" {
# https://registry.terraform.io/providers/signalsciences/sigsci/latest/docs/resources/edge_deployment_service
site_short_name = var.NGWAF_SITE
fastly_sid = fastly_service_vcl.frontend-vcl-service.id
activate_version = true
percent_enabled = 100
depends_on = [
sigsci_edge_deployment.ngwaf_edge_site_service,
fastly_service_vcl.frontend-vcl-service,
fastly_service_dictionary_items.edge_security_dictionary_items,
fastly_service_dynamic_snippet_content.ngwaf_config_init,
fastly_service_dynamic_snippet_content.ngwaf_config_miss,
fastly_service_dynamic_snippet_content.ngwaf_config_pass,
fastly_service_dynamic_snippet_content.ngwaf_config_deliver,
]
}
resource "sigsci_edge_deployment_service_backend" "ngwaf_edge_service_backend_sync" {
site_short_name = var.NGWAF_SITE
fastly_sid = fastly_service_vcl.frontend-vcl-service.id
fastly_service_vcl_active_version = fastly_service_vcl.frontend-vcl-service.active_version
depends_on = [
sigsci_edge_deployment_service.ngwaf_edge_service_link,
]
}
#### NGWAF Edge deploy - End
output "love_laugh_live_ngwaf" {
value = <<tfmultiline
#### Click the URL to go to the service ####
https://cfg.fastly.com/${fastly_service_vcl.frontend-vcl-service.id}
#### Send a test request with curl. ####
curl -i "https://${var.USER_VCL_SERVICE_DOMAIN_NAME}/anything/whydopirates?likeurls=theargs" -d foo=bar
#### Send an test as cmd exe request with curl. ####
curl -i "https://${var.USER_VCL_SERVICE_DOMAIN_NAME}/anything/myattackreq?i=../../../../etc/passwd'" -d foo=bar
#### Troubleshoot the logging configuration if necessary. ####
curl https://api.fastly.com/service/${fastly_service_vcl.frontend-vcl-service.id}/logging_status -H fastly-key:$FASTLY_API_KEY
tfmultiline
description = "Output hints on what to do next."
depends_on = [
sigsci_edge_deployment_service.ngwaf_edge_service_link
]
}
上記の要件のすべて (Fastly Edge API キー、NGWAF API キー、権限、NGWAF の Corp/Site) が揃ったら、後は「terraform apply」を実行してリクエストを送信し、新しいデプロイのために作成したこのデプロイをテストします。幸い、(お客様の作業を楽にするために) テストリクエストが Terraform に組み込まれています。これで、他のデプロイオプションと同様に、Fastly NGWAF のコンソールでアプリケーションのセキュリティ設定を管理することも、Terraform を使用し続けることもできます。
仕組みについて
Signal Sciences の Terraform プロバイダーは次の2つを実行します。
NGWAF のエッジサービスを作成する
NGWAF のエッジサービスを VCL サービスにリンクする
VCL サービスと NGWAF のエッジサービスをリンクすることで、以下が実行されます。
Edge Dictionary の作成
Fastly が管理する動的スニペットの作成
VCL サービスで設定されたオリジンと NGWAF のエッジサービスの同期化
最初に「terraform apply」を実行する際に、3つの動的スニペットと一緒に VCL サービスが作成されます。これらすべてに「managed = false」が設定されており、これらのリソースは Terraform の外で管理されることを意味しています (https://registry.terraform.io/providers/fastly/fastly/latest/docs/resources/service_dynamic_snippet_content#manage_snippets</u>)。この場合「Terraform の外」は、Fastly でこれらのスニペットが管理され、必要に応じて変更できることを意味します。
おめでとうございます!
このようにシンプルなプロセスで、サイトは保護されている状態になりました。今回は、Terraform を使用して 新しい VCL サービスに対して NGWAF のエッジデプロイを簡単にプロビジョニングする方法を解説しました。既存の Fastly サービスで Terraform を使用する方法については、また別の機会にブログでご紹介します。ご意見、ご質問等がございましたら、お気軽にご連絡ください。