Update the firewall cookbook to the latest version

This gives us comments from the named resources
This commit is contained in:
Greg Karékinian
2023-06-29 15:08:44 +02:00
parent 916ae8094c
commit 68ce3c4834
72 changed files with 4774 additions and 448 deletions

View File

@@ -0,0 +1,28 @@
unified_mode true
provides :firewalld,
os: 'linux'
action :install do
chef_gem 'ruby-dbus'
require 'dbus'
package 'firewalld'
end
action :reload do
service 'firewalld' do
action :reload
end
end
action :restart do
service 'firewalld' do
action :restart
end
end
action :disable do
service 'firewalld' do
action [:disable, :stop]
end
end

View File

@@ -0,0 +1,39 @@
unified_mode true
provides :firewalld_config,
os: 'linux'
property :default_zone,
String,
description: 'Set default zone for connections and interfaces where no zone has been selected to zone. Setting the default zone changes the zone for the connections or interfaces, that are using the default zone.'
property :log_denied,
String,
equal_to: %w(all unicast broadcast multicast off),
description: 'Set LogDenied value to value. If LogDenied is enabled, then logging rules are added right before reject and drop rules in the INPUT, FORWARD and OUTPUT chains for the default rules and also final reject and drop rules in zones.'
load_current_value do |_new_resource|
sysbus = DBus.system_bus
firewalld_service = sysbus['org.fedoraproject.FirewallD1']
firewalld_object = firewalld_service['/org/fedoraproject/FirewallD1']
interface = firewalld_object['org.fedoraproject.FirewallD1']
default_zone interface.getDefaultZone
log_denied interface.getLogDenied
end
action :update do
dbus = DBus.system_bus
fw = firewalld_interface(dbus)
converge_if_changed :default_zone do
fw.setDefaultZone new_resource.default_zone
end
converge_if_changed :log_denied do
fw.setLogDenied new_resource.log_denied
end
end
action_class do
include FirewallCookbook::Helpers::FirewalldDBus
end

View File

@@ -0,0 +1,106 @@
unified_mode true
provides :firewalld_helper,
os: 'linux'
property :version,
String,
default: '',
description: 'see version attribute of helper tag in firewalld.helper(5).'
property :short,
String,
name_property: true,
description: 'see short tag in firewalld.helper(5).'
property :description,
String,
description: 'see description tag in firewalld.helper(5).'
property :family,
String,
equal_to: %w(ipv4 ipv6),
default: 'ipv4',
description: 'see family tag in firewalld.helper(5).'
property :nf_module,
String,
description: 'see module tag in firewalld.helper(5).'
property :ports,
[Array, String],
default: [],
description: 'array of port and protocol pairs. See port tag in firewalld.helper(5).',
coerce: proc { |o| Array(o) }
load_current_value do |new_resource|
dbus = DBus.system_bus
firewalld_service = dbus['org.fedoraproject.FirewallD1']
firewalld_object = firewalld_service['/org/fedoraproject/FirewallD1/config']
fw_config = firewalld_object['org.fedoraproject.FirewallD1.config']
if fw_config.getHelperNames.include?(new_resource.short)
helper_path = fw_config.getHelperByName(new_resource.short)
object = firewalld_service[helper_path]
config_helper = object['org.fedoraproject.FirewallD1.config.helper']
settings = config_helper.getSettings
version settings[0]
# short settings[1]
description settings[2]
family settings[3]
nf_module settings[4]
ports settings[5]
else
Chef::Log.info "Helper #{new_resource.short} does not exist. Will be created."
end
end
action :update do
dbus = DBus.system_bus
fw = firewalld_interface(dbus)
fw_config = config_interface(dbus)
helper_names = fw_config.getHelperNames
reload = false
if !helper_names.include?(new_resource.short)
values = [
new_resource.version,
new_resource.short,
default_description(new_resource),
new_resource.family,
new_resource.nf_module,
new_resource.ports.map { |e| e.split('/') },
]
converge_by "Add Helper #{new_resource.short}" do
fw_config.addHelper(new_resource.short, values)
end
reload = true
else
helper_path = fw_config.getHelperByName(new_resource.short)
helper = helper_interface(dbus, helper_path)
converge_if_changed :version do
helper.setVersion new_resource.version
reload = true
end
converge_if_changed :description do
helper.setDescription default_description(new_resource)
reload = true
end
converge_if_changed :family do
helper.setFamily new_resource.family
reload = true
end
converge_if_changed :nf_module do
helper.setModule new_resource.nf_module
reload = true
end
converge_if_changed :ports do
helper.setPorts new_resource.ports.map { |e| e.split('/') }
reload = true
end
end
if reload
converge_by ['reload permanent configuration of firewalld'] do
fw.reload
end
end
end
action_class do
include FirewallCookbook::Helpers
include FirewallCookbook::Helpers::FirewalldDBus
end

