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

@@ -67,8 +67,8 @@ module FirewallCookbook
end
end
def ubuntu?(current_node)
current_node['platform'] == 'ubuntu'
def debian?(current_node)
current_node['platform_family'] == 'debian'
end
def build_rule_file(rules)
@@ -96,5 +96,10 @@ module FirewallCookbook
false
end
def default_description(new_resource)
new_resource.description ||
"Generated by chef from #{cookbook_name}[#{recipe_name}] by #{new_resource}"
end
end
end

View File

@@ -21,7 +21,7 @@ module FirewallCookbook
return false unless firewalld_active?
cmd = shell_out('firewall-cmd', '--get-default-zone')
cmd.stdout =~ /^#{z.to_s}$/
cmd.stdout =~ /^#{z}$/
end
def firewalld_default_zone!(z)

View File

@@ -0,0 +1,72 @@
module FirewallCookbook
module Helpers
module FirewalldDBus
def firewalld(system_bus)
system_bus['org.fedoraproject.FirewallD1']
end
def firewalld_object(system_bus)
firewalld(system_bus)['/org/fedoraproject/FirewallD1']
end
def firewalld_interface(system_bus)
firewalld_object(system_bus)['org.fedoraproject.FirewallD1']
end
def config_object(system_bus)
firewalld(system_bus)['/org/fedoraproject/FirewallD1/config']
end
def config_interface(system_bus)
config_object(system_bus)['org.fedoraproject.FirewallD1.config']
end
def icmptype_interface(dbus, icmptype_path)
icmptype_object = firewalld(dbus)[icmptype_path]
icmptype_object['org.fedoraproject.FirewallD1.config.icmptype']
end
def ipset_interface(dbus, ipset_path)
ipset_object = firewalld(dbus)[ipset_path]
ipset_object['org.fedoraproject.FirewallD1.config.ipset']
end
def helper_interface(dbus, helper_path)
helper_object = firewalld(dbus)[helper_path]
helper_object['org.fedoraproject.FirewallD1.config.helper']
end
def service_interface(dbus, service_path)
service_object = firewalld(dbus)[service_path]
service_object['org.fedoraproject.FirewallD1.config.service']
end
def policy_interface(dbus, policy_path)
policy_object = firewalld(dbus)[policy_path]
policy_object['org.fedoraproject.FirewallD1.config.policy']
end
def zone_interface(dbus, zone_path)
zone_object = firewalld(dbus)[zone_path]
zone_object['org.fedoraproject.FirewallD1.config.zone']
end
# port=portid[-portid]:proto=protocol[:toport=portid[-portid]][:toaddr=address[/mask]]
def parse_forward_ports(forward_ports)
port_regex = %r{port=([\w-]+):proto=([\w]+)(:toport=([\w-]+)|)(:toaddr=([\d\./]+)|)}
captures = forward_ports.match(port_regex).captures
captures.delete_at(4)
captures.delete_at(2)
captures.map { |e| e || '' }
end
def forward_ports_to_dbus(new_resource)
fwp = new_resource.forward_ports.map do |e|
parse_forward_ports(e)
end
new_resource.forward_ports = fwp
DBus.variant('a(ssss)', new_resource.forward_ports)
end
end
end
end

View File

@@ -49,14 +49,14 @@ module FirewallCookbook
end
def iptables_packages(new_resource)
packages = if ipv6_enabled?(new_resource)
packages = if ipv6_enabled?(new_resource) && !amazon_linux? && node['platform_version'].to_i < 8
%w(iptables iptables-ipv6)
else
%w(iptables)
end
# centos 7 requires extra service
if !ubuntu?(node) && node['platform_version'].to_i >= 7
if (!debian?(node) && node['platform_version'].to_i >= 7) || amazon_linux?
packages << %w(iptables-services)
end

View File

