cloud_armor — a GCP Cloud Armor rule

Blocks at Google's edge by rewriting the source ranges of one Cloud Armor security-policy rule via the gcloud CLI. The policy, the deny rule, and the load balancer attachment are yours; the kur owns that one rule's --src-ip-ranges, rendered wholesale from its ban book on every change.

[kur.web]
backend = "cloud_armor"

[kur.web.options]
policy   = "kur-policy"
priority = 1000
project  = "my-project"

The 10-range limit — read this first

Cloud Armor allows at most 10 source IP ranges per rule, and the kur does not shard across rules — the 11th concurrently banned IP makes the gcloud update fail and the ban error. A banned CIDR range consumes a slot exactly like a single IP. The failed ban is rolled back out of the ban set, so it does not wedge later updates — but the limit is still the limit. This backend is for small, curated ban sets at the edge (a handful of abusers on ban_time = 0, say), not volume banning. For volume, block at the instances or use a different edge.

GCP-side setup — required first

gcloud compute security-policies rules create 1000 \
    --security-policy kur-policy --action deny-403 \
    --src-ip-ranges 192.0.2.255/32

(the placeholder range gets overwritten at the first mutation).

Requirements

Settings

Options

| option | default | what | |--------------|--------------|-------------------------------------------| | policy | (required) | the security policy name | | priority | 1000 | the rule (priority) the kur owns | | project | (unset) | adds --project <project> when set | | gcloud_cmd | gcloud | the gcloud binary |

What each operation runs

| operation | command | |------------|--------------------------------------------------------------------------| | init | gcloud compute security-policies rules describe <priority> --security-policy <policy> | | ban | gcloud compute security-policies rules update <priority> --security-policy <policy> --src-ip-ranges <ip1>/32,<ip2>/128,... — the full sorted book | | unban | the same render, minus the IP | | list | no command — the kur's own ban book | | check | the same describe as init | | flush | the update with an empty range list | | re_init | teardown (best effort), init, update with the full book | | teardown | update with empty ranges (ban book kept) |

self_heal

check verifies the rule exists and gcloud auth works — not the rule's contents. Hand-edits to the ranges are overwritten at the next mutation, since every update ships the whole book.

Gotchas