View File

@@ -0,0 +1,88 @@
unified_mode true
provides :firewalld_icmptype,
os: 'linux'
property :version,
String,
default: '',
description: 'see version attribute of icmptype tag in firewalld.icmptype(5).'
property :short,
String,
name_property: true,
description: 'see short tag in firewalld.icmptype(5).'
property :description,
String,
description: 'see description tag in firewalld.icmptype(5).'
property :destinations,
Array,
equal_to: [['ipv4'], ['ipv6'], %w(ipv4 ipv6)],
default: 'ipv4',
description: 'array, either empty or containing strings \'ipv4\' and/or \'ipv6\', see destination tag in firewalld.icmptype(5).',
coerce: proc { |o| Array(o) }
load_current_value do |new_resource|
sysbus = DBus.system_bus
firewalld_service = sysbus['org.fedoraproject.FirewallD1']
firewalld_object = firewalld_service['/org/fedoraproject/FirewallD1/config']
fw_config = firewalld_object['org.fedoraproject.FirewallD1.config']
if fw_config.getIcmpTypeNames.include?(new_resource.short)
icmptype_path = fw_config.getIcmpTypeByName(new_resource.short)
object = firewalld_service[icmptype_path]
config_icmptype = object['org.fedoraproject.FirewallD1.config.icmptype']
settings = config_icmptype.getSettings
version settings[0]
# short settings[1]
description settings[2]
destinations settings[3]
else
Chef::Log.info "IcmpType #{new_resource.short} does not exist. Will be created."
end
end
action :update do
dbus = DBus.system_bus
fw_config = config_interface(dbus)
fw = firewalld_interface(dbus)
reload = false
icmptype_names = fw_config.getIcmpTypeNames
if !icmptype_names.include?(new_resource.short)
values = [
new_resource.version,
new_resource.short,
default_description(new_resource),
new_resource.destinations,
]
converge_by "Add IcmpType #{new_resource.short}" do
fw_config.addIcmpType(new_resource.short, values)
end
reload = true
else
icmptype_path = fw_config.getIcmpTypeByName(new_resource.short)
icmptype = icmptype_interface(dbus, icmptype_path)
converge_if_changed :version do
icmptype.setVersion new_resource.version
reload = true
end
converge_if_changed :description do
icmptype.setDescription default_description(new_resource)
reload = true
end
converge_if_changed :destinations do
icmptype.setDestinations new_resource.destinations
reload = true
end
end
if reload
converge_by ['reload permanent configuration of firewalld'] do
fw.reload
end
end
end
action_class do
include FirewallCookbook::Helpers
include FirewallCookbook::Helpers::FirewalldDBus
end

View File

