diff --git a/resources/attributes/default.rb b/resources/attributes/default.rb index c01d498..fb2cd25 100644 --- a/resources/attributes/default.rb +++ b/resources/attributes/default.rb @@ -2,7 +2,7 @@ default['firewall']['roles'] = { 'manager' => { - 'home_zone' => { + 'home' => { 'tcp_ports' => [ 53, 443, 2056, 2057, 2058, 2181, 2888, 3888, 4443, 5432, 7946, 7980, 8080, 8081, 8083, 8084, 8300, 8301, @@ -10,7 +10,7 @@ 'udp_ports' => [123, 161, 162, 1812, 1813, 2055, 5353, 6343], 'protocols' => ['igmp'], }, - 'public_zone' => { + 'public' => { 'tcp_ports' => [53, 443, 2056, 2057, 2058, 8080, 8081, 8083, 8084, 9000, 9001], 'udp_ports' => [53, 161, 162, 123, 2055, 6343, 5353], 'protocols' => ['112'], @@ -18,13 +18,13 @@ }, }, 'proxy' => { - 'public_zone' => { + 'public' => { 'tcp_ports' => [514, 2056, 2057, 2058, 7779], 'udp_ports' => [161, 162, 1812, 1813, 2055, 6343], }, }, 'ips' => { - 'public_zone' => { + 'public' => { 'udp_ports' => [161, 162], }, }, diff --git a/resources/libraries/helper.rb b/resources/libraries/helper.rb index 6859f7d..3e6d581 100644 --- a/resources/libraries/helper.rb +++ b/resources/libraries/helper.rb @@ -4,96 +4,38 @@ module Helpers require 'socket' include ::Chef::Mixin::ShellOut - def fetch_existing_rules(zone) - ports = shell_out!("firewall-cmd --zone=#{zone} --list-ports").stdout.strip.split(/\s+/) - protos = shell_out!("firewall-cmd --zone=#{zone} --list-protocols").stdout.strip.split(/\s+/) - rich_rules = shell_out!("firewall-cmd --zone=#{zone} --list-rich-rules").stdout.strip.split(/\n/) - return ports, protos, rich_rules - end - - def configure_firewalld_rules - if is_manager? - ports_home, protos_home, rich_rules_home = fetch_existing_rules('home') - apply_zone_rules(node['firewall']['roles']['manager']['home_zone'], 'home', ports_home, protos_home, rich_rules_home) - - ports_pub, protos_pub, rich_rules_pub = fetch_existing_rules('public') - apply_zone_rules(node['firewall']['roles']['manager']['public_zone'], 'public', ports_pub, protos_pub, rich_rules_pub) - end - if is_proxy? - ports_pub, protos_pub, rich_rules_pub = fetch_existing_rules('public') - apply_zone_rules(node['firewall']['roles']['proxy']['public_zone'], 'public', ports_pub, protos_pub, rich_rules_pub) - end - if is_ips? - ports_pub, protos_pub, rich_rules_pub = fetch_existing_rules('public') - apply_zone_rules(node['firewall']['roles']['ips']['public_zone'], 'public', ports_pub, protos_pub, rich_rules_pub) - end - end - - def apply_zone_rules(zone_rules, zone, existing_ports, existing_protocols, existing_rich_rules) - return if zone_rules.nil? - zone_rules['tcp_ports']&.each { |port| apply_rule(:port, port, zone, existing_ports, 'tcp') } - zone_rules['udp_ports']&.each { |port| apply_rule(:port, port, zone, existing_ports, 'udp') } - zone_rules['protocols']&.each { |protocol| apply_rule(:protocol, protocol, zone, existing_protocols) } - zone_rules['rich_rules']&.each { |rule| apply_rule(:rich_rule, rule, zone, existing_rich_rules) } - end - - def apply_rule(type, value, zone, existing_items, protocol = nil) - value = "#{value}/#{protocol || 'tcp'}" if type == :port - unless existing_items.include?(value) - case type - when :port - firewall_rule "Allow port #{value} in #{zone} zone" do - port value - protocol protocol - zone zone - action :create - permanent true - end - when :protocol - firewall_rule "Allow protocol #{value} in #{zone} zone" do - protocols value - zone zone - action :create - permanent true - end - when :rich_rule - firewall_rule "Adding rich rule #{value} in #{zone} zone" do - rules value - zone zone - action :create - permanent true - end + def apply_rule(type, value, zone, protocol = nil) + case type + when :port + firewall_rule "Allow port #{value}/#{protocol} in #{zone} zone" do + port value + protocol protocol + zone zone + action :create + permanent true + not_if "firewall-cmd --permanent --zone=#{zone} --query-port=#{value}/#{protocol}" end - end - end - - def manage_kafka_rule_for_ips(ip, rich_rules) - unless rich_rules.include?(ip) - firewall_rule "Open Kafka port 9092 for manager ips" do - rules "rule family='ipv4' source address=#{ip} port port=9092 protocol=tcp accept" - zone 'public' + when :protocol + firewall_rule "Allow protocol #{value} in #{zone} zone" do + protocols value + zone zone action :create permanent true + not_if "firewall-cmd --permanent --zone=#{zone} --query-protocol=#{value}" end - end - end - - def remove_kafka_rule_for_ips(ip, rich_rules) - if rich_rules.include?(ip) - firewall_rule "Remove Kafka port 9092 for manager IPs" do - rules "rule family='ipv4' source address=#{ip} port port=9092 protocol=tcp accept" - zone 'public' - action :delete + when :rich_rule + firewall_rule "Adding rich rule #{value} in #{zone} zone" do + rules value + zone zone + action :create permanent true + not_if "firewall-cmd --permanent --zone=#{zone} --query-rich-rule='#{value}'" end end end - def reload! - shell_out!('firewall-cmd --reload') - end - - def get_existing_ips_for_port(rich_rules) + def get_existing_ip_addresses_in_rules + rich_rules = shell_out!('firewall-cmd --zone=public --list-rich-rules').stdout existing_ips = [] rich_rules.split("\n").each do |rule| if rule.include?('port="9092"') @@ -131,7 +73,7 @@ def is_ips? node.role?('ips-sensor') || node.role?('ipscp-sensor') end - def get_ip_of_manager_ips + def get_ip_of_manager_ips_nodes sensors = search(:node, 'role:ips-sensor').sort sensors.map { |s| { ipaddress: s['ipaddress'] } } end diff --git a/resources/providers/config.rb b/resources/providers/config.rb index df6e182..8344817 100644 --- a/resources/providers/config.rb +++ b/resources/providers/config.rb @@ -6,11 +6,7 @@ action :add do sync_ip = new_resource.sync_ip ip_addr = new_resource.ip_addr - ip_address_ips = get_ip_of_manager_ips - - service 'firewalld' do - action [:enable, :start] - end + ip_address_ips_nodes = get_ip_of_manager_ips_nodes dnf_package 'firewalld' do action :upgrade @@ -23,57 +19,80 @@ notifies :restart, 'service[firewalld]', :delayed end + # Add sync interface and subnet to home zone if is_manager? sync_interface = interface_for_ip(sync_ip) sync_subnet = ip_to_subnet(sync_ip) - interfaces = shell_out!('firewall-cmd --zone=home --list-interfaces').stdout.strip.split - sources = shell_out!('firewall-cmd --zone=home --list-sources').stdout.strip.split - unless interfaces.include?(interface_for_ip(sync_ip)) - firewall_rule 'Add sync interface to home' do - interface sync_interface - zone 'home' - action :create - permanent true - end + firewall_rule 'Add sync interface to home' do + interface sync_interface + zone 'home' + action :create + permanent true + not_if "firewall-cmd --zone=home --query-interface=#{sync_interface}" end - unless sources.include?(ip_to_subnet(sync_ip)) - firewall_rule 'Add sync subnet to home' do - sources sync_subnet - zone 'home' - action :create - permanent true - end + firewall_rule 'Add sync subnet to home' do + sources sync_subnet + zone 'home' + action :create + permanent true + not_if "firewall-cmd --zone=home --query-source=#{sync_subnet}" end end - configure_firewalld_rules + # Applying firewall ports, protocols, and rich rules based on zones + roles = { + 'manager' => ['home', 'public'], + 'proxy' => ['public'], + 'ips' => ['public'] + } + roles.each do |role, zones| + next unless send("is_#{role}?") + zones.each do |zone| + zone_rules = node['firewall']['roles'][role][zone] + next if zone_rules.nil? + zone_rules['tcp_ports']&.each { |port| apply_rule(:port, port, zone, 'tcp') } + zone_rules['udp_ports']&.each { |port| apply_rule(:port, port, zone, 'udp') } + zone_rules['protocols']&.each { |protocol| apply_rule(:protocol, protocol, zone) } + zone_rules['rich_rules']&.each { |rule| apply_rule(:rich_rule, rule, zone) } + end + end + # Managing port 9092 on the manager only for that specific IPS if is_manager? && sync_ip != ip_addr - rich_rules = shell_out!('firewall-cmd --zone=public --list-rich-rules').stdout - existing_ips = get_existing_ips_for_port(rich_rules) - if ip_address_ips.empty? - existing_ips.each do |ip| - if rich_rules.match(/source address=\"#{ip}\".*port port=\"9092\".*protocol=\"tcp\"/) - manage_kafka_rule_for_ips(ip, rich_rules) - end - end - else - ips_to_remove = existing_ips - ip_address_ips.map { |ips| ips[:ipaddress] } + existing_addresses = get_existing_ip_addresses_in_rules + aux = ip_address_ips_nodes.empty? ? existing_addresses : ip_address_ips_nodes.map { |ips| ips[:ipaddress] } + + unless ip_address_ips_nodes.empty? + ips_to_remove = existing_addresses - aux ips_to_remove.each do |ip| - if rich_rules.match(/source address=\"#{ip}\".*port port=\"9092\".*protocol=\"tcp\"/) - remove_kafka_rule_for_ips(ip, rich_rules) + firewall_rule "Remove Kafka port 9092 for IP: #{ip}" do + rules "rule family='ipv4' source address=#{ip} port port=9092 protocol=tcp accept" + zone 'public' + action :delete + permanent true + only_if "firewall-cmd --permanent --zone=public --query-rich-rule='rule family=\"ipv4\" source address=\"#{ip}\" port port=\"9092\" protocol=\"tcp\" accept'" end end - ip_address_ips.each do |ip| - unless rich_rules.match(/source address=\"#{ip[:ipaddress]}\".*port port=\"9092\".*protocol=\"tcp\"/) - manage_kafka_rule_for_ips(ip[:ipaddress], rich_rules) - end + end + + aux.each do |ip| + firewall_rule "Open Kafka port 9092 for IP: #{ip}" do + rules "rule family='ipv4' source address=#{ip} port port=9092 protocol=tcp accept" + zone 'public' + action :create + permanent true + not_if "firewall-cmd --permanent --zone=public --query-rich-rule='rule family=\"ipv4\" source address=\"#{ip}\" port port=\"9092\" protocol=\"tcp\" accept'" end end end - reload! + + service 'firewalld' do + service_name 'firewalld' + supports status: true, reload: true, restart: true, start: true, enable: true + action [:enable, :start, :reload] + end Chef::Log.info('Firewall configuration has been applied.') end