voxpupuli / puppet-firewalld

Puppet module for managing firewalld
Apache License 2.0
39 stars 77 forks source link

Firewalld rich rules purged every time when priority enabled #366

Open adam-kosseck opened 6 months ago

adam-kosseck commented 6 months ago

I have an issue with FirewallD module 5.0.0 running against Puppet 7.27.

We have a number of firewalld rich rules declared in Hiera in a zone like this:

  internal:
    ensure: present
    target: '%%REJECT%%'
    sources: [ ]  
    purge_rich_rules: true
    purge_services: true
    purge_ports: true
    icmp_block_inversion: false  
    icmp_blocks: [ ]

firewalld::rich_rules:
  '000 Accept ICMP from company Subnets':
    zone: internal
    source:
      ipset: company
    protocol: icmp
    action: accept
  '001 Accept SSH from company Subnets':
    zone: internal
    source:
      ipset: company
    service: ssh
    action: accept

These rules work ok, however if I add a "priority" parameter to the rich rules then EVERY time the Puppet agent runs it purges all the rich rules and re-applies them. Here's the debug output from one of these runs:

Debug: Exec[firewalld::set_log_denied_offline](provider=posix): Executing check '[ $(firewall-offline-cmd --get-log-denied) = unicast ]'
Debug: Executing: '[ $(firewall-offline-cmd --get-log-denied) = unicast ]'
Debug: /Stage[main]/Firewalld/Exec[firewalld::set_log_denied_offline]: '["firewall-offline-cmd", "--set-log-denied", "unicast"]' won't be executed because of failed check 'unless'
Debug: Augeas[firewalld::zone_drifting](provider=augeas): Opening augeas with root /, lens path /opt/puppetlabs/puppet/cache/lib/augeas/lenses, flags 64
Debug: Augeas[firewalld::zone_drifting](provider=augeas): Augeas version 1.13.0 is installed
Debug: Augeas[firewalld::zone_drifting](provider=augeas): Will attempt to save and only run if files changed
Debug: Augeas[firewalld::zone_drifting](provider=augeas): sending command 'set' with params ["/files/etc/firewalld/firewalld.conf/AllowZoneDrifting", "no"]
Debug: Augeas[firewalld::zone_drifting](provider=augeas): Skipping because no files were changed
Debug: Augeas[firewalld::zone_drifting](provider=augeas): Closed the augeas connection
Debug: Augeas[firewalld::firewall_backend](provider=augeas): Opening augeas with root /, lens path /opt/puppetlabs/puppet/cache/lib/augeas/lenses, flags 64
Debug: Augeas[firewalld::firewall_backend](provider=augeas): Augeas version 1.13.0 is installed
Debug: Augeas[firewalld::firewall_backend](provider=augeas): Will attempt to save and only run if files changed
Debug: Augeas[firewalld::firewall_backend](provider=augeas): sending command 'set' with params ["/files/etc/firewalld/firewalld.conf/FirewallBackend", "nftables"]
Debug: Augeas[firewalld::firewall_backend](provider=augeas): Skipping because no files were changed
Debug: Augeas[firewalld::firewall_backend](provider=augeas): Closed the augeas connection
Debug: Executing: '/usr/bin/systemctl is-active -- firewalld'
Debug: Executing: '/usr/bin/systemctl is-enabled -- firewalld'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --get-zones'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --get-target'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --list-sources'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --list-icmp-blocks'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --query-icmp-block-inversion'
Notice: /Stage[main]/Firewalld/Firewalld_zone[internal]/purge_rich_rules: purge_rich_rules changed 'purgable' to 'true' (corrective)
Debug: Executing: '/usr/bin/firewall-cmd --reload'
Debug: /Stage[main]/Firewalld/Firewalld_zone[internal]: The container Class[Firewalld] will propagate my refresh event
Debug: Executing: '/usr/bin/firewall-cmd --permanent --get-zones'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone external --get-target'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone external --list-icmp-blocks'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone external --query-icmp-block-inversion'
Debug: Prefetching firewall_cmd resources for firewalld_service
Debug: Executing: '/usr/bin/firewall-cmd --permanent --get-services'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --list-services'
Debug: /Stage[main]/Firewalld/Firewalld_service[000 Remove Default Cockpit Service Rule]: Nothing to manage: no ensure and the resource doesn't exist
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --list-services'
Debug: /Stage[main]/Firewalld/Firewalld_service[000 Remove Default dhcpv6-client Service Rule]: Nothing to manage: no ensure and the resource doesn't exist
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --list-services'
Debug: /Stage[main]/Firewalld/Firewalld_service[000 Remove Default mdns Service Rule]: Nothing to manage: no ensure and the resource doesn't exist
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --list-services'
Debug: /Stage[main]/Firewalld/Firewalld_service[000 Remove Default samba-client Rule]: Nothing to manage: no ensure and the resource doesn't exist
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --query-rich-rule rule family="ipv4" priority="-32500" source ipset="company" protocol value="icmp" accept'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --add-rich-rule rule family="ipv4" priority="-32500" source ipset="company" protocol value="icmp" accept'
Notice: /Stage[main]/Firewalld/Firewalld_rich_rule[000 Accept ICMP from company Subnets]/ensure: created (corrective)
Debug: /Stage[main]/Firewalld/Firewalld_rich_rule[000 Accept ICMP from company Subnets]: The container Class[Firewalld] will propagate my refresh event
Info: /Stage[main]/Firewalld/Firewalld_rich_rule[000 Accept ICMP from company Subnets]: Scheduling refresh of Class[Firewalld::Reload]
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --query-rich-rule rule family="ipv4" priority="-32000" source ipset="company" service name="ssh" accept'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --add-rich-rule rule family="ipv4" priority="-32000" source ipset="company" service name="ssh" accept'
Notice: /Stage[main]/Firewalld/Firewalld_rich_rule[001 Accept SSH from company Subnets]/ensure: created (corrective)
Debug: /Stage[main]/Firewalld/Firewalld_rich_rule[001 Accept SSH from company Subnets]: The container Class[Firewalld] will propagate my refresh event
Info: /Stage[main]/Firewalld/Firewalld_rich_rule[001 Accept SSH from company Subnets]: Scheduling refresh of Class[Firewalld::Reload]

