diff --git a/.foodcritic b/.foodcritic new file mode 100644 index 00000000..b56b3539 --- /dev/null +++ b/.foodcritic @@ -0,0 +1,3 @@ +~FC001 +~FC057 +~FC019 diff --git a/.kitchen.yml b/.kitchen.yml index e75693ca..1d26c455 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -3,7 +3,7 @@ driver: provisioner: name: chef_zero - require_chef_omnibus: 12.8.1 + require_chef_omnibus: 13.0.118 attributes: firewall: allow_ssh: true @@ -12,7 +12,6 @@ provisioner: permanent: true platforms: - - name: centos-5.11 - name: centos-6.8 - name: centos-7.2 - name: debian-7.11 @@ -21,9 +20,6 @@ platforms: - name: debian-8.6 run_list: - recipe[apt] - - name: ubuntu-12.04 - run_list: - - recipe[apt::default] - name: ubuntu-14.04 run_list: - recipe[apt::default] @@ -31,8 +27,6 @@ platforms: run_list: - recipe[apt::default] - name: windows-2012r2 - driver_config: - box: windows2012r2 suites: - name: default diff --git a/Gemfile b/Gemfile index 8526b466..f15ac1a4 100644 --- a/Gemfile +++ b/Gemfile @@ -1,29 +1,29 @@ source 'https://rubygems.org' group :lint do - gem 'foodcritic', '~> 5.0' - gem 'rubocop', '~> 0.34' - gem 'cookstyle', '~> 0.0.1' + gem 'cookstyle', '~> 1.3' + gem 'foodcritic', '~> 10.3' + gem 'rubocop', '~> 0.47' end group :unit do - gem 'berkshelf', '~> 4.0' - gem 'chefspec' + gem 'berkshelf', '~> 5.6' + gem 'chef', '>= 13' gem 'chef-sugar' - gem 'chef', '>= 12' + gem 'chefspec' end group :kitchen_windows do - gem 'winrm-transport' - gem 'winrm-fs', '~> 0.4.1' + gem 'winrm', '~> 2.0' + gem 'winrm-fs', '~> 1.0' end group :kitchen_common do - gem 'test-kitchen', '~> 1.4' + gem 'test-kitchen', '~> 1.16' end group :kitchen_vagrant do - gem 'kitchen-vagrant', '~> 0.19' + gem 'kitchen-vagrant', '~> 1.1' gem 'vagrant-wrapper' end @@ -33,14 +33,14 @@ group :kitchen_cloud do end group :development do - gem 'ruby_gntp' gem 'growl' - gem 'rb-fsevent' gem 'guard' - gem 'guard-kitchen' gem 'guard-foodcritic' + gem 'guard-kitchen' gem 'guard-rspec' gem 'guard-rubocop' gem 'rake', '~> 11.0' + gem 'rb-fsevent' + gem 'ruby_gntp' gem 'stove' end diff --git a/attributes/iptables.rb b/attributes/iptables.rb index 32113fc3..f26ac551 100644 --- a/attributes/iptables.rb +++ b/attributes/iptables.rb @@ -1,14 +1,14 @@ default['firewall']['iptables']['defaults'][:policy] = { input: 'DROP', forward: 'DROP', - output: 'ACCEPT' + output: 'ACCEPT', } default['firewall']['iptables']['defaults'][:ruleset] = { '*filter' => 1, ":INPUT #{node['firewall']['iptables']['defaults'][:policy][:input]}" => 2, ":FORWARD #{node['firewall']['iptables']['defaults'][:policy][:forward]}" => 3, ":OUTPUT #{node['firewall']['iptables']['defaults'][:policy][:output]}" => 4, - 'COMMIT_FILTER' => 100 + 'COMMIT_FILTER' => 100, } default['firewall']['ubuntu_iptables'] = false diff --git a/attributes/ufw.rb b/attributes/ufw.rb index 957613a4..35c8366b 100644 --- a/attributes/ufw.rb +++ b/attributes/ufw.rb @@ -7,6 +7,6 @@ input: 'DROP', output: 'ACCEPT', forward: 'DROP', - application: 'SKIP' - } + application: 'SKIP', + }, } diff --git a/attributes/windows.rb b/attributes/windows.rb index 68c6c05a..382dd82a 100644 --- a/attributes/windows.rb +++ b/attributes/windows.rb @@ -3,6 +3,6 @@ default['firewall']['windows']['defaults'] = { policy: { input: 'blockinbound', - output: 'allowoutbound' - } + output: 'allowoutbound', + }, } diff --git a/libraries/helpers_firewalld.rb b/libraries/helpers_firewalld.rb index aa3019fb..20330331 100644 --- a/libraries/helpers_firewalld.rb +++ b/libraries/helpers_firewalld.rb @@ -18,14 +18,14 @@ def firewalld_active? end def firewalld_default_zone?(z) - raise false unless firewalld_active? + 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 'firewall not active' unless firewalld_active? + raise 'firewalld not active' unless firewalld_active? shell_out!('firewall-cmd', "--set-default-zone=#{z}") end diff --git a/libraries/provider_firewall_firewalld.rb b/libraries/provider_firewall_firewalld.rb index 0a9fb40a..b8fc8c52 100644 --- a/libraries/provider_firewall_firewalld.rb +++ b/libraries/provider_firewall_firewalld.rb @@ -27,36 +27,39 @@ def whyrun_supported? false end - action :install do - next if disabled?(new_resource) + def action_install + return if disabled?(new_resource) - converge_by('install firewalld, create template for /etc/sysconfig') do - package 'firewalld' do - action :install - options new_resource.package_options - end - - service 'firewalld' do - action [:enable, :start] - end + 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 - file "create empty #{firewalld_rules_filename}" do - path firewalld_rules_filename - content '# created by chef to allow service to start' - not_if { ::File.exist?(firewalld_rules_filename) } - 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 - action :restart do - next if disabled?(new_resource) + 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 = run_context.resource_collection.select { |item| item.is_a?(Chef::Resource::FirewallRule) } + 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) @@ -79,23 +82,15 @@ def whyrun_supported? end # ensure a file resource exists with the current firewalld rules - begin - firewalld_file = run_context.resource_collection.find(file: firewalld_rules_filename) - rescue - firewalld_file = file firewalld_rules_filename do - action :nothing - end - end - firewalld_file.content build_rule_file(new_resource.rules['firewalld']) - firewalld_file.run_action(:create) + 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. - firewall_service = service 'firewalld' do - action :nothing - end + firewalld_service = lookup_or_create_service [:enable, :start].each do |a| - firewall_service.run_action(a) - new_resource.updated_by_last_action(firewall_service.updated_by_last_action?) + 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 @@ -105,20 +100,19 @@ def whyrun_supported? end # if the file was changed, load new ruleset - if firewalld_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 + return unless rules_file.updated_by_last_action? + firewalld_flush! + # TODO: support logging - new_resource.updated_by_last_action(true) + 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 - action :disable do - next if disabled?(new_resource) + def action_disable + return if disabled?(new_resource) if firewalld_active? firewalld_flush! @@ -126,38 +120,60 @@ def whyrun_supported? new_resource.updated_by_last_action(true) end - service 'firewalld' do - action [:disable, :stop] + # 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 - file "create empty #{firewalld_rules_filename}" do - path firewalld_rules_filename - content '# created by chef to allow service to start' - action :create - 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 - action :flush do - next if disabled?(new_resource) - next unless firewalld_active? + def action_flush + return if disabled?(new_resource) + return unless firewalld_active? firewalld_flush! new_resource.updated_by_last_action(true) - file "create empty #{firewalld_rules_filename}" do - path firewalld_rules_filename - content '# created by chef to allow service to start' - action :create - 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 - action :save do - next if disabled?(new_resource) + def action_save + return if disabled?(new_resource) + return if firewalld_all_rules_permanent! - unless firewalld_all_rules_permanent! - firewalld_save! - new_resource.updated_by_last_action(true) + 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 diff --git a/libraries/provider_firewall_iptables.rb b/libraries/provider_firewall_iptables.rb index afa90af7..6c1cb81e 100644 --- a/libraries/provider_firewall_iptables.rb +++ b/libraries/provider_firewall_iptables.rb @@ -30,34 +30,38 @@ def whyrun_supported? false end - action :install do - next if disabled?(new_resource) - - converge_by('install iptables and enable/start services') do - # can't pass an array without breaking chef 11 support - iptables_packages(new_resource).each do |p| - package p do - action :install - 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| + 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 - file "create empty /etc/sysconfig/#{svc}" do - path "/etc/sysconfig/#{svc}" - content '# created by chef to allow service to start' - not_if { ::File.exist?("/etc/sysconfig/#{svc}") } - end - - service svc do - action [:enable, :start] - end + 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 - action :restart do - next if disabled?(new_resource) + def action_restart + return if disabled?(new_resource) # prints all the firewall rules log_iptables(new_resource) @@ -67,7 +71,7 @@ def whyrun_supported? ensure_default_rules_exist(node, new_resource) # this populates the hash of rules from firewall_rule resources - firewall_rules = run_context.resource_collection.select { |item| item.is_a?(Chef::Resource::FirewallRule) } + 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) @@ -91,65 +95,77 @@ def whyrun_supported? end iptables_commands(new_resource).each do |iptables_type| - iptables_filename = "/etc/sysconfig/#{iptables_type}" - # ensure a file resource exists with the current iptables rules - begin - iptables_file = run_context.resource_collection.find(file: iptables_filename) - rescue - iptables_file = file iptables_filename do - action :nothing - end - end - # 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? - service_affected = service iptables_type do - action :nothing - end - - new_resource.notifies(:restart, service_affected, :delayed) + iptables_service = lookup_or_create_service(iptables_type) + new_resource.notifies(:restart, iptables_service, :delayed) new_resource.updated_by_last_action(true) end end - action :disable do - next if disabled?(new_resource) + 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| - service svc do - action [:disable, :stop] + 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 - file "create empty /etc/sysconfig/#{svc}" do - path "/etc/sysconfig/#{svc}" - content '# created by chef to allow service to start' - end + 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 - action :flush do - next if disabled?(new_resource) + 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 - file "create empty /etc/sysconfig/#{svc}" do - path "/etc/sysconfig/#{svc}" - content '# created by chef to allow 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 diff --git a/libraries/provider_firewall_iptables_ubuntu.rb b/libraries/provider_firewall_iptables_ubuntu.rb index 44919917..c89320de 100644 --- a/libraries/provider_firewall_iptables_ubuntu.rb +++ b/libraries/provider_firewall_iptables_ubuntu.rb @@ -30,37 +30,41 @@ def whyrun_supported? false end - action :install do - next if disabled?(new_resource) - - converge_by('install iptables and enable/start services') do - # Can't pass an array without breaking chef 11 support - %w(iptables-persistent).each do |p| - package p do - action :install - end - end + def action_install + return if disabled?(new_resource) - 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 - file "create empty /etc/iptables/#{svc}" do - path "/etc/iptables/#{svc}" - content '# created by chef to allow service to start' - not_if { ::File.exist?("/etc/iptables/#{svc}") } - end - end + # 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? - service 'netfilter-persistent' do - action [:enable, :start] - status_command 'true' # netfilter-persistent isn't a real service - end + rule_files = %w(rules.v4) + rule_files << 'rules.v6' if ipv6_enabled?(new_resource) + rule_files.each do |svc| + next unless ::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 - action :restart do - next if disabled?(new_resource) + def action_restart + return if disabled?(new_resource) # prints all the firewall rules log_iptables(new_resource) @@ -70,7 +74,7 @@ def whyrun_supported? ensure_default_rules_exist(node, new_resource) # this populates the hash of rules from firewall_rule resources - firewall_rules = run_context.resource_collection.select { |item| item.is_a?(Chef::Resource::FirewallRule) } + 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) @@ -105,7 +109,7 @@ def whyrun_supported? # ensure a file resource exists with the current iptables rules begin - iptables_file = run_context.resource_collection.find(file: iptables_filename) + iptables_file = Chef.run_context.resource_collection.find(file: iptables_filename) rescue iptables_file = file iptables_filename do action :nothing @@ -125,29 +129,31 @@ def whyrun_supported? end end - action :disable do - next if disabled?(new_resource) + def action_disable + return if disabled?(new_resource) iptables_flush!(new_resource) iptables_default_allow!(new_resource) new_resource.updated_by_last_action(true) - service 'netfilter-persistent' do - action [:disable, :stop] + 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 - file "create empty /etc/iptables/#{svc}" do - path "/etc/iptables/#{svc}" - content '# created by chef to allow service to start' - action :create - end + 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 - action :flush do - next if disabled?(new_resource) + def action_flush + return if disabled?(new_resource) iptables_flush!(new_resource) new_resource.updated_by_last_action(true) @@ -156,11 +162,34 @@ def whyrun_supported? rule_files << 'rules.v6' if ipv6_enabled?(new_resource) rule_files.each do |svc| # must create empty file for service to start - file "create empty /etc/iptables/#{svc}" do - path "/etc/iptables/#{svc}" - content '# created by chef to allow 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 diff --git a/libraries/provider_firewall_iptables_ubuntu1404.rb b/libraries/provider_firewall_iptables_ubuntu1404.rb index b4c0200f..8332be1a 100644 --- a/libraries/provider_firewall_iptables_ubuntu1404.rb +++ b/libraries/provider_firewall_iptables_ubuntu1404.rb @@ -30,37 +30,41 @@ def whyrun_supported? false end - action :install do - next if disabled?(new_resource) - - converge_by('install iptables and enable/start services') do - # Can't pass an array without breaking chef 11 support - %w(iptables-persistent).each do |p| - package p do - action :install - end - end + def action_install + return if disabled?(new_resource) - 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 - file "create empty /etc/iptables/#{svc}" do - path "/etc/iptables/#{svc}" - content '# created by chef to allow service to start' - not_if { ::File.exist?("/etc/iptables/#{svc}") } - end - end + # 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? - service 'iptables-persistent' do - action [:enable, :start] - status_command 'true' # iptables-persistent isn't a real service - end + rule_files = %w(rules.v4) + rule_files << 'rules.v6' if ipv6_enabled?(new_resource) + rule_files.each do |svc| + next unless ::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 - action :restart do - next if disabled?(new_resource) + def action_restart + return if disabled?(new_resource) # prints all the firewall rules log_iptables(new_resource) @@ -70,7 +74,7 @@ def whyrun_supported? ensure_default_rules_exist(node, new_resource) # this populates the hash of rules from firewall_rule resources - firewall_rules = run_context.resource_collection.select { |item| item.is_a?(Chef::Resource::FirewallRule) } + 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) @@ -105,7 +109,7 @@ def whyrun_supported? # ensure a file resource exists with the current iptables rules begin - iptables_file = run_context.resource_collection.find(file: iptables_filename) + iptables_file = Chef.run_context.resource_collection.find(file: iptables_filename) rescue iptables_file = file iptables_filename do action :nothing @@ -125,29 +129,31 @@ def whyrun_supported? end end - action :disable do - next if disabled?(new_resource) + def action_disable + return if disabled?(new_resource) iptables_flush!(new_resource) iptables_default_allow!(new_resource) new_resource.updated_by_last_action(true) - service 'iptables-persistent' do - action [:disable, :stop] + 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 - file "create empty /etc/iptables/#{svc}" do - path "/etc/iptables/#{svc}" - content '# created by chef to allow service to start' - action :create - end + 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 - action :flush do - next if disabled?(new_resource) + def action_flush + return if disabled?(new_resource) iptables_flush!(new_resource) new_resource.updated_by_last_action(true) @@ -156,11 +162,34 @@ def whyrun_supported? rule_files << 'rules.v6' if ipv6_enabled?(new_resource) rule_files.each do |svc| # must create empty file for service to start - file "create empty /etc/iptables/#{svc}" do - path "/etc/iptables/#{svc}" - content '# created by chef to allow 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 diff --git a/libraries/provider_firewall_rule.rb b/libraries/provider_firewall_rule.rb index f4486106..85a27c59 100644 --- a/libraries/provider_firewall_rule.rb +++ b/libraries/provider_firewall_rule.rb @@ -21,14 +21,14 @@ class Chef class Provider::FirewallRuleGeneric < Chef::Provider::LWRPBase provides :firewall_rule - action :create do - if new_resource.notify_firewall - firewall_resource = run_context.resource_collection.find(firewall: new_resource.firewall_name) - raise 'could not find a firewall resource' unless firewall_resource + def action_create + return unless new_resource.notify_firewall - new_resource.notifies(:restart, firewall_resource, :delayed) - new_resource.updated_by_last_action(true) - end + 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 diff --git a/libraries/provider_firewall_ufw.rb b/libraries/provider_firewall_ufw.rb index 25e5a127..cc1aeb73 100644 --- a/libraries/provider_firewall_ufw.rb +++ b/libraries/provider_firewall_ufw.rb @@ -29,40 +29,44 @@ def whyrun_supported? false end - action :install do - next if disabled?(new_resource) + def action_install + return if disabled?(new_resource) - converge_by('install ufw, create template for /etc/default') do - package 'ufw' do - action :install - end + 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? - template '/etc/default/ufw' do - action [:create] - owner 'root' - group 'root' - mode '0644' - source 'ufw/default.erb' - cookbook 'firewall' - end + return if ::File.exist?(ufw_rules_filename) - file "create empty #{ufw_rules_filename}" do - path ufw_rules_filename - content '# created by chef to allow service to start' - not_if { ::File.exist?(ufw_rules_filename) } - end - end + 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 - action :restart do - next if disabled?(new_resource) + 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 = run_context.resource_collection.select { |item| item.is_a?(Chef::Resource::FirewallRule) } + 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) @@ -77,55 +81,58 @@ def whyrun_supported? end # ensure a file resource exists with the current ufw rules - begin - ufw_file = run_context.resource_collection.find(file: ufw_rules_filename) - rescue - ufw_file = file ufw_rules_filename do - action :nothing - end - end + 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 - if 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 + return unless ufw_file.updated_by_last_action? + ufw_reset! + ufw_logging!(new_resource.log_level) if new_resource.log_level - # ensure it's enabled _after_ rules are inputted, to catch malformed rules - ufw_enable! unless ufw_active? - new_resource.updated_by_last_action(true) + 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 - action :disable do - next if disabled?(new_resource) + def action_disable + return if disabled?(new_resource) - file "create empty #{ufw_rules_filename}" do - path ufw_rules_filename - content '# created by chef to allow service to start' - end + 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? - if ufw_active? - ufw_disable! - new_resource.updated_by_last_action(true) - end + return unless ufw_active? + ufw_disable! + new_resource.updated_by_last_action(true) end - action :flush do - next if disabled?(new_resource) + def action_flush + return if disabled?(new_resource) ufw_reset! new_resource.updated_by_last_action(true) - file "create empty #{ufw_rules_filename}" do - path ufw_rules_filename - content '# created by chef to allow service to start' + 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 diff --git a/libraries/provider_firewall_windows.rb b/libraries/provider_firewall_windows.rb index 0d242b2c..d261f03e 100644 --- a/libraries/provider_firewall_windows.rb +++ b/libraries/provider_firewall_windows.rb @@ -26,8 +26,8 @@ def whyrun_supported? false end - action :install do - next if disabled?(new_resource) + def action_install + return if disabled?(new_resource) svc = service 'MpsSvc' do action :nothing @@ -39,14 +39,14 @@ def whyrun_supported? end end - action :restart do - next if disabled?(new_resource) + 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 = run_context.resource_collection.select { |item| item.is_a?(Chef::Resource::FirewallRule) } + 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) @@ -69,7 +69,7 @@ def whyrun_supported? # ensure a file resource exists with the current rules begin - windows_file = run_context.resource_collection.find(file: windows_rules_filename) + windows_file = Chef.run_context.resource_collection.find(file: windows_rules_filename) rescue windows_file = file windows_rules_filename do action :nothing @@ -79,23 +79,23 @@ def whyrun_supported? windows_file.run_action(:create) # if the file was changed, restart iptables - if windows_file.updated_by_last_action? - disable! if active? - delete_all_rules! # clear entirely - reset! # populate default rules + return unless windows_file.updated_by_last_action? - 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? + disable! if active? + delete_all_rules! # clear entirely + reset! # populate default rules - new_resource.updated_by_last_action(true) + 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 - action :disable do - next if disabled?(new_resource) + def action_disable + return if disabled?(new_resource) if active? disable! @@ -115,8 +115,8 @@ def whyrun_supported? end end - action :flush do - next if disabled?(new_resource) + def action_flush + return if disabled?(new_resource) reset! Chef::Log.info("#{new_resource} reset.") diff --git a/metadata.rb b/metadata.rb index 0368a178..1af940f2 100644 --- a/metadata.rb +++ b/metadata.rb @@ -1,7 +1,7 @@ name 'firewall' maintainer 'Chef Software, Inc.' maintainer_email 'cookbooks@chef.io' -license 'Apache 2.0' +license 'Apache-2.0' description 'Provides a set of primitives for managing firewalls and associated rules.' long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) version '2.5.4' @@ -20,4 +20,4 @@ source_url 'https://github.com/chef-cookbooks/firewall' issues_url 'https://github.com/chef-cookbooks/firewall/issues' -chef_version '>= 12.4' if respond_to?(:chef_version) +chef_version '>= 13' if respond_to?(:chef_version) diff --git a/test/fixtures/cookbooks/firewall-test/recipes/windows.rb b/test/fixtures/cookbooks/firewall-test/recipes/windows.rb index a5388a4a..9fcb0c4d 100644 --- a/test/fixtures/cookbooks/firewall-test/recipes/windows.rb +++ b/test/fixtures/cookbooks/firewall-test/recipes/windows.rb @@ -2,6 +2,6 @@ node.override['firewall']['windows']['defaults'] = { policy: { input: 'blockinbound', - output: 'blockoutbound' - } + output: 'blockoutbound', + }, } diff --git a/test/integration/default/serverspec/firewalld_spec.rb b/test/integration/default/serverspec/firewalld_spec.rb index b912564c..f2156919 100644 --- a/test/integration/default/serverspec/firewalld_spec.rb +++ b/test/integration/default/serverspec/firewalld_spec.rb @@ -30,7 +30,7 @@ %r{ipv6 filter INPUT 50 -p tcp -m tcp -m multiport --dports 5431,5432 -m comment --comment 'same comment' -j ACCEPT}, %r{ipv6 filter INPUT 50 -s 2001:db8::ff00:42:8329/128 -p tcp -m tcp -m multiport --dports 80 -m comment --comment ipv6-source -j ACCEPT}, %r{ipv6 filter INPUT 50 -p tcp -m tcp -m multiport --dports 1000:1100 -m comment --comment range -j ACCEPT}, - %r{ipv6 filter INPUT 50 -p tcp -m tcp -m multiport --dports 1234,5000:5100,5678 -m comment --comment array -j ACCEPT} + %r{ipv6 filter INPUT 50 -p tcp -m tcp -m multiport --dports 1234,5000:5100,5678 -m comment --comment array -j ACCEPT}, ] describe command('firewall-cmd --permanent --direct --get-all-rules'), if: firewalld? do diff --git a/test/integration/default/serverspec/iptables_spec.rb b/test/integration/default/serverspec/iptables_spec.rb index 73d4cabe..064edaf8 100644 --- a/test/integration/default/serverspec/iptables_spec.rb +++ b/test/integration/default/serverspec/iptables_spec.rb @@ -10,7 +10,7 @@ %r{-A INPUT -p tcp -m tcp -m multiport --dports 1235 .*-j REJECT --reject-with icmp-port-unreachable}, %r{-A INPUT -p tcp -m tcp -m multiport --dports 1236 .*-j DROP}, %r{-A INPUT -p vrrp .*-j ACCEPT}, - %r{-A INPUT -s 192.168.99.99(/32)? -p tcp -m tcp .*-j REJECT --reject-with icmp-port-unreachable} + %r{-A INPUT -s 192.168.99.99(/32)? -p tcp -m tcp .*-j REJECT --reject-with icmp-port-unreachable}, ] expected_ipv6_rules = [ @@ -22,7 +22,7 @@ %r{-A INPUT( -s ::/0 -d ::/0)? -p tcp -m tcp -m multiport --dports 1235 .*-j REJECT --reject-with icmp6-port-unreachable}, %r{-A INPUT( -s ::/0 -d ::/0)? -p tcp -m tcp -m multiport --dports 1236 .*-j DROP}, %r{-A INPUT( -s ::/0 -d ::/0)? -p vrrp .*-j ACCEPT}, - %r{-A INPUT -s 2001:db8::ff00:42:8329/128( -d ::/0)? -p tcp -m tcp -m multiport --dports 80 .*-j ACCEPT} + %r{-A INPUT -s 2001:db8::ff00:42:8329/128( -d ::/0)? -p tcp -m tcp -m multiport --dports 80 .*-j ACCEPT}, ] # due to bug on centos 5 on ipv6, see firewall-test::default recipe for more info diff --git a/test/integration/default/serverspec/ufw_spec.rb b/test/integration/default/serverspec/ufw_spec.rb index faf0d40f..753204f5 100644 --- a/test/integration/default/serverspec/ufw_spec.rb +++ b/test/integration/default/serverspec/ufw_spec.rb @@ -11,7 +11,7 @@ %r{ 80/tcp + ALLOW IN +2001:db8::ff00:42:8329}, %r{ 1000:1100/tcp + ALLOW IN +Anywhere}, %r{ 1234,5000:5100,5678/tcp + ALLOW IN +Anywhere}, - %r{ 23/tcp + LIMIT IN +Anywhere} + %r{ 23/tcp + LIMIT IN +Anywhere}, ] describe command('ufw status numbered'), if: debian? || ubuntu? do diff --git a/test/integration/default/serverspec/windows_spec.rb b/test/integration/default/serverspec/windows_spec.rb index f3319665..2f47afed 100644 --- a/test/integration/default/serverspec/windows_spec.rb +++ b/test/integration/default/serverspec/windows_spec.rb @@ -16,7 +16,7 @@ %r{firewall add rule name="duplicate1" description="same comment" dir=in protocol=tcp localip=any localport=5431,5432 interfacetype=any remoteip=any remoteport=any action=allow}, %r{firewall add rule name="ipv6-source" description="ipv6-source" dir=in protocol=tcp localip=any localport=80 interfacetype=any remoteip=2001:db8::ff00:42:8329 remoteport=any action=allow}, %r{firewall add rule name="range" description="range" dir=in protocol=tcp localip=any localport=1000-1100 interfacetype=any remoteip=any remoteport=any action=allow}, - %r{firewall add rule name="array" description="array" dir=in protocol=tcp localip=any localport=1234,5000-5100,5678 interfacetype=any remoteip=any remoteport=any action=allow} + %r{firewall add rule name="array" description="array" dir=in protocol=tcp localip=any localport=1234,5000-5100,5678 interfacetype=any remoteip=any remoteport=any action=allow}, ] describe file("#{ENV['HOME']}/windows-chef.rules"), if: windows? do diff --git a/test/integration/iptables/serverspec/iptables_redhat_spec.rb b/test/integration/iptables/serverspec/iptables_redhat_spec.rb index e8928dd2..3fa5d7c0 100644 --- a/test/integration/iptables/serverspec/iptables_redhat_spec.rb +++ b/test/integration/iptables/serverspec/iptables_redhat_spec.rb @@ -10,7 +10,7 @@ %r{-A INPUT -p tcp -m tcp -m multiport --dports 1235 .*-j REJECT --reject-with icmp-port-unreachable}, %r{-A INPUT -p tcp -m tcp -m multiport --dports 1236 .*-j DROP}, %r{-A INPUT -p vrrp .*-j ACCEPT}, - %r{-A INPUT -s 192.168.99.99(/32)? -p tcp -m tcp .*-j REJECT --reject-with icmp-port-unreachable} + %r{-A INPUT -s 192.168.99.99(/32)? -p tcp -m tcp .*-j REJECT --reject-with icmp-port-unreachable}, ] expected_ipv6_rules = [ @@ -22,7 +22,7 @@ %r{-A INPUT( -s ::/0 -d ::/0)? -p tcp -m tcp -m multiport --dports 1235 .*-j REJECT --reject-with icmp6-port-unreachable}, %r{-A INPUT( -s ::/0 -d ::/0)? -p tcp -m tcp -m multiport --dports 1236 .*-j DROP}, %r{-A INPUT( -s ::/0 -d ::/0)? -p vrrp .*-j ACCEPT}, - %r{-A INPUT -s 2001:db8::ff00:42:8329/128( -d ::/0)? -p tcp -m tcp -m multiport --dports 80 .*-j ACCEPT} + %r{-A INPUT -s 2001:db8::ff00:42:8329/128( -d ::/0)? -p tcp -m tcp -m multiport --dports 80 .*-j ACCEPT}, ] describe command('iptables-save'), if: redhat? do diff --git a/test/integration/iptables/serverspec/iptables_ubuntu_spec.rb b/test/integration/iptables/serverspec/iptables_ubuntu_spec.rb index 31fed64f..27e79d7a 100644 --- a/test/integration/iptables/serverspec/iptables_ubuntu_spec.rb +++ b/test/integration/iptables/serverspec/iptables_ubuntu_spec.rb @@ -7,7 +7,7 @@ %r{-A INPUT -p tcp -m tcp -m multiport --dports 1234 .*-j DROP}, %r{-A INPUT -p tcp -m tcp -m multiport --dports 1235 .*-j REJECT}, %r{-A INPUT -p tcp -m tcp -m multiport --dports 1236 .*-j DROP}, - %r{-A INPUT -s 192.168.99.99(/32)? -p tcp -m tcp .*-j REJECT} + %r{-A INPUT -s 192.168.99.99(/32)? -p tcp -m tcp .*-j REJECT}, ] expected_ipv6_rules = [ @@ -17,7 +17,7 @@ %r{-A INPUT( -s ::/0 -d ::/0)? -p tcp -m tcp -m multiport --dports 1234 .*-j DROP}, %r{-A INPUT( -s ::/0 -d ::/0)? -p tcp -m tcp -m multiport --dports 1235 .*-j REJECT}, %r{-A INPUT( -s ::/0 -d ::/0)? -p tcp -m tcp -m multiport --dports 1236 .*-j DROP}, - %r{-A INPUT -s 2001:db8::ff00:42:8329/128( -d ::/0)? -p tcp -m tcp -m multiport --dports 80 .*-j ACCEPT} + %r{-A INPUT -s 2001:db8::ff00:42:8329/128( -d ::/0)? -p tcp -m tcp -m multiport --dports 80 .*-j ACCEPT}, ] describe command('iptables-save'), if: ubuntu? do