jdx/mise · critical

refusing firewall default incoming {} over SSH: blocking rul

Error message

refusing firewall default incoming {} over SSH: blocking rule '{}' also covers peer {} on server port {}, and firewalld cannot guarantee the allow wins; narrow the rule or set allow_lockout = true

What it means

The firewalld variant of the lockout guard: firewalld policies give no strict first-match ordering mise can rely on, so a blocking rule that also covers the current SSH peer and server port is refused regardless of declaration order — an allow elsewhere cannot be proven to win. The fix is to make the blocking rule stop matching the session, or to acknowledge the risk explicitly.

Source

Thrown at src/system/firewall.rs:509

                    .port
                    .is_none_or(|port| port.contains(connection.server_port))
                && rule
                    .source
                    .is_none_or(|source| source.contains(&connection.peer))
                && rule
                    .destination
                    .is_none_or(|destination| destination.contains(&connection.server))
        }) {
            if rule.action != FirewallAction::Allow {
                match backend {
                    Some(FirewallBackend::Nftables | FirewallBackend::Ufw) if !covered => bail!(
                        "refusing firewall default incoming {} over SSH: blocking rule '{}' precedes a proven allow for peer {} on server port {}; reorder or narrow the rule, or set allow_lockout = true",
                        self.default_incoming.ufw(),
                        rule.name,
                        connection.peer,
                        connection.server_port
                    ),
                    Some(FirewallBackend::Firewalld) => bail!(
                        "refusing firewall default incoming {} over SSH: blocking rule '{}' also covers peer {} on server port {}, and firewalld cannot guarantee the allow wins; narrow the rule or set allow_lockout = true",
                        self.default_incoming.ufw(),
                        rule.name,
                        connection.peer,
                        connection.server_port
                    ),
                    // An automatic backend is validated again after it is
                    // resolved.
                    _ => {}
                }
                continue;
            }
            // SSH_CONNECTION does not identify the ingress interface. An
            // interface-constrained allow cannot prove that it preserves this
            // session, so keep looking for an unrestricted covering allow.
            if rule.interface.is_none() {
                covered = true;
                if matches!(

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Narrow the blocking rule until it cannot match the session: different source CIDR excluding your peer, a port range excluding the SSH port, or a different interface scope.
  2. Pin `backend = "nftables"` or `"ufw"` (installing that tool if needed) where declaration order is honored, and put the allow first.
  3. With out-of-band console access, set `allow_lockout = true` under `[bootstrap.linux.firewall]` to accept the ambiguity.

Example fix

# before — firewalld cannot prove the allow wins
backend = "firewalld"
[[bootstrap.linux.firewall.rules]]
name = "deny-guest"
source = "0.0.0.0/0"
port = "1-65535"
protocol = "tcp"
action = "deny"

[[bootstrap.linux.firewall.rules]]
name = "ssh-ops"
source = "203.0.113.5/32"
port = 22
protocol = "tcp"
action = "allow"

# after — exclude the management peer from the deny
[[bootstrap.linux.firewall.rules]]
name = "deny-guest"
source = "0.0.0.0/1"        # plus a second rule for 128.0.0.0/1, both excluding the peer
port = "1-21"
protocol = "tcp"
action = "deny"
# or simpler: pin backend = "nftables" and order the allow first
Defensive patterns

Strategy: try-catch

Validate before calling

# pre-flight: on firewalld, no deny rule may cover the SSH peer/port at all
# (order cannot save you; narrow or exclude the peer before apply)

Try / catch

if ! mise bootstrap firewall apply 2>fw.err; then
  if grep -q "firewalld cannot guarantee the allow wins" fw.err; then
    echo "narrow the deny so it stops covering the SSH peer/port, or switch backend"; exit 1
  fi
  cat fw.err; exit 1
fi

Prevention

When it happens

Trigger: Backend firewalld (pinned or auto-resolved), deny-ish `default_incoming`, and any non-allow rule whose source/port/destination match the `SSH_CONNECTION` peer and server port — even if an allow rule for the same session exists, firewalld cannot guarantee it takes precedence.

Common situations: RHEL/CentOS-family hosts where firewalld is the default; migrating iptables rule sets into policy objects; broad denies coexisting with a specific SSH allow on hosts that previously used nftables ordering semantics.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/34b5e5ff07039f33. Report an issue: GitHub.