@@ -0,0 +1,104 @@
unified_mode true
provides :firewalld_ipset,
os: 'linux'
property :version,
String,
description: 'see version attribute of ipset tag in firewalld.ipset(5).'
property :short,
String,
name_property: true,
description: 'see short tag in firewalld.ipset(5).'
property :description,
String,
description: 'see description tag in firewalld.ipset(5).'
property :type,
String,
default: 'hash:ip',
description: 'see type attribute of ipset tag in firewalld.ipset(5).',
equal_to:
%w(hash:ip hash:ip,mark hash:ip,port hash:ip,port,ip hash:ip,port,net hash:mac hash:net hash:net,iface hash:net,net hash:net,port hash:net,port,net)
property :options,
Hash,
description: 'hash of {option : value} . See options tag in firewalld.ipset(5).'
property :entries,
[Array, String],
description: 'array of entries, see entry tag in firewalld.ipset(5).',
coerce: proc { |o| Array(o) }
load_current_value do |new_resource|
sysbus = DBus.system_bus
firewalld_service = sysbus['org.fedoraproject.FirewallD1']
firewalld_object = firewalld_service['/org/fedoraproject/FirewallD1/config']
fw_config = firewalld_object['org.fedoraproject.FirewallD1.config']
if fw_config.getIPSetNames.include?(new_resource.short)
ipset_path = fw_config.getIPSetByName(new_resource.short)
object = firewalld_service[ipset_path]
config_ipset = object['org.fedoraproject.FirewallD1.config.ipset']
settings = config_ipset.getSettings
version settings[0]
# short settings[1]
description settings[2]
type settings[3]
options settings[4]
entries settings[5]
else
Chef::Log.info "Ipset #{new_resource.short} does not exist. Will be created."
end
end
action :update do
dbus = DBus.system_bus
fw = firewalld_interface(dbus)
fw_config = config_interface(dbus)
reload = false
if !fw_config.getIPSetNames.include?(new_resource.short)
values = [
new_resource.version || '',
new_resource.short,
default_description(new_resource),
new_resource.type,
new_resource.options || {},
new_resource.entries,
]
converge_by "Add ipset #{new_resource.short}" do
fw_config.addIPSet(new_resource.short, values)
end
reload = true
else
ipset_path = fw_config.getIPSetByName(new_resource.short)
ipset = ipset_interface(dbus, ipset_path)
converge_if_changed :version do
ipset.setVersion new_resource.version
reload = true
end
converge_if_changed :description do
ipset.setDescriptions default_description(new_resource)
reload = true
end
converge_if_changed :type do
ipset.setType new_resource.type
reload = true
end
converge_if_changed :options do
ipset.setOptions(new_resource.options || {})
reload = true
end
converge_if_changed :entries do
ipset.setEntries new_resource.entries
reload = true
end
end
if reload
converge_by ['reload permanent configuration of firewalld'] do
fw.reload
end
end
end
action_class do
include FirewallCookbook::Helpers
include FirewallCookbook::Helpers::FirewalldDBus
end

View File

@@ -0,0 +1,115 @@
unified_mode true
provides :firewalld_policy,
os: 'linux'
property :description,
String,
description: 'see description tag in firewalld.policy(5).'
property :egress_zones,
[Array, String],
description: 'array of zone names. See egress-zone tag in firewalld.policy(5).',
coerce: proc { |o| Array(o) }
property :forward_ports,
[Array, String],
description: 'array of `portid[-portid]:proto=protocol[:toport=portid[-portid]][:toaddr=address[/mask]]`. See forward-port tag in firewalld.policy(5).',
coerce: proc { |o| Array(o) }
property :icmp_blocks,
[Array, String],
description: 'array of icmp-blocks. See icmp-block tag in firewalld.policy(5).'
property :ingress_zones,
[Array, String],
description: 'array of zone names. See ingress-zone tag in firewalld.policy(5).',
coerce: proc { |o| Array(o) }
property :masquerade,
[true, false],
description: 'see masquerade tag in firewalld.policy(5).'
property :ports,
[Array, String],
description: 'array of port and protocol pairs. See port tag in firewalld.policy(5).',
coerce: proc { |o| Array(o) }
property :priority,
Integer,
description: 'see priority tag in firewalld.policy(5).'
property :protocols,
[Array, String],
description: 'array of protocols, see protocol tag in firewalld.policy(5).',
coerce: proc { |o| Array(o) }
property :rich_rules,
[Array, String],
description: 'array of rich-language rules. See rule tag in firewalld.policy(5).',
coerce: proc { |o| Array(o) }
property :services,
[Array, String],
description: 'array of service names, see service tag in firewalld.policy(5).',
coerce: proc { |o| Array(o) }
property :short,
String,
description: 'see short tag in firewalld.policy(5).',
name_property: true
property :source_ports,
[Array, String],
description: 'array of port and protocol pairs. See source-port tag in firewalld.policy(5).',
coerce: proc { |o| Array(o) }
property :target,
String,
description: 'see target attribute of policy tag in firewalld.policy(5).'
property :version,
String,
description: 'see version attribute of policy tag in firewalld.policy(5).'
load_current_value do |new_resource|
sysbus = DBus.system_bus
firewalld_service = sysbus['org.fedoraproject.FirewallD1']
firewalld_object = firewalld_service['/org/fedoraproject/FirewallD1/config']
fw_config = firewalld_object['org.fedoraproject.FirewallD1.config']
if fw_config.getPolicyNames.include?(new_resource.short)
policy_path = fw_config.getPolicyByName(new_resource.short)
object = firewalld_service[policy_path]
config_policy = object['org.fedoraproject.FirewallD1.config.policy']
config_policy.getSettings.each do |k, v|
send(k, v)
end
else
Chef::Log.info "Zone #{new_resource.short} does not exist. Will be created."
end
end
action :update do
dbus = DBus.system_bus
fw = firewalld_interface(dbus)
fw_config = config_interface(dbus)
reload = false
unless fw_config.getPolicyNames.include?(new_resource.short)
fw_config.addPolicy(new_resource.short, {})
end
policy_path = fw_config.getPolicyByName(new_resource.short)
policy = policy_interface(dbus, policy_path)
properties = new_resource.class.state_properties.map(&:name)
properties.each do |property|
new_value = new_resource.send(property)
next if new_value.nil?
if [:ports, :source_ports].include?(property)
new_value = DBus.variant('a(ss)', new_value.map { |e| e.split('/') })
elsif [:forward_ports].include?(property)
new_value = forward_ports_to_dbus(new_resource)
elsif [:priority].include?(property)
new_value = DBus.variant('i', new_value)
end
converge_if_changed property do
policy.update({ property.to_s => new_value })
reload = true
end
end
if reload
converge_by ['reload permanent configuration of firewalld'] do
fw.reload
end
end
end
action_class do
include FirewallCookbook::Helpers::FirewalldDBus
end

