X-Git-Url: https://git.openstreetmap.org./chef.git/blobdiff_plain/52f0a525050450d5d41431314a5c8d9a9b81950b..11fdeeaa56975b200a46cc3ee7124e529621fba9:/cookbooks/networking/resources/firewall_rule.rb diff --git a/cookbooks/networking/resources/firewall_rule.rb b/cookbooks/networking/resources/firewall_rule.rb index e5f07dca6..22bde6ca9 100644 --- a/cookbooks/networking/resources/firewall_rule.rb +++ b/cookbooks/networking/resources/firewall_rule.rb @@ -17,6 +17,8 @@ # limitations under the License. # +require "ipaddr" + resource_name :firewall_rule provides :firewall_rule @@ -25,81 +27,57 @@ unified_mode true default_action :nothing property :rule, :kind_of => String, :name_property => true -property :family, :kind_of => [String, Symbol] -property :source, :kind_of => String, :required => true -property :dest, :kind_of => String, :required => true -property :proto, :kind_of => String, :required => true +property :context, :kind_of => Symbol, :required => true, :is => [:incoming, :outgoing] +property :protocol, :kind_of => Symbol, :required => true, :is => [:udp, :tcp] +property :source, :kind_of => [String, Symbol, Array] +property :dest, :kind_of => [String, Symbol, Array] property :dest_ports, :kind_of => [String, Integer, Array] property :source_ports, :kind_of => [String, Integer, Array] -property :rate_limit, :kind_of => String, :default => "-" -property :connection_limit, :kind_of => [String, Integer], :default => "-" +property :rate_limit, :kind_of => String +property :connection_limit, :kind_of => [String, Integer] +property :helper, :kind_of => String property :compile_time, TrueClass, :default => true action :accept do - add_rule :accept + add_rule(:accept, "ip") + add_rule(:accept, "ip6") end action :drop do - add_rule :drop + add_rule(:drop, "ip") + add_rule(:drop, "ip6") end action :reject do - add_rule :reject + add_rule(:reject, "ip") + add_rule(:reject, "ip6") end action_class do - def add_rule(action) - if new_resource.family.nil? - add_nftables_rule(action, "inet") - add_nftables_rule(action, "inet6") - elsif new_resource.family.to_s == "inet" - add_nftables_rule(action, "inet") - elsif new_resource.family.to_s == "inet6" - add_nftables_rule(action, "inet6") - end - end - - def add_nftables_rule(action, family) + def add_rule(action, ip) rule = [] - ip = case family - when "inet" then "ip" - when "inet6" then "ip6" - end - - proto = new_resource.proto - - if new_resource.source_ports - rule << "#{proto} sport { #{nftables_source_ports} }" - end - - if new_resource.dest_ports - rule << "#{proto} dport { #{nftables_dest_ports} }" - end + protocol = new_resource.protocol.to_s - if new_resource.source == "osm" - rule << "#{ip} saddr @#{ip}-osm-addresses" - elsif new_resource.source =~ /^net:(.*)$/ - addresses = Regexp.last_match(1).split(",").join(", ") + source = addresses(new_resource.source, ip) + dest = addresses(new_resource.dest, ip) - rule << "#{ip} saddr { #{addresses} }" - end - - if new_resource.dest == "osm" - rule << "#{ip} daddr @#{ip}-osm-addresses" - elsif new_resource.dest =~ /^net:(.*)$/ - addresses = Regexp.last_match(1).split(",").join(", ") + return if new_resource.source && source.empty? + return if new_resource.dest && dest.empty? - rule << "#{ip} daddr { #{addresses} }" - end + rule << "#{protocol} sport #{format_ports(new_resource.source_ports)}" if new_resource.source_ports + rule << "#{protocol} dport #{format_ports(new_resource.dest_ports)}" if new_resource.dest_ports + rule << "#{ip} saddr #{format_addresses(source, ip)}" if new_resource.source + rule << "#{ip} daddr #{format_addresses(dest, ip)}" if new_resource.dest + rule << "ct state new" if new_resource.protocol == :tcp - rule << "ct state new" if new_resource.proto == "tcp" - - if new_resource.connection_limit != "-" + if new_resource.connection_limit set = "connlimit-#{new_resource.rule}-#{ip}" - node.default[:networking][:firewall][:sets] << set + node.default[:networking][:firewall][:sets] << { + :name => set, :type => set_type(ip), :flags => %w[dynamic] + } rule << "add @#{set} { #{ip} saddr ct count #{new_resource.connection_limit} }" end @@ -109,29 +87,62 @@ action_class do rate = Regexp.last_match(1) burst = Regexp.last_match(2) - node.default[:networking][:firewall][:sets] << set + node.default[:networking][:firewall][:sets] << { + :name => set, :type => set_type(ip), :flags => %w[dynamic], :timeout => 120 + } rule << "update @#{set} { #{ip} saddr limit rate #{rate}/second burst #{burst} packets }" end + if new_resource.helper + helper = "#{new_resource.rule}-#{new_resource.helper}" + + node.default[:networking][:firewall][:helpers] << { + :name => helper, :helper => new_resource.helper, :protocol => protocol + } + + rule << "ct helper set #{helper}" + end + rule << case action when :accept then "accept" when :drop then "jump log-and-drop" when :reject then "jump log-and-reject" end - if new_resource.source == "fw" - node.default[:networking][:firewall][:outgoing] << rule.join(" ") - elsif new_resource.dest == "fw" - node.default[:networking][:firewall][:incoming] << rule.join(" ") + node.default[:networking][:firewall][new_resource.context] << rule.join(" ") + end + + def addresses(addresses, ip) + if addresses.is_a?(Symbol) + addresses + else + Array(addresses).map do |address| + if ip == "ip" && IPAddr.new(address.to_s).ipv4? + address + elsif ip == "ip6" && IPAddr.new(address.to_s).ipv6? + address + end + end.compact end end - def nftables_source_ports - Array(new_resource.source_ports).map(&:to_s).join(",") + def format_ports(ports) + "{ #{Array(ports).map(&:to_s).join(', ')} }" end - def nftables_dest_ports - Array(new_resource.dest_ports).map(&:to_s).join(",") + def format_addresses(addresses, ip) + if addresses.is_a?(Symbol) + "@#{ip}-#{addresses}-addresses" + else + "{ #{Array(addresses).map(&:to_s).join(', ')} }" + end + end + + def set_type(ip) + case ip + when "ip" then "ipv4_addr" + when "ip6" then "ipv6_addr" + end end end