@@ -0,0 +1,170 @@
module FirewallCookbook
module Helpers
module Nftables
include FirewallCookbook::Helpers
CHAIN ||= {
in: 'INPUT',
out: 'OUTPUT',
pre: 'PREROUTING',
post: 'POSTROUTING',
forward: 'FORWARD',
}.freeze
TARGET ||= {
accept: 'accept',
allow: 'accept',
counter: 'counter',
deny: 'drop',
drop: 'drop',
log: 'log',
masquerade: 'masquerade',
redirect: 'redirect',
reject: 'reject',
}.freeze
def port_to_s(ports)
case ports
when String
ports
when Integer
ports.to_s
when Array
p_strings = ports.map { |o| port_to_s(o) }
"{#{p_strings.sort.join(',')}}"
when Range
"#{ports.first}-#{ports.last}"
else
raise "unknown class of port definition: #{ports.class}"
end
end
def nftables_command_log(rule_resource)
log_prefix = 'prefix '
log_prefix << if rule_resource.log_prefix.nil?
"\"#{CHAIN[rule_resource.direction]}:\""
else
"\"#{rule_resource.log_prefix}\""
end
log_group = if rule_resource.log_group.nil?
nil
else
"group #{rule_resource.log_group} "
end
"log #{log_prefix} #{log_group}"
end
def nftables_command_redirect(rule_resource)
if rule_resource.redirect_port.nil?
raise 'Specify redirect_port when using :redirect as commmand'
end
"redirect to #{rule_resource.redirect_port} "
end
def nftables_commands(rule_resource)
firewall_rule = ''
Array(rule_resource.command).each do |command|
begin
target = TARGET.fetch(command)
rescue KeyError
raise "Invalid command: #{command.inspect}. Use one of #{TARGET.keys}"
end
firewall_rule << case target
when 'log'
nftables_command_log(rule_resource)
when 'redirect'
nftables_command_redirect(rule_resource)
else
"#{TARGET[command.to_sym]} "
end
end
firewall_rule
end
def build_firewall_rule(rule_resource)
return rule_resource.raw.strip if rule_resource.raw
ip = ipv6_rule?(rule_resource) ? 'ip6' : 'ip'
table = if [:pre, :post].include?(rule_resource.direction)
'nat'
else
'filter'
end
firewall_rule = if table == 'nat'
"add rule #{ip} #{table} "
else
"add rule inet #{table} "
end
firewall_rule << "#{CHAIN.fetch(rule_resource.direction.to_sym, 'FORWARD')} "
firewall_rule << "iif #{rule_resource.interface} " if rule_resource.interface
firewall_rule << "oif #{rule_resource.outerface} " if rule_resource.outerface
if rule_resource.source
source_with_mask = ip_with_mask(rule_resource, rule_resource.source)
if source_with_mask != '0.0.0.0/0' && source_with_mask != '::/128'
firewall_rule << "#{ip} saddr #{source_with_mask} "
end
end
firewall_rule << "#{ip} daddr #{rule_resource.destination} " if rule_resource.destination
case rule_resource.protocol
when :icmp
firewall_rule << 'icmp type echo-request '
when :'ipv6-icmp', :icmpv6
firewall_rule << 'icmpv6 type { echo-request, nd-router-solicit, nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } '
when :tcp, :udp
firewall_rule << "#{rule_resource.protocol} sport #{port_to_s(rule_resource.sport)} " if rule_resource.sport
firewall_rule << "#{rule_resource.protocol} dport #{port_to_s(rule_resource.dport)} " if rule_resource.dport
when :esp, :ah
firewall_rule << "#{ip} #{ip == 'ip6' ? 'nexthdr' : 'protocol'} #{rule_resource.protocol} "
when :ipv6, :none
# nothing to do
end
firewall_rule << "ct state #{Array(rule_resource.stateful).join(',').downcase} " if rule_resource.stateful
firewall_rule << nftables_commands(rule_resource)
firewall_rule << "comment \"#{rule_resource.description}\" " if rule_resource.include_comment
firewall_rule.strip!
firewall_rule
end
def default_ruleset(new_resource)
rules = {
'add table inet filter' => 1,
"add chain inet filter INPUT { type filter hook input priority 0 ; policy #{new_resource.input_policy}; }" => 2,
"add chain inet filter OUTPUT { type filter hook output priority 0 ; policy #{new_resource.output_policy}; }" => 2,
"add chain inet filter FOWARD { type filter hook forward priority 0 ; policy #{new_resource.forward_policy}; }" => 2,
}
if new_resource.table_ip_nat
rules['add table ip nat'] = 1
rules['add chain ip nat POSTROUTING { type nat hook postrouting priority 100 ;}'] = 2
rules['add chain ip nat PREROUTING { type nat hook prerouting priority -100 ;}'] = 2
end
if new_resource.table_ip6_nat
rules['add table ip6 nat'] = 1
rules['add chain ip6 nat POSTROUTING { type nat hook postrouting priority 100 ;}'] = 2
rules['add chain ip6 nat PREROUTING { type nat hook prerouting priority -100 ;}'] = 2
end
rules
end
def ensure_default_rules_exist(new_resource)
input = new_resource.rules || {}
input.merge!(default_ruleset(new_resource))
end
def default_nftables_conf_path
case node['platform_family']
when 'rhel'
'/etc/sysconfig/nftables.conf'
when 'debian'
'/etc/nftables.conf'
else
raise "default_nftables_conf_path: Unsupported platform_family #{node['platform_family']}."
end
end
end
end
end

