-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
118 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,89 +1,139 @@ | ||
# Cookbook:: firewall | ||
# Provider:: config | ||
module Firewall | ||
module Helpers | ||
require 'ipaddr' | ||
require 'socket' | ||
include ::Chef::Mixin::ShellOut | ||
|
||
include Firewall::Helpers | ||
|
||
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 | ||
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 | ||
|
||
dnf_package 'firewalld' do | ||
action :upgrade | ||
flush_cache [:before] | ||
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) | ||
|
||
template '/etc/firewalld.conf' do | ||
source 'firewalld.conf.erb' | ||
cookbook 'rb-firewall' | ||
notifies :restart, 'service[firewalld]', :delayed | ||
end | ||
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 | ||
|
||
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 | ||
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 | ||
|
||
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 | ||
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 | ||
end | ||
end | ||
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 | ||
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' | ||
action :create | ||
permanent true | ||
end | ||
end | ||
end | ||
end | ||
|
||
configure_firewalld_rules | ||
|
||
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\"/) | ||
remove_kafka_rule_for_ips(ip) | ||
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 | ||
permanent true | ||
end | ||
end | ||
else | ||
ips_to_remove = existing_ips - ip_address_ips.map { |ips| ips[:ipaddress] } | ||
ips_to_remove.each do |ip| | ||
if rich_rules.match(/source address=\"#{ip}\".*port port=\"9092\".*protocol=\"tcp\"/) | ||
remove_kafka_rule_for_ips(ip) | ||
end | ||
|
||
def reload! | ||
shell_out!('firewall-cmd --reload') | ||
end | ||
|
||
def get_existing_ips_for_port(rich_rules) | ||
existing_ips = [] | ||
rich_rules.split("\n").each do |rule| | ||
if rule.include?('port="9092"') | ||
ip_match = rule.match(/source address="([^"]+)"/) | ||
existing_ips << ip_match[1] if ip_match | ||
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]) | ||
end | ||
existing_ips | ||
end | ||
|
||
def interface_for_ip(ip_address) | ||
return nil if ip_address.nil? || ip_address.empty? | ||
interfaces = Socket.getifaddrs | ||
interface = interfaces.find do |ifaddr| | ||
ifaddr.addr.ipv4? && ifaddr.addr.ip_address == ip_address | ||
end | ||
interface.name | ||
end | ||
|
||
def ip_to_subnet(ip_address, prefix = 24) | ||
ip = IPAddr.new(ip_address) | ||
subnet = ip.mask(prefix) | ||
"#{subnet}/#{prefix}" | ||
end | ||
end | ||
|
||
reload! | ||
def is_proxy? | ||
node.role?('proxy-sensor') | ||
end | ||
|
||
Chef::Log.info('Firewall configuration has been applied.') | ||
end | ||
def is_manager? | ||
node.role?('manager') | ||
end | ||
|
||
action :remove do | ||
service 'firewalld' do | ||
action [:disable, :stop] | ||
end | ||
def is_ips? | ||
node.role?('ips-sensor') || node.role?('ipscp-sensor') | ||
end | ||
|
||
Chef::Log.info('Firewall configuration has been removed.') | ||
def get_ip_of_manager_ips | ||
sensors = search(:node, 'role:ips-sensor').sort | ||
sensors.map { |s| { ipaddress: s['ipaddress'] } } | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters