Skip to content

Audit remoteAccess firewall rules and listener without false drift (#143) - #148

Merged
shipmill-romamo[bot] merged 2 commits into
mainfrom
fix/143-audit-remote-access
Oct 27, 2026
Merged

shipmill-romamo[bot] merged 2 commits into
mainfrom
fix/143-audit-remote-access

Conversation

@shipmill-romamo

@shipmill-romamo shipmill-romamo Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

cloudfall audit reported false drift on a server whose PostgreSQL service declares spec.postgresql.remoteAccess:

  • firewall.allowedInbound now expects one tcp/<port> from <cidr> entry per declared source, next to today's tcp/22-style entries. The observed side reads the ip saddr / ip6 saddr match of each accepted rule in nft -j output: a bare address (nft's form for a /32 or /128) and {"prefix": {"addr", "len"}} are normalised to canonical CIDR, so 10.1.0.7/32 matches nft's 10.1.0.7. Any other saddr shape (set, negation, range) is kept as its raw JSON, so it never matches and shows as drift
  • services.bind[<id>] for a service with remoteAccess matches only when both the bind address and remoteAccess.listenAddress have a listener on the port and no other non-loopback listener exists: a PostgreSQL that failed to bind listenAddress is drift. For such a service the desired object reports loopbackOnly: false and adds remoteAccess: {listenAddress}; services without remoteAccess keep the same keys and values
  • The source-restricted rules come from one SDK function, cloudfall.inventory.remote_access_rules_for_server (returning SourceRestrictedFirewallRule), which replaces the engine's private _remote_access_rules. The engine's refusals (no firewall on the server; a source of every address) keep their order and messages

Servers without remoteAccess audit exactly as before.

Tests

  • sdk/tests/test_audit.py: a snapshot with the rendered remoteAccess rules (IPv4 prefix, a bare /32, an ip6 saddr prefix) and the 10.0.0.2:5432 listener audits compliant (fails on main); the port open to every address, a wrong source (fails on main's output form), a listener on an undeclared or wildcard address (next to the declared one), and a remoteAccess service listening only on 127.0.0.1 are drift; a server without remoteAccess yields the same firewall.allowedInbound and services.bind values as before
  • Ran uv run ruff check ., uv run mypy, and uv run pytest sdk/tests/test_audit.py sdk/tests/test_owned_postgresql.py engine/tests/test_postgresql_remote_access.py engine/tests/test_ansible_inventory.py engine/tests/test_firewall_templates.py (85 passed)

Fixes #143

🤖 Generated with Claude Code

shipmill-romamo Bot and others added 2 commits October 27, 2026 13:18
)

firewall.allowedInbound now expects one 'tcp/<port> from <cidr>' entry per
declared remoteAccess source and parses the ip/ip6 saddr match of each
accepted nftables rule, normalising nft's bare /32 and /128 addresses.
services.bind accepts a listener on the declared listenAddress. The
source-restricted rules come from one SDK function,
remote_access_rules_for_server, which the engine inventory now uses too.
Servers without remoteAccess audit exactly as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A service that declares remoteAccess now matches services.bind only when
both its bind address and its listenAddress have a listener on the port,
so a PostgreSQL that failed to bind listenAddress is reported as drift.
Services without remoteAccess keep today's check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shipmill-romamo
shipmill-romamo Bot merged commit b49740f into main Oct 27, 2026
1 check passed
@shipmill-romamo
shipmill-romamo Bot deleted the fix/143-audit-remote-access branch October 27, 2026 11:27
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.

cloudfall audit reports false drift once a PostgreSQL service declares remoteAccess

0 participants