View File

@@ -74,6 +74,7 @@ module FirewallCookbook
rule << rule_proto(new_resource)
rule << rule_dest_port(new_resource)
rule << rule_source_port(new_resource)
rule << rule_description(new_resource)
rule = rule.strip
if rule == 'ufw allow in proto tcp to any from any'
@@ -97,6 +98,12 @@ module FirewallCookbook
rule
end
def rule_description(new_resource)
rule = ''
rule << "comment \"#{new_resource.description}\" " if new_resource.description && new_resource.include_comment
rule
end
def rule_dest_port(new_resource)
rule = if new_resource.destination
"to #{new_resource.destination} "

View File

@@ -44,12 +44,11 @@ module FirewallCookbook
def to_type(new_resource)
cmd = new_resource.command
type = if cmd == :reject || cmd == :deny
:block
else
:allow
end
type
if cmd == :reject || cmd == :deny
:block
else
:allow
end
end
def build_rule(new_resource)
@@ -66,13 +65,13 @@ module FirewallCookbook
if new_resource.direction.to_sym == :out
parameters['localip'] = new_resource.source ? fixup_cidr(new_resource.source) : 'any'
parameters['localport'] = new_resource.source_port ? port_to_s(new_resource.source_port) : 'any'
parameters['interfacetype'] = new_resource.interface ? new_resource.interface : 'any'
parameters['interfacetype'] = new_resource.interface || 'any'
parameters['remoteip'] = new_resource.destination ? fixup_cidr(new_resource.destination) : 'any'
parameters['remoteport'] = new_resource.dest_port ? port_to_s(new_resource.dest_port) : 'any'
else
parameters['localip'] = new_resource.destination ? new_resource.destination : 'any'
parameters['localip'] = new_resource.destination || 'any'
parameters['localport'] = dport_calc(new_resource) ? port_to_s(dport_calc(new_resource)) : 'any'
parameters['interfacetype'] = new_resource.dest_interface ? new_resource.dest_interface : 'any'
parameters['interfacetype'] = new_resource.dest_interface || 'any'
parameters['remoteip'] = new_resource.source ? fixup_cidr(new_resource.source) : 'any'
parameters['remoteport'] = new_resource.source_port ? port_to_s(new_resource.source_port) : 'any'
end

View File

@@ -1,30 +0,0 @@
if defined?(ChefSpec)
ChefSpec.define_matcher(:firewall)
ChefSpec.define_matcher(:firewall_rule)
# actions(:install, :restart, :disable, :flush, :save)
def install_firewall(resource)
ChefSpec::Matchers::ResourceMatcher.new(:firewall, :install, resource)
end
def restart_firewall(resource)
ChefSpec::Matchers::ResourceMatcher.new(:firewall, :restart, resource)
end
def disable_firewall(resource)
ChefSpec::Matchers::ResourceMatcher.new(:firewall, :disable, resource)
end
def flush_firewall(resource)
ChefSpec::Matchers::ResourceMatcher.new(:firewall, :flush, resource)
end
def save_firewall(resource)
ChefSpec::Matchers::ResourceMatcher.new(:firewall, :save, resource)
end
def create_firewall_rule(resource)
ChefSpec::Matchers::ResourceMatcher.new(:firewall_rule, :create, resource)
end
end

View File

@@ -19,15 +19,15 @@ class Chef
class Provider::FirewallFirewalld < Chef::Provider::LWRPBase
include FirewallCookbook::Helpers::Firewalld
provides :firewall, os: 'linux', platform_family: %w(rhel fedora) do |node|
node['platform_version'].to_f >= 7.0 && !node['firewall']['redhat7_iptables']
provides :firewall, os: 'linux', platform_family: %w(rhel fedora amazon) do |node|
(node['platform_version'].to_i == 7 && !node['firewall']['redhat7_iptables']) || (amazon_linux? && !node['firewall']['redhat7_iptables'])
end
def whyrun_supported?
false
end
def action_install
action :install do
return if disabled?(new_resource)
firewalld_package = package 'firewalld' do
@@ -51,7 +51,7 @@ class Chef
end
end
def action_restart
action :restart do
return if disabled?(new_resource)
# ensure it's initialized
@@ -111,7 +111,7 @@ class Chef
new_resource.updated_by_last_action(true)
end
def action_disable
action :disable do
return if disabled?(new_resource)
if firewalld_active?
@@ -133,7 +133,7 @@ class Chef
new_resource.updated_by_last_action(rules_file.updated_by_last_action?)
end
def action_flush
action :flush do
return if disabled?(new_resource)
return unless firewalld_active?
@@ -146,7 +146,7 @@ class Chef
new_resource.updated_by_last_action(rules_file.updated_by_last_action?)
end
def action_save
action :save do
return if disabled?(new_resource)
return if firewalld_all_rules_permanent!

