Ereshkigal

 view release on metacpan or  search on metacpan

docs/kurs/abuseipdb.md  view on Meta::CPAN

| `check`    | same probe as init                                                           |
| `flush`    | nothing (ban book cleared)                                                   |
| `re_init`  | teardown (no-op) + init                                                      |
| `teardown` | nothing (ban book kept)                                                      |

## self_heal

There is nothing on the AbuseIPDB side to establish, so there is
nothing to repair — the re_init after a failed `check` just probes
again. `check` re-runs init's credential probe (catching a revoked or
expired key), so a kur stuck failing it has a credentials problem,
not a firewall one.

## Gotchas

- Because unban costs no API call, `ban_time` here only governs the
  kur's own book (and thus which IPs a restart re-reports). Matching
  the blocking kur's `ban_time` keeps gate members' books aligned.
- The already-banned check means one report per IP per sentence —
  the kur will not spam reports while an IP sits in the book, even
  if the ban source keeps firing (a refreshed sentence is not a new

docs/kurs/akamai.md  view on Meta::CPAN

| `timeout`         | `30`         | HTTP timeout in seconds               |
| `insecure`        | `0`          | skip TLS certificate verification     |

## What each operation does

Base URL:
`https://<host>/network-list/v2/network-lists/<network_list_id>`:

| operation  | API traffic                                                   |
|------------|--------------------------------------------------------------------|
| `init`     | `GET` the list — verifies credentials and the list            |
| `ban`      | `POST .../append` with `{"list":["<ip>"]}`                    |
| `unban`    | `DELETE .../elements?element=<ip>`                            |
| `list`     | no API call — the kur's own ban book                          |
| `check`    | same probe as init                                            |
| `flush`    | the DELETE per banned IP                                      |
| `re_init`  | teardown (best effort), init, re-append every banned IP       |
| `teardown` | the DELETE per banned IP (ban book kept)                      |

Deleting an element the list no longer has succeeds quietly.

## self_heal

`check` verifies the credentials still read the list — not its
membership, not the policies consuming it, and certainly not
activation state.

## Gotchas

- The activation caveat above is the whole ballgame.
- Akamai rate-limits the API; pace chatty ban sources.
- Errors carry Error::Helper flags (`hostNotDefined`,
  `clientTokenNotDefined`, `clientSecretNotDefined`,
  `accessTokenNotDefined`, `networkListIdNotDefined`, …) — [`Net::Firewall::BlockerHelper::backends::akamai`](https://metacpan.org/pod/Net::Firewall::BlockerHelper::backends::akamai) has the full

docs/kurs/aws_wafv2.md  view on Meta::CPAN


## AWS-side setup — required first

- The IP set(s): `aws wafv2 create-ip-set --scope REGIONAL
  --ip-address-version IPV4 --name kur-web-v4 --addresses ...` (and
  an IPV6 twin if you feed it IPv6). Note the returned **Id** — the
  options take both name and id.
- A WebACL rule with a block action whose statement references the
  IP set(s), and the WebACL associated with the ALB/API
  Gateway/CloudFront distribution.
- CLI credentials for a principal with `wafv2:GetIPSet` and
  `wafv2:UpdateIPSet`.
- `scope = "CLOUDFRONT"` operates on the global (CloudFront) scope —
  the CLI must then talk to `us-east-1` (set `region` accordingly).

## Requirements

- The `aws` CLI in the `PATH` of the kur process (or `aws_cmd`),
  with working credentials — an instance/task role, or a profile the
  kur's environment resolves.

## Settings

- `ports` / `protocols` — accepted for parity but **ignored**;
  scoping lives on the WebACL rule.
- `enable_cidr` — supported; WAFv2 IP sets take real CIDRs, which
  render alongside the single IPs.
- `prefix` — unused; the IP sets are addressed by name and ID.
- At least one family must be fully configured (`name4`+`id4` or

docs/kurs/azure.md  view on Meta::CPAN


## Gotchas

- **An NSG deny rule with an empty source prefix list matches
  nothing** — after flush/teardown the rule sits inert, which is the
  intended state, but don't be surprised that it still exists.
- NSG rules take a large number of prefixes (well into the
  thousands), so volume is fine; each mutation is one `az` CLI
  invocation, which is slow (seconds) — cloud pace, not packet pace.
- `az` sessions/service principal tokens can expire under a
  long-running kur; auth errors on ban mean credentials, not code.
- Errors carry Error::Helper flags (`resourceGroupNotDefined`,
  `nsgNotDefined`, `ruleNotDefined`, …) — [`Net::Firewall::BlockerHelper::backends::azure`](https://metacpan.org/pod/Net::Firewall::BlockerHelper::backends::azure) has the full table.

docs/kurs/cloud_armor.md  view on Meta::CPAN


## Gotchas

- The 10-range ceiling, again — it is the design constraint
  everything else here follows from.
- Each mutation is a full `gcloud` invocation (slow — seconds, not
  milliseconds) and Cloud Armor propagation adds more; sentences
  land at cloud pace.
- gcloud auth (service account tokens) can expire out from under a
  long-running kur; a failed ban with an auth error means
  re-activating credentials, not a kur bug.
- Errors carry Error::Helper flags (`policyNotDefined`, …) —
  [`Net::Firewall::BlockerHelper::backends::cloud_armor`](https://metacpan.org/pod/Net::Firewall::BlockerHelper::backends::cloud_armor) has
  the full table.

docs/kurs/cloudflare.md  view on Meta::CPAN


`mode` is what Cloudflare does with matching requests — `block`
refuses outright, the challenge modes interpose a CAPTCHA / JS proof
/ managed challenge instead, useful when you would rather turn back than
banish.

## What each operation does

| operation  | API traffic                                                              |
|------------|------------------------------------------------------------------------------|
| `init`     | `GET <endpoint>?per_page=5` — verifies credentials and endpoint          |
| `ban`      | `POST <endpoint>` with mode/configuration/notes                          |
| `unban`    | `GET <endpoint>?mode=..&notes=..&configuration.target=..&configuration.value=..` to find the rule ID, then `DELETE <endpoint>/<id>` |
| `list`     | no API call — the kur's own ban book                                     |
| `check`    | same probe as init                                                       |
| `flush`    | the unban lookup+DELETE per banned IP                                    |
| `re_init`  | teardown (best effort), init, re-POST every banned IP                    |
| `teardown` | the unban lookup+DELETE per banned IP (ban book kept for re_init)        |

`<endpoint>` is
`.../zones/<zone>/firewall/access_rules/rules` or
`.../user/firewall/access_rules/rules`.

API-level failures die with the HTTP status and Cloudflare's error
codes/messages included, which is what lands in the kur's error
responses and log.

## self_heal and remote drift

`check` verifies the endpoint and credentials still answer — it does
**not** verify individual rules still exist, so a rule someone
deleted in the dashboard stays deleted until `re_init`. The converse
is handled: unbanning an IP whose rule is already gone is treated as
already-unbanned, not an error.

## Gotchas

- **Every kur ban is an API round trip**, and Cloudflare rate-limits
  the API (per-account request budgets). A hostile flood of
  ban-worthy IPs turns into a flood of API calls — consider longer

docs/kurs/juniper_srx.md  view on Meta::CPAN

| `ban`      | `<load-configuration action="set" format="text">` carrying `set security address-book global address <obj> <ip>/<mask>` and `set ... address-set <set> address <obj>`, then `<commit-configuration/>` |
| `unban`    | the load with `delete security address-book global address <obj>` (which also drops it from the set), then commit |
| `list`     | no API call — the kur's own ban book                                |
| `check`    | the same software-information probe as init                         |
| `flush`    | the delete-load + commit per banned IP                              |
| `re_init`  | teardown (best effort), init, re-load + commit per banned IP        |
| `teardown` | the delete-load + commit per banned IP (ban book kept)              |

## self_heal

`check` verifies reachability and credentials — not the address-book
contents, the set, or the policy. Hand-removed entries stay gone
until `re_init` (whose re-`set` of existing objects is harmlessly
idempotent, Junos being Junos).

## Gotchas

- **A commit per ban.** Junos commits take seconds on an SRX and
  serialize with any other configuration activity — an admin sitting
  in `configure exclusive` blocks the kur, and the kur's commits
  will sweep up any uncommitted candidate changes an admin left

docs/kurs/netscaler.md  view on Meta::CPAN

| `timeout`    | `30`              | HTTP timeout in seconds                                          |

`host` is required, as is either `auth` or both `user` and `pass`.
Auth is sent as `Authorization: Basic <base64>` — built from
user/pass at request time, or your `auth` value verbatim.

`ssl_verify` defaults **off**, matching the fail2ban action's
`curl -k` (appliances commonly wear self-signed certificates). Off
means `verify_hostname => 0` — the connection is encrypted but the
peer unauthenticated; anything that can MITM the path can harvest the
credentials. Set `ssl_verify = 1` if the appliance has a real
certificate, and consider giving it one if not.

## What each operation does

| operation  | API traffic                                                          |
|------------|--------------------------------------------------------------------------|
| `init`     | `GET <scheme>://<host>/nitro/v1/config` — verifies reachability and auth |
| `ban`      | the `PUT policydataset_value_binding` above                          |
| `unban`    | `DELETE .../policydataset_value_binding/<dataset>?args=value:<ip>`   |
| `list`     | no API call — the kur's own ban book                                 |

docs/kurs/routeros_api.md  view on Meta::CPAN

| `flush`    | the lookup+DELETE per banned IP                                      |
| `re_init`  | teardown (best effort), init, re-PUT every banned IP                 |
| `teardown` | the lookup+DELETE per banned IP (ban book kept)                      |

An entry already removed on the router by hand is treated as already
unbanned, not an error.

## self_heal

`check`/init probe only the IPv4 list endpoint — reachability and
credentials, not list contents, not the IPv6 side, and never whether
any rule consumes the lists. As with [npf](npf.md), the kur will
happily manage a list nothing reads; if bans don't bite, check the
rules first.

## Gotchas

- `insecure = 1` disables certificate verification — encrypted but
  unauthenticated, so credentials are exposed to an on-path
  attacker. Give the router a real cert if the path matters.
- Every ban is one HTTP round trip; an unban is two (a lookup, then
  the delete — or just the lookup when the entry is already gone), so
  a timed ban costs three calls over its lifetime. Fine for a
  router's management plane at normal rates.
- Errors carry Error::Helper flags (`hostNotDefined`,
  `userNotDefined`, `passwordNotDefined`, …) — [`Net::Firewall::BlockerHelper::backends::routeros_api`](https://metacpan.org/pod/Net::Firewall::BlockerHelper::backends::routeros_api) has the full
  table.



( run in 2.859 seconds using v1.01-cache-2.11-cpan-007c89162af )