View File

@@ -0,0 +1,98 @@
unified_mode true
provides :firewalld_service,
os: 'linux'
property :version,
String,
description: 'see version attribute of service tag in firewalld.service(5).'
property :short,
String,
name_property: true,
description: 'see short tag in firewalld.service(5).'
property :description,
String,
description: 'see description tag in firewalld.service(5).'
property :ports,
[Array, String],
description: 'array of port and protocol pairs. See port tag in firewalld.service(5).',
coerce: proc { |o| Array(o) }
property :module_names,
[Array, String],
description: 'array of kernel netfilter helpers, see module tag in firewalld.service(5).',
coerce: proc { |o| Array(o) }
property :destination,
Hash,
description: 'hash of {IP family : IP address} where \'IP family\' key can be either \'ipv4\' or \'ipv6\'. See destination tag in firewalld.service(5).'
property :protocols,
[Array, String],
description: 'array of protocols, see protocol tag in firewalld.service(5).',
coerce: proc { |o| Array(o) }
property :source_ports,
[Array, String],
description: 'array of port and protocol pairs. See source-port tag in firewalld.service(5).',
coerce: proc { |o| Array(o) }
property :includes,
[Array, String],
description: 'array of service includes, see include tag in firewalld.service(5).',
coerce: proc { |o| Array(o) }
property :helpers,
[Array, String],
description: 'array of service helpers, see helper tag in firewalld.service(5).',
coerce: proc { |o| Array(o) }
load_current_value do |new_resource|
sysbus = DBus.system_bus
firewalld_service = sysbus['org.fedoraproject.FirewallD1']
firewalld_object = firewalld_service['/org/fedoraproject/FirewallD1/config']
fw_config = firewalld_object['org.fedoraproject.FirewallD1.config']
if fw_config.getServiceNames.include?(new_resource.short)
service_path = fw_config.getServiceByName(new_resource.short)
object = firewalld_service[service_path]
config_service = object['org.fedoraproject.FirewallD1.config.service']
config_service.getSettings2.each do |k, v|
send(k, v)
end
else
Chef::Log.info "Service #{new_resource.short} does not exist. Will be created."
end
end
action :update do
dbus = DBus.system_bus
fw = firewalld_interface(dbus)
fw_config = config_interface(dbus)
reload = false
unless fw_config.getServiceNames.include?(new_resource.short)
fw_config.addService2(new_resource.short, {})
end
service_path = fw_config.getServiceByName(new_resource.short)
service = service_interface(dbus, service_path)
properties = new_resource.class.state_properties.map(&:name)
properties.each do |property|
new_value = new_resource.send(property)
next unless new_value
if [:ports, :source_ports].include?(property)
new_value = DBus.variant('a(ss)', new_value.map { |e| e.split('/') })
elsif property == :description
new_value = default_description(new_resource)
end
converge_if_changed property do
key = property == :short ? 'name' : property.to_s
service.update2({ key => new_value })
reload = true
end
end
if reload
converge_by ['reload permanent configuration of firewalld'] do
fw.reload
end
end
end
action_class do
include FirewallCookbook::Helpers
include FirewallCookbook::Helpers::FirewalldDBus
end

