cloud-mu 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Berksfile +2 -1
- data/bin/mu-upload-chef-artifacts +3 -0
- data/cloud-mu.gemspec +2 -2
- data/cookbooks/firewall/CHANGELOG.md +295 -0
- data/cookbooks/firewall/CONTRIBUTING.md +2 -0
- data/cookbooks/firewall/MAINTAINERS.md +19 -0
- data/cookbooks/firewall/README.md +339 -0
- data/cookbooks/firewall/attributes/default.rb +5 -0
- data/cookbooks/firewall/attributes/firewalld.rb +1 -0
- data/cookbooks/firewall/attributes/iptables.rb +17 -0
- data/cookbooks/firewall/attributes/ufw.rb +12 -0
- data/cookbooks/firewall/attributes/windows.rb +8 -0
- data/cookbooks/firewall/libraries/helpers.rb +100 -0
- data/cookbooks/firewall/libraries/helpers_firewalld.rb +116 -0
- data/cookbooks/firewall/libraries/helpers_iptables.rb +112 -0
- data/cookbooks/firewall/libraries/helpers_ufw.rb +135 -0
- data/cookbooks/firewall/libraries/helpers_windows.rb +130 -0
- data/cookbooks/firewall/libraries/matchers.rb +30 -0
- data/cookbooks/firewall/libraries/provider_firewall_firewalld.rb +179 -0
- data/cookbooks/firewall/libraries/provider_firewall_iptables.rb +171 -0
- data/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu.rb +196 -0
- data/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu1404.rb +196 -0
- data/cookbooks/firewall/libraries/provider_firewall_rule.rb +34 -0
- data/cookbooks/firewall/libraries/provider_firewall_ufw.rb +138 -0
- data/cookbooks/firewall/libraries/provider_firewall_windows.rb +126 -0
- data/cookbooks/firewall/libraries/resource_firewall.rb +26 -0
- data/cookbooks/firewall/libraries/resource_firewall_rule.rb +52 -0
- data/cookbooks/firewall/metadata.json +1 -0
- data/cookbooks/firewall/recipes/default.rb +80 -0
- data/cookbooks/firewall/recipes/disable_firewall.rb +23 -0
- data/cookbooks/firewall/templates/default/ufw/default.erb +13 -0
- data/cookbooks/mu-firewall/metadata.rb +1 -1
- data/cookbooks/mu-master/recipes/default.rb +3 -1
- data/cookbooks/mu-master/recipes/init.rb +3 -1
- data/cookbooks/mu-master/templates/default/mu.rc.erb +3 -0
- data/cookbooks/mu-tools/recipes/apply_security.rb +2 -2
- data/cookbooks/mu-tools/recipes/aws_api.rb +1 -1
- data/cookbooks/mu-tools/recipes/base_repositories.rb +1 -1
- data/cookbooks/mu-tools/recipes/clamav.rb +1 -1
- data/cookbooks/mu-tools/recipes/cloudinit.rb +1 -1
- data/cookbooks/mu-tools/recipes/disable-requiretty.rb +2 -2
- data/cookbooks/mu-tools/recipes/eks.rb +1 -1
- data/cookbooks/mu-tools/recipes/gcloud.rb +1 -1
- data/cookbooks/mu-tools/recipes/nrpe.rb +1 -1
- data/cookbooks/mu-tools/recipes/rsyslog.rb +2 -2
- data/cookbooks/mu-tools/recipes/set_local_fw.rb +37 -28
- data/environments/dev.json +1 -1
- data/environments/prod.json +1 -1
- data/modules/mu/cleanup.rb +4 -0
- data/modules/mu/clouds/aws/container_cluster.rb +3 -0
- data/modules/mu/clouds/aws/role.rb +14 -2
- data/modules/mu/clouds/aws/userdata/linux.erb +2 -3
- data/modules/mu/clouds/aws.rb +30 -14
- data/modules/mu.rb +4 -0
- metadata +30 -2
@@ -0,0 +1,112 @@
|
|
1
|
+
module FirewallCookbook
|
2
|
+
module Helpers
|
3
|
+
module Iptables
|
4
|
+
include FirewallCookbook::Helpers
|
5
|
+
include Chef::Mixin::ShellOut
|
6
|
+
|
7
|
+
CHAIN = { in: 'INPUT', out: 'OUTPUT', pre: 'PREROUTING', post: 'POSTROUTING' }.freeze unless defined? CHAIN # , nil => "FORWARD"}
|
8
|
+
TARGET = { allow: 'ACCEPT', reject: 'REJECT', deny: 'DROP', masquerade: 'MASQUERADE', redirect: 'REDIRECT', log: 'LOG --log-prefix "iptables: " --log-level 7' }.freeze unless defined? TARGET
|
9
|
+
|
10
|
+
def build_firewall_rule(current_node, rule_resource, ipv6 = false)
|
11
|
+
el5 = current_node['platform_family'] == 'rhel' && Gem::Dependency.new('', '~> 5.0').match?('', current_node['platform_version'])
|
12
|
+
|
13
|
+
return rule_resource.raw.strip if rule_resource.raw
|
14
|
+
firewall_rule = if rule_resource.direction
|
15
|
+
"-A #{CHAIN[rule_resource.direction.to_sym]} "
|
16
|
+
else
|
17
|
+
'-A FORWARD '
|
18
|
+
end
|
19
|
+
|
20
|
+
if [:pre, :post].include?(rule_resource.direction)
|
21
|
+
firewall_rule << '-t nat '
|
22
|
+
end
|
23
|
+
|
24
|
+
# Iptables order of prameters is important here see example output below:
|
25
|
+
# -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
|
26
|
+
firewall_rule << "-s #{ip_with_mask(rule_resource, rule_resource.source)} " if rule_resource.source && rule_resource.source != '0.0.0.0/0'
|
27
|
+
firewall_rule << "-d #{rule_resource.destination} " if rule_resource.destination
|
28
|
+
|
29
|
+
firewall_rule << "-i #{rule_resource.interface} " if rule_resource.interface
|
30
|
+
firewall_rule << "-o #{rule_resource.dest_interface} " if rule_resource.dest_interface
|
31
|
+
|
32
|
+
firewall_rule << "-p #{rule_resource.protocol} " if rule_resource.protocol && rule_resource.protocol.to_s.to_sym != :none
|
33
|
+
firewall_rule << '-m tcp ' if rule_resource.protocol && rule_resource.protocol.to_s.to_sym == :tcp
|
34
|
+
|
35
|
+
# using multiport here allows us to simplify our greps and rule building
|
36
|
+
firewall_rule << "-m multiport --sports #{port_to_s(rule_resource.source_port)} " if rule_resource.source_port
|
37
|
+
firewall_rule << "-m multiport --dports #{port_to_s(dport_calc(rule_resource))} " if dport_calc(rule_resource)
|
38
|
+
|
39
|
+
firewall_rule << "-m state --state #{rule_resource.stateful.is_a?(Array) ? rule_resource.stateful.join(',').upcase : rule_resource.stateful.upcase} " if rule_resource.stateful
|
40
|
+
# the comments extension is not available for ip6tables on rhel/centos 5
|
41
|
+
unless el5 && ipv6
|
42
|
+
firewall_rule << "-m comment --comment \"#{rule_resource.description}\" " if rule_resource.include_comment
|
43
|
+
end
|
44
|
+
|
45
|
+
firewall_rule << "-j #{TARGET[rule_resource.command.to_sym]} "
|
46
|
+
firewall_rule << "--to-ports #{rule_resource.redirect_port} " if rule_resource.command == :redirect
|
47
|
+
firewall_rule.strip!
|
48
|
+
firewall_rule
|
49
|
+
end
|
50
|
+
|
51
|
+
def iptables_packages(new_resource)
|
52
|
+
packages = if ipv6_enabled?(new_resource)
|
53
|
+
%w(iptables iptables-ipv6)
|
54
|
+
else
|
55
|
+
%w(iptables)
|
56
|
+
end
|
57
|
+
|
58
|
+
# centos 7 requires extra service
|
59
|
+
if !debian?(node) && node['platform_family'] != "amazon" && node['platform_version'].to_i >= 7
|
60
|
+
packages << %w(iptables-services)
|
61
|
+
end
|
62
|
+
|
63
|
+
packages.flatten
|
64
|
+
end
|
65
|
+
|
66
|
+
def iptables_commands(new_resource)
|
67
|
+
if ipv6_enabled?(new_resource)
|
68
|
+
%w(iptables ip6tables)
|
69
|
+
else
|
70
|
+
%w(iptables)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def log_iptables(new_resource)
|
75
|
+
iptables_commands(new_resource).each do |cmd|
|
76
|
+
shell_out!("#{cmd} -L -n")
|
77
|
+
end
|
78
|
+
rescue
|
79
|
+
Chef::Log.info('log_iptables failed!')
|
80
|
+
end
|
81
|
+
|
82
|
+
def iptables_flush!(new_resource)
|
83
|
+
iptables_commands(new_resource).each do |cmd|
|
84
|
+
shell_out!("#{cmd} -F")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def iptables_default_allow!(new_resource)
|
89
|
+
iptables_commands(new_resource).each do |cmd|
|
90
|
+
shell_out!("#{cmd} -P INPUT ACCEPT")
|
91
|
+
shell_out!("#{cmd} -P OUTPUT ACCEPT")
|
92
|
+
shell_out!("#{cmd} -P FORWARD ACCEPT")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def default_ruleset(current_node)
|
97
|
+
current_node['firewall']['iptables']['defaults'][:ruleset].to_h
|
98
|
+
end
|
99
|
+
|
100
|
+
def ensure_default_rules_exist(current_node, new_resource)
|
101
|
+
input = new_resource.rules
|
102
|
+
|
103
|
+
# don't use iptables_commands here since we do populate the
|
104
|
+
# hash regardless of ipv6 status
|
105
|
+
%w(iptables ip6tables).each do |name|
|
106
|
+
input[name] = {} unless input[name]
|
107
|
+
input[name].merge!(default_ruleset(current_node).to_h)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module FirewallCookbook
|
2
|
+
module Helpers
|
3
|
+
module Ufw
|
4
|
+
include FirewallCookbook::Helpers
|
5
|
+
include Chef::Mixin::ShellOut
|
6
|
+
|
7
|
+
def ufw_rules_filename
|
8
|
+
'/etc/default/ufw-chef.rules'
|
9
|
+
end
|
10
|
+
|
11
|
+
def ufw_active?
|
12
|
+
cmd = shell_out!('ufw', 'status')
|
13
|
+
cmd.stdout =~ /^Status:\sactive/
|
14
|
+
end
|
15
|
+
|
16
|
+
def ufw_disable!
|
17
|
+
shell_out!('ufw', 'disable', input: 'yes')
|
18
|
+
end
|
19
|
+
|
20
|
+
def ufw_enable!
|
21
|
+
shell_out!('ufw', 'enable', input: 'yes')
|
22
|
+
end
|
23
|
+
|
24
|
+
def ufw_reset!
|
25
|
+
shell_out!('ufw', 'reset', input: 'yes')
|
26
|
+
end
|
27
|
+
|
28
|
+
def ufw_logging!(param)
|
29
|
+
shell_out!('ufw', 'logging', param.to_s)
|
30
|
+
end
|
31
|
+
|
32
|
+
def ufw_rule!(cmd)
|
33
|
+
shell_out!(cmd, input: 'yes')
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_rule(new_resource)
|
37
|
+
Chef::Log.info("#{new_resource.name} apply_rule #{new_resource.command}")
|
38
|
+
|
39
|
+
# 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
|
40
|
+
if new_resource.stateful
|
41
|
+
msg = ''
|
42
|
+
msg << "firewall_rule[#{new_resource.name}] was asked to "
|
43
|
+
msg << "#{new_resource.command} a stateful rule using #{new_resource.stateful} "
|
44
|
+
msg << 'but ufw does not support this kind of rule. Consider guarding by platform_family.'
|
45
|
+
raise msg
|
46
|
+
end
|
47
|
+
|
48
|
+
# 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
|
49
|
+
if new_resource.protocol && !new_resource.protocol.to_s.downcase.match('^(tcp|udp|esp|ah|ipv6|none)$')
|
50
|
+
msg = ''
|
51
|
+
msg << "firewall_rule[#{new_resource.name}] was asked to "
|
52
|
+
msg << "#{new_resource.command} a rule using protocol #{new_resource.protocol} "
|
53
|
+
msg << 'but ufw does not support this kind of rule. Consider guarding by platform_family.'
|
54
|
+
raise msg
|
55
|
+
end
|
56
|
+
|
57
|
+
# some examples:
|
58
|
+
# ufw allow from 192.168.0.4 to any port 22
|
59
|
+
# ufw deny proto tcp from 10.0.0.0/8 to 192.168.0.1 port 25
|
60
|
+
# ufw insert 1 allow proto tcp from 0.0.0.0/0 to 192.168.0.1 port 25
|
61
|
+
|
62
|
+
if new_resource.raw
|
63
|
+
"ufw #{new_resource.raw.strip}"
|
64
|
+
else
|
65
|
+
"ufw #{rule(new_resource)}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def rule(new_resource)
|
70
|
+
rule = ''
|
71
|
+
rule << "#{new_resource.command} "
|
72
|
+
rule << rule_interface(new_resource)
|
73
|
+
rule << rule_logging(new_resource)
|
74
|
+
rule << rule_proto(new_resource)
|
75
|
+
rule << rule_dest_port(new_resource)
|
76
|
+
rule << rule_source_port(new_resource)
|
77
|
+
rule = rule.strip
|
78
|
+
|
79
|
+
if rule == 'ufw allow in proto tcp to any from any'
|
80
|
+
Chef::Log.warn("firewall_rule[#{new_resource.name}] produced a rule that opens all traffic. This may be a logic error in your cookbook.")
|
81
|
+
end
|
82
|
+
|
83
|
+
rule
|
84
|
+
end
|
85
|
+
|
86
|
+
def rule_interface(new_resource)
|
87
|
+
rule = ''
|
88
|
+
rule << "#{new_resource.direction} " if new_resource.direction
|
89
|
+
rule << "on #{new_resource.interface} " if new_resource.interface && new_resource.direction
|
90
|
+
rule << "in on #{new_resource.interface} " if new_resource.interface && !new_resource.direction
|
91
|
+
rule
|
92
|
+
end
|
93
|
+
|
94
|
+
def rule_proto(new_resource)
|
95
|
+
rule = ''
|
96
|
+
rule << "proto #{new_resource.protocol} " if new_resource.protocol && new_resource.protocol.to_s.to_sym != :none
|
97
|
+
rule
|
98
|
+
end
|
99
|
+
|
100
|
+
def rule_dest_port(new_resource)
|
101
|
+
rule = if new_resource.destination
|
102
|
+
"to #{new_resource.destination} "
|
103
|
+
else
|
104
|
+
'to any '
|
105
|
+
end
|
106
|
+
rule << "port #{port_to_s(dport_calc(new_resource))} " if dport_calc(new_resource)
|
107
|
+
rule
|
108
|
+
end
|
109
|
+
|
110
|
+
def rule_source_port(new_resource)
|
111
|
+
rule = if new_resource.source
|
112
|
+
"from #{new_resource.source} "
|
113
|
+
else
|
114
|
+
'from any '
|
115
|
+
end
|
116
|
+
|
117
|
+
if new_resource.source_port
|
118
|
+
rule << "port #{port_to_s(new_resource.source_port)} "
|
119
|
+
end
|
120
|
+
rule
|
121
|
+
end
|
122
|
+
|
123
|
+
def rule_logging(new_resource)
|
124
|
+
case new_resource.logging && new_resource.logging.to_sym
|
125
|
+
when :connections
|
126
|
+
'log '
|
127
|
+
when :packets
|
128
|
+
'log-all '
|
129
|
+
else
|
130
|
+
''
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module FirewallCookbook
|
2
|
+
module Helpers
|
3
|
+
module Windows
|
4
|
+
include FirewallCookbook::Helpers
|
5
|
+
include Chef::Mixin::ShellOut
|
6
|
+
|
7
|
+
def fixup_cidr(str)
|
8
|
+
newstr = str.clone
|
9
|
+
newstr.gsub!('0.0.0.0/0', 'any') if newstr.include?('0.0.0.0/0')
|
10
|
+
newstr.gsub!('/0', '') if newstr.include?('/0')
|
11
|
+
newstr
|
12
|
+
end
|
13
|
+
|
14
|
+
def windows_rules_filename
|
15
|
+
"#{ENV['HOME']}/windows-chef.rules"
|
16
|
+
end
|
17
|
+
|
18
|
+
def active?
|
19
|
+
@active ||= begin
|
20
|
+
cmd = shell_out!('netsh advfirewall show currentprofile')
|
21
|
+
cmd.stdout =~ /^State\sON/
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def enable!
|
26
|
+
shell_out!('netsh advfirewall set currentprofile state on')
|
27
|
+
end
|
28
|
+
|
29
|
+
def disable!
|
30
|
+
shell_out!('netsh advfirewall set currentprofile state off')
|
31
|
+
end
|
32
|
+
|
33
|
+
def reset!
|
34
|
+
shell_out!('netsh advfirewall reset')
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_rule!(params)
|
38
|
+
shell_out!("netsh advfirewall #{params}")
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete_all_rules!
|
42
|
+
shell_out!('netsh advfirewall firewall delete rule name=all')
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_type(new_resource)
|
46
|
+
cmd = new_resource.command
|
47
|
+
type = if cmd == :reject || cmd == :deny
|
48
|
+
:block
|
49
|
+
else
|
50
|
+
:allow
|
51
|
+
end
|
52
|
+
type
|
53
|
+
end
|
54
|
+
|
55
|
+
def build_rule(new_resource)
|
56
|
+
type = to_type(new_resource)
|
57
|
+
parameters = {}
|
58
|
+
|
59
|
+
parameters['description'] = "\"#{new_resource.description}\""
|
60
|
+
parameters['dir'] = new_resource.direction
|
61
|
+
|
62
|
+
new_resource.program && parameters['program'] = new_resource.program
|
63
|
+
new_resource.service && parameters['service'] = new_resource.service
|
64
|
+
parameters['protocol'] = new_resource.protocol
|
65
|
+
|
66
|
+
if new_resource.direction.to_sym == :out
|
67
|
+
parameters['localip'] = new_resource.source ? fixup_cidr(new_resource.source) : 'any'
|
68
|
+
parameters['localport'] = new_resource.source_port ? port_to_s(new_resource.source_port) : 'any'
|
69
|
+
parameters['interfacetype'] = new_resource.interface ? new_resource.interface : 'any'
|
70
|
+
parameters['remoteip'] = new_resource.destination ? fixup_cidr(new_resource.destination) : 'any'
|
71
|
+
parameters['remoteport'] = new_resource.dest_port ? port_to_s(new_resource.dest_port) : 'any'
|
72
|
+
else
|
73
|
+
parameters['localip'] = new_resource.destination ? new_resource.destination : 'any'
|
74
|
+
parameters['localport'] = dport_calc(new_resource) ? port_to_s(dport_calc(new_resource)) : 'any'
|
75
|
+
parameters['interfacetype'] = new_resource.dest_interface ? new_resource.dest_interface : 'any'
|
76
|
+
parameters['remoteip'] = new_resource.source ? fixup_cidr(new_resource.source) : 'any'
|
77
|
+
parameters['remoteport'] = new_resource.source_port ? port_to_s(new_resource.source_port) : 'any'
|
78
|
+
end
|
79
|
+
|
80
|
+
parameters['action'] = type.to_s
|
81
|
+
|
82
|
+
partial_command = parameters.map { |k, v| "#{k}=#{v}" }.join(' ')
|
83
|
+
"firewall add rule name=\"#{new_resource.name}\" #{partial_command}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def rule_exists?(name)
|
87
|
+
@exists ||= begin
|
88
|
+
cmd = shell_out!("netsh advfirewall firewall show rule name=\"#{name}\"", returns: [0, 1])
|
89
|
+
cmd.stdout !~ /^No rules match the specified criteria/
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def show_all_rules!
|
94
|
+
cmd = shell_out!('netsh advfirewall firewall show rule name=all')
|
95
|
+
cmd.stdout.each_line do |line|
|
96
|
+
Chef::Log.warn(line)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def rule_up_to_date?(name, type)
|
101
|
+
@up_to_date ||= begin
|
102
|
+
desired_parameters = rule_parameters(type)
|
103
|
+
current_parameters = {}
|
104
|
+
|
105
|
+
cmd = shell_out!("netsh advfirewall firewall show rule name=\"#{name}\" verbose")
|
106
|
+
cmd.stdout.each_line do |line|
|
107
|
+
current_parameters['description'] = "\"#{Regexp.last_match(1).chomp}\"" if line =~ /^Description:\s+(.*)$/
|
108
|
+
current_parameters['dir'] = Regexp.last_match(1).chomp if line =~ /^Direction:\s+(.*)$/
|
109
|
+
current_parameters['program'] = Regexp.last_match(1).chomp if line =~ /^Program:\s+(.*)$/
|
110
|
+
current_parameters['service'] = Regexp.last_match(1).chomp if line =~ /^Service:\s+(.*)$/
|
111
|
+
current_parameters['protocol'] = Regexp.last_match(1).chomp if line =~ /^Protocol:\s+(.*)$/
|
112
|
+
current_parameters['localip'] = Regexp.last_match(1).chomp if line =~ /^LocalIP:\s+(.*)$/
|
113
|
+
current_parameters['localport'] = Regexp.last_match(1).chomp if line =~ /^LocalPort:\s+(.*)$/
|
114
|
+
current_parameters['interfacetype'] = Regexp.last_match(1).chomp if line =~ /^InterfaceTypes:\s+(.*)$/
|
115
|
+
current_parameters['remoteip'] = Regexp.last_match(1).chomp if line =~ /^RemoteIP:\s+(.*)$/
|
116
|
+
current_parameters['remoteport'] = Regexp.last_match(1).chomp if line =~ /^RemotePort:\s+(.*)$/
|
117
|
+
current_parameters['action'] = Regexp.last_match(1).chomp if line =~ /^Action:\s+(.*)$/
|
118
|
+
end
|
119
|
+
|
120
|
+
up_to_date = true
|
121
|
+
desired_parameters.each do |k, v|
|
122
|
+
up_to_date = false if current_parameters[k] !~ /^["]?#{v}["]?$/i
|
123
|
+
end
|
124
|
+
|
125
|
+
up_to_date
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
if defined?(ChefSpec)
|
2
|
+
ChefSpec.define_matcher(:firewall)
|
3
|
+
ChefSpec.define_matcher(:firewall_rule)
|
4
|
+
|
5
|
+
# actions(:install, :restart, :disable, :flush, :save)
|
6
|
+
|
7
|
+
def install_firewall(resource)
|
8
|
+
ChefSpec::Matchers::ResourceMatcher.new(:firewall, :install, resource)
|
9
|
+
end
|
10
|
+
|
11
|
+
def restart_firewall(resource)
|
12
|
+
ChefSpec::Matchers::ResourceMatcher.new(:firewall, :restart, resource)
|
13
|
+
end
|
14
|
+
|
15
|
+
def disable_firewall(resource)
|
16
|
+
ChefSpec::Matchers::ResourceMatcher.new(:firewall, :disable, resource)
|
17
|
+
end
|
18
|
+
|
19
|
+
def flush_firewall(resource)
|
20
|
+
ChefSpec::Matchers::ResourceMatcher.new(:firewall, :flush, resource)
|
21
|
+
end
|
22
|
+
|
23
|
+
def save_firewall(resource)
|
24
|
+
ChefSpec::Matchers::ResourceMatcher.new(:firewall, :save, resource)
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_firewall_rule(resource)
|
28
|
+
ChefSpec::Matchers::ResourceMatcher.new(:firewall_rule, :create, resource)
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Ronald Doorn (<rdoorn@schubergphilis.com>)
|
3
|
+
# Cookbook:: firewall
|
4
|
+
# Resource:: default
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
class Chef
|
19
|
+
class Provider::FirewallFirewalld < Chef::Provider::LWRPBase
|
20
|
+
include FirewallCookbook::Helpers::Firewalld
|
21
|
+
|
22
|
+
provides :firewall, os: 'linux', platform_family: %w(rhel fedora) do |node|
|
23
|
+
node['platform_version'].to_f >= 7.0 && !node['firewall']['redhat7_iptables']
|
24
|
+
end
|
25
|
+
|
26
|
+
def whyrun_supported?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
30
|
+
def action_install
|
31
|
+
return if disabled?(new_resource)
|
32
|
+
|
33
|
+
firewalld_package = package 'firewalld' do
|
34
|
+
action :nothing
|
35
|
+
options new_resource.package_options
|
36
|
+
end
|
37
|
+
firewalld_package.run_action(:install)
|
38
|
+
new_resource.updated_by_last_action(firewalld_package.updated_by_last_action?)
|
39
|
+
|
40
|
+
unless ::File.exist?(firewalld_rules_filename)
|
41
|
+
rules_file = lookup_or_create_rulesfile
|
42
|
+
rules_file.content '# created by chef to allow service to start'
|
43
|
+
rules_file.run_action(:create)
|
44
|
+
new_resource.updated_by_last_action(rules_file.updated_by_last_action?)
|
45
|
+
end
|
46
|
+
|
47
|
+
firewalld_service = lookup_or_create_service
|
48
|
+
[:enable, :start].each do |a|
|
49
|
+
firewalld_service.run_action(a)
|
50
|
+
new_resource.updated_by_last_action(firewalld_service.updated_by_last_action?)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def action_restart
|
55
|
+
return if disabled?(new_resource)
|
56
|
+
|
57
|
+
# ensure it's initialized
|
58
|
+
new_resource.rules({}) unless new_resource.rules
|
59
|
+
new_resource.rules['firewalld'] = {} unless new_resource.rules['firewalld']
|
60
|
+
|
61
|
+
# this populates the hash of rules from firewall_rule resources
|
62
|
+
firewall_rules = Chef.run_context.resource_collection.select { |item| item.is_a?(Chef::Resource::FirewallRule) }
|
63
|
+
firewall_rules.each do |firewall_rule|
|
64
|
+
next unless firewall_rule.action.include?(:create) && !firewall_rule.should_skip?(:create)
|
65
|
+
|
66
|
+
ip_versions(firewall_rule).each do |ip_version|
|
67
|
+
# build rules to apply with weight
|
68
|
+
k = "firewall-cmd --direct --add-rule #{build_firewall_rule(firewall_rule, ip_version)}"
|
69
|
+
v = firewall_rule.position
|
70
|
+
|
71
|
+
# unless we're adding them for the first time.... bail out.
|
72
|
+
next if new_resource.rules['firewalld'].key?(k) && new_resource.rules['firewalld'][k] == v
|
73
|
+
new_resource.rules['firewalld'][k] = v
|
74
|
+
|
75
|
+
# If persistent rules is enabled (default) make sure we add a permanent rule at the same time
|
76
|
+
perm_rules = node && node['firewall'] && node['firewall']['firewalld'] && node['firewall']['firewalld']['permanent']
|
77
|
+
if firewall_rule.permanent || perm_rules
|
78
|
+
k = "firewall-cmd --permanent --direct --add-rule #{build_firewall_rule(firewall_rule, ip_version)}"
|
79
|
+
new_resource.rules['firewalld'][k] = v
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# ensure a file resource exists with the current firewalld rules
|
85
|
+
rules_file = lookup_or_create_rulesfile
|
86
|
+
rules_file.content build_rule_file(new_resource.rules['firewalld'])
|
87
|
+
rules_file.run_action(:create)
|
88
|
+
|
89
|
+
# ensure the service is running without waiting.
|
90
|
+
firewalld_service = lookup_or_create_service
|
91
|
+
[:enable, :start].each do |a|
|
92
|
+
firewalld_service.run_action(a)
|
93
|
+
new_resource.updated_by_last_action(firewalld_service.updated_by_last_action?)
|
94
|
+
end
|
95
|
+
|
96
|
+
# mark updated if we changed the zone
|
97
|
+
unless firewalld_default_zone?(new_resource.enabled_zone)
|
98
|
+
firewalld_default_zone!(new_resource.enabled_zone)
|
99
|
+
new_resource.updated_by_last_action(true)
|
100
|
+
end
|
101
|
+
|
102
|
+
# if the file was changed, load new ruleset
|
103
|
+
return unless rules_file.updated_by_last_action?
|
104
|
+
firewalld_flush!
|
105
|
+
# TODO: support logging
|
106
|
+
|
107
|
+
new_resource.rules['firewalld'].sort_by { |_k, v| v }.map { |k, _v| k }.each do |cmd|
|
108
|
+
firewalld_rule!(cmd)
|
109
|
+
end
|
110
|
+
|
111
|
+
new_resource.updated_by_last_action(true)
|
112
|
+
end
|
113
|
+
|
114
|
+
def action_disable
|
115
|
+
return if disabled?(new_resource)
|
116
|
+
|
117
|
+
if firewalld_active?
|
118
|
+
firewalld_flush!
|
119
|
+
firewalld_default_zone!(new_resource.disabled_zone)
|
120
|
+
new_resource.updated_by_last_action(true)
|
121
|
+
end
|
122
|
+
|
123
|
+
# ensure the service is stopped without waiting.
|
124
|
+
firewalld_service = lookup_or_create_service
|
125
|
+
[:disable, :stop].each do |a|
|
126
|
+
firewalld_service.run_action(a)
|
127
|
+
new_resource.updated_by_last_action(firewalld_service.updated_by_last_action?)
|
128
|
+
end
|
129
|
+
|
130
|
+
rules_file = lookup_or_create_rulesfile
|
131
|
+
rules_file.content '# created by chef to allow service to start'
|
132
|
+
rules_file.run_action(:create)
|
133
|
+
new_resource.updated_by_last_action(rules_file.updated_by_last_action?)
|
134
|
+
end
|
135
|
+
|
136
|
+
def action_flush
|
137
|
+
return if disabled?(new_resource)
|
138
|
+
return unless firewalld_active?
|
139
|
+
|
140
|
+
firewalld_flush!
|
141
|
+
new_resource.updated_by_last_action(true)
|
142
|
+
|
143
|
+
rules_file = lookup_or_create_rulesfile
|
144
|
+
rules_file.content '# created by chef to allow service to start'
|
145
|
+
rules_file.run_action(:create)
|
146
|
+
new_resource.updated_by_last_action(rules_file.updated_by_last_action?)
|
147
|
+
end
|
148
|
+
|
149
|
+
def action_save
|
150
|
+
return if disabled?(new_resource)
|
151
|
+
return if firewalld_all_rules_permanent!
|
152
|
+
|
153
|
+
firewalld_save!
|
154
|
+
new_resource.updated_by_last_action(true)
|
155
|
+
end
|
156
|
+
|
157
|
+
def lookup_or_create_service
|
158
|
+
begin
|
159
|
+
firewalld_service = Chef.run_context.resource_collection.find(service: 'firewalld')
|
160
|
+
rescue
|
161
|
+
firewalld_service = service 'firewalld' do
|
162
|
+
action :nothing
|
163
|
+
end
|
164
|
+
end
|
165
|
+
firewalld_service
|
166
|
+
end
|
167
|
+
|
168
|
+
def lookup_or_create_rulesfile
|
169
|
+
begin
|
170
|
+
firewalld_file = Chef.run_context.resource_collection.find(file: firewalld_rules_filename)
|
171
|
+
rescue
|
172
|
+
firewalld_file = file firewalld_rules_filename do
|
173
|
+
action :nothing
|
174
|
+
end
|
175
|
+
end
|
176
|
+
firewalld_file
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|