feat: port configure actions (base, ufw, crowdsec, cron, systemd, routing)

This commit is contained in:
deytenit committed 2026-07-04 21:26:56 +03:00
1 parent 63c4b6c7eb
commit 05469332e8
7 files changed
+158

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
# actions/configure/base.py
"""Port of configure/base — base packages + ufw + ufw-docker helper."""
import os, shutil, stat, urllib.request
from engine.descriptor import Meta
METADATA = Meta(summary="Configure base system packages (curl, wget, git, rsyslog, ufw, ufw-docker).")
UFW_DOCKER_URL = "https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker"
def run(ctx, args):
log, s = ctx.log, ctx.sys
log.info("Starting base system initialization...")
if not os.path.isfile("/etc/debian_version"):
log.error("Requires a Debian-based system (Debian/Ubuntu)."); raise SystemExit(1)
log.info("Updating package lists..."); s.sudo(["apt-get", "update", "-y"])
log.info("Installing essential packages...")
s.sudo(["apt-get", "install", "-y", "curl", "wget", "git", "rsyslog"])
s.ensure_running("rsyslog")
if not shutil.which("ufw"):
log.info("Installing UFW..."); s.sudo(["apt-get", "install", "-y", "ufw"])
else:
log.info("UFW already installed.")
binp = os.path.expanduser("~/.local/bin/ufw-docker")
if not (os.path.isfile(binp) and os.access(binp, os.X_OK)):
log.info("Downloading ufw-docker helper...")
os.makedirs(os.path.dirname(binp), exist_ok=True)
urllib.request.urlretrieve(UFW_DOCKER_URL, binp) # stdlib; replaces wget/curl
os.chmod(binp, os.stat(binp).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
log.success(f"ufw-docker downloaded to {binp}.")
else:
log.info(f"ufw-docker already exists at {binp}.")
log.success("Base system initialization completed.")
+14
View File
@@ -0,0 +1,14 @@
# actions/configure/cron.py
"""Port of configure/cron — install crontab from configs/cron/crontab."""
import os
from engine.descriptor import Meta, Flag
METADATA = Meta(summary="Install the node crontab from configs/cron/crontab.",
args=[Flag("--dry-run", "Render + preview; do not install.")])
def run(ctx, args):
crontab = os.path.join(ctx.paths.configs, "cron", "crontab")
if not os.path.isfile(crontab):
ctx.log.error(f"Crontab file not found: {crontab}"); raise SystemExit(1)
text = ctx.tpl.render(crontab, ctx.vars())
ctx.host.install_crontab(text, dry_run=args.dry_run)
+24
View File
@@ -0,0 +1,24 @@
# actions/configure/crowdsec.py
"""Port of configure/crowdsec — install, deploy /etc/crowdsec, collections, bouncer."""
import os
from engine.descriptor import Meta, Flag
METADATA = Meta(summary="Install + configure CrowdSec from configs/crowdsec.",
args=[Flag("--dry-run", "Render only; do not write/reload.")])
def run(ctx, args):
cfg = os.path.join(ctx.paths.configs, "crowdsec")
if not os.path.isdir(cfg):
ctx.log.error(f"Config directory not found: {cfg}"); raise SystemExit(1)
ctx.log.info("Configuring CrowdSec...")
if not args.dry_run:
ctx.crowdsec.ensure_installed()
ctx.crowdsec.deploy("crowdsec", ctx.vars(), dry_run=args.dry_run)
if not args.dry_run:
ctx.crowdsec.install_collections(["crowdsecurity/linux", "crowdsecurity/traefik"])
bouncer = os.path.join(cfg, "bouncers", "crowdsec-firewall-bouncer.yaml.local")
if os.path.isfile(bouncer) and not ctx.sys.ok(
["bash", "-c", "dpkg -l | grep -q crowdsec-firewall-bouncer-iptables"]):
ctx.log.info("Installing crowdsec-firewall-bouncer-iptables...")
ctx.sys.sudo(["apt-get", "install", "-y", "crowdsec-firewall-bouncer-iptables"])
ctx.log.success("Configured crowdsec.")
+21
View File
@@ -0,0 +1,21 @@
# actions/configure/routing.py
"""Port of configure/routing — idempotent node routing (ip_forward, fwmark rule, table 100)."""
from engine.descriptor import Meta
METADATA = Meta(summary="Idempotent node-level routing rules and routes.")
def run(ctx, args):
log, s = ctx.log, ctx.sys
log.info("Applying persistent node-level routing configuration...")
s.sudo(["sysctl", "-w", "net.ipv4.ip_forward=1"])
if s.ok(["bash", "-c", "sudo ip rule show | grep -q 'fwmark 0x1 lookup 100'"]):
log.info("IP rule for mark 0x1 already exists.")
else:
s.run(["bash", "-c", "sudo ip rule add fwmark 0x1 lookup 100 priority 100 || true"])
log.info("IP rule added for mark 0x1.")
if s.ok(["bash", "-c", "sudo ip route show table 100 2>/dev/null | grep -q 'local default dev lo'"]):
log.info("Local route in table 100 already exists.")
else:
s.run(["bash", "-c", "sudo ip route add local 0.0.0.0/0 dev lo table 100 || true"])
log.info("Local route added to table 100.")
log.success("Routing configuration applied.")
+15
View File
@@ -0,0 +1,15 @@
# actions/configure/systemd.py
"""Port of configure/systemd — deploy + enable units from configs/systemd."""
import os
from engine.descriptor import Meta, Flag
METADATA = Meta(summary="Deploy + enable systemd units from configs/systemd.",
args=[Flag("--dry-run", "Render only; do not write/enable.")])
def run(ctx, args):
cfg = os.path.join(ctx.paths.configs, "systemd")
if not os.path.isdir(cfg):
ctx.log.error(f"Config directory not found: {cfg}"); raise SystemExit(1)
ctx.log.info("Deploying systemd units...")
ctx.systemd.deploy_units("systemd", ctx.vars(), dry_run=args.dry_run)
ctx.log.success("Configured systemd.")
+19
View File
@@ -0,0 +1,19 @@
# actions/configure/ufw.py
"""Port of configure/ufw — apply docker + host ufw rules from configs/ufw."""
import os
from engine.descriptor import Meta, Flag
METADATA = Meta(summary="Render + apply this node's UFW rules (configs/ufw).",
args=[Flag("--dry-run", "Preview; do not apply.")])
def run(ctx, args):
cfg = os.path.join(ctx.paths.configs, "ufw")
if not os.path.isdir(cfg):
ctx.log.error(f"Config directory not found: {cfg}"); raise SystemExit(1)
docker_dir = os.path.join(cfg, "docker")
host_dir = os.path.join(cfg, "host")
ctx.log.info("Configuring UFW rules...")
if not os.path.isdir(docker_dir):
ctx.log.warn(f"Docker rules dir not found at {docker_dir}. Skipping ufw-docker rules.")
ctx.ufw.apply(docker_dir, host_dir if os.path.isdir(host_dir) else None, dry_run=args.dry_run)
ctx.log.success("Configured ufw.")