How to allow traffic from one source with a firewalld rich rule

Opening an application or management port to an entire firewalld zone can expose it to every source that reaches that zone. A rich rule narrows the exception to one host or CIDR while the rest of the zone keeps its existing deny or reject behavior.

A rich rule combines the address family, source condition, service or port selector, and action in one quoted rule string. When the source is an IPv4 or IPv6 address, include the matching family="ipv4" or family="ipv6" value so firewalld parses the address in the intended protocol family.

The sample rule allows TCP port 8443 from 10.77.0.10/32 in the public zone. Confirm the client source as seen by the server before applying the rule, especially when traffic passes through a VPN, proxy, NAT gateway, or load balancer, because the rule must match the address that reaches the host firewall.

Steps to allow traffic from one source with a firewalld rich rule:

  1. Confirm that firewalld is running before changing zone rules.
    $ sudo firewall-cmd --state
    running
  2. Identify the zone that receives traffic from the client network.
    $ sudo firewall-cmd --get-active-zones
    public (default)
      interfaces: enp1s0
  3. Choose the source CIDR and destination port or service for the exception.

    Use the narrowest source range that matches the real client path. Tool: CIDR Allowlist Risk Checker

  4. Inspect the zone before adding the source-limited allow rule.
    $ sudo firewall-cmd --zone=public --list-all
    public (default, active)
      target: default
      icmp-block-inversion: no
      interfaces: enp1s0
      sources:
      services: dhcpv6-client ssh
      ports:
      protocols:
      forward: yes
      masquerade: no
      forward-ports:
      source-ports:
      icmp-blocks:
      rich rules:

    If the same port or service is already open under ports or services, remove the broader allow rule before relying on the rich rule as the access boundary.

  5. Add the permanent rich rule for the trusted source.
    $ sudo firewall-cmd --zone=public --permanent --add-rich-rule='rule family="ipv4" source address="10.77.0.10/32" port port="8443" protocol="tcp" accept'
    success

    For a predefined service, replace the port selector with a service selector such as service name="https".

  6. Validate the permanent firewalld configuration.
    $ sudo firewall-cmd --check-config
    success
  7. Reload firewalld so the permanent rich rule is active at runtime.
    $ sudo firewall-cmd --reload
    success
  8. List the rich rules in the zone.
    $ sudo firewall-cmd --zone=public --list-rich-rules
    rule family="ipv4" source address="10.77.0.10/32" port port="8443" protocol="tcp" accept
  9. Query the exact rich rule when a script or change ticket needs a yes/no proof.
    $ sudo firewall-cmd --zone=public --query-rich-rule='rule family="ipv4" source address="10.77.0.10/32" port port="8443" protocol="tcp" accept'
    yes
  10. Test the application port from the trusted source host.
    $ nc -vz app01.example.net 8443
    Connection to app01.example.net 8443 port [tcp/*] succeeded!
  11. Test the same port from an untrusted source path.
    $ nc -vz -w 2 app01.example.net 8443
    nc: connect to app01.example.net port 8443 (tcp) failed: Connection refused

    A timeout is also expected when the zone drops unmatched traffic instead of rejecting it. If the untrusted source connects, check for a broader service, port, source-zone, or rich rule that still allows the traffic.