Skip to content

feat(firewall): basic per-VM firewall rules (#36)#147

Merged
v0l merged 2 commits into
masterfrom
feat/basic-firewall
Jun 25, 2026
Merged

feat(firewall): basic per-VM firewall rules (#36)#147
v0l merged 2 commits into
masterfrom
feat/basic-firewall

Conversation

@v0l

@v0l v0l commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Implements basic user-configurable per-VM firewall rules.

Fixes #36

What

User-defined ACCEPT/DROP firewall rules per VM, applied on top of the
always-enforced ipfilter (anti-spoof) protection. The default policy stays
allow-all inbound/outbound, so there is no behaviour change for existing VMs.

Changes

Data model (lnvps_db)

  • Migration 20260624123544_vm_firewall_rule.sql: new vm_firewall_rule table +
    nullable firewall_rule_limit on vm_template / vm_custom_template
  • VmFirewallRule model + VmFirewallDirection / VmFirewallProtocol /
    VmFirewallRuleAction enums
  • LNVpsDbBase CRUD methods (MySQL + MockDb impls)

User API (lnvps_api)

  • GET/POST /api/v1/vm/{id}/firewall
  • PATCH/DELETE /api/v1/vm/{id}/firewall/{rule_id}
  • Ownership check, per-VM rule limit (template-configurable, default 20),
    CIDR + port-range validation (ports 1–65535, start ≤ end)

Re-apply plumbing

  • New WorkJob::ApplyVmFirewall { vm_id } + worker handler; queued on every change
  • FullVmInfo now loads firewall_rules

Proxmox backend

  • to_pve_firewall_rule translates DB rules → PVE firewall rules (tagged with a
    lnvps-fw:{id} comment)
  • patch_firewall syncs: deletes stale tagged rules (by position, descending)
    then re-adds the current set in reverse priority order, always preserving the
    ipfilter anti-spoof rule
  • New delete_vm_firewall_rule API client method

Docs: API_CHANGELOG.md + API_DOCUMENTATION.md (OpenAPI auto-generated).

Out of scope

nftables backend (#33) and the use_nftables host flag (#34) — libvirt's
patch_firewall remains a stub until then.

Testing

  • Unit tests: validators, enum round-trips, ApiVmFirewallRule::from, mock DB
    CRUD, Proxmox rule translation
  • cargo test --workspace --exclude lnvps_e2e -- --test-threads=1 green
  • cargo fmt clean; builds with --features openapi

Add user-configurable per-VM firewall rules applied on top of the
always-enforced ipfilter anti-spoof rules. Default policy stays allow-all.

- DB: vm_firewall_rule table + migration; firewall_rule_limit on templates;
  VmFirewallRule model + enums; LNVpsDbBase CRUD methods (mysql + mock)
- API: GET/POST/PATCH/DELETE /api/v1/vm/{id}/firewall with ownership,
  per-VM rule limit (default 20), and CIDR/port validation
- Re-apply: WorkJob::ApplyVmFirewall + worker handler; FullVmInfo loads rules
- Proxmox: translate DB rules to PVE firewall rules and sync (delete stale
  lnvps-fw-tagged rules, re-add current set), preserving the ipfilter rule
- Docs: API_CHANGELOG.md + API_DOCUMENTATION.md

nftables backend (#33) and use_nftables host flag (#34) remain out of scope.

@v0l v0l left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also support REJECT action and vm level input/output policy instead of always being accept

Address PR #147 review: support a REJECT rule action alongside ACCEPT/DROP
and a user-configurable per-VM inbound/outbound default policy (accept/drop/
reject), instead of always defaulting to accept.

- DB: VmFirewallRuleAction::Reject; new VmFirewallPolicy enum; fw_policy_in/
  fw_policy_out columns on vm; update_vm_firewall_policy CRUD (mysql + mock)
- API: ApiFirewallAction::Reject, ApiFirewallPolicy + GET/PATCH
  /api/v1/vm/{id}/firewall/policy; queues ApplyVmFirewall on change
- Proxmox: map Reject -> REJECT; per-VM policy overrides host default in
  patch_firewall
- Docs: API_CHANGELOG.md + API_DOCUMENTATION.md; tests for enum round-trips,
  rule translation, policy CRUD
@v0l v0l merged commit 37b21ff into master Jun 25, 2026
7 checks passed
@v0l v0l deleted the feat/basic-firewall branch June 25, 2026 09:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Basic Firewall

1 participant