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 (plugin)¶
This repository doubles as a single-plugin marketplace:
/plugin marketplace add shigechika/cloudarmor-mcp
/plugin install cloudarmor-mcp@cloudarmor-mcp
The plugin launches uvx cloudarmor-mcp and reads the same environment
variables as every other transport; export them before
starting Claude Code. GOOGLE_APPLICATION_CREDENTIALS still has to point at a
service-account key file that exists on your own machine — the plugin can't
ship or fetch that file for you, so this server can't be fully configured
through the plugin's own settings alone.
uvx must be on the PATH of the process that runs Claude Code — a login
shell usually has it, but a GUI-launched app may not; install
uv system-wide if the plugin fails to start.
Claude Code (manual)¶
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>"