summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Smith <tsmith@chef.io>2020-07-15 14:11:18 -0700
committerGitHub <noreply@github.com>2020-07-15 14:11:18 -0700
commite01a00934565c40b053145b91bf97dc96e18d5d7 (patch)
tree29e548f68ad82e5980768210e933ceebe932d0c4
parent6462439e3a7583b4a3a60c13456e5fdf8188bd04 (diff)
parent9bdf2b344af5b98905f8bc5b4744cc9d2830b08d (diff)
downloadchef-e01a00934565c40b053145b91bf97dc96e18d5d7.tar.gz
Merge pull request #9994 from chef-davin/windows_firewall_profile
Create the windows_firewall_profile resource for use with enabling/disabling and configuring the Windows firewall Domain, Private, and Public profiles
-rw-r--r--cspell.json3
-rw-r--r--lib/chef/provider/package/snap.rb2
-rw-r--r--lib/chef/resource/windows_firewall_profile.rb197
-rw-r--r--lib/chef/resources.rb1
-rw-r--r--spec/unit/resource/windows_firewall_profile_spec.rb77
5 files changed, 279 insertions, 1 deletions
diff --git a/cspell.json b/cspell.json
index c900adbc84..30f26af8b0 100644
--- a/cspell.json
+++ b/cspell.json
@@ -302,6 +302,7 @@
"cpio",
"cpjones",
"CPPFLAGS",
+ "Crae",
"Cragun",
"CREAT",
"createhomedir",
@@ -1988,6 +1989,8 @@
"unformatter",
"Unformatter",
"unhold",
+ "unicast",
+ "Unicast",
"unignored",
"uninst",
"unintuitive",
diff --git a/lib/chef/provider/package/snap.rb b/lib/chef/provider/package/snap.rb
index 921227ad06..77b33d5c7f 100644
--- a/lib/chef/provider/package/snap.rb
+++ b/lib/chef/provider/package/snap.rb
@@ -137,7 +137,7 @@ class Chef
# while it is expected to allow clients to connect using https over
# a tcp socket, at this point only a unix socket is supported. the
- # socket is /run/snapd.socket note - unix socket is not defined on
+ # socket is /run/snapd.socket note - UNIXSocket is not defined on
# windows systems
if defined?(::UNIXSocket)
UNIXSocket.open("/run/snapd.socket") do |socket|
diff --git a/lib/chef/resource/windows_firewall_profile.rb b/lib/chef/resource/windows_firewall_profile.rb
new file mode 100644
index 0000000000..c17572a0bd
--- /dev/null
+++ b/lib/chef/resource/windows_firewall_profile.rb
@@ -0,0 +1,197 @@
+#
+# Author:: John McCrae (<jmccrae@chef.io>)
+# Author:: Davin Taddeo (<davin@chef.io>)
+# Copyright:: Copyright (c) Chef Software Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class Resource
+ class WindowsFirewallProfile < Chef::Resource
+ provides :windows_firewall_profile
+ description "Use the **windows_firewall_profile** resource to enable, disable, and configure the Windows firewall."
+ introduced "16.3"
+
+ examples <<~DOC
+ **Enable and Configure the Private Profile of the Windows Profile**:
+
+ ```ruby
+ windows_firewall_profile 'Private' do
+ default_inbound_action 'Block'
+ default_outbound_action 'Allow'
+ allow_inbound_rules 'True'
+ display_notification 'False'
+ action :enable
+ end
+ ```
+
+ **Enable and Configure the Public Profile of the Windows Firewall**:
+
+ ```ruby
+ windows_firewall_profile 'Public' do
+ default_inbound_action 'Block'
+ default_outbound_action 'Allow'
+ allow_inbound_rules 'False'
+ display_notification 'False'
+ action :enable
+ end
+ ```
+
+ **Disable the Domain Profile of the Windows Firewall**:
+
+ ```ruby
+ windows_firewall_profile 'Disable the Domain Profile of the Windows Firewall' do
+ profile 'Domain'
+ action :disable
+ end
+ ```
+ DOC
+
+ unified_mode true
+
+ property :profile, String,
+ name_property: true,
+ equal_to: %w{ Domain Public Private },
+ description: "Set the Windows Profile being configured"
+
+ property :default_inbound_action, [String, nil],
+ equal_to: %w{ Allow Block NotConfigured },
+ description: "Set the default policy for inbound network traffic"
+
+ property :default_outbound_action, [String, nil],
+ equal_to: %w{ Allow Block NotConfigured },
+ description: "Set the default policy for outbound network traffic"
+
+ property :allow_inbound_rules, [true, false, String], equal_to: [true, false, "NotConfigured"], description: "Allow users to set inbound firewall rules"
+ property :allow_local_firewall_rules, [true, false, String], equal_to: [true, false, "NotConfigured"], description: "Merges inbound firewall rules into the policy"
+ property :allow_local_ipsec_rules, [true, false, String], equal_to: [true, false, "NotConfigured"], description: "Allow users to manage local connection security rules"
+ property :allow_user_apps, [true, false, String], equal_to: [true, false, "NotConfigured"], description: "Allow user applications to manage firewall"
+ property :allow_user_ports, [true, false, String], equal_to: [true, false, "NotConfigured"], description: "Allow users to manage firewall port rules"
+ property :allow_unicast_response, [true, false, String], equal_to: [true, false, "NotConfigured"], description: "Allow unicast responses to multicast and broadcast messages"
+ property :display_notification, [true, false, String], equal_to: [true, false, "NotConfigured"], description: "Display a notification when firewall blocks certain activity"
+
+ load_current_value do |desired|
+ ps_get_net_fw_profile = load_firewall_state(desired.profile)
+ output = powershell_out(ps_get_net_fw_profile)
+ if output.stdout.empty?
+ current_value_does_not_exist!
+ else
+ state = Chef::JSONCompat.from_json(output.stdout)
+ end
+
+ default_inbound_action state["default_inbound_action"]
+ default_outbound_action state["default_outbound_action"]
+ allow_inbound_rules convert_to_ruby(state["allow_inbound_rules"])
+ allow_local_firewall_rules convert_to_ruby(state["allow_local_firewall_rules"])
+ allow_local_ipsec_rules convert_to_ruby(state["allow_local_ipsec_rules"])
+ allow_user_apps convert_to_ruby(state["allow_user_apps"])
+ allow_user_ports convert_to_ruby(state["allow_user_ports"])
+ allow_unicast_response convert_to_ruby(state["allow_unicast_response"])
+ display_notification convert_to_ruby(state["display_notification"])
+ end
+
+ def convert_to_ruby(obj)
+ if obj.to_s.downcase == "true"
+ true
+ elsif obj.to_s.downcase == "false"
+ false
+ elsif obj.to_s.downcase == "notconfigured"
+ "NotConfigured"
+ end
+ end
+
+ def convert_to_powershell(obj)
+ if obj.to_s.downcase == "true"
+ "True"
+ elsif obj.to_s.downcase == "false"
+ "False"
+ elsif obj.to_s.downcase == "notconfigured"
+ "NotConfigured"
+ end
+ end
+
+ action :enable do
+ converge_if_changed :default_inbound_action, :default_outbound_action, :allow_inbound_rules, :allow_local_firewall_rules,
+ :allow_local_ipsec_rules, :allow_user_apps, :allow_user_ports, :allow_unicast_response, :display_notification do
+ fw_cmd = firewall_command(new_resource.profile)
+ powershell_exec!(fw_cmd)
+ end
+ unless firewall_enabled?(new_resource.profile)
+ converge_by "Enable the #{new_resource.profile} Firewall Profile" do
+ cmd = "Set-NetFirewallProfile -Profile #{new_resource.profile} -Enabled \"True\""
+ powershell_out!(cmd)
+ end
+ end
+ end
+
+ action :disable do
+ if firewall_enabled?(new_resource.profile)
+ converge_by "Disable the #{new_resource.profile} Firewall Profile" do
+ cmd = "Set-NetFirewallProfile -Profile #{new_resource.profile} -Enabled \"False\""
+ powershell_out!(cmd)
+ end
+ end
+ end
+
+ action_class do
+ def firewall_command(fw_profile)
+ cmd = "Set-NetFirewallProfile -Profile \"#{fw_profile}\""
+ cmd << " -DefaultInboundAction \"#{new_resource.default_inbound_action}\"" unless new_resource.default_inbound_action.nil?
+ cmd << " -DefaultOutboundAction \"#{new_resource.default_outbound_action}\"" unless new_resource.default_outbound_action.nil?
+ cmd << " -AllowInboundRules \"#{convert_to_powershell(new_resource.allow_inbound_rules)}\"" unless new_resource.allow_inbound_rules.nil?
+ cmd << " -AllowLocalFirewallRules \"#{convert_to_powershell(new_resource.allow_local_firewall_rules)}\"" unless new_resource.allow_local_firewall_rules.nil?
+ cmd << " -AllowLocalIPsecRules \"#{convert_to_powershell(new_resource.allow_local_ipsec_rules)}\"" unless new_resource.allow_local_ipsec_rules.nil?
+ cmd << " -AllowUserApps \"#{convert_to_powershell(new_resource.allow_user_apps)}\"" unless new_resource.allow_user_apps.nil?
+ cmd << " -AllowUserPorts \"#{convert_to_powershell(new_resource.allow_user_ports)}\"" unless new_resource.allow_user_ports.nil?
+ cmd << " -AllowUnicastResponseToMulticast \"#{convert_to_powershell(new_resource.allow_unicast_response)}\"" unless new_resource.allow_unicast_response.nil?
+ cmd << " -NotifyOnListen \"#{convert_to_powershell(new_resource.display_notification)}\"" unless new_resource.display_notification.nil?
+ cmd
+ end
+
+ def load_firewall_state(profile_name)
+ <<-EOH
+ Remove-TypeData System.Array # workaround for PS bug here: https://bit.ly/2SRMQ8M
+ $#{profile_name} = Get-NetFirewallProfile -Profile #{profile_name}
+ ([PSCustomObject]@{
+ default_inbound_action = $#{profile_name}.DefaultInboundAction.ToString()
+ default_outbound_action = $#{profile_name}.DefaultOutboundAction.ToString()
+ allow_inbound_rules = $#{profile_name}.AllowInboundRules.ToString()
+ allow_local_firewall_rules = $#{profile_name}.AllowLocalFirewallRules.ToString()
+ allow_local_ipsec_rules = $#{profile_name}.AllowLocalIPsecRules.ToString()
+ allow_user_apps = $#{profile_name}.AllowUserApps.ToString()
+ allow_user_ports = $#{profile_name}.AllowUserPorts.ToString()
+ allow_unicast_response = $#{profile_name}.AllowUnicastResponseToMulticast.ToString()
+ display_notification = $#{profile_name}.NotifyOnListen.ToString()
+ }) | ConvertTo-Json
+ EOH
+ end
+
+ def firewall_enabled?(profile_name)
+ cmd = <<~CODE
+ $#{profile_name} = Get-NetFirewallProfile -Profile #{profile_name}
+ if ($#{profile_name}.Enabled) {
+ return $true
+ } else {return $false}
+ CODE
+ firewall_status = powershell_out(cmd).stdout
+ if firewall_status =~ /True/
+ true
+ elsif firewall_status =~ /False/
+ false
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb
index 619ffe6f6f..a47b96cb5c 100644
--- a/lib/chef/resources.rb
+++ b/lib/chef/resources.rb
@@ -153,6 +153,7 @@ require_relative "resource/windows_dns_zone"
require_relative "resource/windows_feature"
require_relative "resource/windows_feature_dism"
require_relative "resource/windows_feature_powershell"
+require_relative "resource/windows_firewall_profile"
require_relative "resource/windows_firewall_rule"
require_relative "resource/windows_font"
require_relative "resource/windows_pagefile"
diff --git a/spec/unit/resource/windows_firewall_profile_spec.rb b/spec/unit/resource/windows_firewall_profile_spec.rb
new file mode 100644
index 0000000000..086ac78998
--- /dev/null
+++ b/spec/unit/resource/windows_firewall_profile_spec.rb
@@ -0,0 +1,77 @@
+#
+# Copyright:: Copyright (c) Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# 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.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::WindowsFirewallProfile do
+ let(:resource) { Chef::Resource::WindowsFirewallProfile.new("fakey_fakerton") }
+
+ it "sets resource name as :windows_firewall_profile" do
+ expect(resource.resource_name).to eql(:windows_firewall_profile)
+ end
+
+ %w{ Domain Private Public }.each do |this_profile|
+ it "The profile accepts values for the \"#{this_profile}\" Profile" do
+ expect { resource.profile this_profile }.not_to raise_error
+ end
+ end
+
+ it "the profile property does not accept bad profile names" do
+ expect { resource.profile "Special" }.to raise_error(Chef::Exceptions::ValidationFailed)
+ end
+
+ it "the resource's default_inbound_action property only strings Block, Allow, or NotConfigured" do
+ expect { resource.default_inbound_action "AllowSome" }.to raise_error(ArgumentError)
+ expect { resource.default_inbound_action "Block" }.not_to raise_error
+ end
+ it "the resource's default_outbound_action property only accepts strings Block, Allow, or NotConfigured" do
+ expect { resource.default_outbound_action "BlockMost" }.to raise_error(ArgumentError)
+ expect { resource.default_outbound_action "Allow" }.not_to raise_error
+ end
+ it "the resource's allow_inbound_rules property only accepts strings true, false, or NotConfigured" do
+ expect { resource.allow_inbound_rules "Yes" }.to raise_error(ArgumentError)
+ expect { resource.allow_inbound_rules true }.not_to raise_error
+ end
+ it "the resource's allow_local_firewall_rules property only accepts strings true, false, or NotConfigured" do
+ expect { resource.allow_local_firewall_rules "No" }.to raise_error(ArgumentError)
+ expect { resource.allow_local_firewall_rules false }.not_to raise_error
+ end
+ it "the resource's allow_local_ipsec_rules property only accepts strings true, false, or NotConfigured" do
+ expect { resource.allow_local_ipsec_rules "Yes" }.to raise_error(ArgumentError)
+ expect { resource.allow_local_ipsec_rules true }.not_to raise_error
+ end
+ it "the resource's allow_user_apps property only accepts strings true, false, or NotConfigured" do
+ expect { resource.allow_user_apps "No" }.to raise_error(ArgumentError)
+ expect { resource.allow_user_apps false }.not_to raise_error
+ end
+ it "the resource's allow_user_ports property only accepts strings true, false, or NotConfigured" do
+ expect { resource.allow_user_ports "Nope" }.to raise_error(ArgumentError)
+ expect { resource.allow_user_ports "NotConfigured" }.not_to raise_error
+ end
+ it "the resource's allow_unicast_response property only accepts strings true, false, or NotConfigured" do
+ expect { resource.allow_unicast_response "True" }.to raise_error(ArgumentError)
+ expect { resource.allow_unicast_response true }.not_to raise_error
+ end
+ it "the resource's display_notification property only accepts strings true, false, or NotConfigured" do
+ expect { resource.display_notification "False" }.to raise_error(ArgumentError)
+ expect { resource.display_notification false }.not_to raise_error
+ end
+
+ it "sets the default action as :configure" do
+ expect(resource.action).to eql([:enable])
+ end
+end