View File

@@ -0,0 +1,118 @@
unified_mode true
provides :firewalld_zone,
os: 'linux'
property :description,
String,
description: 'see description tag in firewalld.zone(5).'
property :forward,
[true, false],
description: 'see forward tag in firewalld.zone(5).'
property :forward_ports,
[Array, String],
description: 'array of (port, protocol, to-port, to-addr). See forward-port tag in firewalld.zone(5).',
coerce: proc { |o| Array(o) }
property :icmp_block_inversion,
[true, false],
description: 'see icmp-block-inversion tag in firewalld.zone(5).'
property :icmp_blocks,
[Array, String],
description: 'array of icmp-blocks. See icmp-block tag in firewalld.zone(5).',
coerce: proc { |o| Array(o) }
property :interfaces,
[Array, String],
description: 'array of interfaces. See interface tag in firewalld.zone(5).',
coerce: proc { |o| Array(o) }
property :masquerade,
[true, false],
description: 'see masquerade tag in firewalld.zone(5).'
property :ports,
[Array, String],
description: 'array of port and protocol pairs. See port tag in firewalld.zone(5).',
coerce: proc { |o| Array(o) }
property :protocols,
[Array, String],
description: 'array of protocols, see protocol tag in firewalld.zone(5).',
coerce: proc { |o| Array(o) }
property :rules_str,
[Array, String],
description: 'array of rich-language rules. See rule tag in firewalld.zone(5).',
coerce: proc { |o| Array(o) }
property :services,
[Array, String],
description: 'array of service names, see service tag in firewalld.zone(5).',
coerce: proc { |o| Array(o) }
property :short,
String,
name_property: true,
description: 'see short tag in firewalld.zone(5).'
property :source_ports,
[Array, String],
description: 'array of port and protocol pairs. See source-port tag in firewalld.zone(5).',
coerce: proc { |o| Array(o) }
property :sources,
[Array, String],
description: 'array of source addresses. See source tag in firewalld.zone(5).',
coerce: proc { |o| Array(o) }
property :target,
String,
description: 'see target attribute of zone tag in firewalld.zone(5).'
property :version,
String,
description: 'see version attribute of zone tag in firewalld.zone(5).'
load_current_value do |new_resource|
sysbus = DBus.system_bus
firewalld_service = sysbus['org.fedoraproject.FirewallD1']
firewalld_object = firewalld_service['/org/fedoraproject/FirewallD1/config']
fw_config = firewalld_object['org.fedoraproject.FirewallD1.config']
if fw_config.getZoneNames.include?(new_resource.short)
zone_path = fw_config.getZoneByName(new_resource.short)
object = firewalld_service[zone_path]
config_zone = object['org.fedoraproject.FirewallD1.config.zone']
config_zone.getSettings2.each do |k, v|
send(k, v)
end
else
Chef::Log.info "Zone #{new_resource.short} does not exist. Will be created."
end
end
action :update do
dbus = DBus.system_bus
fw = firewalld_interface(dbus)
fw_config = config_interface(dbus)
unless fw_config.getZoneNames.include?(new_resource.short)
fw_config.addZone2(new_resource.short, {})
end
zone_path = fw_config.getZoneByName(new_resource.short)
zone = zone_interface(dbus, zone_path)
reload = false
properties = new_resource.class.state_properties.map(&:name)
properties.each do |property|
new_value = new_resource.send(property)
next unless new_value
if [:ports, :source_ports].include?(property)
new_value = DBus.variant('a(ss)', new_value.map { |e| e.split('/') })
elsif [:forward_ports].include?(property)
new_value = forward_ports_to_dbus(new_resource)
end
converge_if_changed property do
zone.update2({ property.to_s => new_value })
reload = true
end
end
if reload
converge_by ['reload permanent configuration of firewalld'] do
fw.reload
end
end
end
action_class do
include FirewallCookbook::Helpers::FirewalldDBus
end

