Skip to content

Setup

1. A least-privilege service account

Create a service account with roles/logging.viewer only and download a key:

gcloud iam service-accounts create waf-log-viewer --project=YOUR_PROJECT
gcloud projects add-iam-policy-binding YOUR_PROJECT \
  --member=serviceAccount:waf-log-viewer@YOUR_PROJECT.iam.gserviceaccount.com \
  --role=roles/logging.viewer
gcloud iam service-accounts keys create key.json \
  --iam-account=waf-log-viewer@YOUR_PROJECT.iam.gserviceaccount.com

Why not a human account

Organizations commonly enforce a re-authentication policy on human Google accounts: the refresh token stays valid but obtaining an access token demands an interactive identity check every day or so. A background patrol running as a human account therefore fails with Reauthentication failed at an unpredictable hour, and the failure looks like an outage rather than a policy. Service accounts are exempt, which is why this server is built around one.

Keep the key at mode 600 and out of version control.

2. Install

pip install cloudarmor-mcp
# or
uv tool install cloudarmor-mcp

3. Environment

Variable Required Meaning
CLOUDARMOR_PROJECT yes GCP project ID that receives the load-balancer logs
GOOGLE_APPLICATION_CREDENTIALS yes Path to the service-account key file
CLOUDARMOR_BACKEND_SERVICES no Comma-separated backend service names to filter (default: all)
CLOUDARMOR_HOME_REGION no ISO region code treated as home traffic, e.g. JP. Enables the false-positive lens
CLOUDARMOR_RULES_INI no Path to a rules INI (see below)
CLOUDARMOR_MAX_ENTRIES no Max entries fetched per query (default 2000)

Find your backend service names with:

gcloud compute backend-services list --project=YOUR_PROJECT --format='value(name)'

Leaving CLOUDARMOR_BACKEND_SERVICES unset queries every backend in the project, which is correct when one load balancer serves everything and noisy when several do.

4. Rules INI (optional)

Rule priorities are just numbers in the log. This file gives them names and tells the home-region lens which ones are expected:

[rules]
101 = block non-home deep-path crawlers
500 = AutoDiscover probe block
1002 = OWASP LFI protection

[home]
; home-region DENYs on these priorities are expected, not false positives
known_normal_priorities = 500, 600

Both sections are optional. Without [rules] the reports show bare priority numbers; without [home] every home-region deny is listed as suspicious.

Priorities are matched as integer strings

Cloud Logging returns rule priorities as JSON numbers, so a priority arrives as 101.0. The server folds integral floats back to 101 before matching, so write plain integers in the INI — 101, not 101.0.

5. Register with an MCP client

Claude Code:

claude mcp add cloudarmor -- cloudarmor-mcp

Set the environment variables above in the server's environment. Verify the whole chain — config, credentials and API access — before wiring it into a scheduled patrol:

cloudarmor-mcp --check   # exit 0 and "healthy — cloudarmor-mcp <version> project=<id>"