Vendor the external cookbooks
Knife-Zero doesn't include Berkshelf support, so vendoring everything in the repo is convenient again
This commit is contained in:
100
cookbooks/firewall/libraries/helpers.rb
Normal file
100
cookbooks/firewall/libraries/helpers.rb
Normal file
@@ -0,0 +1,100 @@
|
||||
module FirewallCookbook
|
||||
module Helpers
|
||||
def dport_calc(new_resource)
|
||||
new_resource.dest_port || new_resource.port
|
||||
end
|
||||
|
||||
def port_to_s(p)
|
||||
if p.is_a?(String)
|
||||
p
|
||||
elsif p && p.is_a?(Integer)
|
||||
p.to_s
|
||||
elsif p && p.is_a?(Array)
|
||||
p_strings = p.map { |o| port_to_s(o) }
|
||||
p_strings.sort.join(',')
|
||||
elsif p && p.is_a?(Range)
|
||||
if platform_family?('windows')
|
||||
"#{p.first}-#{p.last}"
|
||||
else
|
||||
"#{p.first}:#{p.last}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def ipv6_enabled?(new_resource)
|
||||
new_resource.ipv6_enabled
|
||||
end
|
||||
|
||||
def disabled?(new_resource)
|
||||
# if either flag is found in the non-default boolean state
|
||||
disable_flag = !(new_resource.enabled && !new_resource.disabled)
|
||||
|
||||
Chef::Log.warn("#{new_resource} has been disabled, not proceeding") if disable_flag
|
||||
disable_flag
|
||||
end
|
||||
|
||||
def ip_with_mask(new_resource, ip)
|
||||
if ip.include?('/')
|
||||
ip
|
||||
elsif ipv4_rule?(new_resource)
|
||||
"#{ip}/32"
|
||||
elsif ipv6_rule?(new_resource)
|
||||
"#{ip}/128"
|
||||
else
|
||||
ip
|
||||
end
|
||||
end
|
||||
|
||||
# ipv4-specific rule?
|
||||
def ipv4_rule?(new_resource)
|
||||
if (new_resource.source && IPAddr.new(new_resource.source).ipv4?) ||
|
||||
(new_resource.destination && IPAddr.new(new_resource.destination).ipv4?)
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# ipv6-specific rule?
|
||||
def ipv6_rule?(new_resource)
|
||||
if (new_resource.source && IPAddr.new(new_resource.source).ipv6?) ||
|
||||
(new_resource.destination && IPAddr.new(new_resource.destination).ipv6?) ||
|
||||
new_resource.protocol =~ /ipv6/ ||
|
||||
new_resource.protocol =~ /icmpv6/
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def ubuntu?(current_node)
|
||||
current_node['platform'] == 'ubuntu'
|
||||
end
|
||||
|
||||
def build_rule_file(rules)
|
||||
contents = []
|
||||
sorted_values = rules.values.sort.uniq
|
||||
sorted_values.each do |sorted_value|
|
||||
contents << "# position #{sorted_value}"
|
||||
rules.each do |k, v|
|
||||
next unless v == sorted_value
|
||||
|
||||
contents << if repeatable_directives(k)
|
||||
k[/[^_]+/]
|
||||
else
|
||||
k
|
||||
end
|
||||
end
|
||||
end
|
||||
"#{contents.join("\n")}\n"
|
||||
end
|
||||
|
||||
def repeatable_directives(s)
|
||||
%w(:OUTPUT :INPUT :POSTROUTING :PREROUTING COMMIT).each do |special|
|
||||
return true if s.start_with?(special)
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
116
cookbooks/firewall/libraries/helpers_firewalld.rb
Normal file
116
cookbooks/firewall/libraries/helpers_firewalld.rb
Normal file
@@ -0,0 +1,116 @@
|
||||
module FirewallCookbook
|
||||
module Helpers
|
||||
module Firewalld
|
||||
include FirewallCookbook::Helpers
|
||||
include Chef::Mixin::ShellOut
|
||||
|
||||
def firewalld_rules_filename
|
||||
'/etc/sysconfig/firewalld-chef.rules'
|
||||
end
|
||||
|
||||
def firewalld_rule!(cmd)
|
||||
shell_out!(cmd, input: 'yes')
|
||||
end
|
||||
|
||||
def firewalld_active?
|
||||
cmd = shell_out('firewall-cmd', '--state')
|
||||
cmd.stdout =~ /^running$/
|
||||
end
|
||||
|
||||
def firewalld_default_zone?(z)
|
||||
return false unless firewalld_active?
|
||||
|
||||
cmd = shell_out('firewall-cmd', '--get-default-zone')
|
||||
cmd.stdout =~ /^#{z.to_s}$/
|
||||
end
|
||||
|
||||
def firewalld_default_zone!(z)
|
||||
raise 'firewalld not active' unless firewalld_active?
|
||||
|
||||
shell_out!('firewall-cmd', "--set-default-zone=#{z}")
|
||||
end
|
||||
|
||||
def log_current_firewalld
|
||||
shell_out!('firewall-cmd --direct --get-all-rules')
|
||||
end
|
||||
|
||||
def firewalld_flush!
|
||||
raise 'firewall not active' unless firewalld_active?
|
||||
|
||||
shell_out!('firewall-cmd', '--direct', '--remove-rules', 'ipv4', 'filter', 'INPUT')
|
||||
shell_out!('firewall-cmd', '--direct', '--remove-rules', 'ipv4', 'filter', 'OUTPUT')
|
||||
shell_out!('firewall-cmd', '--direct', '--permanent', '--remove-rules', 'ipv4', 'filter', 'INPUT')
|
||||
shell_out!('firewall-cmd', '--direct', '--permanent', '--remove-rules', 'ipv4', 'filter', 'OUTPUT')
|
||||
end
|
||||
|
||||
def firewalld_all_rules_permanent!
|
||||
raise 'firewall not active' unless firewalld_active?
|
||||
|
||||
rules = shell_out!('firewall-cmd', '--direct', '--get-all-rules').stdout
|
||||
perm_rules = shell_out!('firewall-cmd', '--direct', '--permanent', '--get-all-rules').stdout
|
||||
rules == perm_rules
|
||||
end
|
||||
|
||||
def firewalld_save!
|
||||
raise 'firewall not active' unless firewalld_active?
|
||||
|
||||
shell_out!('firewall-cmd', '--direct', '--permanent', '--remove-rules', 'ipv4', 'filter', 'INPUT')
|
||||
shell_out!('firewall-cmd', '--direct', '--permanent', '--remove-rules', 'ipv4', 'filter', 'OUTPUT')
|
||||
shell_out!('firewall-cmd', '--direct', '--get-all-rules').stdout.lines do |line|
|
||||
shell_out!("firewall-cmd --direct --permanent --add-rule #{line}")
|
||||
end
|
||||
end
|
||||
|
||||
def ip_versions(resource)
|
||||
if ipv4_rule?(resource)
|
||||
%w(ipv4)
|
||||
elsif ipv6_rule?(resource)
|
||||
%w(ipv6)
|
||||
else # no source or destination address, add rules for both ipv4 and ipv6
|
||||
%w(ipv4 ipv6)
|
||||
end
|
||||
end
|
||||
|
||||
CHAIN = { in: 'INPUT', out: 'OUTPUT', pre: 'PREROUTING', post: 'POSTROUTING' }.freeze unless defined? CHAIN # , nil => "FORWARD"}
|
||||
TARGET = { allow: 'ACCEPT', reject: 'REJECT', deny: 'DROP', masquerade: 'MASQUERADE', redirect: 'REDIRECT', log: 'LOG --log-prefix \'iptables: \' --log-level 7' }.freeze unless defined? TARGET
|
||||
|
||||
def build_firewall_rule(new_resource, ip_version = 'ipv4')
|
||||
return new_resource.raw.strip if new_resource.raw
|
||||
|
||||
type = new_resource.command
|
||||
firewall_rule = if new_resource.direction
|
||||
"#{ip_version} filter #{CHAIN[new_resource.direction.to_sym]} "
|
||||
else
|
||||
"#{ip_version} filter FORWARD "
|
||||
end
|
||||
firewall_rule << "#{new_resource.position} "
|
||||
|
||||
if [:pre, :post].include?(new_resource.direction)
|
||||
firewall_rule << '-t nat '
|
||||
end
|
||||
|
||||
# Firewalld order of prameters is important here see example output below:
|
||||
# ipv4 filter INPUT 1 -s 1.2.3.4/32 -d 5.6.7.8/32 -i lo -p tcp -m tcp -m state --state NEW -m comment --comment "hello" -j DROP
|
||||
firewall_rule << "-s #{ip_with_mask(new_resource, new_resource.source)} " if new_resource.source && new_resource.source != '0.0.0.0/0'
|
||||
firewall_rule << "-d #{new_resource.destination} " if new_resource.destination
|
||||
|
||||
firewall_rule << "-i #{new_resource.interface} " if new_resource.interface
|
||||
firewall_rule << "-o #{new_resource.dest_interface} " if new_resource.dest_interface
|
||||
|
||||
firewall_rule << "-p #{new_resource.protocol} " if new_resource.protocol && new_resource.protocol.to_s.to_sym != :none
|
||||
firewall_rule << '-m tcp ' if new_resource.protocol && new_resource.protocol.to_s.to_sym == :tcp
|
||||
|
||||
# using multiport here allows us to simplify our greps and rule building
|
||||
firewall_rule << "-m multiport --sports #{port_to_s(new_resource.source_port)} " if new_resource.source_port
|
||||
firewall_rule << "-m multiport --dports #{port_to_s(dport_calc(new_resource))} " if dport_calc(new_resource)
|
||||
|
||||
firewall_rule << "-m state --state #{new_resource.stateful.is_a?(Array) ? new_resource.stateful.join(',').upcase : new_resource.stateful.to_s.upcase} " if new_resource.stateful
|
||||
firewall_rule << "-m comment --comment '#{new_resource.description}' " if new_resource.include_comment
|
||||
firewall_rule << "-j #{TARGET[type]} "
|
||||
firewall_rule << "--to-ports #{new_resource.redirect_port} " if type == :redirect
|
||||
firewall_rule.strip!
|
||||
firewall_rule
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
112
cookbooks/firewall/libraries/helpers_iptables.rb
Normal file
112
cookbooks/firewall/libraries/helpers_iptables.rb
Normal file
@@ -0,0 +1,112 @@
|
||||
module FirewallCookbook
|
||||
module Helpers
|
||||
module Iptables
|
||||
include FirewallCookbook::Helpers
|
||||
include Chef::Mixin::ShellOut
|
||||
|
||||
CHAIN = { in: 'INPUT', out: 'OUTPUT', pre: 'PREROUTING', post: 'POSTROUTING' }.freeze unless defined? CHAIN # , nil => "FORWARD"}
|
||||
TARGET = { allow: 'ACCEPT', reject: 'REJECT', deny: 'DROP', masquerade: 'MASQUERADE', redirect: 'REDIRECT', log: 'LOG --log-prefix "iptables: " --log-level 7' }.freeze unless defined? TARGET
|
||||
|
||||
def build_firewall_rule(current_node, rule_resource, ipv6 = false)
|
||||
el5 = current_node['platform_family'] == 'rhel' && Gem::Dependency.new('', '~> 5.0').match?('', current_node['platform_version'])
|
||||
|
||||
return rule_resource.raw.strip if rule_resource.raw
|
||||
firewall_rule = if rule_resource.direction
|
||||
"-A #{CHAIN[rule_resource.direction.to_sym]} "
|
||||
else
|
||||
'-A FORWARD '
|
||||
end
|
||||
|
||||
if [:pre, :post].include?(rule_resource.direction)
|
||||
firewall_rule << '-t nat '
|
||||
end
|
||||
|
||||
# Iptables order of prameters is important here see example output below:
|
||||
# -A INPUT -s 1.2.3.4/32 -d 5.6.7.8/32 -i lo -p tcp -m tcp -m state --state NEW -m comment --comment "hello" -j DROP
|
||||
firewall_rule << "-s #{ip_with_mask(rule_resource, rule_resource.source)} " if rule_resource.source && rule_resource.source != '0.0.0.0/0'
|
||||
firewall_rule << "-d #{rule_resource.destination} " if rule_resource.destination
|
||||
|
||||
firewall_rule << "-i #{rule_resource.interface} " if rule_resource.interface
|
||||
firewall_rule << "-o #{rule_resource.dest_interface} " if rule_resource.dest_interface
|
||||
|
||||
firewall_rule << "-p #{rule_resource.protocol} " if rule_resource.protocol && rule_resource.protocol.to_s.to_sym != :none
|
||||
firewall_rule << '-m tcp ' if rule_resource.protocol && rule_resource.protocol.to_s.to_sym == :tcp
|
||||
|
||||
# using multiport here allows us to simplify our greps and rule building
|
||||
firewall_rule << "-m multiport --sports #{port_to_s(rule_resource.source_port)} " if rule_resource.source_port
|
||||
firewall_rule << "-m multiport --dports #{port_to_s(dport_calc(rule_resource))} " if dport_calc(rule_resource)
|
||||
|
||||
firewall_rule << "-m state --state #{rule_resource.stateful.is_a?(Array) ? rule_resource.stateful.join(',').upcase : rule_resource.stateful.upcase} " if rule_resource.stateful
|
||||
# the comments extension is not available for ip6tables on rhel/centos 5
|
||||
unless el5 && ipv6
|
||||
firewall_rule << "-m comment --comment \"#{rule_resource.description}\" " if rule_resource.include_comment
|
||||
end
|
||||
|
||||
firewall_rule << "-j #{TARGET[rule_resource.command.to_sym]} "
|
||||
firewall_rule << "--to-ports #{rule_resource.redirect_port} " if rule_resource.command == :redirect
|
||||
firewall_rule.strip!
|
||||
firewall_rule
|
||||
end
|
||||
|
||||
def iptables_packages(new_resource)
|
||||
packages = if ipv6_enabled?(new_resource)
|
||||
%w(iptables iptables-ipv6)
|
||||
else
|
||||
%w(iptables)
|
||||
end
|
||||
|
||||
# centos 7 requires extra service
|
||||
if !ubuntu?(node) && node['platform_version'].to_i >= 7
|
||||
packages << %w(iptables-services)
|
||||
end
|
||||
|
||||
packages.flatten
|
||||
end
|
||||
|
||||
def iptables_commands(new_resource)
|
||||
if ipv6_enabled?(new_resource)
|
||||
%w(iptables ip6tables)
|
||||
else
|
||||
%w(iptables)
|
||||
end
|
||||
end
|
||||
|
||||
def log_iptables(new_resource)
|
||||
iptables_commands(new_resource).each do |cmd|
|
||||
shell_out!("#{cmd} -L -n")
|
||||
end
|
||||
rescue
|
||||
Chef::Log.info('log_iptables failed!')
|
||||
end
|
||||
|
||||
def iptables_flush!(new_resource)
|
||||
iptables_commands(new_resource).each do |cmd|
|
||||
shell_out!("#{cmd} -F")
|
||||
end
|
||||
end
|
||||
|
||||
def iptables_default_allow!(new_resource)
|
||||
iptables_commands(new_resource).each do |cmd|
|
||||
shell_out!("#{cmd} -P INPUT ACCEPT")
|
||||
shell_out!("#{cmd} -P OUTPUT ACCEPT")
|
||||
shell_out!("#{cmd} -P FORWARD ACCEPT")
|
||||
end
|
||||
end
|
||||
|
||||
def default_ruleset(current_node)
|
||||
current_node['firewall']['iptables']['defaults'][:ruleset].to_h
|
||||
end
|
||||
|
||||
def ensure_default_rules_exist(current_node, new_resource)
|
||||
input = new_resource.rules
|
||||
|
||||
# don't use iptables_commands here since we do populate the
|
||||
# hash regardless of ipv6 status
|
||||
%w(iptables ip6tables).each do |name|
|
||||
input[name] = {} unless input[name]
|
||||
input[name].merge!(default_ruleset(current_node).to_h)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
135
cookbooks/firewall/libraries/helpers_ufw.rb
Normal file
135
cookbooks/firewall/libraries/helpers_ufw.rb
Normal file
@@ -0,0 +1,135 @@
|
||||
module FirewallCookbook
|
||||
module Helpers
|
||||
module Ufw
|
||||
include FirewallCookbook::Helpers
|
||||
include Chef::Mixin::ShellOut
|
||||
|
||||
def ufw_rules_filename
|
||||
'/etc/default/ufw-chef.rules'
|
||||
end
|
||||
|
||||
def ufw_active?
|
||||
cmd = shell_out!('ufw', 'status')
|
||||
cmd.stdout =~ /^Status:\sactive/
|
||||
end
|
||||
|
||||
def ufw_disable!
|
||||
shell_out!('ufw', 'disable', input: 'yes')
|
||||
end
|
||||
|
||||
def ufw_enable!
|
||||
shell_out!('ufw', 'enable', input: 'yes')
|
||||
end
|
||||
|
||||
def ufw_reset!
|
||||
shell_out!('ufw', 'reset', input: 'yes')
|
||||
end
|
||||
|
||||
def ufw_logging!(param)
|
||||
shell_out!('ufw', 'logging', param.to_s)
|
||||
end
|
||||
|
||||
def ufw_rule!(cmd)
|
||||
shell_out!(cmd, input: 'yes')
|
||||
end
|
||||
|
||||
def build_rule(new_resource)
|
||||
Chef::Log.info("#{new_resource.name} apply_rule #{new_resource.command}")
|
||||
|
||||
# if we don't do this, we may see some bugs where traffic is opened on all ports to all hosts when only RELATED,ESTABLISHED was intended
|
||||
if new_resource.stateful
|
||||
msg = ''
|
||||
msg << "firewall_rule[#{new_resource.name}] was asked to "
|
||||
msg << "#{new_resource.command} a stateful rule using #{new_resource.stateful} "
|
||||
msg << 'but ufw does not support this kind of rule. Consider guarding by platform_family.'
|
||||
raise msg
|
||||
end
|
||||
|
||||
# if we don't do this, ufw will fail as it does not support protocol numbers, so we'll only allow it to run if specifying icmp/tcp/udp protocol types
|
||||
if new_resource.protocol && !new_resource.protocol.to_s.downcase.match('^(tcp|udp|esp|ah|ipv6|none)$')
|
||||
msg = ''
|
||||
msg << "firewall_rule[#{new_resource.name}] was asked to "
|
||||
msg << "#{new_resource.command} a rule using protocol #{new_resource.protocol} "
|
||||
msg << 'but ufw does not support this kind of rule. Consider guarding by platform_family.'
|
||||
raise msg
|
||||
end
|
||||
|
||||
# some examples:
|
||||
# ufw allow from 192.168.0.4 to any port 22
|
||||
# ufw deny proto tcp from 10.0.0.0/8 to 192.168.0.1 port 25
|
||||
# ufw insert 1 allow proto tcp from 0.0.0.0/0 to 192.168.0.1 port 25
|
||||
|
||||
if new_resource.raw
|
||||
"ufw #{new_resource.raw.strip}"
|
||||
else
|
||||
"ufw #{rule(new_resource)}"
|
||||
end
|
||||
end
|
||||
|
||||
def rule(new_resource)
|
||||
rule = ''
|
||||
rule << "#{new_resource.command} "
|
||||
rule << rule_interface(new_resource)
|
||||
rule << rule_logging(new_resource)
|
||||
rule << rule_proto(new_resource)
|
||||
rule << rule_dest_port(new_resource)
|
||||
rule << rule_source_port(new_resource)
|
||||
rule = rule.strip
|
||||
|
||||
if rule == 'ufw allow in proto tcp to any from any'
|
||||
Chef::Log.warn("firewall_rule[#{new_resource.name}] produced a rule that opens all traffic. This may be a logic error in your cookbook.")
|
||||
end
|
||||
|
||||
rule
|
||||
end
|
||||
|
||||
def rule_interface(new_resource)
|
||||
rule = ''
|
||||
rule << "#{new_resource.direction} " if new_resource.direction
|
||||
rule << "on #{new_resource.interface} " if new_resource.interface && new_resource.direction
|
||||
rule << "in on #{new_resource.interface} " if new_resource.interface && !new_resource.direction
|
||||
rule
|
||||
end
|
||||
|
||||
def rule_proto(new_resource)
|
||||
rule = ''
|
||||
rule << "proto #{new_resource.protocol} " if new_resource.protocol && new_resource.protocol.to_s.to_sym != :none
|
||||
rule
|
||||
end
|
||||
|
||||
def rule_dest_port(new_resource)
|
||||
rule = if new_resource.destination
|
||||
"to #{new_resource.destination} "
|
||||
else
|
||||
'to any '
|
||||
end
|
||||
rule << "port #{port_to_s(dport_calc(new_resource))} " if dport_calc(new_resource)
|
||||
rule
|
||||
end
|
||||
|
||||
def rule_source_port(new_resource)
|
||||
rule = if new_resource.source
|
||||
"from #{new_resource.source} "
|
||||
else
|
||||
'from any '
|
||||
end
|
||||
|
||||
if new_resource.source_port
|
||||
rule << "port #{port_to_s(new_resource.source_port)} "
|
||||
end
|
||||
rule
|
||||
end
|
||||
|
||||
def rule_logging(new_resource)
|
||||
case new_resource.logging && new_resource.logging.to_sym
|
||||
when :connections
|
||||
'log '
|
||||
when :packets
|
||||
'log-all '
|
||||
else
|
||||
''
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
130
cookbooks/firewall/libraries/helpers_windows.rb
Normal file
130
cookbooks/firewall/libraries/helpers_windows.rb
Normal file
@@ -0,0 +1,130 @@
|
||||
module FirewallCookbook
|
||||
module Helpers
|
||||
module Windows
|
||||
include FirewallCookbook::Helpers
|
||||
include Chef::Mixin::ShellOut
|
||||
|
||||
def fixup_cidr(str)
|
||||
newstr = str.clone
|
||||
newstr.gsub!('0.0.0.0/0', 'any') if newstr.include?('0.0.0.0/0')
|
||||
newstr.gsub!('/0', '') if newstr.include?('/0')
|
||||
newstr
|
||||
end
|
||||
|
||||
def windows_rules_filename
|
||||
"#{ENV['HOME']}/windows-chef.rules"
|
||||
end
|
||||
|
||||
def active?
|
||||
@active ||= begin
|
||||
cmd = shell_out!('netsh advfirewall show currentprofile')
|
||||
cmd.stdout =~ /^State\sON/
|
||||
end
|
||||
end
|
||||
|
||||
def enable!
|
||||
shell_out!('netsh advfirewall set currentprofile state on')
|
||||
end
|
||||
|
||||
def disable!
|
||||
shell_out!('netsh advfirewall set currentprofile state off')
|
||||
end
|
||||
|
||||
def reset!
|
||||
shell_out!('netsh advfirewall reset')
|
||||
end
|
||||
|
||||
def add_rule!(params)
|
||||
shell_out!("netsh advfirewall #{params}")
|
||||
end
|
||||
|
||||
def delete_all_rules!
|
||||
shell_out!('netsh advfirewall firewall delete rule name=all')
|
||||
end
|
||||
|
||||
def to_type(new_resource)
|
||||
cmd = new_resource.command
|
||||
type = if cmd == :reject || cmd == :deny
|
||||
:block
|
||||
else
|
||||
:allow
|
||||
end
|
||||
type
|
||||
end
|
||||
|
||||
def build_rule(new_resource)
|
||||
type = to_type(new_resource)
|
||||
parameters = {}
|
||||
|
||||
parameters['description'] = "\"#{new_resource.description}\""
|
||||
parameters['dir'] = new_resource.direction
|
||||
|
||||
new_resource.program && parameters['program'] = new_resource.program
|
||||
new_resource.service && parameters['service'] = new_resource.service
|
||||
parameters['protocol'] = new_resource.protocol
|
||||
|
||||
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['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['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['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
|
||||
|
||||
parameters['action'] = type.to_s
|
||||
|
||||
partial_command = parameters.map { |k, v| "#{k}=#{v}" }.join(' ')
|
||||
"firewall add rule name=\"#{new_resource.name}\" #{partial_command}"
|
||||
end
|
||||
|
||||
def rule_exists?(name)
|
||||
@exists ||= begin
|
||||
cmd = shell_out!("netsh advfirewall firewall show rule name=\"#{name}\"", returns: [0, 1])
|
||||
cmd.stdout !~ /^No rules match the specified criteria/
|
||||
end
|
||||
end
|
||||
|
||||
def show_all_rules!
|
||||
cmd = shell_out!('netsh advfirewall firewall show rule name=all')
|
||||
cmd.stdout.each_line do |line|
|
||||
Chef::Log.warn(line)
|
||||
end
|
||||
end
|
||||
|
||||
def rule_up_to_date?(name, type)
|
||||
@up_to_date ||= begin
|
||||
desired_parameters = rule_parameters(type)
|
||||
current_parameters = {}
|
||||
|
||||
cmd = shell_out!("netsh advfirewall firewall show rule name=\"#{name}\" verbose")
|
||||
cmd.stdout.each_line do |line|
|
||||
current_parameters['description'] = "\"#{Regexp.last_match(1).chomp}\"" if line =~ /^Description:\s+(.*)$/
|
||||
current_parameters['dir'] = Regexp.last_match(1).chomp if line =~ /^Direction:\s+(.*)$/
|
||||
current_parameters['program'] = Regexp.last_match(1).chomp if line =~ /^Program:\s+(.*)$/
|
||||
current_parameters['service'] = Regexp.last_match(1).chomp if line =~ /^Service:\s+(.*)$/
|
||||
current_parameters['protocol'] = Regexp.last_match(1).chomp if line =~ /^Protocol:\s+(.*)$/
|
||||
current_parameters['localip'] = Regexp.last_match(1).chomp if line =~ /^LocalIP:\s+(.*)$/
|
||||
current_parameters['localport'] = Regexp.last_match(1).chomp if line =~ /^LocalPort:\s+(.*)$/
|
||||
current_parameters['interfacetype'] = Regexp.last_match(1).chomp if line =~ /^InterfaceTypes:\s+(.*)$/
|
||||
current_parameters['remoteip'] = Regexp.last_match(1).chomp if line =~ /^RemoteIP:\s+(.*)$/
|
||||
current_parameters['remoteport'] = Regexp.last_match(1).chomp if line =~ /^RemotePort:\s+(.*)$/
|
||||
current_parameters['action'] = Regexp.last_match(1).chomp if line =~ /^Action:\s+(.*)$/
|
||||
end
|
||||
|
||||
up_to_date = true
|
||||
desired_parameters.each do |k, v|
|
||||
up_to_date = false if current_parameters[k] !~ /^["]?#{v}["]?$/i
|
||||
end
|
||||
|
||||
up_to_date
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
30
cookbooks/firewall/libraries/matchers.rb
Normal file
30
cookbooks/firewall/libraries/matchers.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
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
|
||||
179
cookbooks/firewall/libraries/provider_firewall_firewalld.rb
Normal file
179
cookbooks/firewall/libraries/provider_firewall_firewalld.rb
Normal file
@@ -0,0 +1,179 @@
|
||||
#
|
||||
# Author:: Ronald Doorn (<rdoorn@schubergphilis.com>)
|
||||
# Cookbook:: firewall
|
||||
# Resource:: default
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
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']
|
||||
end
|
||||
|
||||
def whyrun_supported?
|
||||
false
|
||||
end
|
||||
|
||||
def action_install
|
||||
return if disabled?(new_resource)
|
||||
|
||||
firewalld_package = package 'firewalld' do
|
||||
action :nothing
|
||||
options new_resource.package_options
|
||||
end
|
||||
firewalld_package.run_action(:install)
|
||||
new_resource.updated_by_last_action(firewalld_package.updated_by_last_action?)
|
||||
|
||||
unless ::File.exist?(firewalld_rules_filename)
|
||||
rules_file = lookup_or_create_rulesfile
|
||||
rules_file.content '# created by chef to allow service to start'
|
||||
rules_file.run_action(:create)
|
||||
new_resource.updated_by_last_action(rules_file.updated_by_last_action?)
|
||||
end
|
||||
|
||||
firewalld_service = lookup_or_create_service
|
||||
[:enable, :start].each do |a|
|
||||
firewalld_service.run_action(a)
|
||||
new_resource.updated_by_last_action(firewalld_service.updated_by_last_action?)
|
||||
end
|
||||
end
|
||||
|
||||
def action_restart
|
||||
return if disabled?(new_resource)
|
||||
|
||||
# ensure it's initialized
|
||||
new_resource.rules({}) unless new_resource.rules
|
||||
new_resource.rules['firewalld'] = {} unless new_resource.rules['firewalld']
|
||||
|
||||
# this populates the hash of rules from firewall_rule resources
|
||||
firewall_rules = Chef.run_context.resource_collection.select { |item| item.is_a?(Chef::Resource::FirewallRule) }
|
||||
firewall_rules.each do |firewall_rule|
|
||||
next unless firewall_rule.action.include?(:create) && !firewall_rule.should_skip?(:create)
|
||||
|
||||
ip_versions(firewall_rule).each do |ip_version|
|
||||
# build rules to apply with weight
|
||||
k = "firewall-cmd --direct --add-rule #{build_firewall_rule(firewall_rule, ip_version)}"
|
||||
v = firewall_rule.position
|
||||
|
||||
# unless we're adding them for the first time.... bail out.
|
||||
next if new_resource.rules['firewalld'].key?(k) && new_resource.rules['firewalld'][k] == v
|
||||
new_resource.rules['firewalld'][k] = v
|
||||
|
||||
# If persistent rules is enabled (default) make sure we add a permanent rule at the same time
|
||||
perm_rules = node && node['firewall'] && node['firewall']['firewalld'] && node['firewall']['firewalld']['permanent']
|
||||
if firewall_rule.permanent || perm_rules
|
||||
k = "firewall-cmd --permanent --direct --add-rule #{build_firewall_rule(firewall_rule, ip_version)}"
|
||||
new_resource.rules['firewalld'][k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ensure a file resource exists with the current firewalld rules
|
||||
rules_file = lookup_or_create_rulesfile
|
||||
rules_file.content build_rule_file(new_resource.rules['firewalld'])
|
||||
rules_file.run_action(:create)
|
||||
|
||||
# ensure the service is running without waiting.
|
||||
firewalld_service = lookup_or_create_service
|
||||
[:enable, :start].each do |a|
|
||||
firewalld_service.run_action(a)
|
||||
new_resource.updated_by_last_action(firewalld_service.updated_by_last_action?)
|
||||
end
|
||||
|
||||
# mark updated if we changed the zone
|
||||
unless firewalld_default_zone?(new_resource.enabled_zone)
|
||||
firewalld_default_zone!(new_resource.enabled_zone)
|
||||
new_resource.updated_by_last_action(true)
|
||||
end
|
||||
|
||||
# if the file was changed, load new ruleset
|
||||
return unless rules_file.updated_by_last_action?
|
||||
firewalld_flush!
|
||||
# TODO: support logging
|
||||
|
||||
new_resource.rules['firewalld'].sort_by { |_k, v| v }.map { |k, _v| k }.each do |cmd|
|
||||
firewalld_rule!(cmd)
|
||||
end
|
||||
|
||||
new_resource.updated_by_last_action(true)
|
||||
end
|
||||
|
||||
def action_disable
|
||||
return if disabled?(new_resource)
|
||||
|
||||
if firewalld_active?
|
||||
firewalld_flush!
|
||||
firewalld_default_zone!(new_resource.disabled_zone)
|
||||
new_resource.updated_by_last_action(true)
|
||||
end
|
||||
|
||||
# ensure the service is stopped without waiting.
|
||||
firewalld_service = lookup_or_create_service
|
||||
[:disable, :stop].each do |a|
|
||||
firewalld_service.run_action(a)
|
||||
new_resource.updated_by_last_action(firewalld_service.updated_by_last_action?)
|
||||
end
|
||||
|
||||
rules_file = lookup_or_create_rulesfile
|
||||
rules_file.content '# created by chef to allow service to start'
|
||||
rules_file.run_action(:create)
|
||||
new_resource.updated_by_last_action(rules_file.updated_by_last_action?)
|
||||
end
|
||||
|
||||
def action_flush
|
||||
return if disabled?(new_resource)
|
||||
return unless firewalld_active?
|
||||
|
||||
firewalld_flush!
|
||||
new_resource.updated_by_last_action(true)
|
||||
|
||||
rules_file = lookup_or_create_rulesfile
|
||||
rules_file.content '# created by chef to allow service to start'
|
||||
rules_file.run_action(:create)
|
||||
new_resource.updated_by_last_action(rules_file.updated_by_last_action?)
|
||||
end
|
||||
|
||||
def action_save
|
||||
return if disabled?(new_resource)
|
||||
return if firewalld_all_rules_permanent!
|
||||
|
||||
firewalld_save!
|
||||
new_resource.updated_by_last_action(true)
|
||||
end
|
||||
|
||||
def lookup_or_create_service
|
||||
begin
|
||||
firewalld_service = Chef.run_context.resource_collection.find(service: 'firewalld')
|
||||
rescue
|
||||
firewalld_service = service 'firewalld' do
|
||||
action :nothing
|
||||
end
|
||||
end
|
||||
firewalld_service
|
||||
end
|
||||
|
||||
def lookup_or_create_rulesfile
|
||||
begin
|
||||
firewalld_file = Chef.run_context.resource_collection.find(file: firewalld_rules_filename)
|
||||
rescue
|
||||
firewalld_file = file firewalld_rules_filename do
|
||||
action :nothing
|
||||
end
|
||||
end
|
||||
firewalld_file
|
||||
end
|
||||
end
|
||||
end
|
||||
171
cookbooks/firewall/libraries/provider_firewall_iptables.rb
Normal file
171
cookbooks/firewall/libraries/provider_firewall_iptables.rb
Normal file
@@ -0,0 +1,171 @@
|
||||
#
|
||||
# Author:: Seth Chisamore (<schisamo@opscode.com>)
|
||||
# Cookbook:: firewall
|
||||
# Resource:: default
|
||||
#
|
||||
# Copyright:: 2011-2016, 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.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
class Chef
|
||||
class Provider::FirewallIptables < Chef::Provider::LWRPBase
|
||||
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']
|
||||
end
|
||||
|
||||
def whyrun_supported?
|
||||
false
|
||||
end
|
||||
|
||||
def action_install
|
||||
return if disabled?(new_resource)
|
||||
|
||||
# Ensure the package is installed
|
||||
iptables_packages(new_resource).each do |p|
|
||||
iptables_pkg = package p do
|
||||
action :nothing
|
||||
end
|
||||
iptables_pkg.run_action(:install)
|
||||
new_resource.updated_by_last_action(true) if iptables_pkg.updated_by_last_action?
|
||||
end
|
||||
|
||||
iptables_commands(new_resource).each do |svc|
|
||||
# must create empty file for service to start
|
||||
unless ::File.exist?("/etc/sysconfig/#{svc}")
|
||||
# must create empty file for service to start
|
||||
iptables_file = lookup_or_create_rulesfile(svc)
|
||||
iptables_file.content '# created by chef to allow service to start'
|
||||
iptables_file.run_action(:create)
|
||||
new_resource.updated_by_last_action(true) if iptables_file.updated_by_last_action?
|
||||
end
|
||||
|
||||
iptables_service = lookup_or_create_service(svc)
|
||||
[:enable, :start].each do |a|
|
||||
iptables_service.run_action(a)
|
||||
new_resource.updated_by_last_action(true) if iptables_service.updated_by_last_action?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def action_restart
|
||||
return if disabled?(new_resource)
|
||||
|
||||
# prints all the firewall rules
|
||||
log_iptables(new_resource)
|
||||
|
||||
# ensure it's initialized
|
||||
new_resource.rules({}) unless new_resource.rules
|
||||
ensure_default_rules_exist(node, new_resource)
|
||||
|
||||
# this populates the hash of rules from firewall_rule resources
|
||||
firewall_rules = Chef.run_context.resource_collection.select { |item| item.is_a?(Chef::Resource::FirewallRule) }
|
||||
firewall_rules.each do |firewall_rule|
|
||||
next unless firewall_rule.action.include?(:create) && !firewall_rule.should_skip?(:create)
|
||||
|
||||
types = if ipv6_rule?(firewall_rule) # an ip4 specific rule
|
||||
%w(ip6tables)
|
||||
elsif ipv4_rule?(firewall_rule) # an ip6 specific rule
|
||||
%w(iptables)
|
||||
else # or not specific
|
||||
%w(iptables ip6tables)
|
||||
end
|
||||
|
||||
types.each do |iptables_type|
|
||||
# build rules to apply with weight
|
||||
k = build_firewall_rule(node, firewall_rule, iptables_type == 'ip6tables')
|
||||
v = firewall_rule.position
|
||||
|
||||
# unless we're adding them for the first time.... bail out.
|
||||
next if new_resource.rules[iptables_type].key?(k) && new_resource.rules[iptables_type][k] == v
|
||||
new_resource.rules[iptables_type][k] = v
|
||||
end
|
||||
end
|
||||
|
||||
iptables_commands(new_resource).each do |iptables_type|
|
||||
# this takes the commands in each hash entry and builds a rule file
|
||||
iptables_file = lookup_or_create_rulesfile(iptables_type)
|
||||
iptables_file.content build_rule_file(new_resource.rules[iptables_type])
|
||||
iptables_file.run_action(:create)
|
||||
|
||||
# if the file was unchanged, skip loop iteration, otherwise restart iptables
|
||||
next unless iptables_file.updated_by_last_action?
|
||||
|
||||
iptables_service = lookup_or_create_service(iptables_type)
|
||||
new_resource.notifies(:restart, iptables_service, :delayed)
|
||||
new_resource.updated_by_last_action(true)
|
||||
end
|
||||
end
|
||||
|
||||
def action_disable
|
||||
return if disabled?(new_resource)
|
||||
|
||||
iptables_flush!(new_resource)
|
||||
iptables_default_allow!(new_resource)
|
||||
new_resource.updated_by_last_action(true)
|
||||
|
||||
iptables_commands(new_resource).each do |svc|
|
||||
iptables_service = lookup_or_create_service(svc)
|
||||
[:disable, :stop].each do |a|
|
||||
iptables_service.run_action(a)
|
||||
new_resource.updated_by_last_action(true) if iptables_service.updated_by_last_action?
|
||||
end
|
||||
|
||||
# must create empty file for service to start
|
||||
iptables_file = lookup_or_create_rulesfile(svc)
|
||||
iptables_file.content '# created by chef to allow service to start'
|
||||
iptables_file.run_action(:create)
|
||||
new_resource.updated_by_last_action(true) if iptables_file.updated_by_last_action?
|
||||
end
|
||||
end
|
||||
|
||||
def action_flush
|
||||
return if disabled?(new_resource)
|
||||
|
||||
iptables_flush!(new_resource)
|
||||
new_resource.updated_by_last_action(true)
|
||||
|
||||
iptables_commands(new_resource).each do |svc|
|
||||
# must create empty file for service to start
|
||||
iptables_file = lookup_or_create_rulesfile(svc)
|
||||
iptables_file.content '# created by chef to allow service to start'
|
||||
iptables_file.run_action(:create)
|
||||
new_resource.updated_by_last_action(true) if iptables_file.updated_by_last_action?
|
||||
end
|
||||
end
|
||||
|
||||
def lookup_or_create_service(name)
|
||||
begin
|
||||
iptables_service = Chef.run_context.resource_collection.find(service: svc)
|
||||
rescue
|
||||
iptables_service = service name do
|
||||
action :nothing
|
||||
end
|
||||
end
|
||||
iptables_service
|
||||
end
|
||||
|
||||
def lookup_or_create_rulesfile(name)
|
||||
begin
|
||||
iptables_file = Chef.run_context.resource_collection.find(file: name)
|
||||
rescue
|
||||
iptables_file = file "/etc/sysconfig/#{name}" do
|
||||
action :nothing
|
||||
end
|
||||
end
|
||||
iptables_file
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,195 @@
|
||||
#
|
||||
# Author:: Seth Chisamore (<schisamo@opscode.com>)
|
||||
# Cookbook:: firewall
|
||||
# Resource:: default
|
||||
#
|
||||
# Copyright:: 2011-2016, 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.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
class Chef
|
||||
class Provider::FirewallIptablesUbuntu < Chef::Provider::LWRPBase
|
||||
include FirewallCookbook::Helpers
|
||||
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']
|
||||
end
|
||||
|
||||
def whyrun_supported?
|
||||
false
|
||||
end
|
||||
|
||||
def action_install
|
||||
return if disabled?(new_resource)
|
||||
|
||||
# Ensure the package is installed
|
||||
pkg = package 'iptables-persistent' do
|
||||
action :nothing
|
||||
end
|
||||
pkg.run_action(:install)
|
||||
new_resource.updated_by_last_action(true) if pkg.updated_by_last_action?
|
||||
|
||||
rule_files = %w(rules.v4)
|
||||
rule_files << 'rules.v6' if ipv6_enabled?(new_resource)
|
||||
rule_files.each do |svc|
|
||||
next if ::File.exist?("/etc/iptables/#{svc}")
|
||||
|
||||
# must create empty file for service to start
|
||||
f = lookup_or_create_rulesfile(svc)
|
||||
f.content '# created by chef to allow service to start'
|
||||
f.run_action(:create)
|
||||
|
||||
new_resource.updated_by_last_action(true) if f.updated_by_last_action?
|
||||
end
|
||||
|
||||
iptables_service = lookup_or_create_service('netfilter-persistent')
|
||||
[:enable, :start].each do |act|
|
||||
# iptables-persistent isn't a real service
|
||||
iptables_service.status_command 'true'
|
||||
|
||||
iptables_service.run_action(act)
|
||||
new_resource.updated_by_last_action(true) if iptables_service.updated_by_last_action?
|
||||
end
|
||||
end
|
||||
|
||||
def action_restart
|
||||
return if disabled?(new_resource)
|
||||
|
||||
# prints all the firewall rules
|
||||
log_iptables(new_resource)
|
||||
|
||||
# ensure it's initialized
|
||||
new_resource.rules({}) unless new_resource.rules
|
||||
ensure_default_rules_exist(node, new_resource)
|
||||
|
||||
# this populates the hash of rules from firewall_rule resources
|
||||
firewall_rules = Chef.run_context.resource_collection.select { |item| item.is_a?(Chef::Resource::FirewallRule) }
|
||||
firewall_rules.each do |firewall_rule|
|
||||
next unless firewall_rule.action.include?(:create) && !firewall_rule.should_skip?(:create)
|
||||
|
||||
types = if ipv6_rule?(firewall_rule) # an ip4 specific rule
|
||||
%w(ip6tables)
|
||||
elsif ipv4_rule?(firewall_rule) # an ip6 specific rule
|
||||
%w(iptables)
|
||||
else # or not specific
|
||||
%w(iptables ip6tables)
|
||||
end
|
||||
|
||||
types.each do |iptables_type|
|
||||
# build rules to apply with weight
|
||||
k = build_firewall_rule(node, firewall_rule, iptables_type == 'ip6tables')
|
||||
v = firewall_rule.position
|
||||
|
||||
# unless we're adding them for the first time.... bail out.
|
||||
next if new_resource.rules[iptables_type].key?(k) && new_resource.rules[iptables_type][k] == v
|
||||
new_resource.rules[iptables_type][k] = v
|
||||
end
|
||||
end
|
||||
|
||||
rule_files = %w(iptables)
|
||||
rule_files << 'ip6tables' if ipv6_enabled?(new_resource)
|
||||
|
||||
rule_files.each do |iptables_type|
|
||||
iptables_filename = if iptables_type == 'ip6tables'
|
||||
'/etc/iptables/rules.v6'
|
||||
else
|
||||
'/etc/iptables/rules.v4'
|
||||
end
|
||||
|
||||
# ensure a file resource exists with the current iptables rules
|
||||
begin
|
||||
iptables_file = Chef.run_context.resource_collection.find(file: iptables_filename)
|
||||
rescue
|
||||
iptables_file = file iptables_filename do
|
||||
action :nothing
|
||||
end
|
||||
end
|
||||
iptables_file.content build_rule_file(new_resource.rules[iptables_type])
|
||||
iptables_file.run_action(:create)
|
||||
|
||||
# if the file was changed, restart iptables
|
||||
next unless iptables_file.updated_by_last_action?
|
||||
service_affected = service 'netfilter-persistent' do
|
||||
action :nothing
|
||||
end
|
||||
|
||||
new_resource.notifies(:restart, service_affected, :delayed)
|
||||
new_resource.updated_by_last_action(true)
|
||||
end
|
||||
end
|
||||
|
||||
def action_disable
|
||||
return if disabled?(new_resource)
|
||||
|
||||
iptables_flush!(new_resource)
|
||||
iptables_default_allow!(new_resource)
|
||||
new_resource.updated_by_last_action(true)
|
||||
|
||||
iptables_service = lookup_or_create_service('netfilter-persistent')
|
||||
[:disable, :stop].each do |act|
|
||||
iptables_service.run_action(act)
|
||||
new_resource.updated_by_last_action(true) if iptables_service.updated_by_last_action?
|
||||
end
|
||||
|
||||
%w(rules.v4 rules.v6).each do |svc|
|
||||
# must create empty file for service to start
|
||||
f = lookup_or_create_rulesfile(svc)
|
||||
f.content '# created by chef to allow service to start'
|
||||
f.run_action(:create)
|
||||
|
||||
new_resource.updated_by_last_action(true) if f.updated_by_last_action?
|
||||
end
|
||||
end
|
||||
|
||||
def action_flush
|
||||
return if disabled?(new_resource)
|
||||
|
||||
iptables_flush!(new_resource)
|
||||
new_resource.updated_by_last_action(true)
|
||||
|
||||
rule_files = %w(rules.v4)
|
||||
rule_files << 'rules.v6' if ipv6_enabled?(new_resource)
|
||||
rule_files.each do |svc|
|
||||
# must create empty file for service to start
|
||||
f = lookup_or_create_rulesfile(svc)
|
||||
f.content '# created by chef to allow service to start'
|
||||
f.run_action(:create)
|
||||
|
||||
new_resource.updated_by_last_action(true) if f.updated_by_last_action?
|
||||
end
|
||||
end
|
||||
|
||||
def lookup_or_create_service(name)
|
||||
begin
|
||||
iptables_service = Chef.run_context.resource_collection.find(service: svc)
|
||||
rescue
|
||||
iptables_service = service name do
|
||||
action :nothing
|
||||
end
|
||||
end
|
||||
iptables_service
|
||||
end
|
||||
|
||||
def lookup_or_create_rulesfile(name)
|
||||
begin
|
||||
iptables_file = Chef.run_context.resource_collection.find(file: name)
|
||||
rescue
|
||||
iptables_file = file "/etc/iptables/#{name}" do
|
||||
action :nothing
|
||||
end
|
||||
end
|
||||
iptables_file
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,195 @@
|
||||
#
|
||||
# Author:: Seth Chisamore (<schisamo@opscode.com>)
|
||||
# Cookbook Name:: firewall
|
||||
# Resource:: default
|
||||
#
|
||||
# Copyright:: 2011, Opscode, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
class Chef
|
||||
class Provider::FirewallIptablesUbuntu1404 < Chef::Provider::LWRPBase
|
||||
include FirewallCookbook::Helpers
|
||||
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']
|
||||
end
|
||||
|
||||
def whyrun_supported?
|
||||
false
|
||||
end
|
||||
|
||||
def action_install
|
||||
return if disabled?(new_resource)
|
||||
|
||||
# Ensure the package is installed
|
||||
pkg = package 'iptables-persistent' do
|
||||
action :nothing
|
||||
end
|
||||
pkg.run_action(:install)
|
||||
new_resource.updated_by_last_action(true) if pkg.updated_by_last_action?
|
||||
|
||||
rule_files = %w(rules.v4)
|
||||
rule_files << 'rules.v6' if ipv6_enabled?(new_resource)
|
||||
rule_files.each do |svc|
|
||||
next if ::File.exist?("/etc/iptables/#{svc}")
|
||||
|
||||
# must create empty file for service to start
|
||||
f = lookup_or_create_rulesfile(svc)
|
||||
f.content '# created by chef to allow service to start'
|
||||
f.run_action(:create)
|
||||
|
||||
new_resource.updated_by_last_action(true) if f.updated_by_last_action?
|
||||
end
|
||||
|
||||
iptables_service = lookup_or_create_service('iptables-persistent')
|
||||
[:enable, :start].each do |act|
|
||||
# iptables-persistent isn't a real service
|
||||
iptables_service.status_command 'true'
|
||||
|
||||
iptables_service.run_action(act)
|
||||
new_resource.updated_by_last_action(true) if iptables_service.updated_by_last_action?
|
||||
end
|
||||
end
|
||||
|
||||
def action_restart
|
||||
return if disabled?(new_resource)
|
||||
|
||||
# prints all the firewall rules
|
||||
log_iptables(new_resource)
|
||||
|
||||
# ensure it's initialized
|
||||
new_resource.rules({}) unless new_resource.rules
|
||||
ensure_default_rules_exist(node, new_resource)
|
||||
|
||||
# this populates the hash of rules from firewall_rule resources
|
||||
firewall_rules = Chef.run_context.resource_collection.select { |item| item.is_a?(Chef::Resource::FirewallRule) }
|
||||
firewall_rules.each do |firewall_rule|
|
||||
next unless firewall_rule.action.include?(:create) && !firewall_rule.should_skip?(:create)
|
||||
|
||||
types = if ipv6_rule?(firewall_rule) # an ip4 specific rule
|
||||
%w(ip6tables)
|
||||
elsif ipv4_rule?(firewall_rule) # an ip6 specific rule
|
||||
%w(iptables)
|
||||
else # or not specific
|
||||
%w(iptables ip6tables)
|
||||
end
|
||||
|
||||
types.each do |iptables_type|
|
||||
# build rules to apply with weight
|
||||
k = build_firewall_rule(node, firewall_rule, iptables_type == 'ip6tables')
|
||||
v = firewall_rule.position
|
||||
|
||||
# unless we're adding them for the first time.... bail out.
|
||||
next if new_resource.rules[iptables_type].key?(k) && new_resource.rules[iptables_type][k] == v
|
||||
new_resource.rules[iptables_type][k] = v
|
||||
end
|
||||
end
|
||||
|
||||
rule_files = %w(iptables)
|
||||
rule_files << 'ip6tables' if ipv6_enabled?(new_resource)
|
||||
|
||||
rule_files.each do |iptables_type|
|
||||
iptables_filename = if iptables_type == 'ip6tables'
|
||||
'/etc/iptables/rules.v6'
|
||||
else
|
||||
'/etc/iptables/rules.v4'
|
||||
end
|
||||
|
||||
# ensure a file resource exists with the current iptables rules
|
||||
begin
|
||||
iptables_file = Chef.run_context.resource_collection.find(file: iptables_filename)
|
||||
rescue
|
||||
iptables_file = file iptables_filename do
|
||||
action :nothing
|
||||
end
|
||||
end
|
||||
iptables_file.content build_rule_file(new_resource.rules[iptables_type])
|
||||
iptables_file.run_action(:create)
|
||||
|
||||
# if the file was changed, restart iptables
|
||||
next unless iptables_file.updated_by_last_action?
|
||||
service_affected = service 'iptables-persistent' do
|
||||
action :nothing
|
||||
end
|
||||
|
||||
new_resource.notifies(:restart, service_affected, :delayed)
|
||||
new_resource.updated_by_last_action(true)
|
||||
end
|
||||
end
|
||||
|
||||
def action_disable
|
||||
return if disabled?(new_resource)
|
||||
|
||||
iptables_flush!(new_resource)
|
||||
iptables_default_allow!(new_resource)
|
||||
new_resource.updated_by_last_action(true)
|
||||
|
||||
iptables_service = lookup_or_create_service('iptables-persistent')
|
||||
[:disable, :stop].each do |act|
|
||||
iptables_service.run_action(act)
|
||||
new_resource.updated_by_last_action(true) if iptables_service.updated_by_last_action?
|
||||
end
|
||||
|
||||
%w(rules.v4 rules.v6).each do |svc|
|
||||
# must create empty file for service to start
|
||||
f = lookup_or_create_rulesfile(svc)
|
||||
f.content '# created by chef to allow service to start'
|
||||
f.run_action(:create)
|
||||
|
||||
new_resource.updated_by_last_action(true) if f.updated_by_last_action?
|
||||
end
|
||||
end
|
||||
|
||||
def action_flush
|
||||
return if disabled?(new_resource)
|
||||
|
||||
iptables_flush!(new_resource)
|
||||
new_resource.updated_by_last_action(true)
|
||||
|
||||
rule_files = %w(rules.v4)
|
||||
rule_files << 'rules.v6' if ipv6_enabled?(new_resource)
|
||||
rule_files.each do |svc|
|
||||
# must create empty file for service to start
|
||||
f = lookup_or_create_rulesfile(svc)
|
||||
f.content '# created by chef to allow service to start'
|
||||
f.run_action(:create)
|
||||
|
||||
new_resource.updated_by_last_action(true) if f.updated_by_last_action?
|
||||
end
|
||||
end
|
||||
|
||||
def lookup_or_create_service(name)
|
||||
begin
|
||||
iptables_service = Chef.run_context.resource_collection.find(service: svc)
|
||||
rescue
|
||||
iptables_service = service name do
|
||||
action :nothing
|
||||
end
|
||||
end
|
||||
iptables_service
|
||||
end
|
||||
|
||||
def lookup_or_create_rulesfile(name)
|
||||
begin
|
||||
iptables_file = Chef.run_context.resource_collection.find(file: name)
|
||||
rescue
|
||||
iptables_file = file "/etc/iptables/#{name}" do
|
||||
action :nothing
|
||||
end
|
||||
end
|
||||
iptables_file
|
||||
end
|
||||
end
|
||||
end
|
||||
34
cookbooks/firewall/libraries/provider_firewall_rule.rb
Normal file
34
cookbooks/firewall/libraries/provider_firewall_rule.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Author:: Ronald Doorn (<rdoorn@schubergphilis.com>)
|
||||
# Cookbook:: firewall
|
||||
# Provider:: rule_iptables
|
||||
#
|
||||
# Copyright:: 2015-2016, computerlyrik
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
class Chef
|
||||
class Provider::FirewallRuleGeneric < Chef::Provider::LWRPBase
|
||||
provides :firewall_rule
|
||||
|
||||
def action_create
|
||||
return unless new_resource.notify_firewall
|
||||
|
||||
firewall_resource = Chef.run_context.resource_collection.find(firewall: new_resource.firewall_name)
|
||||
raise 'could not find a firewall resource' unless firewall_resource
|
||||
|
||||
new_resource.notifies(:restart, firewall_resource, :delayed)
|
||||
new_resource.updated_by_last_action(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
138
cookbooks/firewall/libraries/provider_firewall_ufw.rb
Normal file
138
cookbooks/firewall/libraries/provider_firewall_ufw.rb
Normal file
@@ -0,0 +1,138 @@
|
||||
#
|
||||
# Author:: Seth Chisamore (<schisamo@opscode.com>)
|
||||
# Cookbook:: firewall
|
||||
# Resource:: default
|
||||
#
|
||||
# Copyright:: 2011-2016, 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.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
class Chef
|
||||
class Provider::FirewallUfw < Chef::Provider::LWRPBase
|
||||
include FirewallCookbook::Helpers::Ufw
|
||||
|
||||
provides :firewall, os: 'linux', platform_family: %w(debian) do |node|
|
||||
!(node['firewall'] && node['firewall']['ubuntu_iptables'])
|
||||
end
|
||||
|
||||
def whyrun_supported?
|
||||
false
|
||||
end
|
||||
|
||||
def action_install
|
||||
return if disabled?(new_resource)
|
||||
|
||||
pkg_ufw = package 'ufw' do
|
||||
action :nothing
|
||||
end
|
||||
pkg_ufw.run_action(:install)
|
||||
new_resource.updated_by_last_action(true) if pkg_ufw.updated_by_last_action?
|
||||
|
||||
defaults_ufw = template '/etc/default/ufw' do
|
||||
action :nothing
|
||||
owner 'root'
|
||||
group 'root'
|
||||
mode '0644'
|
||||
source 'ufw/default.erb'
|
||||
cookbook 'firewall'
|
||||
end
|
||||
defaults_ufw.run_action(:create)
|
||||
new_resource.updated_by_last_action(true) if defaults_ufw.updated_by_last_action?
|
||||
|
||||
return if ::File.exist?(ufw_rules_filename)
|
||||
|
||||
ufw_file = lookup_or_create_rulesfile
|
||||
ufw_file.content '# created by chef to allow service to start'
|
||||
ufw_file.run_action(:create)
|
||||
|
||||
new_resource.updated_by_last_action(true) if ufw_file.updated_by_last_action?
|
||||
end
|
||||
|
||||
def action_restart
|
||||
return if disabled?(new_resource)
|
||||
|
||||
# ensure it's initialized
|
||||
new_resource.rules({}) unless new_resource.rules
|
||||
new_resource.rules['ufw'] = {} unless new_resource.rules['ufw']
|
||||
|
||||
# this populates the hash of rules from firewall_rule resources
|
||||
firewall_rules = Chef.run_context.resource_collection.select { |item| item.is_a?(Chef::Resource::FirewallRule) }
|
||||
firewall_rules.each do |firewall_rule|
|
||||
next unless firewall_rule.action.include?(:create) && !firewall_rule.should_skip?(:create)
|
||||
|
||||
# build rules to apply with weight
|
||||
k = build_rule(firewall_rule)
|
||||
v = firewall_rule.position
|
||||
|
||||
# unless we're adding them for the first time.... bail out.
|
||||
unless new_resource.rules['ufw'].key?(k) && new_resource.rules['ufw'][k] == v
|
||||
new_resource.rules['ufw'][k] = v
|
||||
end
|
||||
end
|
||||
|
||||
# ensure a file resource exists with the current ufw rules
|
||||
ufw_file = lookup_or_create_rulesfile
|
||||
ufw_file.content build_rule_file(new_resource.rules['ufw'])
|
||||
ufw_file.run_action(:create)
|
||||
|
||||
# if the file was changed, restart iptables
|
||||
return unless ufw_file.updated_by_last_action?
|
||||
ufw_reset!
|
||||
ufw_logging!(new_resource.log_level) if new_resource.log_level
|
||||
|
||||
new_resource.rules['ufw'].sort_by { |_k, v| v }.map { |k, _v| k }.each do |cmd|
|
||||
ufw_rule!(cmd)
|
||||
end
|
||||
|
||||
# ensure it's enabled _after_ rules are inputted, to catch malformed rules
|
||||
ufw_enable! unless ufw_active?
|
||||
new_resource.updated_by_last_action(true)
|
||||
end
|
||||
|
||||
def action_disable
|
||||
return if disabled?(new_resource)
|
||||
|
||||
ufw_file = lookup_or_create_rulesfile
|
||||
ufw_file.content '# created by chef to allow service to start'
|
||||
ufw_file.run_action(:create)
|
||||
new_resource.updated_by_last_action(true) if ufw_file.updated_by_last_action?
|
||||
|
||||
return unless ufw_active?
|
||||
ufw_disable!
|
||||
new_resource.updated_by_last_action(true)
|
||||
end
|
||||
|
||||
def action_flush
|
||||
return if disabled?(new_resource)
|
||||
|
||||
ufw_reset!
|
||||
new_resource.updated_by_last_action(true)
|
||||
|
||||
ufw_file = lookup_or_create_rulesfile
|
||||
ufw_file.content '# created by chef to allow service to start'
|
||||
ufw_file.run_action(:create)
|
||||
new_resource.updated_by_last_action(true) if ufw_file.updated_by_last_action?
|
||||
end
|
||||
|
||||
def lookup_or_create_rulesfile
|
||||
begin
|
||||
ufw_file = Chef.run_context.resource_collection.find(file: ufw_rules_filename)
|
||||
rescue
|
||||
ufw_file = file ufw_rules_filename do
|
||||
action :nothing
|
||||
end
|
||||
end
|
||||
ufw_file
|
||||
end
|
||||
end
|
||||
end
|
||||
126
cookbooks/firewall/libraries/provider_firewall_windows.rb
Normal file
126
cookbooks/firewall/libraries/provider_firewall_windows.rb
Normal file
@@ -0,0 +1,126 @@
|
||||
#
|
||||
# Author:: Sander van Harmelen (<svanharmelen@schubergphilis.com>)
|
||||
# Cookbook:: firewall
|
||||
# Provider:: windows
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
class Chef
|
||||
class Provider::FirewallWindows < Chef::Provider::LWRPBase
|
||||
include FirewallCookbook::Helpers::Windows
|
||||
|
||||
provides :firewall, os: 'windows'
|
||||
|
||||
def whyrun_supported?
|
||||
false
|
||||
end
|
||||
|
||||
def action_install
|
||||
return if disabled?(new_resource)
|
||||
|
||||
svc = service 'MpsSvc' do
|
||||
action :nothing
|
||||
end
|
||||
|
||||
[:enable, :start].each do |act|
|
||||
svc.run_action(act)
|
||||
new_resource.updated_by_last_action(true) if svc.updated_by_last_action?
|
||||
end
|
||||
end
|
||||
|
||||
def action_restart
|
||||
return if disabled?(new_resource)
|
||||
|
||||
# ensure it's initialized
|
||||
new_resource.rules({}) unless new_resource.rules
|
||||
new_resource.rules['windows'] = {} unless new_resource.rules['windows']
|
||||
|
||||
firewall_rules = Chef.run_context.resource_collection.select { |item| item.is_a?(Chef::Resource::FirewallRule) }
|
||||
firewall_rules.each do |firewall_rule|
|
||||
next unless firewall_rule.action.include?(:create) && !firewall_rule.should_skip?(:create)
|
||||
|
||||
# build rules to apply with weight
|
||||
k = build_rule(firewall_rule)
|
||||
v = firewall_rule.position
|
||||
|
||||
# unless we're adding them for the first time.... bail out.
|
||||
unless new_resource.rules['windows'].key?(k) && new_resource.rules['windows'][k] == v
|
||||
new_resource.rules['windows'][k] = v
|
||||
end
|
||||
end
|
||||
|
||||
input_policy = node['firewall']['windows']['defaults']['policy']['input']
|
||||
output_policy = node['firewall']['windows']['defaults']['policy']['output']
|
||||
unless new_resource.rules['windows'].key?("set currentprofile firewallpolicy #{input_policy},#{output_policy}")
|
||||
# Make this the possible last rule in the list
|
||||
new_resource.rules['windows']["set currentprofile firewallpolicy #{input_policy},#{output_policy}"] = 99999
|
||||
end
|
||||
|
||||
# ensure a file resource exists with the current rules
|
||||
begin
|
||||
windows_file = Chef.run_context.resource_collection.find(file: windows_rules_filename)
|
||||
rescue
|
||||
windows_file = file windows_rules_filename do
|
||||
action :nothing
|
||||
end
|
||||
end
|
||||
windows_file.content build_rule_file(new_resource.rules['windows'])
|
||||
windows_file.run_action(:create)
|
||||
|
||||
# if the file was changed, restart iptables
|
||||
return unless windows_file.updated_by_last_action?
|
||||
|
||||
disable! if active?
|
||||
delete_all_rules! # clear entirely
|
||||
reset! # populate default rules
|
||||
|
||||
new_resource.rules['windows'].sort_by { |_k, v| v }.map { |k, _v| k }.each do |cmd|
|
||||
add_rule!(cmd)
|
||||
end
|
||||
# ensure it's enabled _after_ rules are inputted, to catch malformed rules
|
||||
enable! unless active?
|
||||
|
||||
new_resource.updated_by_last_action(true)
|
||||
end
|
||||
|
||||
def action_disable
|
||||
return if disabled?(new_resource)
|
||||
|
||||
if active?
|
||||
disable!
|
||||
Chef::Log.info("#{new_resource} disabled.")
|
||||
new_resource.updated_by_last_action(true)
|
||||
else
|
||||
Chef::Log.debug("#{new_resource} already disabled.")
|
||||
end
|
||||
|
||||
svc = service 'MpsSvc' do
|
||||
action :nothing
|
||||
end
|
||||
|
||||
[:disable, :stop].each do |act|
|
||||
svc.run_action(act)
|
||||
new_resource.updated_by_last_action(true) if svc.updated_by_last_action?
|
||||
end
|
||||
end
|
||||
|
||||
def action_flush
|
||||
return if disabled?(new_resource)
|
||||
|
||||
reset!
|
||||
Chef::Log.info("#{new_resource} reset.")
|
||||
new_resource.updated_by_last_action(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
26
cookbooks/firewall/libraries/resource_firewall.rb
Normal file
26
cookbooks/firewall/libraries/resource_firewall.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
class Chef
|
||||
class Resource::Firewall < Chef::Resource::LWRPBase
|
||||
resource_name(:firewall)
|
||||
provides(:firewall)
|
||||
actions(:install, :restart, :disable, :flush, :save)
|
||||
default_action(:install)
|
||||
|
||||
# allow both kinds of logic -- eventually remove the :disabled one.
|
||||
# the positive logic is much easier to follow.
|
||||
attribute(:disabled, kind_of: [TrueClass, FalseClass], default: false)
|
||||
attribute(:enabled, kind_of: [TrueClass, FalseClass], default: true)
|
||||
|
||||
attribute(:log_level, kind_of: Symbol, equal_to: [:low, :medium, :high, :full, :off], default: :low)
|
||||
attribute(:rules, kind_of: Hash)
|
||||
|
||||
# for firewalld, specify the zone when firewall is disable and enabled
|
||||
attribute(:disabled_zone, kind_of: Symbol, default: :public)
|
||||
attribute(:enabled_zone, kind_of: Symbol, default: :drop)
|
||||
|
||||
# for firewall implementations where ipv6 can be skipped (currently iptables-specific)
|
||||
attribute(:ipv6_enabled, kind_of: [TrueClass, FalseClass], default: true)
|
||||
|
||||
# allow override of package options for firewalld package
|
||||
attribute(:package_options, kind_of: String, default: nil)
|
||||
end
|
||||
end
|
||||
52
cookbooks/firewall/libraries/resource_firewall_rule.rb
Normal file
52
cookbooks/firewall/libraries/resource_firewall_rule.rb
Normal file
@@ -0,0 +1,52 @@
|
||||
require 'ipaddr'
|
||||
|
||||
class Chef
|
||||
class Resource::FirewallRule < Chef::Resource::LWRPBase
|
||||
include FirewallCookbook::Helpers
|
||||
|
||||
resource_name(:firewall_rule)
|
||||
provides(:firewall_rule)
|
||||
actions(:create)
|
||||
default_action(:create)
|
||||
|
||||
attribute(:firewall_name, kind_of: String, default: 'default')
|
||||
|
||||
attribute(:command, kind_of: Symbol, equal_to: [:reject, :allow, :deny, :masquerade, :redirect, :log], default: :allow)
|
||||
|
||||
attribute(:protocol, kind_of: [Integer, Symbol], default: :tcp,
|
||||
callbacks: { 'must be either :tcp, :udp, :icmp, :\'ipv6-icmp\', :icmpv6, :none, or a valid IP protocol number' => lambda do |p|
|
||||
!!(p.to_s =~ /(udp|tcp|icmp|icmpv6|ipv6-icmp|esp|ah|ipv6|none)/ || (p.to_s =~ /^\d+$/ && p.between?(0, 142)))
|
||||
end })
|
||||
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_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(:dest_port, kind_of: [Integer, Array, Range])
|
||||
attribute(:dest_interface, kind_of: String)
|
||||
|
||||
attribute(:position, kind_of: Integer, default: 50)
|
||||
attribute(:stateful, kind_of: [Symbol, Array])
|
||||
attribute(:redirect_port, kind_of: Integer)
|
||||
attribute(:description, kind_of: String, name_attribute: true)
|
||||
attribute(:include_comment, kind_of: [TrueClass, FalseClass], default: true)
|
||||
|
||||
# only used for firewalld
|
||||
attribute(:permanent, kind_of: [TrueClass, FalseClass], default: false)
|
||||
|
||||
# only used for Windows Firewalls
|
||||
attribute(:program, kind_of: String)
|
||||
attribute(:service, kind_of: String)
|
||||
|
||||
# for when you just want to pass a raw rule
|
||||
attribute(:raw, kind_of: String)
|
||||
|
||||
# do you want this rule to notify the firewall to recalculate
|
||||
# (and potentially reapply) the firewall_rule(s) it finds?
|
||||
attribute(:notify_firewall, kind_of: [TrueClass, FalseClass], default: true)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user