View File

@@ -0,0 +1,71 @@
unified_mode true
include FirewallCookbook::Helpers
include FirewallCookbook::Helpers::Nftables
provides :nftables,
os: 'linux'
property :rules,
Hash,
default: {}
property :input_policy,
String,
equal_to: %w(drop accept),
default: 'accept'
property :output_policy,
String,
equal_to: %w(drop accept),
default: 'accept'
property :forward_policy,
String,
equal_to: %w(drop accept),
default: 'accept'
property :table_ip_nat,
[true, false],
default: false
property :table_ip6_nat,
[true, false],
default: false
property :nftables_conf_path, String,
description: 'nftables.conf filepath',
default: lazy { default_nftables_conf_path }
action :install do
package 'nftables' do
action :install
notifies :rebuild, "nftables[#{new_resource.name}]"
end
end
action :rebuild do
ensure_default_rules_exist(new_resource)
file new_resource.nftables_conf_path do
content <<~NFT
#!/usr/sbin/nft -f
flush ruleset
#{build_rule_file(new_resource.rules)}
NFT
mode '0750'
owner 'root'
group 'root'
notifies :restart, 'service[nftables]'
end
service 'nftables' do
action [:enable, :start]
end
end
action :restart do
service 'nftables' do
action :restart
end
end
action :disable do
service 'nftables' do
action [:disable, :stop]
end
end

View File

@@ -0,0 +1,113 @@
unified_mode true
require 'ipaddr'
action_class do
include FirewallCookbook::Helpers
include FirewallCookbook::Helpers::Nftables
def return_early?(new_resource)
!new_resource.notify_firewall ||
!(new_resource.action.include?(:create) &&
!new_resource.should_skip?(:create))
end
end
provides :nftables_rule
default_action :create
property :firewall_name,
String,
default: 'default'
property :command,
[Array, Symbol],
default: :accept
property :protocol,
[Integer, Symbol],
default: :tcp,
callbacks: {
'must be either :tcp, :udp, :icmp, :\'ipv6-icmp\', :icmpv6, :none, or a valid IP protocol number' => lambda do |p|
%i(udp tcp icmp icmpv6 ipv6-icmp esp ah ipv6 none).include?(p) || (0..142).include?(p)
end,
}
property :direction,
Symbol,
equal_to: [:in, :out, :pre, :post, :forward],
default: :in
# nftables handles ip6 and ip simultaneously. Except for directions
# :pre and :post, where where either :ip6 or :ip must be specified.
# callback should prevent from mixing that up.
property :family,
Symbol,
equal_to: [:ip6, :ip],
default: :ip
property :source,
[String, Array],
callbacks: {
'must be a valid ip address' => lambda do |ips|
Array(ips).inject(false) do |a, ip|
a || !!IPAddr.new(ip)
end
end,
}
property :sport,
[Integer, String, Array, Range]
property :interface,
String
property :dport,
[Integer, String, Array, Range]
property :destination,
[String, Array],
callbacks: {
'must be a valid ip address' => lambda do |ips|
Array(ips).inject(false) do |a, ip|
a || !!IPAddr.new(ip)
end
end,
}
property :outerface,
String
property :position,
Integer,
default: 50
property :stateful,
[Symbol, Array]
property :redirect_port,
Integer
property :description,
String,
name_property: true
property :include_comment,
[true, false],
default: true
property :log_prefix,
String
property :log_group,
Integer
# for when you just want to pass a raw rule
property :raw,
String
# do you want this rule to notify the firewall to recalculate
# (and potentially reapply) the firewall_rule(s) it finds?
property :notify_firewall,
[true, false],
default: true
action :create do
return if return_early?(new_resource)
fwr = build_firewall_rule(new_resource)
with_run_context :root do
edit_resource!('nftables', new_resource.firewall_name) do |fw_rule|
r = rules.dup || {}
r.merge!({
fwr => fw_rule.position,
})
rules(r)
delayed_action :rebuild
end
end
end