router: make CrowdSec opt-in (crowdsec.enable, default off)
Not every site wants the ban engine (hub sync needs internet at activation, and it is one more moving part on a small box). Gate crowdsec.nix on a new `crowdsec.enable` option like `omada.enable`. gw-cnx-1 keeps it on; the VM test drops its mkForce overrides.
This commit is contained in:
@@ -28,7 +28,7 @@ mgmt-only trust model, SSH exposure and the Wi-Fi bridge ports. Run it with
|
|||||||
| DHCP | Kea, one subnet per VLAN |
|
| DHCP | Kea, one subnet per VLAN |
|
||||||
| DNS | Blocky (blocklist resolver), metrics on :4000 scraped by control |
|
| DNS | Blocky (blocklist resolver), metrics on :4000 scraped by control |
|
||||||
| IPv6 | DHCPv6-PD on ppp0, /64 per VLAN via SLAAC |
|
| IPv6 | DHCPv6-PD on ppp0, /64 per VLAN via SLAAC |
|
||||||
| Bans | CrowdSec + nftables bouncer (sshd log parsing) |
|
| Bans | Optional per site (`crowdsec.enable`): CrowdSec + nftables bouncer (sshd log parsing) |
|
||||||
| Omada | Optional per site: TP-Link Omada controller as a podman container |
|
| Omada | Optional per site: TP-Link Omada controller as a podman container |
|
||||||
| Wi-Fi | Optional: hostapd on the router's radios; each SSID (`wifi.networks`) is an untagged access port of its VLAN, passphrases via vars prompts — see `modules/clan/router/README.md` |
|
| Wi-Fi | Optional: hostapd on the router's radios; each SSID (`wifi.networks`) is an untagged access port of its VLAN, passphrases via vars prompts — see `modules/clan/router/README.md` |
|
||||||
| Proxy | Optional: Caddy reverse proxy for internal services under `*.<site><n>.cnx.network` with a real Let's Encrypt wildcard (DNS-01 against ns1) |
|
| Proxy | Optional: Caddy reverse proxy for internal services under `*.<site><n>.cnx.network` with a real Let's Encrypt wildcard (DNS-01 against ns1) |
|
||||||
@@ -71,7 +71,7 @@ Trust model: mgmt → everything; other VLANs → router DNS/DHCP + internet onl
|
|||||||
installer: `ls -l /dev/disk/by-id/`).
|
installer: `ls -l /dev/disk/by-id/`).
|
||||||
2. Add the machine to `inventory.machines` in `clan.nix`, to the `router`
|
2. Add the machine to `inventory.machines` in `clan.nix`, to the `router`
|
||||||
instance in `inventory.nix` (`roles.default.machines.gw-<city>-<n>.settings`: `site`,
|
instance in `inventory.nix` (`roles.default.machines.gw-<city>-<n>.settings`: `site`,
|
||||||
`siteId` (next free number), port names, VLANs, `omada.enable`; keep the
|
`siteId` (next free number), port names, VLANs, `omada.enable`, `crowdsec.enable`; keep the
|
||||||
`mgmt`/`lan` VLANs), and to the machine list in `modules/mesh-hosts.nix`.
|
`mgmt`/`lan` VLANs), and to the machine list in `modules/mesh-hosts.nix`.
|
||||||
Do **not** add it to `modules/hosts.nix` (dynamic PPPoE IP; clan connects
|
Do **not** add it to `modules/hosts.nix` (dynamic PPPoE IP; clan connects
|
||||||
over the mesh).
|
over the mesh).
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ in
|
|||||||
};
|
};
|
||||||
# This site runs the Omada controller for its APs/switches.
|
# This site runs the Omada controller for its APs/switches.
|
||||||
omada.enable = true;
|
omada.enable = true;
|
||||||
|
# sshd ban engine (was unconditional before the option existed).
|
||||||
|
crowdsec.enable = true;
|
||||||
|
|
||||||
# Internal reverse proxy: real wildcard cert *.cnx1.cnx.network; Blocky
|
# Internal reverse proxy: real wildcard cert *.cnx1.cnx.network; Blocky
|
||||||
# resolves the names to the router's LAN address for mgmt+lan clients.
|
# resolves the names to the router's LAN address for mgmt+lan clients.
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
Turns a machine with several NICs into a site gateway: PPPoE WAN (ISP
|
Turns a machine with several NICs into a site gateway: PPPoE WAN (ISP
|
||||||
credentials via vars prompts), a VLAN-filtering bridge over the LAN ports with
|
credentials via vars prompts), a VLAN-filtering bridge over the LAN ports with
|
||||||
one L3 interface per VLAN, Kea DHCP and Blocky DNS per VLAN, nftables
|
one L3 interface per VLAN, Kea DHCP and Blocky DNS per VLAN, nftables
|
||||||
firewall/NAT, DHCPv6-PD, CrowdSec, an iperf3 server and a WAN speed-test
|
firewall/NAT, DHCPv6-PD, an iperf3 server and a WAN speed-test timer.
|
||||||
timer. Optional: a Wi-Fi access point on the router's own radios (hostapd),
|
Optional: a Wi-Fi access point on the router's own radios (hostapd), CrowdSec
|
||||||
the TP-Link Omada controller (podman) and an internal Caddy reverse proxy
|
with the nftables bouncer (sshd log parsing), the TP-Link Omada controller
|
||||||
with a real wildcard certificate (ACME DNS-01).
|
(podman) and an internal Caddy reverse proxy with a real wildcard certificate
|
||||||
|
(ACME DNS-01).
|
||||||
|
|
||||||
Addressing convention: a site owns `10.<siteId>.0.0/16`; VLAN `<id>` defaults
|
Addressing convention: a site owns `10.<siteId>.0.0/16`; VLAN `<id>` defaults
|
||||||
to `10.<siteId>.<id>.0/24`, router at `.1`, DHCP pool `.100-.199`. The `mgmt`
|
to `10.<siteId>.<id>.0/24`, router at `.1`, DHCP pool `.100-.199`. The `mgmt`
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
# CrowdSec security engine + nftables bouncer: parses sshd auth attempts from
|
# CrowdSec security engine + nftables bouncer: parses sshd auth attempts from
|
||||||
# the journal and bans offending source IPs at the firewall. Log-based (no
|
# the journal and bans offending source IPs at the firewall. Log-based (no
|
||||||
# inline DPI) so it costs the N300 next to nothing.
|
# inline DPI) so it costs the N300 next to nothing. Opt-in per site
|
||||||
|
# (`crowdsec.enable`): the hub sync needs internet at activation time.
|
||||||
{ settings }:
|
{ settings }:
|
||||||
{ ... }:
|
{ lib, ... }:
|
||||||
let
|
let
|
||||||
cfg = settings;
|
cfg = settings;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
config = lib.mkIf cfg.crowdsec.enable {
|
||||||
services.crowdsec = {
|
services.crowdsec = {
|
||||||
enable = true;
|
enable = true;
|
||||||
autoUpdateService = true;
|
autoUpdateService = true;
|
||||||
@@ -43,4 +45,5 @@ in
|
|||||||
registerBouncer.enable = true;
|
registerBouncer.enable = true;
|
||||||
settings.mode = "nftables";
|
settings.mode = "nftables";
|
||||||
};
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -285,6 +285,8 @@ in
|
|||||||
|
|
||||||
omada.enable = lib.mkEnableOption "TP-Link Omada SDN controller (podman container)";
|
omada.enable = lib.mkEnableOption "TP-Link Omada SDN controller (podman container)";
|
||||||
|
|
||||||
|
crowdsec.enable = lib.mkEnableOption "CrowdSec (sshd log parsing) with the nftables bouncer";
|
||||||
|
|
||||||
proxy = {
|
proxy = {
|
||||||
enable = lib.mkEnableOption "internal reverse proxy (Caddy, wildcard cert via DNS-01)";
|
enable = lib.mkEnableOption "internal reverse proxy (Caddy, wildcard cert via DNS-01)";
|
||||||
|
|
||||||
|
|||||||
@@ -131,13 +131,11 @@ in
|
|||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
|
|
||||||
# The sandbox has no internet: serve the blocklist from a local file
|
# The sandbox has no internet: serve the blocklist from a local file
|
||||||
# instead of GitHub, and skip CrowdSec, whose hub sync needs the network
|
# instead of GitHub. (CrowdSec, whose hub sync needs the network too,
|
||||||
# (it is not what this test exercises).
|
# is opt-in and stays off.)
|
||||||
services.blocky.settings.blocking.denylists.ads = lib.mkForce [
|
services.blocky.settings.blocking.denylists.ads = lib.mkForce [
|
||||||
(toString (pkgs.writeText "ads.hosts" "0.0.0.0 ads.example.com\n"))
|
(toString (pkgs.writeText "ads.hosts" "0.0.0.0 ads.example.com\n"))
|
||||||
];
|
];
|
||||||
services.crowdsec.enable = lib.mkForce false;
|
|
||||||
services.crowdsec-firewall-bouncer.enable = lib.mkForce false;
|
|
||||||
|
|
||||||
# Two simulated radios: wlan0 is the AP (settings above), wlan1 plays a
|
# Two simulated radios: wlan0 is the AP (settings above), wlan1 plays a
|
||||||
# wireless client. It lives in its own network namespace, like the
|
# wireless client. It lives in its own network namespace, like the
|
||||||
|
|||||||
Reference in New Issue
Block a user