diff --git a/Batali b/Batali index 2268d4f..e065c45 100644 --- a/Batali +++ b/Batali @@ -25,8 +25,7 @@ Batali.define do cookbook 'redis', git: 'https://github.com/phlipper/chef-redis.git', ref: 'v0.5.6' - cookbook 'ufw' - cookbook 'firewall' + cookbook 'firewall', '~> 2.6.1' cookbook 'chef_nginx' cookbook 'build-essential' cookbook 'mysql' diff --git a/batali.manifest b/batali.manifest index 44e7752..8f3c5f8 100644 --- a/batali.manifest +++ b/batali.manifest @@ -962,21 +962,6 @@ "subdirectory": null } }, - { - "name": "ufw", - "dependencies": [ - [ - "firewall", - ">= 2.0" - ] - ], - "version": "3.1.0", - "source": { - "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/ufw/versions/3.1.0/download", - "version": "3.1.0" - } - }, { "name": "firewall", "dependencies": [ @@ -985,11 +970,11 @@ ">= 0.0.0" ] ], - "version": "2.5.4", + "version": "2.6.1", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/firewall/versions/2.5.4/download", - "version": "2.5.4" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/firewall/versions/2.6.1/download", + "version": "2.6.1" } }, { diff --git a/cookbooks/firewall/.foodcritic b/cookbooks/firewall/.foodcritic new file mode 100644 index 0000000..b56b353 --- /dev/null +++ b/cookbooks/firewall/.foodcritic @@ -0,0 +1,3 @@ +~FC001 +~FC057 +~FC019 diff --git a/cookbooks/firewall/CHANGELOG.md b/cookbooks/firewall/CHANGELOG.md index bcc623c..e8dd996 100644 --- a/cookbooks/firewall/CHANGELOG.md +++ b/cookbooks/firewall/CHANGELOG.md @@ -2,6 +2,17 @@ firewall Cookbook CHANGELOG ======================= This file is used to list changes made in each version of the firewall cookbook. +v2.6.1 (2017-04-21) +------------------- +* Add recipe to disable firewall (#164) + +v2.6.0 (2017-04-17) +------------------- +* Initial Chef 13.x support (#160, #159) +* Allow loopback and icmp, when enabled (#161) +* Address various newer rubocop and foodcritic complaints +* Convert rule provider away from DSL (#159) + v2.5.4 (2017-02-13) ------------------- * Update Test Kitchen platforms to the latest diff --git a/cookbooks/firewall/README.md b/cookbooks/firewall/README.md index 532968a..6e60bed 100644 --- a/cookbooks/firewall/README.md +++ b/cookbooks/firewall/README.md @@ -84,13 +84,18 @@ keys must be unique but we need multiple commit lines. # Recipes ### default -The default recipe creates a firewall resource with action install, and if `node['firewall']['allow_ssh']`, opens port 22 from the world. +The default recipe creates a firewall resource with action install. + +### disable_firewall +Used to disable platform specific firewall. Many clouds have their own firewall configured outside of the OS instance such as AWS Security Groups. # Attributes * `default['firewall']['allow_ssh'] = false`, set true to open port 22 for SSH when the default recipe runs * `default['firewall']['allow_mosh'] = false`, set to true to open UDP ports 60000 - 61000 for [Mosh][0] when the default recipe runs * `default['firewall']['allow_winrm'] = false`, set true to open port 5989 for WinRM when the default recipe runs +* `default['firewall']['allow_loopback'] = false`, set to true to allow all traffic on the loopback interface +* `default['firewall']['allow_icmp'] = false`, set true to allow icmp protocol on supported OSes (note: ufw and windows implementations don't support this) * `default['firewall']['ubuntu_iptables'] = false`, set to true to use iptables on Ubuntu / Debian when using the default recipe * `default['firewall']['redhat7_iptables'] = false`, set to true to use iptables on Red Hat / CentOS 7 when using the default recipe diff --git a/cookbooks/firewall/attributes/default.rb b/cookbooks/firewall/attributes/default.rb index b8bfcbe..7f72dcf 100644 --- a/cookbooks/firewall/attributes/default.rb +++ b/cookbooks/firewall/attributes/default.rb @@ -1,3 +1,5 @@ default['firewall']['allow_ssh'] = false default['firewall']['allow_winrm'] = false default['firewall']['allow_mosh'] = false +default['firewall']['allow_loopback'] = false +default['firewall']['allow_icmp'] = false diff --git a/cookbooks/firewall/attributes/iptables.rb b/cookbooks/firewall/attributes/iptables.rb index 32113fc..f26ac55 100644 --- a/cookbooks/firewall/attributes/iptables.rb +++ b/cookbooks/firewall/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/cookbooks/firewall/attributes/ufw.rb b/cookbooks/firewall/attributes/ufw.rb index 957613a..35c8366 100644 --- a/cookbooks/firewall/attributes/ufw.rb +++ b/cookbooks/firewall/attributes/ufw.rb @@ -7,6 +7,6 @@ default['firewall']['ufw']['defaults'] = { input: 'DROP', output: 'ACCEPT', forward: 'DROP', - application: 'SKIP' - } + application: 'SKIP', + }, } diff --git a/cookbooks/firewall/attributes/windows.rb b/cookbooks/firewall/attributes/windows.rb index 68c6c05..382dd82 100644 --- a/cookbooks/firewall/attributes/windows.rb +++ b/cookbooks/firewall/attributes/windows.rb @@ -3,6 +3,6 @@ default['firewall']['windows']['defaults'] = { policy: { input: 'blockinbound', - output: 'allowoutbound' - } + output: 'allowoutbound', + }, } diff --git a/cookbooks/firewall/libraries/helpers_firewalld.rb b/cookbooks/firewall/libraries/helpers_firewalld.rb index aa3019f..2033033 100644 --- a/cookbooks/firewall/libraries/helpers_firewalld.rb +++ b/cookbooks/firewall/libraries/helpers_firewalld.rb @@ -18,14 +18,14 @@ module FirewallCookbook 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/cookbooks/firewall/libraries/helpers_ufw.rb b/cookbooks/firewall/libraries/helpers_ufw.rb index 3844272..9e035c5 100644 --- a/cookbooks/firewall/libraries/helpers_ufw.rb +++ b/cookbooks/firewall/libraries/helpers_ufw.rb @@ -46,7 +46,7 @@ module FirewallCookbook 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|icmp|esp|ah|ipv6|none)$') + 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} " diff --git a/cookbooks/firewall/libraries/provider_firewall_firewalld.rb b/cookbooks/firewall/libraries/provider_firewall_firewalld.rb index 0a9fb40..b8fc8c5 100644 --- a/cookbooks/firewall/libraries/provider_firewall_firewalld.rb +++ b/cookbooks/firewall/libraries/provider_firewall_firewalld.rb @@ -27,36 +27,39 @@ class Chef 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 + 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?) - service 'firewalld' do - action [:enable, :start] - end + 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 @@ class Chef 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 @@ class Chef end # if the file was changed, load new ruleset - if firewalld_file.updated_by_last_action? - firewalld_flush! - # TODO: support logging + 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) + 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 @@ class Chef 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/cookbooks/firewall/libraries/provider_firewall_iptables.rb b/cookbooks/firewall/libraries/provider_firewall_iptables.rb index afa90af..6c1cb81 100644 --- a/cookbooks/firewall/libraries/provider_firewall_iptables.rb +++ b/cookbooks/firewall/libraries/provider_firewall_iptables.rb @@ -30,34 +30,38 @@ class Chef false end - action :install do - next if disabled?(new_resource) + def action_install + return 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 + # 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_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' - not_if { ::File.exist?("/etc/sysconfig/#{svc}") } - end - - service svc do - action [:enable, :start] - 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 @@ class Chef 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 @@ class Chef 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/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu.rb b/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu.rb index 4491991..c89320d 100644 --- a/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu.rb +++ b/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu.rb @@ -30,37 +30,41 @@ class Chef false end - action :install do - next if disabled?(new_resource) + def action_install + return 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 + # 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| - # 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 + 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}") - service 'netfilter-persistent' do - action [:enable, :start] - status_command 'true' # netfilter-persistent isn't a real service - end + # 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 @@ class Chef 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 @@ class Chef # 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 @@ class Chef 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 @@ class Chef 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/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu1404.rb b/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu1404.rb index b4c0200..8332be1 100644 --- a/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu1404.rb +++ b/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu1404.rb @@ -30,37 +30,41 @@ class Chef false end - action :install do - next if disabled?(new_resource) + def action_install + return 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 + # 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| - # 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 + 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}") - service 'iptables-persistent' do - action [:enable, :start] - status_command 'true' # iptables-persistent isn't a real service - end + # 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 @@ class Chef 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 @@ class Chef # 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 @@ class Chef 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 @@ class Chef 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/cookbooks/firewall/libraries/provider_firewall_rule.rb b/cookbooks/firewall/libraries/provider_firewall_rule.rb index f448610..85a27c5 100644 --- a/cookbooks/firewall/libraries/provider_firewall_rule.rb +++ b/cookbooks/firewall/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/cookbooks/firewall/libraries/provider_firewall_ufw.rb b/cookbooks/firewall/libraries/provider_firewall_ufw.rb index 25e5a12..cc1aeb7 100644 --- a/cookbooks/firewall/libraries/provider_firewall_ufw.rb +++ b/cookbooks/firewall/libraries/provider_firewall_ufw.rb @@ -29,40 +29,44 @@ class Chef 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 - - template '/etc/default/ufw' do - action [:create] - owner 'root' - group 'root' - mode '0644' - source 'ufw/default.erb' - cookbook 'firewall' - end - - 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 + 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 - 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 @@ class Chef 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 = run_context.resource_collection.find(file: ufw_rules_filename) + 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.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 - - # 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 - end - - action :disable do - next 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 - - if ufw_active? - ufw_disable! - new_resource.updated_by_last_action(true) - end - end - - action :flush do - next 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' - end + ufw_file end end end diff --git a/cookbooks/firewall/libraries/provider_firewall_windows.rb b/cookbooks/firewall/libraries/provider_firewall_windows.rb index 0d242b2..d261f03 100644 --- a/cookbooks/firewall/libraries/provider_firewall_windows.rb +++ b/cookbooks/firewall/libraries/provider_firewall_windows.rb @@ -26,8 +26,8 @@ class Chef 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 @@ class Chef 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 @@ class Chef # 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 @@ class Chef 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 @@ class Chef 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/cookbooks/firewall/metadata.json b/cookbooks/firewall/metadata.json index 6381404..1a05794 100644 --- a/cookbooks/firewall/metadata.json +++ b/cookbooks/firewall/metadata.json @@ -1 +1 @@ -{"name":"firewall","version":"2.5.4","description":"Provides a set of primitives for managing firewalls and associated rules.","long_description":"firewall Cookbook\n=================\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/firewall.svg?branch=master)](http://travis-ci.org/chef-cookbooks/firewall)\n[![Cookbook Version](https://img.shields.io/cookbook/v/firewall.svg)](https://supermarket.chef.io/cookbooks/firewall)\n\nProvides a set of primitives for managing firewalls and associated rules.\n\nPLEASE NOTE - The resource/providers in this cookbook are under heavy development. An attempt is being made to keep the resource simple/stupid by starting with less sophisticated firewall implementations first and refactor/vet the resource definition with each successive provider.\n\nRequirements\n------------\n**Chef 12.4.x+** is required. We are currently testing against 12.8.1. If you need Chef 11 support, please try pinning back to a version less than 2.0, e.g.:\n```\ndepends 'firewall', '< 2.0'\n```\n\n### Supported firewalls and platforms\n* UFW - Ubuntu, Debian\n* IPTables - Red Hat & CentOS, Ubuntu\n* FirewallD - Red Hat & CentOS >= 7.0 (IPv4 only support, [needs contributions/testing](https://github.com/chef-cookbooks/firewall/issues/86))\n* Windows Advanced Firewall - 2012 R2\n\nTested on:\n* Ubuntu 12.04, 14.04, 16.04 with iptables, ufw\n* Debian 7.8, 8.1 with ufw\n* CentOS 5.11, 6.7 with iptables\n* CentOS 7.1 with firewalld\n* Windows Server 2012r2 with Windows Advanced Firewall\n\nBy default, Ubuntu chooses ufw. To switch to iptables, set this in an attribute file:\n```\ndefault['firewall']['ubuntu_iptables'] = true\n```\n\nBy default, Red Hat & CentOS >= 7.0 chooses firewalld. To switch to iptables, set this in an attribute file:\n```\ndefault['firewall']['redhat7_iptables'] = true\n```\n\n# Considerations that apply to all firewall providers and resources\n\nThis cookbook comes with two resources, firewall and firewall rule. The typical usage scenario is as follows:\n\n- run the `:install` action on the `firewall` resource named 'default', which installs appropriate packages and configures services to start on boot and starts them\n\n- run the `:create` action on every `firewall_rule` resource, which adds to the list of rules that should be configured on the firewall. `firewall_rule` then automatically sends a delayed notification to the `firewall['default']` resource to run the `:restart` action.\n\n- run the delayed notification with action `:restart` on the `firewall` resource. if any rules are different than the last run, the provider will update the current state of the firewall rules to match the expected rules.\n\nThere is a fundamental mismatch between the idea of a chef action and the action that should be taken on a firewall rule. For this reason, the chef action for a firewall_rule may be `:nothing` (the rule should not be present in the firewall) or `:create` (the rule should be present in the firewall), but the action taken on a packet in a firewall (`DROP`, `ACCEPT`, etc) is denoted as a `command` parameter on the `firewall_rule` resource.\n\n# iptables considerations\n\nIf you need to use a table other than `*filter`, the best way to do so is like so:\n```\nnode.default['firewall']['iptables']['defaults'][:ruleset] = {\n '*filter' => 1,\n ':INPUT DROP' => 2,\n ':FORWARD DROP' => 3,\n ':OUTPUT ACCEPT_FILTER' => 4,\n 'COMMIT_FILTER' => 100,\n '*nat' => 101,\n ':PREROUTING DROP' => 102,\n ':POSTROUTING DROP' => 103,\n ':OUTPUT ACCEPT_NAT' => 104,\n 'COMMIT_NAT' => 200\n}\n```\n\nNote -- in order to support multiple hash keys containing the same rule, anything found after the underscore will be stripped for: `:OUTPUT :INPUT :POSTROUTING :PREROUTING COMMIT`. This allows an example like the above to be reduced to just repeated lines of `COMMIT` and `:OUTPUT ACCEPT` while still avoiding duplication of other things.\n\nThen it's trivial to add additional rules to the `*nat` table using the raw parameter:\n```\nfirewall_rule \"postroute\" do\n raw \"-A POSTROUTING -o eth1 -p tcp -d 172.28.128.21 -j SNAT --to-source 172.28.128.6\"\n position 150\nend\n```\n\nNote that any line starting with `COMMIT` will become just `COMMIT`, as hash\nkeys must be unique but we need multiple commit lines.\n\n# Recipes\n\n### default\nThe default recipe creates a firewall resource with action install, and if `node['firewall']['allow_ssh']`, opens port 22 from the world.\n\n# Attributes\n\n* `default['firewall']['allow_ssh'] = false`, set true to open port 22 for SSH when the default recipe runs\n* `default['firewall']['allow_mosh'] = false`, set to true to open UDP ports 60000 - 61000 for [Mosh][0] when the default recipe runs\n* `default['firewall']['allow_winrm'] = false`, set true to open port 5989 for WinRM when the default recipe runs\n\n* `default['firewall']['ubuntu_iptables'] = false`, set to true to use iptables on Ubuntu / Debian when using the default recipe\n* `default['firewall']['redhat7_iptables'] = false`, set to true to use iptables on Red Hat / CentOS 7 when using the default recipe\n\n* `default['firewall']['ufw']['defaults']` hash for template `/etc/default/ufw`\n* `default['firewall']['iptables']['defaults']` hash for default policies for 'filter' table's chains`\n\n* `default['firewall']['windows']['defaults']` hash to define inbound / outbound firewall policy on Windows platform\n\n* `default['firewall']['allow_established'] = true`, set to false if you don't want a related/established default rule on iptables\n* `default['firewall']['ipv6_enabled'] = true`, set to false if you don't want IPv6 related/established default rule on iptables (this enables ICMPv6, which is required for much of IPv6 communication)\n\n* `default['firewall']['firewalld']['permanent'] = false`, set to true if you want firewalld rules to be added with `--permanent` so they survive a reboot. This will be changed to `true` by default in a future major version release.\n\n# Resources\n\n### firewall\n\n***NB***: The name 'default' of this resource is important as it is used for firewall_rule providers to locate the firewall resource. If you change it, you must also supply the same value to any firewall_rule resources using the `firewall_name` parameter.\n\n#### Actions\n- `:install` (*default action*): Install and Enable the firewall. This will ensure the appropriate packages are installed and that any services have been started.\n- `:disable`: Disable the firewall. Drop any rules and put the node in an unprotected state. Flush all current rules. Also erase any internal state used to detect when rules should be applied.\n- `:flush`: Flush all current rules. Also erase any internal state used to detect when rules should be applied.\n- `:save`: Ensure all rules are added permanently under firewalld using `--permanent`. Not supported on ufw, iptables. You must notify this action at the end of the chef run if you want permanent firewalld rules (they are not persistent by default).\n\n#### Parameters\n\n- `disabled` (default to `false`): If set to true, all actions will no-op on this resource. This is a way to prevent included cookbooks from configuring a firewall.\n- `ipv6_enabled` (default to `true`): If set to false, firewall will not perform any ipv6 related work. Currently only supported in iptables.\n- `log_level`: UFW only. Level of verbosity the firewall should log at. valid values are: :low, :medium, :high, :full, :off. default is :low.\n- `rules`: This is used internally for firewall_rule resources to append their rules. You should NOT touch this value unless you plan to supply an entire firewall ruleset at once, and skip using firewall_rule resources.\n- `disabled_zone` (firewalld only): The zone to set on firewalld when the firewall should be disabled. Can be any string in symbol form, e.g. :public, :drop, etc. Defaults to `:public.`\n- `enabled_zone` (firewalld only): The zone to set on firewalld when the firewall should be enabled. Can be any string in symbol form, e.g. :public, :drop, etc. Defaults to `:drop.`\n- `package_options`: Used to pass options to the package install of firewall\n\n#### Examples\n\n```ruby\n# all defaults\nfirewall 'default'\n\n# enable platform default firewall\nfirewall 'default' do\n action :install\nend\n\n# increase logging past default of 'low'\nfirewall 'default' do\n log_level :high\n action :install\nend\n```\n\n### firewall_rule\n\n#### Actions\n- `:create` (_default action_): If a firewall_rule runs this action, the rule will be recorded in a chef resource's internal state, and applied when providers automatically notify the firewall resource with action `:reload`. The notification happens automatically.\n\n#### Parameters\n\n- `firewall_name`: the matching firewall resource that this rule applies to. Default value: `default`\n\n- `raw`: Used to pass an entire rule as a string, omitting all other parameters. This line will be directly loaded by `iptables-restore`, fed directly into `ufw` on the command line, or run using `firewall-cmd`.\n\n- `description` (_default: same as rule name_): Used to provide a comment that will be included when adding the firewall rule.\n\n- `position` (_default: 50_): **relative** position to insert rule at. Position may be any integer between 0 < n < 100 (exclusive), and more than one rule may specify the same position.\n\n- `command`: What action to take on a particular packet\n\n - `:allow` (_default action_): the rule should allow matching packets\n - `:deny`: the rule should deny matching packets\n - `:reject`: the rule should reject matching packets\n - `:masqerade`: Masquerade the matching packets\n - `:redirect`: Redirect the matching packets\n - `:log`: Configure logging\n\n- `stateful`: a symbol or array of symbols, such as ``[:related, :established]` that will be passed to the state module in iptables or firewalld.\n\n- `protocol`: `:tcp` (_default_), `:udp`, `:icmp`, `:none` or protocol number. Using protocol numbers is not supported using the ufw provider (default for debian/ubuntu systems).\n\n- `direction`: For ufw, direction of the rule. valid values are: `:in` (_default_), `:out`, `:pre`, `:post`.\n\n- `source` (_Default is `0.0.0.0/0` or `Anywhere`_): source ip address or subnet to filter.\n\n- `source_port` (_Default is nil_): source port for filtering packets.\n\n- `destination`: ip address or subnet to filter on packet destination, must be a valid IP\n\n- `port` or `dest_port`: target port number (ie. 22 to allow inbound SSH), or an array of incoming port numbers (ie. [80,443] to allow inbound HTTP & HTTPS).\n\n NOTE: `protocol` attribute is required with multiple ports, or a range of incoming port numbers (ie. 60000..61000 to allow inbound mobile-shell. NOTE: `protocol`, or an attribute is required with a range of ports.\n\n- `interface`: (source) interface to apply rule (ie. `eth0`).\n\n- `dest_interface`: interface where packets may be destined to go\n\n- `redirect_port`: redirected port for rules with command `:redirect`\n\n- `logging`: may be added to enable logging for a particular rule. valid values are: `:connections`, `:packets`. In the ufw provider, `:connections` logs new connections while `:packets` logs all packets.\n\n#### Examples\n\n```ruby\n# open standard ssh port\nfirewall_rule 'ssh' do\n port 22\n command :allow\nend\n\n# open standard http port to tcp traffic only; insert as first rule\nfirewall_rule 'http' do\n port 80\n protocol :tcp\n position 1\n command :allow\nend\n\n# restrict port 13579 to 10.0.111.0/24 on eth0\nfirewall_rule 'myapplication' do\n port 13579\n source '10.0.111.0/24'\n direction :in\n interface 'eth0'\n command :allow\nend\n\n# specify a protocol number (supported on centos/redhat)\nfirewall_rule 'vrrp' do\n protocol 112\n command :allow\nend\n\n# use the iptables provider to specify protocol number on debian/ubuntu\nfirewall_rule 'vrrp' do\n provider Chef::Provider::FirewallRuleIptables\n protocol 112\n command :allow\nend\n\n# can use :raw command with UFW provider for VRRP\nfirewall_rule \"VRRP\" do\n command :allow\n raw \"allow to 224.0.0.18\"\nend\n\n# open UDP ports 60000..61000 for mobile shell (mosh.mit.edu), note\n# that the protocol attribute is required when using port_range\nfirewall_rule 'mosh' do\n protocol :udp\n port 60000..61000\n command :allow\nend\n\n# open multiple ports for http/https, note that the protocol\n# attribute is required when using ports\nfirewall_rule 'http/https' do\n protocol :tcp\n port [80, 443]\n command :allow\nend\n\nfirewall 'default' do\n enabled false\n action :nothing\nend\n```\n\n#### Providers\n\n- See `libraries/z_provider_mapping.rb` for a full list of providers for each platform and version.\n\nDifferent providers will determine the current state of the rules differently -- parsing the output of a command, maintaining the state in a file, or some other way. If the firewall is adjusted from outside of chef (non-idempotent), it's possible that chef may be caught unaware of the current state of the firewall. The best workaround is to add a `:flush` action to the firewall resource as early as possible in the chef run, if you plan to modify the firewall state outside of chef.\n\n# Troubleshooting\n\nTo figure out what the position values are for current rules, print the hash that contains the weights:\n```\nrequire pp\ndefault_firewall = resources(:firewall, 'default')\npp default_firewall.rules\n```\n\n# Development\nThis section details \"quick development\" steps. For a detailed explanation, see [[Contributing.md]].\n\n1. Clone this repository from GitHub:\n\n $ git clone git@github.com:chef-cookbooks/firewall.git\n\n2. Create a git branch\n\n $ git checkout -b my_bug_fix\n\n3. Install dependencies:\n\n $ bundle install\n\n4. Make your changes/patches/fixes, committing appropiately\n5. **Write tests**\n6. Run the tests:\n - `bundle exec foodcritic -f any .`\n - `bundle exec rspec`\n - `bundle exec rubocop`\n - `bundle exec kitchen test`\n\n In detail:\n - Foodcritic will catch any Chef-specific style errors\n - RSpec will run the unit tests\n - Rubocop will check for Ruby-specific style errors\n - Test Kitchen will run and converge the recipes\n\n\n# License & Authors\n\n- Author:: Seth Chisamore ()\n- Author:: Ronald Doorn ()\n- Author:: Martin Smith ()\n- Author:: Sander van Harmelen ()\n\n```text\nCopyright:: 2011-2015, Chef Software, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n\n[0]: https://mosh.mit.edu/\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache 2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","debian":">= 0.0.0","fedora":">= 0.0.0","oracle":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","ubuntu":">= 0.0.0","windows":">= 0.0.0"},"dependencies":{"chef-sugar":">= 0.0.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{}} \ No newline at end of file +{"name":"firewall","version":"2.6.1","description":"Provides a set of primitives for managing firewalls and associated rules.","long_description":"firewall Cookbook\n=================\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/firewall.svg?branch=master)](http://travis-ci.org/chef-cookbooks/firewall)\n[![Cookbook Version](https://img.shields.io/cookbook/v/firewall.svg)](https://supermarket.chef.io/cookbooks/firewall)\n\nProvides a set of primitives for managing firewalls and associated rules.\n\nPLEASE NOTE - The resource/providers in this cookbook are under heavy development. An attempt is being made to keep the resource simple/stupid by starting with less sophisticated firewall implementations first and refactor/vet the resource definition with each successive provider.\n\nRequirements\n------------\n**Chef 12.4.x+** is required. We are currently testing against 12.8.1. If you need Chef 11 support, please try pinning back to a version less than 2.0, e.g.:\n```\ndepends 'firewall', '< 2.0'\n```\n\n### Supported firewalls and platforms\n* UFW - Ubuntu, Debian\n* IPTables - Red Hat & CentOS, Ubuntu\n* FirewallD - Red Hat & CentOS >= 7.0 (IPv4 only support, [needs contributions/testing](https://github.com/chef-cookbooks/firewall/issues/86))\n* Windows Advanced Firewall - 2012 R2\n\nTested on:\n* Ubuntu 12.04, 14.04, 16.04 with iptables, ufw\n* Debian 7.8, 8.1 with ufw\n* CentOS 5.11, 6.7 with iptables\n* CentOS 7.1 with firewalld\n* Windows Server 2012r2 with Windows Advanced Firewall\n\nBy default, Ubuntu chooses ufw. To switch to iptables, set this in an attribute file:\n```\ndefault['firewall']['ubuntu_iptables'] = true\n```\n\nBy default, Red Hat & CentOS >= 7.0 chooses firewalld. To switch to iptables, set this in an attribute file:\n```\ndefault['firewall']['redhat7_iptables'] = true\n```\n\n# Considerations that apply to all firewall providers and resources\n\nThis cookbook comes with two resources, firewall and firewall rule. The typical usage scenario is as follows:\n\n- run the `:install` action on the `firewall` resource named 'default', which installs appropriate packages and configures services to start on boot and starts them\n\n- run the `:create` action on every `firewall_rule` resource, which adds to the list of rules that should be configured on the firewall. `firewall_rule` then automatically sends a delayed notification to the `firewall['default']` resource to run the `:restart` action.\n\n- run the delayed notification with action `:restart` on the `firewall` resource. if any rules are different than the last run, the provider will update the current state of the firewall rules to match the expected rules.\n\nThere is a fundamental mismatch between the idea of a chef action and the action that should be taken on a firewall rule. For this reason, the chef action for a firewall_rule may be `:nothing` (the rule should not be present in the firewall) or `:create` (the rule should be present in the firewall), but the action taken on a packet in a firewall (`DROP`, `ACCEPT`, etc) is denoted as a `command` parameter on the `firewall_rule` resource.\n\n# iptables considerations\n\nIf you need to use a table other than `*filter`, the best way to do so is like so:\n```\nnode.default['firewall']['iptables']['defaults'][:ruleset] = {\n '*filter' => 1,\n ':INPUT DROP' => 2,\n ':FORWARD DROP' => 3,\n ':OUTPUT ACCEPT_FILTER' => 4,\n 'COMMIT_FILTER' => 100,\n '*nat' => 101,\n ':PREROUTING DROP' => 102,\n ':POSTROUTING DROP' => 103,\n ':OUTPUT ACCEPT_NAT' => 104,\n 'COMMIT_NAT' => 200\n}\n```\n\nNote -- in order to support multiple hash keys containing the same rule, anything found after the underscore will be stripped for: `:OUTPUT :INPUT :POSTROUTING :PREROUTING COMMIT`. This allows an example like the above to be reduced to just repeated lines of `COMMIT` and `:OUTPUT ACCEPT` while still avoiding duplication of other things.\n\nThen it's trivial to add additional rules to the `*nat` table using the raw parameter:\n```\nfirewall_rule \"postroute\" do\n raw \"-A POSTROUTING -o eth1 -p tcp -d 172.28.128.21 -j SNAT --to-source 172.28.128.6\"\n position 150\nend\n```\n\nNote that any line starting with `COMMIT` will become just `COMMIT`, as hash\nkeys must be unique but we need multiple commit lines.\n\n# Recipes\n\n### default\nThe default recipe creates a firewall resource with action install.\n\n### disable_firewall\nUsed to disable platform specific firewall. Many clouds have their own firewall configured outside of the OS instance such as AWS Security Groups.\n\n# Attributes\n\n* `default['firewall']['allow_ssh'] = false`, set true to open port 22 for SSH when the default recipe runs\n* `default['firewall']['allow_mosh'] = false`, set to true to open UDP ports 60000 - 61000 for [Mosh][0] when the default recipe runs\n* `default['firewall']['allow_winrm'] = false`, set true to open port 5989 for WinRM when the default recipe runs\n* `default['firewall']['allow_loopback'] = false`, set to true to allow all traffic on the loopback interface\n* `default['firewall']['allow_icmp'] = false`, set true to allow icmp protocol on supported OSes (note: ufw and windows implementations don't support this)\n\n* `default['firewall']['ubuntu_iptables'] = false`, set to true to use iptables on Ubuntu / Debian when using the default recipe\n* `default['firewall']['redhat7_iptables'] = false`, set to true to use iptables on Red Hat / CentOS 7 when using the default recipe\n\n* `default['firewall']['ufw']['defaults']` hash for template `/etc/default/ufw`\n* `default['firewall']['iptables']['defaults']` hash for default policies for 'filter' table's chains`\n\n* `default['firewall']['windows']['defaults']` hash to define inbound / outbound firewall policy on Windows platform\n\n* `default['firewall']['allow_established'] = true`, set to false if you don't want a related/established default rule on iptables\n* `default['firewall']['ipv6_enabled'] = true`, set to false if you don't want IPv6 related/established default rule on iptables (this enables ICMPv6, which is required for much of IPv6 communication)\n\n* `default['firewall']['firewalld']['permanent'] = false`, set to true if you want firewalld rules to be added with `--permanent` so they survive a reboot. This will be changed to `true` by default in a future major version release.\n\n# Resources\n\n### firewall\n\n***NB***: The name 'default' of this resource is important as it is used for firewall_rule providers to locate the firewall resource. If you change it, you must also supply the same value to any firewall_rule resources using the `firewall_name` parameter.\n\n#### Actions\n- `:install` (*default action*): Install and Enable the firewall. This will ensure the appropriate packages are installed and that any services have been started.\n- `:disable`: Disable the firewall. Drop any rules and put the node in an unprotected state. Flush all current rules. Also erase any internal state used to detect when rules should be applied.\n- `:flush`: Flush all current rules. Also erase any internal state used to detect when rules should be applied.\n- `:save`: Ensure all rules are added permanently under firewalld using `--permanent`. Not supported on ufw, iptables. You must notify this action at the end of the chef run if you want permanent firewalld rules (they are not persistent by default).\n\n#### Parameters\n\n- `disabled` (default to `false`): If set to true, all actions will no-op on this resource. This is a way to prevent included cookbooks from configuring a firewall.\n- `ipv6_enabled` (default to `true`): If set to false, firewall will not perform any ipv6 related work. Currently only supported in iptables.\n- `log_level`: UFW only. Level of verbosity the firewall should log at. valid values are: :low, :medium, :high, :full, :off. default is :low.\n- `rules`: This is used internally for firewall_rule resources to append their rules. You should NOT touch this value unless you plan to supply an entire firewall ruleset at once, and skip using firewall_rule resources.\n- `disabled_zone` (firewalld only): The zone to set on firewalld when the firewall should be disabled. Can be any string in symbol form, e.g. :public, :drop, etc. Defaults to `:public.`\n- `enabled_zone` (firewalld only): The zone to set on firewalld when the firewall should be enabled. Can be any string in symbol form, e.g. :public, :drop, etc. Defaults to `:drop.`\n- `package_options`: Used to pass options to the package install of firewall\n\n#### Examples\n\n```ruby\n# all defaults\nfirewall 'default'\n\n# enable platform default firewall\nfirewall 'default' do\n action :install\nend\n\n# increase logging past default of 'low'\nfirewall 'default' do\n log_level :high\n action :install\nend\n```\n\n### firewall_rule\n\n#### Actions\n- `:create` (_default action_): If a firewall_rule runs this action, the rule will be recorded in a chef resource's internal state, and applied when providers automatically notify the firewall resource with action `:reload`. The notification happens automatically.\n\n#### Parameters\n\n- `firewall_name`: the matching firewall resource that this rule applies to. Default value: `default`\n\n- `raw`: Used to pass an entire rule as a string, omitting all other parameters. This line will be directly loaded by `iptables-restore`, fed directly into `ufw` on the command line, or run using `firewall-cmd`.\n\n- `description` (_default: same as rule name_): Used to provide a comment that will be included when adding the firewall rule.\n\n- `position` (_default: 50_): **relative** position to insert rule at. Position may be any integer between 0 < n < 100 (exclusive), and more than one rule may specify the same position.\n\n- `command`: What action to take on a particular packet\n\n - `:allow` (_default action_): the rule should allow matching packets\n - `:deny`: the rule should deny matching packets\n - `:reject`: the rule should reject matching packets\n - `:masqerade`: Masquerade the matching packets\n - `:redirect`: Redirect the matching packets\n - `:log`: Configure logging\n\n- `stateful`: a symbol or array of symbols, such as ``[:related, :established]` that will be passed to the state module in iptables or firewalld.\n\n- `protocol`: `:tcp` (_default_), `:udp`, `:icmp`, `:none` or protocol number. Using protocol numbers is not supported using the ufw provider (default for debian/ubuntu systems).\n\n- `direction`: For ufw, direction of the rule. valid values are: `:in` (_default_), `:out`, `:pre`, `:post`.\n\n- `source` (_Default is `0.0.0.0/0` or `Anywhere`_): source ip address or subnet to filter.\n\n- `source_port` (_Default is nil_): source port for filtering packets.\n\n- `destination`: ip address or subnet to filter on packet destination, must be a valid IP\n\n- `port` or `dest_port`: target port number (ie. 22 to allow inbound SSH), or an array of incoming port numbers (ie. [80,443] to allow inbound HTTP & HTTPS).\n\n NOTE: `protocol` attribute is required with multiple ports, or a range of incoming port numbers (ie. 60000..61000 to allow inbound mobile-shell. NOTE: `protocol`, or an attribute is required with a range of ports.\n\n- `interface`: (source) interface to apply rule (ie. `eth0`).\n\n- `dest_interface`: interface where packets may be destined to go\n\n- `redirect_port`: redirected port for rules with command `:redirect`\n\n- `logging`: may be added to enable logging for a particular rule. valid values are: `:connections`, `:packets`. In the ufw provider, `:connections` logs new connections while `:packets` logs all packets.\n\n#### Examples\n\n```ruby\n# open standard ssh port\nfirewall_rule 'ssh' do\n port 22\n command :allow\nend\n\n# open standard http port to tcp traffic only; insert as first rule\nfirewall_rule 'http' do\n port 80\n protocol :tcp\n position 1\n command :allow\nend\n\n# restrict port 13579 to 10.0.111.0/24 on eth0\nfirewall_rule 'myapplication' do\n port 13579\n source '10.0.111.0/24'\n direction :in\n interface 'eth0'\n command :allow\nend\n\n# specify a protocol number (supported on centos/redhat)\nfirewall_rule 'vrrp' do\n protocol 112\n command :allow\nend\n\n# use the iptables provider to specify protocol number on debian/ubuntu\nfirewall_rule 'vrrp' do\n provider Chef::Provider::FirewallRuleIptables\n protocol 112\n command :allow\nend\n\n# can use :raw command with UFW provider for VRRP\nfirewall_rule \"VRRP\" do\n command :allow\n raw \"allow to 224.0.0.18\"\nend\n\n# open UDP ports 60000..61000 for mobile shell (mosh.mit.edu), note\n# that the protocol attribute is required when using port_range\nfirewall_rule 'mosh' do\n protocol :udp\n port 60000..61000\n command :allow\nend\n\n# open multiple ports for http/https, note that the protocol\n# attribute is required when using ports\nfirewall_rule 'http/https' do\n protocol :tcp\n port [80, 443]\n command :allow\nend\n\nfirewall 'default' do\n enabled false\n action :nothing\nend\n```\n\n#### Providers\n\n- See `libraries/z_provider_mapping.rb` for a full list of providers for each platform and version.\n\nDifferent providers will determine the current state of the rules differently -- parsing the output of a command, maintaining the state in a file, or some other way. If the firewall is adjusted from outside of chef (non-idempotent), it's possible that chef may be caught unaware of the current state of the firewall. The best workaround is to add a `:flush` action to the firewall resource as early as possible in the chef run, if you plan to modify the firewall state outside of chef.\n\n# Troubleshooting\n\nTo figure out what the position values are for current rules, print the hash that contains the weights:\n```\nrequire pp\ndefault_firewall = resources(:firewall, 'default')\npp default_firewall.rules\n```\n\n# Development\nThis section details \"quick development\" steps. For a detailed explanation, see [[Contributing.md]].\n\n1. Clone this repository from GitHub:\n\n $ git clone git@github.com:chef-cookbooks/firewall.git\n\n2. Create a git branch\n\n $ git checkout -b my_bug_fix\n\n3. Install dependencies:\n\n $ bundle install\n\n4. Make your changes/patches/fixes, committing appropiately\n5. **Write tests**\n6. Run the tests:\n - `bundle exec foodcritic -f any .`\n - `bundle exec rspec`\n - `bundle exec rubocop`\n - `bundle exec kitchen test`\n\n In detail:\n - Foodcritic will catch any Chef-specific style errors\n - RSpec will run the unit tests\n - Rubocop will check for Ruby-specific style errors\n - Test Kitchen will run and converge the recipes\n\n\n# License & Authors\n\n- Author:: Seth Chisamore ()\n- Author:: Ronald Doorn ()\n- Author:: Martin Smith ()\n- Author:: Sander van Harmelen ()\n\n```text\nCopyright:: 2011-2015, Chef Software, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n\n[0]: https://mosh.mit.edu/\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","debian":">= 0.0.0","fedora":">= 0.0.0","oracle":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","ubuntu":">= 0.0.0","windows":">= 0.0.0"},"dependencies":{"chef-sugar":">= 0.0.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{},"source_url":"https://github.com/chef-cookbooks/firewall","issues_url":"https://github.com/chef-cookbooks/firewall/issues","chef_version":[[">= 12.5"]],"ohai_version":[]} \ No newline at end of file diff --git a/cookbooks/firewall/recipes/default.rb b/cookbooks/firewall/recipes/default.rb index c85d5f5..9c2b10b 100644 --- a/cookbooks/firewall/recipes/default.rb +++ b/cookbooks/firewall/recipes/default.rb @@ -27,6 +27,21 @@ end # create a variable to use as a condition on some rules that follow iptables_firewall = rhel? || node['firewall']['ubuntu_iptables'] +firewall_rule 'allow loopback' do + interface 'lo' + protocol :none + command :allow + only_if { linux? && node['firewall']['allow_loopback'] } +end + +firewall_rule 'allow icmp' do + protocol :icmp + command :allow + # debian ufw doesn't allow 'icmp' protocol, but does open + # icmp by default, so we skip it in default recipe + only_if { (!debian? || iptables_firewall) && node['firewall']['allow_icmp'] } +end + firewall_rule 'allow world to ssh' do port 22 source '0.0.0.0/0' diff --git a/cookbooks/ufw/recipes/disable.rb b/cookbooks/firewall/recipes/disable_firewall.rb similarity index 78% rename from cookbooks/ufw/recipes/disable.rb rename to cookbooks/firewall/recipes/disable_firewall.rb index c0261fe..330953d 100644 --- a/cookbooks/ufw/recipes/disable.rb +++ b/cookbooks/firewall/recipes/disable_firewall.rb @@ -1,9 +1,8 @@ # -# Author:: Matt Ray -# Cookbook:: ufw -# Recipe:: disable +# Cookbook:: firewall +# Recipe:: disable_firewall # -# Copyright:: 2011-2017, Chef Software, Inc. +# 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. @@ -18,6 +17,7 @@ # limitations under the License. # -firewall 'ufw' do +# Disable platform default firewall +firewall 'default' do action :disable end diff --git a/cookbooks/ufw/.foodcritic b/cookbooks/ufw/.foodcritic deleted file mode 100644 index 698ef4c..0000000 --- a/cookbooks/ufw/.foodcritic +++ /dev/null @@ -1 +0,0 @@ -~FC003 diff --git a/cookbooks/ufw/CHANGELOG.md b/cookbooks/ufw/CHANGELOG.md deleted file mode 100644 index 03dceda..0000000 --- a/cookbooks/ufw/CHANGELOG.md +++ /dev/null @@ -1,47 +0,0 @@ -# ufw Cookbook CHANGELOG -This file is used to list changes made in each version of the ufw cookbook. - -## 3.1.0 (2017-03-02) -- Add use of the default['firewall']['allow_ssh'] attribute in the default recipe. Default for this cookbook is set to true, as the default recipe assumed that ssh would be enabled. - -## 3.0.0 (2017-03-01) -- Require Chef 12.4 (Depends on firewall which requires Chef 12.4+ at this point) -- Update default to remove installation of ufw which is duplication from firewall cookbook, and remove state changes - - Due to the change in default recipe, bumping major version in case this is breaking change for some. -- Added debian platform as firewall cookbook supports ufw on debian - -## 2.0.0 (2016-11-25) -- Add chef_version metadata + remove chef 11 compat -- Replace node.set with node.normal -- Require Chef 12.1 -- Fix the recipe to properly converge - -## v1.0.0 (12-14-2015) -- Update to use / require the Firewall v2.0.0+ cookbook, which requires Chef 12 -- Updated all Opscode references to Chef Software Inc. -- Updated testing, contributing, and maintainers docs -- Added source_url and issues_url metadata for supermarket -- Resolved all rubocop warnings and add the standard Chef rubocop file -- Added travis and supermarket version badges to the readme -- Added requirements section to the readme -- Added a chefignore file -- Added a Rakefile for simplified testing -- Added a basic converge chefspec - -## v0.7.4 -No change. Version bump for toolchain - -## v0.7.2 -Updating metadata to depend on firewall >= 0.9 - -## v0.7.0 -[COOK-3592] - allow source ports to be defined as a range in ufw - -## v0.6.4 -### Bug -- **[COOK-3316](https://tickets.chef.io/browse/COOK-3316)** - Fix README.md example - -## v0.6.2 -### Bug -- [COOK-2487]: when setting a node attribute you must specify the precedence -- [COOK-2982]: ufw cookbook has foodcritic failures diff --git a/cookbooks/ufw/CONTRIBUTING.md b/cookbooks/ufw/CONTRIBUTING.md deleted file mode 100644 index ef2f2b8..0000000 --- a/cookbooks/ufw/CONTRIBUTING.md +++ /dev/null @@ -1,2 +0,0 @@ -Please refer to -https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD diff --git a/cookbooks/ufw/MAINTAINERS.md b/cookbooks/ufw/MAINTAINERS.md deleted file mode 100644 index 645ed14..0000000 --- a/cookbooks/ufw/MAINTAINERS.md +++ /dev/null @@ -1,15 +0,0 @@ - - -# Maintainers - -This file lists how this cookbook project is maintained. When making changes to the system, this file tells you who needs to review your patch - you need a review from an existing maintainer for the cookbook to provide a :+1: on your pull request. Additionally, you need to not receive a veto from a Lieutenant or the Project Lead. - -Check out [How Cookbooks are Maintained](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) for details on the process and how to become a maintainer or the project lead. - -# Project Maintainer -* [Tim Smith](https://github.com/tas50) - -# Maintainers -* [Jennifer Davis](https://github.com/sigje) -* [Tim Smith](https://github.com/tas50) -* [Thom May](https://github.com/thommay) diff --git a/cookbooks/ufw/README.md b/cookbooks/ufw/README.md deleted file mode 100644 index ac7aee7..0000000 --- a/cookbooks/ufw/README.md +++ /dev/null @@ -1,173 +0,0 @@ -# Description - -[![Build Status](https://travis-ci.org/chef-cookbooks/ufw.svg?branch=master)](http://travis-ci.org/chef-cookbooks/ufw) [![Cookbook Version](https://img.shields.io/cookbook/v/ufw.svg)](https://supermarket.chef.io/cookbooks/ufw) - -Configures Uncomplicated Firewall (ufw) on Ubuntu and Debian. Including the `ufw` recipe in a run list means the firewall will be enabled and will deny everything except SSH and ICMP ping by default. - -Rules may be added to the node by adding them to the `['firewall']['rules']` attributes in roles or on the node directly. The `firewall` cookbook has an LWRP that may be used to apply rules directly from other recipes as well. There is no need to explicitly remove rules, they are reevaluated on changes and reset. Rules are applied in the order of the run list, unless ordering is explicitly added. - -## Requirements - -### Platforms - -- Ubuntu -- Debian - -### Chef - -- Chef 12.4+ - -### Cookbooks - -- firewall 2.0+ - -## Recipes - -### default - -The `default` recipe looks for the list of firewall rules to apply from the `['firewall']['rules']` attribute added to roles and on the node itself. The list of rules is then applied to the node in the order specified. - -### disable - -The `disable` recipe is used if there is a need to disable the existing firewall, perhaps for testing. It disables the ufw firewall even if other ufw recipes attempt to enable it. - -If you remove this recipe, the firewall does not get automatically re-enabled. You will need clear the value of the `['firewall']['state']` to force a recalculation of the firewall rules. This can be done with `knife node edit`. - -### databag - -The `databag` recipe looks in the `firewall` data bag for to apply firewall rules based on inspecting the runlist for roles and recipe names for keys that map to the data bag items and are applied in the the order specified. - -The `databag` recipe calls the `default` recipe after the `['firewall']['rules']` attribute is set to apply the rules, so you may mix roles with databag items if you want (roles apply first, then data bag contents). - -### recipes - -The `recipes` recipe applies firewall rules based on inspecting the runlist for recipes that have node[ - -]['firewall']['rules'] attributes. These are appended to node['firewall']['rules'] and applied to the node. Cookbooks may define attributes for recipes like so: - -#### attributes/default.rb for test cookbook - -```ruby -default['test']['firewall']['rules'] = [ - {"test"=> { - "port"=> "27901", - "protocol"=> "udp" - } - } -] -default['test::awesome']['firewall']['rules'] = [ - {"awesome"=> { - "port"=> "99427", - "protocol"=> "udp" - } - }, - {"awesome2"=> { - "port"=> "99428" - } - } -] -``` - -Note that the 'test::awesome' rules are only applied if that specific recipe is in the runlist. Recipe-applied firewall rules are applied after any rules defined in role attributes. - -### securitylevel - -The `securitylevel` recipe is used if there are any node['firewall']['securitylevel'] settings that need to be enforced. It is a reference implementation with nothing configured. - -## Attributes - -Roles and the node may have the `['firewall']['rules']` attribute set. This attribute is a list of hashes, the key will be rule name, the value will be the hash of parameters. Application order is based on run list. - -### Example Role - -```ruby -name "fw_example" -description "Firewall rules for Examples" -override_attributes( - "firewall" => { - "rules" => [ - {"tftp" => {}}, - {"http" => { - "port" => "80" - } - }, - {"block tomcat from 192.168.1.0/24" => { - "port" => "8080", - "source" => "192.168.1.0/24", - "action" => "deny" - } - }, - {"Allow access to udp 1.2.3.4 port 5469 from 1.2.3.5 port 5469" => { - "protocol" => "udp", - "port" => "5469", - "source" => "1.2.3.4", - "destination" => "1.2.3.5", - "dest_port" => "5469" - } - }, - {"allow to tcp ports 8000-8010 from 192.168.1.0/24" => { - "port_range" => "8000..8010", - "source" => "192.168.1.0/24", - "protocol" => "tcp" //protocol is mandatory when using port ranges - } - } - ] - } - ) -``` - -* default['firewall']['allow_ssh'] Opens port 22 for SSH when set to true. Default set to true. - -## Data Bags - -The `firewall` data bag may be used with the `databag` recipe. It will contain items that map to role names (eg. the 'apache' role will map to the 'apache' item in the 'firewall' data bag). Either roles or recipes may be keys (role[webserver] is 'webserver', recipe[apache2] is 'apache2'). If you have recipe-specific firewall rules, you will need to replace the '::' with '**' (double underscores) (eg. recipe[apache2::mod_ssl] is 'apache2**mod_ssl' in the data bag item). - -The items in the data bag will contain a 'rules' array of hashes to apply to the `['firewall']['rules']` attribute. - -```shell -% knife data bag create firewall -% knife data bag from file firewall examples/data_bags/firewall/apache2.json -% knife data bag from file firewall examples/data_bags/firewall/apache2__mod_ssl.json -``` - -### Example 'firewall' data bag item - -```javascript -{ - "id": "apache2", - "rules": [ - {"http": { - "port": "80" - }}, - {"block http from 192.168.1.0/24": { - "port": "80", - "source": "192.168.1.0/24", - "action": "deny" - }} - ] -} -``` - -## Resources/Providers - -The `firewall` cookbook provides the `firewall` and `firewall_rule` LWRPs, for which there is a ufw provider. - -## License & Authors - -**Author:** Cookbook Engineering Team ([cookbooks@chef.io](mailto:cookbooks@chef.io)) - -**Copyright:** 2011-2014, 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. -``` diff --git a/cookbooks/ufw/attributes/default.rb b/cookbooks/ufw/attributes/default.rb deleted file mode 100644 index 44a9aea..0000000 --- a/cookbooks/ufw/attributes/default.rb +++ /dev/null @@ -1,3 +0,0 @@ -default['firewall']['rules'] = [] -default['firewall']['securitylevel'] = '' -default['firewall']['allow_ssh'] = true diff --git a/cookbooks/ufw/metadata.json b/cookbooks/ufw/metadata.json deleted file mode 100644 index 717bd6c..0000000 --- a/cookbooks/ufw/metadata.json +++ /dev/null @@ -1 +0,0 @@ -{"name":"ufw","version":"3.1.0","description":"Installs and configures Uncomplicated Firewall (ufw)","long_description":"# Description\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/ufw.svg?branch=master)](http://travis-ci.org/chef-cookbooks/ufw) [![Cookbook Version](https://img.shields.io/cookbook/v/ufw.svg)](https://supermarket.chef.io/cookbooks/ufw)\n\nConfigures Uncomplicated Firewall (ufw) on Ubuntu and Debian. Including the `ufw` recipe in a run list means the firewall will be enabled and will deny everything except SSH and ICMP ping by default.\n\nRules may be added to the node by adding them to the `['firewall']['rules']` attributes in roles or on the node directly. The `firewall` cookbook has an LWRP that may be used to apply rules directly from other recipes as well. There is no need to explicitly remove rules, they are reevaluated on changes and reset. Rules are applied in the order of the run list, unless ordering is explicitly added.\n\n## Requirements\n\n### Platforms\n\n- Ubuntu\n- Debian\n\n### Chef\n\n- Chef 12.4+\n\n### Cookbooks\n\n- firewall 2.0+\n\n## Recipes\n\n### default\n\nThe `default` recipe looks for the list of firewall rules to apply from the `['firewall']['rules']` attribute added to roles and on the node itself. The list of rules is then applied to the node in the order specified.\n\n### disable\n\nThe `disable` recipe is used if there is a need to disable the existing firewall, perhaps for testing. It disables the ufw firewall even if other ufw recipes attempt to enable it.\n\nIf you remove this recipe, the firewall does not get automatically re-enabled. You will need clear the value of the `['firewall']['state']` to force a recalculation of the firewall rules. This can be done with `knife node edit`.\n\n### databag\n\nThe `databag` recipe looks in the `firewall` data bag for to apply firewall rules based on inspecting the runlist for roles and recipe names for keys that map to the data bag items and are applied in the the order specified.\n\nThe `databag` recipe calls the `default` recipe after the `['firewall']['rules']` attribute is set to apply the rules, so you may mix roles with databag items if you want (roles apply first, then data bag contents).\n\n### recipes\n\nThe `recipes` recipe applies firewall rules based on inspecting the runlist for recipes that have node[\n\n]['firewall']['rules'] attributes. These are appended to node['firewall']['rules'] and applied to the node. Cookbooks may define attributes for recipes like so:\n\n#### attributes/default.rb for test cookbook\n\n```ruby\ndefault['test']['firewall']['rules'] = [\n {\"test\"=> {\n \"port\"=> \"27901\",\n \"protocol\"=> \"udp\"\n }\n }\n]\ndefault['test::awesome']['firewall']['rules'] = [\n {\"awesome\"=> {\n \"port\"=> \"99427\",\n \"protocol\"=> \"udp\"\n }\n },\n {\"awesome2\"=> {\n \"port\"=> \"99428\"\n }\n }\n]\n```\n\nNote that the 'test::awesome' rules are only applied if that specific recipe is in the runlist. Recipe-applied firewall rules are applied after any rules defined in role attributes.\n\n### securitylevel\n\nThe `securitylevel` recipe is used if there are any node['firewall']['securitylevel'] settings that need to be enforced. It is a reference implementation with nothing configured.\n\n## Attributes\n\nRoles and the node may have the `['firewall']['rules']` attribute set. This attribute is a list of hashes, the key will be rule name, the value will be the hash of parameters. Application order is based on run list.\n\n### Example Role\n\n```ruby\nname \"fw_example\"\ndescription \"Firewall rules for Examples\"\noverride_attributes(\n \"firewall\" => {\n \"rules\" => [\n {\"tftp\" => {}},\n {\"http\" => {\n \"port\" => \"80\"\n }\n },\n {\"block tomcat from 192.168.1.0/24\" => {\n \"port\" => \"8080\",\n \"source\" => \"192.168.1.0/24\",\n \"action\" => \"deny\"\n }\n },\n {\"Allow access to udp 1.2.3.4 port 5469 from 1.2.3.5 port 5469\" => {\n \"protocol\" => \"udp\",\n \"port\" => \"5469\",\n \"source\" => \"1.2.3.4\",\n \"destination\" => \"1.2.3.5\",\n \"dest_port\" => \"5469\"\n }\n },\n {\"allow to tcp ports 8000-8010 from 192.168.1.0/24\" => {\n \"port_range\" => \"8000..8010\",\n \"source\" => \"192.168.1.0/24\",\n \"protocol\" => \"tcp\" //protocol is mandatory when using port ranges\n }\n }\n ]\n }\n )\n```\n\n* default['firewall']['allow_ssh'] Opens port 22 for SSH when set to true. Default set to true.\n\n## Data Bags\n\nThe `firewall` data bag may be used with the `databag` recipe. It will contain items that map to role names (eg. the 'apache' role will map to the 'apache' item in the 'firewall' data bag). Either roles or recipes may be keys (role[webserver] is 'webserver', recipe[apache2] is 'apache2'). If you have recipe-specific firewall rules, you will need to replace the '::' with '**' (double underscores) (eg. recipe[apache2::mod_ssl] is 'apache2**mod_ssl' in the data bag item).\n\nThe items in the data bag will contain a 'rules' array of hashes to apply to the `['firewall']['rules']` attribute.\n\n```shell\n% knife data bag create firewall\n% knife data bag from file firewall examples/data_bags/firewall/apache2.json\n% knife data bag from file firewall examples/data_bags/firewall/apache2__mod_ssl.json\n```\n\n### Example 'firewall' data bag item\n\n```javascript\n{\n \"id\": \"apache2\",\n \"rules\": [\n {\"http\": {\n \"port\": \"80\"\n }},\n {\"block http from 192.168.1.0/24\": {\n \"port\": \"80\",\n \"source\": \"192.168.1.0/24\",\n \"action\": \"deny\"\n }}\n ]\n}\n```\n\n## Resources/Providers\n\nThe `firewall` cookbook provides the `firewall` and `firewall_rule` LWRPs, for which there is a ufw provider.\n\n## License & Authors\n\n**Author:** Cookbook Engineering Team ([cookbooks@chef.io](mailto:cookbooks@chef.io))\n\n**Copyright:** 2011-2014, Chef Software, Inc.\n\n```\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache 2.0","platforms":{"ubuntu":">= 0.0.0"},"dependencies":{"firewall":">= 2.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{},"source_url":"https://github.com/chef-cookbooks/ufw","issues_url":"https://github.com/chef-cookbooks/ufw/issues","chef_version":">= 12.4","ohai_version":{}} \ No newline at end of file diff --git a/cookbooks/ufw/recipes/databag.rb b/cookbooks/ufw/recipes/databag.rb deleted file mode 100644 index fbebae1..0000000 --- a/cookbooks/ufw/recipes/databag.rb +++ /dev/null @@ -1,58 +0,0 @@ -# -# Author:: Matt Ray -# Cookbook:: ufw -# Recipe:: databag -# -# Copyright:: 2011-2017, 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. -# - -# flatten the run_list to just the names of the roles and recipes in order -def run_list_names(run_list) - names = [] - run_list.each do |entry| - Chef::Log.debug "ufw::databag:run_list_names+name: #{entry.name}" - if entry.name.index('::') # cookbook::recipe - names.push(entry.name.sub('::', '__')) - else - names.push(entry.name) - end - if entry.role? - rol = search(:role, "name:#{entry.name}")[0] - names.concat(run_list_names(rol.run_list)) - end - end - Chef::Log.debug "ufw::databag:run_list_names+names: #{names}" - names -end - -rlist = run_list_names(node.run_list) -rlist.uniq! -Chef::Log.debug "ufw::databag:rlist: #{rlist}" - -fw_db = data_bag('firewall') -Chef::Log.debug "ufw::databag:firewall:#{fw_db}" - -rlist.each do |entry| - Chef::Log.debug "ufw::databag: \"#{entry}\"" - next unless fw_db.member?(entry) - - # add the list of firewall rules to the current list - item = data_bag_item('firewall', entry) - rules = item['rules'] - node.normal['firewall']['rules'].concat(rules) unless rules.nil? -end - -# now go apply the rules -include_recipe 'ufw::default' diff --git a/cookbooks/ufw/recipes/default.rb b/cookbooks/ufw/recipes/default.rb deleted file mode 100644 index f67c889..0000000 --- a/cookbooks/ufw/recipes/default.rb +++ /dev/null @@ -1,71 +0,0 @@ -# -# Author:: Matt Ray -# Cookbook:: ufw -# Recipe:: default -# -# Copyright:: 2011-2017, 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. -# - -firewall 'default' do - action :install -end - -# leave this on by default -firewall_rule 'ssh' do - port 22 - action :create - only_if { node['firewall']['allow_ssh'] } -end - -node['firewall']['rules'].each do |rule_mash| - Chef::Log.debug "ufw:rule \"#{rule_mash}\"" - rule_mash.keys.each do |rule| - Chef::Log.debug "ufw:rule:name \"#{rule}\"" - params = rule_mash[rule] - Chef::Log.debug "ufw:rule:parameters \"#{params}\"" - Chef::Log.debug "ufw:rule:name #{params['name']}" if params['name'] - Chef::Log.debug "ufw:rule:protocol #{params['protocol']}" if params['protocol'] - Chef::Log.debug "ufw:rule:direction #{params['direction']}" if params['direction'] - Chef::Log.debug "ufw:rule:interface #{params['interface']}" if params['interface'] - Chef::Log.debug "ufw:rule:logging #{params['logging']}" if params['logging'] - Chef::Log.debug "ufw:rule:port #{params['port']}" if params['port'] - Chef::Log.debug "ufw:rule:port_range #{params['port_range']}" if params['port_range'] - Chef::Log.debug "ufw:rule:source #{params['source']}" if params['source'] - Chef::Log.debug "ufw:rule:destination #{params['destination']}" if params['destination'] - Chef::Log.debug "ufw:rule:dest_port #{params['dest_port']}" if params['dest_port'] - Chef::Log.debug "ufw:rule:position #{params['position']}" if params['position'] - act = params['action'] - act ||= 'create' - raise 'ufw: port_range was specified to firewall_rule without protocol' if params['port_range'] && !params['protocol'] - Chef::Log.debug "ufw:rule:action :#{act}" - firewall_rule rule do - name params['name'] if params['name'] - protocol params['protocol'].to_sym if params['protocol'] - direction params['direction'].to_sym if params['direction'] - interface params['interface'] if params['interface'] - logging params['logging'].to_sym if params['logging'] - port params['port'].to_i if params['port'] - if params['port_range'] - ends = params['port_range'].split('..').map { |d| Integer(d) } - port_range ends[0]..ends[1] - end - source params['source'] if params['source'] - destination params['destination'] if params['destination'] - dest_port params['dest_port'].to_i if params['dest_port'] - position params['position'].to_i if params['position'] - action act - end - end -end diff --git a/cookbooks/ufw/recipes/recipes.rb b/cookbooks/ufw/recipes/recipes.rb deleted file mode 100644 index 1cd634c..0000000 --- a/cookbooks/ufw/recipes/recipes.rb +++ /dev/null @@ -1,41 +0,0 @@ -# -# Author:: Matt Ray -# Cookbook:: ufw -# Recipe:: recipes -# -# Copyright:: 2011-2017, 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. -# - -# expand and parse the node's runlist for recipes and find attributes of the form node[]['firewall']['rules'] -# append them to the node['firewall']['rules'] array attribute -node.expand!.recipes.each do |recipe| - Chef::Log.debug "ufw::recipes: #{recipe}" - cookbook = recipe.split('::')[0] - # get the cookbook attributes if there are any - if recipe != cookbook && node[cookbook] && node[cookbook]['firewall'] && node[cookbook]['firewall']['rules'] - rules = node[cookbook]['firewall']['rules'] - Chef::Log.debug "ufw::recipes:#{cookbook}:rules #{rules}" - node.normal['firewall']['rules'].concat(rules) unless rules.nil? - end - # get the recipe attributes if there are any - next unless node[recipe] && node[recipe]['firewall'] && node[recipe]['firewall']['rules'] - - rules = node[recipe]['firewall']['rules'] - Chef::Log.debug "ufw::recipes:#{recipe}:rules #{rules}" - node.normal['firewall']['rules'].concat(rules) unless rules.nil? -end - -# now go apply the rules -include_recipe 'ufw::default' diff --git a/cookbooks/ufw/recipes/securitylevel.rb b/cookbooks/ufw/recipes/securitylevel.rb deleted file mode 100644 index 524ac9b..0000000 --- a/cookbooks/ufw/recipes/securitylevel.rb +++ /dev/null @@ -1,41 +0,0 @@ -# -# Author:: Matt Ray -# Cookbook:: ufw -# Recipe:: securitylevel -# -# Copyright:: 2011-2017, 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. -# - -securitylevel = node['firewall']['securitylevel'] - -Chef::Log.info "ufw::securitylevel:#{securitylevel}" - -# verify that only 1 "color" security group is applied" -count = node.expand!.roles.count { |role| role =~ /SecurityLevel-(Red|Green|Yellow)/ } -if count > 1 - raise Chef::Exceptions::AmbiguousRunlistSpecification, "conflicting SecurityLevel-'color' roles, only 1 may be applied." -end - -# case securitylevel -# when 'red' -# # put special stuff for red here -# when 'yellow' -# # put special stuff for red here -# when 'green' -# # put special stuff for red here -# end - -# now go apply the rules -include_recipe 'ufw::default' diff --git a/site-cookbooks/kosmos-base/metadata.rb b/site-cookbooks/kosmos-base/metadata.rb index 9ee04ac..88981e4 100644 --- a/site-cookbooks/kosmos-base/metadata.rb +++ b/site-cookbooks/kosmos-base/metadata.rb @@ -11,6 +11,6 @@ depends 'users' depends 'sudo' depends 'kosmos-postfix' depends 'hostname' -depends 'ufw' +depends 'firewall' depends 'omnibus_updater' depends 'timezone-ii'