If I remove the priority parameter then the problem goes away immediately.

adam-kosseck commented 1 month ago

I have also noted the same behavior with inverted rich rules via hiera. The following hiera rich rules block traffic originating from a loopback adapter that is trying to access a non-loopback address:

firewalld::rich_rules:
'002 Restrict ipv4 loopback traffic':
    zone: internal
    source: '127.0.0.1'
    dest:
      address: '127.0.0.1'
      invert: true
    action: drop
  '003 Restrict ipv6 loopback traffic':
    zone: internal
    source: '::1'
    dest:
      address: '::1'
      invert: true
    family: ipv6
    action: drop

The following is seen in the debug logs of every host which inherits these hiera rules, every time the agent runs:

Debug: Executing: '/usr/bin/systemctl is-enabled -- firewalld'
Debug: Prefetching firewall_cmd resources for firewalld_ipset
Debug: Executing: '/usr/bin/firewall-cmd --permanent --get-ipsets'
** --info-ipset and ipset --get-entries queries removed **
Debug: Executing: '/usr/bin/firewall-cmd --permanent --get-zones'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --get-target'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --list-sources'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --list-icmp-blocks'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --query-icmp-block-inversion'
Notice: /Stage[main]/Firewalld/Firewalld_zone[internal]/purge_rich_rules: purge_rich_rules changed 'purgable' to 'true' (corrective)
Debug: Executing: '/usr/bin/firewall-cmd --reload'
Debug: /Stage[main]/Firewalld/Firewalld_zone[internal]: The container Class[Firewalld] will propagate my refresh event
Debug: Executing: '/usr/bin/firewall-cmd --permanent --get-zones'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone external --get-target'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone external --list-icmp-blocks'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone external --query-icmp-block-inversion'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --get-services'
** Service queries removed **
Debug: Prefetching firewall_cmd resources for firewalld_service
Debug: Executing: '/usr/bin/firewall-cmd --permanent --get-services'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --list-services'
** Service queries removed **
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --list-services'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --query-rich-rule rule family="ipv4" source ipset="company" protocol value="icmp" accept'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --query-rich-rule rule family="ipv4" source ipset="company" service name="ssh" accept'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --query-rich-rule rule family="ipv4" source address="127.0.0.1" destination NOT address="127.0.0.1" drop'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --add-rich-rule rule family="ipv4" source address="127.0.0.1" destination NOT address="127.0.0.1" drop'
Notice: /Stage[main]/Firewalld/Firewalld_rich_rule[002 Restrict ipv4 loopback traffic]/ensure: created (corrective)
Debug: /Stage[main]/Firewalld/Firewalld_rich_rule[002 Restrict ipv4 loopback traffic]: The container Class[Firewalld] will propagate my refresh event
Info: /Stage[main]/Firewalld/Firewalld_rich_rule[002 Restrict ipv4 loopback traffic]: Scheduling refresh of Class[Firewalld::Reload]
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --query-rich-rule rule family="ipv6" source address="::1" destination NOT address="::1" drop'
Debug: Executing: '/usr/bin/firewall-cmd --permanent --zone internal --add-rich-rule rule family="ipv6" source address="::1" destination NOT address="::1" drop'
Notice: /Stage[main]/Firewalld/Firewalld_rich_rule[003 Restrict ipv6 loopback traffic]/ensure: created (corrective)
Debug: /Stage[main]/Firewalld/Firewalld_rich_rule[003 Restrict ipv6 loopback traffic]: The container Class[Firewalld] will propagate my refresh event
Info: /Stage[main]/Firewalld/Firewalld_rich_rule[003 Restrict ipv6 loopback traffic]: Scheduling refresh of Class[Firewalld::Reload]
** Other rich rule queries removed **
Info: Class[Firewalld::Reload]: Scheduling refresh of Exec[firewalld::reload]
Debug: /Stage[main]/Firewalld::Reload/Exec[firewalld::reload]: 'firewall-cmd --reload' won't be executed because of failed check 'refreshonly'
Debug: Exec[firewalld::reload](provider=posix): Executing check 'firewall-cmd --state'
Debug: Executing: 'firewall-cmd --state'
Debug: /Stage[main]/Firewalld::Reload/Exec[firewalld::reload]/onlyif: running
Debug: Exec[firewalld::reload](provider=posix): Executing 'firewall-cmd --reload'
Debug: Executing: 'firewall-cmd --reload'
Notice: /Stage[main]/Firewalld::Reload/Exec[firewalld::reload]: Triggered 'refresh' from 1 event