View File

@@ -3,7 +3,7 @@
# Cookbook:: firewall
# Resource:: default
#
# Copyright:: 2011-2016, Chef Software, Inc.
# Copyright:: 2011-2019, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -22,15 +22,15 @@ class Chef
include FirewallCookbook::Helpers
include FirewallCookbook::Helpers::Iptables
provides :firewall, os: 'linux', platform_family: %w(rhel fedora) do |node|
node['platform_version'].to_f < 7.0 || node['firewall']['redhat7_iptables']
provides :firewall, os: 'linux', platform_family: %w(rhel fedora amazon) do |node|
(node['platform_version'].to_i < 7 && !amazon_linux?) || node['platform_version'].to_i >= 8 || node['firewall']['redhat7_iptables']
end
def whyrun_supported?
false
end
def action_install
action :install do
return if disabled?(new_resource)
# Ensure the package is installed
@@ -60,7 +60,7 @@ class Chef
end
end
def action_restart
action :restart do
return if disabled?(new_resource)
# prints all the firewall rules
@@ -104,12 +104,12 @@ class Chef
next unless iptables_file.updated_by_last_action?
iptables_service = lookup_or_create_service(iptables_type)
new_resource.notifies(:restart, iptables_service, :delayed)
iptables_service.run_action(:restart)
new_resource.updated_by_last_action(true)
end
end
def action_disable
action :disable do
return if disabled?(new_resource)
iptables_flush!(new_resource)
@@ -131,7 +131,7 @@ class Chef
end
end
def action_flush
action :flush do
return if disabled?(new_resource)
iptables_flush!(new_resource)

View File

@@ -3,7 +3,7 @@
# Cookbook:: firewall
# Resource:: default
#
# Copyright:: 2011-2016, Chef Software, Inc.
# Copyright:: 2011-2019, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -23,14 +23,15 @@ class Chef
include FirewallCookbook::Helpers::Iptables
provides :firewall, os: 'linux', platform_family: %w(debian) do |node|
node['platform_version'].to_f > 14.04 && node['firewall'] && node['firewall']['ubuntu_iptables']
node['firewall'] && node['firewall']['ubuntu_iptables'] &&
node['platform_version'].to_f > (node['platform'] == 'ubuntu' ? 14.04 : 7)
end
def whyrun_supported?
false
end
def action_install
action :install do
return if disabled?(new_resource)
# Ensure the package is installed
@@ -63,7 +64,7 @@ class Chef
end
end
def action_restart
action :restart do
return if disabled?(new_resource)
# prints all the firewall rules
@@ -97,6 +98,8 @@ class Chef
end
end
restart_service = false
rule_files = %w(iptables)
rule_files << 'ip6tables' if ipv6_enabled?(new_resource)
@@ -119,17 +122,19 @@ class Chef
iptables_file.run_action(:create)
# if the file was changed, restart iptables
next unless iptables_file.updated_by_last_action?
restart_service = true if iptables_file.updated_by_last_action?
end
if restart_service
service_affected = service 'netfilter-persistent' do
action :nothing
end
new_resource.notifies(:restart, service_affected, :delayed)
service_affected.run_action(:restart)
new_resource.updated_by_last_action(true)
end
end
def action_disable
action :disable do
return if disabled?(new_resource)
iptables_flush!(new_resource)
@@ -152,7 +157,7 @@ class Chef
end
end
def action_flush
action :flush do
return if disabled?(new_resource)
iptables_flush!(new_resource)

View File

