Terraform で Google Cloud Armor ログを有効化、 Logging でログを検索

2021年2月14日

概要

やりたいこと

Cloud Armor ログを確認したい。

全体像

Cloud Armor 用のログが存在するわけでなく、LB のログの一環として出力される。

  • WAF ログを出すためには LB のログを出す
  • LBのログはバックエンドサービスで出す

Cloud Armor ログ (LB ログ)

ログ情報は LB のロギングページで確認できる。

特にこの辺り。

ログ内の「statusDetails」項目(ドキュメントだとstatus_details)に、なぜこのレスポンス コードなのかを説明するテキストが入っている。
詳しくは下記。

Cloud Armor で止めた場合は「denied_by_security_policy」と出る。

Terraform

LB ロギング有効化

Cloud Armor のログを確認するため、バックエンドサービスでのロギングを有効化する。

log_config ブロックを追加する。

vi lb.tf
resource "google_compute_backend_service" "backend-service" {
  name        = "web-backend-service"
  port_name   = "http"
  protocol    = "HTTP"
  timeout_sec = 3000

  backend {
    group = google_compute_instance_group.instance-group.self_link
  }

  log_config {
    enable = true
  }

  health_checks = [google_compute_health_check.health-check.self_link]
}

デプロイ。

terraform apply

「ロギングを有効にする」にチェックが入った。

ログを確認

異常アクセス

試しに 403 Forbidden となるリクエストを送信する。

$ curl -I "http://34.117.94.129/index.html?var='OR'B='B'"
HTTP/1.1 403 Forbidden
Content-Length: 134
Content-Type: text/html; charset=UTF-8
Date: Sun, 17 Jan 2021 14:21:35 GMT

ロギングコンソール (旧Stackdriver) より、以下のクエリを発行。

resource.type=http_load_balancer

Status Code が 403 のログがそれのようだ。

ログは下記のよう形式。

{
  "insertId": "15wci2of1i44qy",
  "jsonPayload": {
    "enforcedSecurityPolicy": {
      "preconfiguredExprIds": [
        "owasp-crs-v030001-id942432-sqli"
      ],
      "name": "sql-injection",
      "configuredAction": "DENY",
      "outcome": "DENY"
    },
    "statusDetails": "denied_by_security_policy",
    "@type": "type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry"
  },
  "httpRequest": {
    "requestMethod": "HEAD",
    "requestUrl": "http://34.117.94.129/index.html?var='OR'B='B'",
    "requestSize": "102",
    "status": 403,
    "responseSize": "124",
    "userAgent": "curl/7.64.1",
    "remoteIp": "111.108.92.1",
    "latency": "0.109929s"
  },
  "resource": {
    "type": "http_load_balancer",
    "labels": {
      "url_map_name": "web-map-http",
      "project_id": "PROJECT_ID",
      "target_proxy_name": "target-http-proxy",
      "zone": "global",
      "forwarding_rule_name": "global-forwarding-rule-http",
      "backend_service_name": "web-backend-service"
    }
  },
  "timestamp": "2021-01-19T01:37:48.079162Z",
  "severity": "WARNING",
  "logName": "projects/PROJECT_ID/logs/requests",
  "trace": "projects/PROJECT_ID/traces/03c5f256bdcc002cb285f0ca683d66e0",
  "receiveTimestamp": "2021-01-19T01:37:49.089994724Z",
  "spanId": "569c608046eb7674"
}

statusDetails を確認すると「denied_by_security_policy」となっている。
Cloud Armor で止められたことを意味する。

Cloud Armor で止めたログだけを抽出したい場合は以下のクエリや

jsonPayload.enforcedSecurityPolicy.outcome="DENY"

以下のクエリを使う。

jsonPayload.statusDetails="denied_by_security_policy"

正常アクセス

Status Code が 200 となっているログ。

{
  "insertId": "qdfv77f1sz7as",
  "jsonPayload": {
    "statusDetails": "response_sent_by_backend",
    "enforcedSecurityPolicy": {
      "configuredAction": "ACCEPT",
      "outcome": "ACCEPT",
      "priority": 2000,
      "name": "sql-injection"
    },
    "@type": "type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry"
  },
  "httpRequest": {
    "requestMethod": "HEAD",
    "requestUrl": "http://34.117.94.129/index.html",
    "requestSize": "88",
    "status": 200,
    "responseSize": "243",
    "userAgent": "curl/7.64.1",
    "remoteIp": "111.108.92.1",
    "serverIp": "10.174.0.20",
    "latency": "0.011301s"
  },
  "resource": {
    "type": "http_load_balancer",
    "labels": {
      "target_proxy_name": "target-http-proxy",
      "forwarding_rule_name": "global-forwarding-rule-http",
      "url_map_name": "web-map-http",
      "backend_service_name": "web-backend-service",
      "project_id": "be-nishiyama-wataru",
      "zone": "global"
    }
  },
  "timestamp": "2021-01-19T01:40:07.892238Z",
  "severity": "INFO",
  "logName": "projects/be-nishiyama-wataru/logs/requests",
  "trace": "projects/be-nishiyama-wataru/traces/ae26c8bdb25cc1cf69e8593f3d8d5ae6",
  "receiveTimestamp": "2021-01-19T01:40:08.313971093Z",
  "spanId": "615107bacff419ec"
}

statusDetails が「response_sent_by_backend」となっている。

リクエストがバックエンドに正常にプロキシされたことを意味する。

参考

HTTP(S) リクエストのロギングを有効にする

HTTP(S) 負荷分散のロギングとモニタリング