@@ -1,9 +1,9 @@
#
# Author:: Seth Chisamore (<schisamo@opscode.com>)
# Cookbook Name:: firewall
# Cookbook:: firewall
# Resource:: default
#
# Copyright:: 2011, Opscode, Inc.
# Copyright:: 2011-2019, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -23,14 +23,15 @@ class Chef
include FirewallCookbook::Helpers::Iptables
provides :firewall, os: 'linux', platform_family: %w(debian) do |node|
node['platform_version'].to_f <= 14.04 && node['firewall'] && node['firewall']['ubuntu_iptables']
node['firewall'] && node['firewall']['ubuntu_iptables'] &&
node['platform_version'].to_f <= (node['platform'] == 'ubuntu' ? 14.04 : 7)
end
def whyrun_supported?
false
end
def action_install
action :install do
return if disabled?(new_resource)
# Ensure the package is installed
@@ -63,7 +64,7 @@ class Chef
end
end
def action_restart
action :restart do
return if disabled?(new_resource)
# prints all the firewall rules
@@ -97,6 +98,8 @@ class Chef
end
end
restart_service = false
rule_files = %w(iptables)
rule_files << 'ip6tables' if ipv6_enabled?(new_resource)
@@ -119,17 +122,19 @@ class Chef
iptables_file.run_action(:create)
# if the file was changed, restart iptables
next unless iptables_file.updated_by_last_action?
restart_service = true if iptables_file.updated_by_last_action?
end
if restart_service
service_affected = service 'iptables-persistent' do
action :nothing
end
new_resource.notifies(:restart, service_affected, :delayed)
service_affected.run_action(:restart)
new_resource.updated_by_last_action(true)
end
end
def action_disable
action :disable do
return if disabled?(new_resource)
iptables_flush!(new_resource)
@@ -152,7 +157,7 @@ class Chef
end
end
def action_flush
action :flush do
return if disabled?(new_resource)
iptables_flush!(new_resource)

View File

@@ -21,7 +21,7 @@ class Chef
class Provider::FirewallRuleGeneric < Chef::Provider::LWRPBase
provides :firewall_rule
def action_create
action :create do
return unless new_resource.notify_firewall
firewall_resource = Chef.run_context.resource_collection.find(firewall: new_resource.firewall_name)

View File

@@ -3,7 +3,7 @@
# Cookbook:: firewall
# Resource:: default
#
# Copyright:: 2011-2016, Chef Software, Inc.
# Copyright:: 2011-2019, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ class Chef
false
end
def action_install
action :install do
return if disabled?(new_resource)
pkg_ufw = package 'ufw' do
@@ -58,7 +58,7 @@ class Chef
new_resource.updated_by_last_action(true) if ufw_file.updated_by_last_action?
end
def action_restart
action :restart do
return if disabled?(new_resource)
# ensure it's initialized
@@ -99,7 +99,7 @@ class Chef
new_resource.updated_by_last_action(true)
end
def action_disable
action :disable do
return if disabled?(new_resource)
ufw_file = lookup_or_create_rulesfile
@@ -112,7 +112,7 @@ class Chef
new_resource.updated_by_last_action(true)
end
def action_flush
action :flush do
return if disabled?(new_resource)
ufw_reset!

View File

@@ -26,7 +26,7 @@ class Chef
false
end
def action_install
action :install do
return if disabled?(new_resource)
svc = service 'MpsSvc' do
@@ -39,7 +39,7 @@ class Chef
end
end
def action_restart
action :restart do
return if disabled?(new_resource)
# ensure it's initialized
@@ -94,7 +94,7 @@ class Chef
new_resource.updated_by_last_action(true)
end
def action_disable
action :disable do
return if disabled?(new_resource)
if active?
@@ -115,7 +115,7 @@ class Chef
end
end
def action_flush
action :flush do
return if disabled?(new_resource)
reset!

View File

@@ -6,7 +6,6 @@ class Chef
resource_name(:firewall_rule)
provides(:firewall_rule)
actions(:create)
default_action(:create)
attribute(:firewall_name, kind_of: String, default: 'default')
@@ -20,12 +19,12 @@ class Chef
attribute(:direction, kind_of: Symbol, equal_to: [:in, :out, :pre, :post], default: :in)
attribute(:logging, kind_of: Symbol, equal_to: [:connections, :packets])
attribute(:source, callbacks: { 'must be a valid ip address' => ->(ip) { !!IPAddr.new(ip) } })
attribute(:source, kind_of: String, callbacks: { 'must be a valid ip address' => ->(ip) { !!IPAddr.new(ip) } })
attribute(:source_port, kind_of: [Integer, Array, Range]) # source port
attribute(:interface, kind_of: String)
attribute(:port, kind_of: [Integer, Array, Range]) # shorthand for dest_port
attribute(:destination, callbacks: { 'must be a valid ip address' => ->(ip) { !!IPAddr.new(ip) } })
attribute(:destination, kind_of: String, callbacks: { 'must be a valid ip address' => ->(ip) { !!IPAddr.new(ip) } })
attribute(:dest_port, kind_of: [Integer, Array, Range])
attribute(:dest_interface, kind_of: String)