[18807] win_firewall_rule module uses HNetCfg.FwPolicy2 COM Object (#27381)

* #18807 win_firewall_rule uses HNetCfg.FwPolicy2 COM object

* Added missing tests

* Added support for InterfaceTypes property

* Added support for EdgeTraversalOptions property

* Added SecureFlags property

* Port ranges are not possible in W2K8

* Added windows version checks

* Fixed doc: removed 'force' option and all notes

* Fixed copirights and docs
This commit is contained in:
Artem Zinenko 2017-08-29 23:18:03 +03:00 committed by Jordan Borean
parent 38a5033b48
commit 06fadefbdc
3 changed files with 414 additions and 522 deletions

View file

@ -1,273 +1,164 @@
#!powershell
#
# (c) 2014, Timothy Vandenbrande <timothy.vandenbrande@gmail.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (c) 2017 Artem Zinenko <zinenkoartem@gmail.com>
# Copyright (c) 2014 Timothy Vandenbrande <timothy.vandenbrande@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# WANT_JSON
# POWERSHELL_COMMON
# TODO: Reimplement this using Powershell cmdlets
function Parse-ProtocolType {
param($protocol)
$protocolNumber = $protocol -as [int]
if ($protocolNumber -is [int]) {
return $protocolNumber
}
switch -wildcard ($protocol) {
"tcp" { return [System.Net.Sockets.ProtocolType]::Tcp -as [int] }
"udp" { return [System.Net.Sockets.ProtocolType]::Udp -as [int] }
"icmpv4*" { return [System.Net.Sockets.ProtocolType]::Icmp -as [int] }
"icmpv6*" { return [System.Net.Sockets.ProtocolType]::IcmpV6 -as [int] }
default { throw "Unknown protocol '$protocol'." }
}
}
# See 'Direction' constants here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364724(v=vs.85).aspx
function Parse-Direction {
param($directionStr)
switch ($directionStr) {
"in" { return 1 }
"out" { return 2 }
default { throw "Unknown direction '$directionStr'." }
}
}
# See 'Action' constants here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364724(v=vs.85).aspx
function Parse-Action {
param($actionStr)
switch ($actionStr) {
"block" { return 0 }
"allow" { return 1 }
default { throw "Unknown action '$actionStr'." }
}
}
# Profile enum values: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366303(v=vs.85).aspx
function Parse-Profiles
{
param($profilesStr)
$profiles = ($profilesStr.Split(',') | Select -uniq | ForEach {
switch ($_) {
"domain" { return 1 }
"private" { return 2 }
"public" { return 4 }
default { throw "Unknown profile '$_'." }
}
} | Measure-Object -Sum).Sum
if ($profiles -eq 7) { return 0x7fffffff }
return $profiles
}
function Parse-InterfaceTypes
{
param($interfaceTypesStr)
return ($interfaceTypesStr.Split(',') | Select -uniq | ForEach {
switch ($_) {
"wireless" { return "Wireless" }
"lan" { return "Lan" }
"ras" { return "RemoteAccess" }
default { throw "Unknown interface type '$_'." }
}
}) -Join ","
}
function Parse-EdgeTraversalOptions
{
param($edgeTraversalOptionsStr)
switch ($edgeTraversalOptionsStr) {
"yes" { return 1 }
"deferapp" { return 2 }
"deferuser" { return 3 }
default { throw "Unknown edge traversal options '$edgeTraversalOptionsStr'." }
}
}
function Parse-SecureFlags
{
param($secureFlagsStr)
switch ($secureFlagsStr) {
"authnoencap" { return 1 }
"authenticate" { return 2 }
"authdynenc" { return 3 }
"authenc" { return 4 }
default { throw "Unknown secure flags '$secureFlagsStr'." }
}
}
function New-FWRule
{
param (
[string]$name,
[string]$description,
[string]$applicationName,
[string]$serviceName,
[string]$protocol,
[string]$localPorts,
[string]$remotePorts,
[string]$localAddresses,
[string]$remoteAddresses,
[string]$direction,
[string]$action,
[bool]$enabled,
[string]$profiles,
[string]$interfaceTypes,
[string]$edgeTraversalOptions,
[string]$secureFlags
)
# INetFwRule interface description: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365344(v=vs.85).aspx
$rule = New-Object -ComObject HNetCfg.FWRule
$rule.Name = $name
$rule.Enabled = $enabled
if ($description) { $rule.Description = $description }
if ($applicationName) { $rule.ApplicationName = $applicationName }
if ($serviceName) { $rule.ServiceName = $serviceName }
if ($protocol -and $protocol -ne "any") { $rule.Protocol = Parse-ProtocolType -protocol $protocol }
if ($localPorts -and $localPorts -ne "any") { $rule.LocalPorts = $localPorts }
if ($remotePorts -and $remotePorts -ne "any") { $rule.RemotePorts = $remotePorts }
if ($localAddresses -and $localAddresses -ne "any") { $rule.LocalAddresses = $localAddresses }
if ($remoteAddresses -and $remoteAddresses -ne "any") { $rule.RemoteAddresses = $remoteAddresses }
if ($direction) { $rule.Direction = Parse-Direction -directionStr $direction }
if ($action) { $rule.Action = Parse-Action -actionStr $action }
if ($profiles) { $rule.Profiles = Parse-Profiles -profilesStr $profiles }
if ($interfaceTypes -and $interfaceTypes -ne "any") { $rule.InterfaceTypes = Parse-InterfaceTypes -interfaceTypesStr $interfaceTypes }
if ($edgeTraversalOptions -and $edgeTraversalOptions -ne "no") {
# EdgeTraversalOptions property exists only from Windows 7/Windows Server 2008 R2: https://msdn.microsoft.com/en-us/library/windows/desktop/dd607256(v=vs.85).aspx
if ($rule | Get-Member -Name 'EdgeTraversalOptions') {
$rule.EdgeTraversalOptions = Parse-EdgeTraversalOptions -edgeTraversalOptionsStr $edgeTraversalOptions
}
}
if ($secureFlags -and $secureFlags -ne "notrequired") {
# SecureFlags property exists only from Windows 8/Windows Server 2012: https://msdn.microsoft.com/en-us/library/windows/desktop/hh447465(v=vs.85).aspx
if ($rule | Get-Member -Name 'SecureFlags') {
$rule.SecureFlags = Parse-SecureFlags -secureFlagsStr $secureFlags
}
}
return $rule
}
$ErrorActionPreference = "Stop"
function convertToNetmask($maskLength) {
[IPAddress] $ip = 0
$ip.Address = ([UInt32]::MaxValue) -shl (32 - $maskLength) -shr (32 - $maskLength)
return $ip.IPAddressToString
}
function ConvertTo-TitleCase($string) {
return (Get-Culture).TextInfo.ToTitleCase($string.ToLower())
}
function ConvertTo-SortedKV($object, $unsupported = @()) {
$output = ""
foreach($item in $object.GetEnumerator() | Sort -Property Name) {
if (($item.Name -notin $unsupported) -and ($item.Value -ne $null)) {
$output += "$($item.Name): $($item.Value)`n"
}
}
return $output
}
function preprocessAndCompare($key, $outputValue, $fwsettingValue) {
if ($key -eq 'RemoteIP') {
if ($outputValue -eq $fwsettingValue) {
return $true
}
if ($outputValue -eq $fwsettingValue+'-'+$fwsettingValue) {
return $true
}
if (($outputValue -eq $fwsettingValue+'/32') -or ($outputValue -eq $fwsettingValue+'/255.255.255.255')) {
return $true
}
if ($outputValue -match '^([\d\.]+)\/(\d+)$') {
$netmask = convertToNetmask($Matches[2])
if ($fwsettingValue -eq $Matches[1]+"/"+$netmask) {
return $true
}
}
if ($fwsettingValue -match '^([\d\.]+)\/(\d+)$') {
$netmask = convertToNetmask($Matches[2])
if ($outputValue -eq $Matches[1]+"/"+$netmask) {
return $true
}
}
}
return $false
}
function getFirewallRule ($fwsettings) {
$diff = $false
$result = @{
changed = $false
identical = $false
exists = $false
failed = $false
msg = @()
multiple = $false
}
try {
$command = "netsh advfirewall firewall show rule name=`"$($fwsettings.'Rule Name')`" verbose"
#$output = Get-NetFirewallRule -name $($fwsettings.'Rule Name')
$result.output = Invoke-Expression $command | Where { $_ }
$rc = $LASTEXITCODE
if ($rc -eq 1) {
$result.msg += @("No rule '$name' could be found")
} elseif ($rc -eq 0) {
# Process command output
$result.output | Where {$_ -match '^([^:]+):\s*(\S.*)$'} | ForEach -Begin {
$FirstRun = $true
$HashProps = @{}
} -Process {
if (($Matches[1] -eq 'Rule Name') -and (-not $FirstRun)) {
$output = $HashProps
$HashProps = @{}
}
$HashProps.$($Matches[1]) = $Matches[2]
$FirstRun = $false
} -End {
$output = $HashProps
}
if ($($output|measure).count -gt 0) {
$diff = $false
$result.exists = $true
#$result.msg += @("The rule '$($fwsettings.'Rule Name')' exists.")
if ($($output|measure).count -gt 1) {
$result.multiple = $true
$result.msg += @("The rule '$($fwsettings.'Rule Name')' has multiple entries.")
$result.diff = @{}
$result.diff.after = ConvertTo-SortedKV $fwsettings
$result.diff.before = ConvertTo-SortedKV $rule $unsupported
if ($result.diff.after -ne $result.diff.before ) {
$diff = $true
}
} else {
if ($diff_support) {
$result.diff = @{}
$result.diff.after = ConvertTo-SortedKV $fwsettings
$result.diff.before = ConvertTo-SortedKV $output $unsupported
}
ForEach($fwsetting in $fwsettings.GetEnumerator()) {
if ($output.$($fwsetting.Key) -ne $fwsettings.$($fwsetting.Key)) {
if ((preprocessAndCompare -key $fwsetting.Key -outputValue $output.$($fwsetting.Key) -fwsettingValue $fwsettings.$($fwsetting.Key))) {
Continue
} elseif (($fwsetting.Key -eq 'DisplayName') -and ($output."Rule Name" -eq $fwsettings.$($fwsetting.Key))) {
Continue
} elseif (($fwsetting.Key -eq 'Program') -and ($output.$($fwsetting.Key) -eq (Expand-Environment($fwsettings.$($fwsetting.Key))))) {
# Ignore difference caused by expanded environment variables
Continue
} else {
$diff = $true
Break
}
}
}
}
if (-not $diff) {
$result.identical = $true
}
if ($result.identical) {
$result.msg += @("The rule '$name' exists and is identical")
} else {
$result.msg += @("The rule '$name' exists but has different values")
}
}
} else {
$result.failed = $true
}
} catch [Exception] {
$result.failed = $true
$result.error = $_.Exception.Message
}
return $result
}
function createFireWallRule ($fwsettings) {
$result = @{
changed = $false
failed = $false
msg = @()
}
$command = "netsh advfirewall firewall add rule"
ForEach ($fwsetting in $fwsettings.GetEnumerator()) {
if ($fwsetting.value -ne $null) {
switch($fwsetting.key) {
"Direction" { $option = "dir" }
"Rule Name" { $option = "name" }
"Enabled" { $option = "enable" }
"Profiles" { $option = "profile" }
"InterfaceTypes" { $option = "interfacetype" }
"Security" { $option = "security" }
"Edge traversal" { $option = "edge" }
default { $option = $($fwsetting.key).ToLower() }
}
$command += " $option='$($fwsetting.value)'"
}
}
try {
$rc = 0
if (-not $check_mode) {
$result.output = Invoke-Expression $command | Where { $_ }
$rc = $LASTEXITCODE
}
if ($rc -eq 0) {
if ($diff_support) {
$result.diff = @{}
$result.diff.after = ConvertTo-SortedKV $fwsettings
$result.diff.before= ""
}
$result.changed = $true
$result.msg += @("Created firewall rule '$name'")
} else {
$result.failed = $true
$result.msg += @("Create command '$command' failed with rc=$rc")
}
} catch [Exception]{
$result.error = $_.Exception.Message
$result.failed = $true
$result.msg = @("Failed to create the rule '$name'")
}
return $result
}
function removeFireWallRule ($fwsettings) {
$result = @{
changed = $false
failed = $false
msg = @()
}
$command = "netsh advfirewall firewall delete rule name='$($fwsettings.'Rule Name')'"
try {
$rc = 0
if (-not $check_mode) {
$result.output = Invoke-Expression $command | Where { $_ }
$rc = $LASTEXITCODE
$result.output | Where {$_ -match '^([^:]+):\s*(\S.*)$'} | Foreach -Begin {
$FirstRun = $true
$HashProps = @{}
} -Process {
if (($Matches[1] -eq 'Rule Name') -and (-not $FirstRun)) {
$result.output = $HashProps
$HashProps = @{}
}
$HashProps.$($Matches[1]) = $Matches[2]
$FirstRun = $false
} -End {
$result.output = $HashProps
}
}
if ($rc -eq 0 -or $rc -eq 1) {
if ($diff_support) {
$result.diff = @{}
$result.diff.after = ""
$result.diff.before = ConvertTo-SortedKV $fwsettings
}
$result.changed = $true
$result.msg += @("Removed the rule '$name'")
} else {
$result.failed = $true
$result.msg += @("Remove command '$command' failed with rc=$rc")
}
} catch [Exception]{
$result.error = $_.Exception.Message
$result.failed = $true
$result.msg += @("Failed to remove the rule '$name'")
}
return $result
}
# FIXME: Unsupported keys
#$unsupported = @("Grouping", "Rule source")
$unsupported = @("Rule source")
$result = @{
changed = $false
fwsettings = @{}
msg = @()
}
$params = Parse-Args $args -supports_check_mode $true
@ -287,167 +178,99 @@ $remoteip = Get-AnsibleParam -obj $params -name "remoteip" -type "str" -default
$localport = Get-AnsibleParam -obj $params -name "localport" -type "str"
$remoteport = Get-AnsibleParam -obj $params -name "remoteport" -type "str"
$protocol = Get-AnsibleParam -obj $params -name "protocol" -type "str" -default "any"
$edge = Get-AnsibleParam -obj $params -name "edge" -type "str" -default "no" -validateset "no","yes","deferapp","deferuser"
$interfacetypes = Get-AnsibleParam -obj $params -name "interfacetypes" -type "str" -default "any"
$security = Get-AnsibleParam -obj $params -name "security" -type "str" -default "notrequired"
$edge = Get-AnsibleParam -obj $params -name "edge" -type "str" -default "no" -validateset "no","yes","deferapp","deferuser"
$security = Get-AnsibleParam -obj $params -name "security" -type "str" -default "notrequired" -validateset "notrequired","authnoencap","authenticate","authdynenc","authenc"
$state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset "present","absent"
$force = Get-AnsibleParam -obj $params -name "force" -type "bool" -default $false
# Check the arguments
if ($enabled) {
$result.fwsettings.Add("Enabled", "Yes")
} else {
$result.fwsettings.Add("Enabled", "No")
if ($diff_support) {
$result.diff = @{}
$result.diff.prepared = ""
}
$result.fwsettings.Add("Rule Name", $name)
#$result.fwsettings.Add("displayname", $name)
try {
$fw = New-Object -ComObject HNetCfg.FwPolicy2
if ($state -eq "present") {
$result.fwsettings.Add("Direction", $(ConvertTo-TitleCase($direction)))
$result.fwsettings.Add("Action", $(ConvertTo-TitleCase $action))
}
$existingRule = $fw.Rules | Where { $_.Name -eq $name }
if ($description -ne $null) {
$result.fwsettings.Add("Description", $description)
}
if ($existingRule -is [System.Array]) {
Fail-Json $result "Multiple firewall rules with name '$name' found."
}
if ($program -ne $null) {
$result.fwsettings.Add("Program", $program)
}
$rule = New-FWRule -name $name `
-description $description `
-direction $direction `
-action $action `
-applicationName $program `
-serviceName $service `
-enabled $enabled `
-profiles $profiles `
-localAddresses $localip `
-remoteAddresses $remoteip `
-localPorts $localport `
-remotePorts $remoteport `
-protocol $protocol `
-interfaceTypes $interfacetypes `
-edgeTraversalOptions $edge `
-secureFlags $security
$result.fwsettings.Add("LocalIP", $localip)
$result.fwsettings.Add("RemoteIP", $remoteip)
if ($localport -ne $null) {
$result.fwsettings.Add("LocalPort", $localport)
}
if ($remoteport -ne $null) {
$result.fwsettings.Add("RemotePort", $remoteport)
}
if ($service -ne $null) {
$result.fwsettings.Add("Service", $(ConvertTo-TitleCase($service)))
}
if ($protocol -eq "Any") {
$result.fwsettings.Add("Protocol", $protocol)
} else {
$result.fwsettings.Add("Protocol", $protocol.toupper())
}
if ($profiles -eq "Any") {
$result.fwsettings.Add("Profiles", "Domain,Private,Public")
} else {
$result.fwsettings.Add("Profiles", $(ConvertTo-TitleCase($profiles)))
}
$result.fwsettings.Add("Edge traversal", $(ConvertTo-TitleCase($edge)))
if ($interfacetypes -ne $null) {
$result.fwsettings.Add("InterfaceTypes", $(ConvertTo-TitleCase($interfacetypes)))
}
switch($security) {
"Authenticate" { $security = "Authenticate" }
"AuthDynEnc" { $security = "AuthDynEnc" }
"AuthEnc" { $security = "AuthEnc" }
"AuthNoEncap" { $security = "AuthNoEncap" }
"NotRequired" { $security = "NotRequired" }
}
$result.fwsettings.Add("Security", $security)
# FIXME: Define unsupported options
#$result.fwsettings.Add("Grouping", "")
#$result.fwsettings.Add("Rule source", "Local Setting")
$get = getFirewallRule($result.fwsettings)
$result.msg += $get.msg
if ($get.failed) {
$result.error = $get.error
$result.output = $get.output
Fail-Json $result $result.msg
}
$result.diff = $get.diff
if ($state -eq "present") {
if (-not $get.exists) {
$create = createFireWallRule($result.fwsettings)
$result.msg += $create.msg
$result.diff = $create.diff
if ($create.failed) {
$result.error = $create.error
$result.output = $create.output
Fail-Json $result $result.msg
}
$result.changed = $true
} elseif (-not $get.identical) {
# FIXME: This ought to use netsh advfirewall firewall set instead !
if ($force) {
$remove = removeFirewallRule($result.fwsettings)
# NOTE: We retain the diff output from $get.diff here
$result.msg += $remove.msg
if ($remove.failed) {
$result.error = $remove.error
$result.output = $remove.output
Fail-Json $result $result.msg
}
$create = createFireWallRule($result.fwsettings)
# NOTE: We retain the diff output from $get.diff here
$result.msg += $create.msg
if ($create.failed) {
$result.error = $create.error
$result.output = $create.output
Fail-Json $result $result.msg
}
$result.changed = $true
$fwPropertiesToCompare = @('Name','Description','Direction','Action','ApplicationName','ServiceName','Enabled','Profiles','LocalAddresses','RemoteAddresses','LocalPorts','RemotePorts','Protocol','InterfaceTypes', 'EdgeTraversalOptions', 'SecureFlags')
if ($state -eq "absent") {
if ($existingRule -eq $null) {
$result.msg = "Firewall rule '$name' does not exist."
} else {
if ($diff_support) {
foreach ($prop in $fwPropertiesToCompare) {
$result.diff.prepared += "-[$($prop)='$($existingRule.$prop)']`n"
}
}
$result.msg += @("There was already a rule '$name' with different values, use the 'force' parameter to overwrite it")
Fail-Json $result $result.msg
if (-not $check_mode) {
$fw.Rules.Remove($existingRule.Name)
}
$result.changed = $true
$result.msg = "Firewall rule '$name' removed."
}
} else {
} elseif ($state -eq "present") {
if ($existingRule -eq $null) {
if ($diff_support) {
foreach ($prop in $fwPropertiesToCompare) {
$result.diff.prepared += "+[$($prop)='$($existingRule.$prop)']`n"
}
}
$result.msg += @("Firewall rule '$name' was already created")
if (-not $check_mode) {
$fw.Rules.Add($rule)
}
$result.changed = $true
$result.msg = "Firewall rule '$name' created."
} else {
foreach ($prop in $fwPropertiesToCompare) {
if ($existingRule.$prop -ne $rule.$prop) {
if ($diff_support) {
$result.diff.prepared += "-[$($prop)='$($existingRule.$prop)']`n"
$result.diff.prepared += "+[$($prop)='$($rule.$prop)']`n"
}
}
if (-not $check_mode) {
$existingRule.$prop = $rule.$prop
}
$result.changed = $true
}
}
} elseif ($state -eq "absent") {
if ($get.exists) {
$remove = removeFirewallRule($result.fwsettings)
$result.diff = $remove.diff
$result.msg += $remove.msg
if ($remove.failed) {
$result.error = $remove.error
$result.output = $remove.output
Fail-Json $result $result.msg
if ($result.changed) {
$result.msg = "Firewall rule '$name' changed."
} else {
$result.msg = "Firewall rule '$name' already exists."
}
}
$result.changed = $true
} else {
$result.msg += @("Firewall rule '$name' did not exist")
}
} catch [Exception] {
Fail-Json $result $_.Exception.Message
}
Exit-Json $result

View file

@ -1,21 +1,7 @@
#!/usr/bin/env python
# (c) 2014, Timothy Vandenbrande <timothy.vandenbrande@gmail.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# Copyright (c) 2017 Artem Zinenko <zinenkoartem@gmail.com>
# Copyright (c) 2014 Timothy Vandenbrande <timothy.vandenbrande@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
@ -26,80 +12,70 @@ DOCUMENTATION = r'''
---
module: win_firewall_rule
version_added: "2.0"
author: Timothy Vandenbrande
author:
- Artem Zinenko (@ar7z1)
- Timothy Vandenbrande (@TimothyVandenbrande)
short_description: Windows firewall automation
description:
- Allows you to create/remove/update firewall rules
- Allows you to create/remove/update firewall rules.
options:
enabled:
description:
- Is this firewall rule enabled or disabled
default: 'yes'
choices: [ 'no', 'yes' ]
aliases: [ 'enable' ]
state:
description:
- Should this rule be added or removed
default: "present"
choices: ['present', 'absent']
name:
description:
- The rules name
required: true
direction:
description:
- Is this rule for inbound or outbound traffic
required: true
choices: ['in', 'out']
action:
description:
- What to do with the items this rule is for
required: true
choices: ['allow', 'block', 'bypass']
enabled:
description:
description:
- Description for the firewall rule
localip:
description:
- The local ip address this rule applies to
default: 'any'
remoteip:
description:
- The remote ip address/range this rule applies to
default: 'any'
localport:
description:
- The local port this rule applies to
remoteport:
description:
- The remote port this rule applies to
program:
description:
- The program this rule applies to
service:
description:
- The service this rule applies to
protocol:
description:
- The protocol this rule applies to
default: 'any'
profiles:
description:
- The profile this rule applies to
default: 'domain,private,public'
aliases: [ 'profile' ]
force:
description:
- Replace any existing rule by removing it first.
default: 'no'
choices: [ 'no', 'yes' ]
notes:
- The implementation uses C(netsh advfirewall) underneath, a pure-Powershell
reimplementation would be more powerful.
- Modifying existing firewall rules is not possible, the module does allow
replacing complete rules based on name, but that works by removing the
existing rule completely, and recreating it with provided information
(when using C(force)).
- Is this firewall rule enabled or disabled.
type: bool
default: 'yes'
aliases: [ 'enable' ]
state:
description:
- Should this rule be added or removed.
default: "present"
choices: ['present', 'absent']
name:
description:
- The rules name
required: true
direction:
description:
- Is this rule for inbound or outbound traffic.
required: true
choices: ['in', 'out']
action:
description:
- What to do with the items this rule is for.
required: true
choices: ['allow', 'block', 'bypass']
description:
description:
- Description for the firewall rule.
localip:
description:
- The local ip address this rule applies to.
default: 'any'
remoteip:
description:
- The remote ip address/range this rule applies to.
default: 'any'
localport:
description:
- The local port this rule applies to.
remoteport:
description:
- The remote port this rule applies to.
program:
description:
- The program this rule applies to.
service:
description:
- The service this rule applies to.
protocol:
description:
- The protocol this rule applies to.
default: 'any'
profiles:
description:
- The profile this rule applies to.
default: 'domain,private,public'
aliases: [ 'profile' ]
'''
EXAMPLES = r'''

View file

@ -2,11 +2,8 @@
win_firewall_rule:
name: http
state: absent
action: "{{ item }}"
action: allow
direction: in
with_items:
- allow
- block
- name: Add firewall rule
win_firewall_rule:
@ -82,7 +79,7 @@
direction: in
protocol: tcp
- name: Add different firewall rule
- name: Change firewall rule
win_firewall_rule:
name: http
enabled: yes
@ -91,31 +88,12 @@
action: block
direction: in
protocol: tcp
ignore_errors: yes
register: add_different_firewall_rule_without_force
register: change_firewall_rule
- name: Check that creating different firewall rule without enabling force setting fails
- name: Check that changing firewall rule succeeds
assert:
that:
- add_different_firewall_rule_without_force.failed == true
- add_different_firewall_rule_without_force.changed == false
- name: Add different firewall rule with force setting
win_firewall_rule:
name: http
enabled: yes
state: present
localport: 80
action: block
direction: in
protocol: tcp
force: yes
register: add_different_firewall_rule_with_force
- name: Check that creating different firewall rule with enabling force setting succeeds
assert:
that:
- add_different_firewall_rule_with_force.changed == true
- change_firewall_rule.changed == true
- name: Add firewall rule when remoteip is range
win_firewall_rule:
@ -127,7 +105,6 @@
action: allow
direction: in
protocol: tcp
force: yes
- name: Add same firewall rule when remoteip is range (again)
win_firewall_rule:
@ -156,7 +133,6 @@
action: allow
direction: in
protocol: tcp
force: yes
- name: Add same firewall rule when remoteip in CIDR notation (again)
win_firewall_rule:
@ -181,11 +157,10 @@
enabled: yes
state: present
localport: 80
remoteip: 192.168.0.0/255.255.255.0
remoteip: 192.168.1.0/255.255.255.0
action: allow
direction: in
protocol: tcp
force: yes
- name: Add same firewall rule when remoteip contains a netmask (again)
win_firewall_rule:
@ -193,7 +168,7 @@
enabled: yes
state: present
localport: 80
remoteip: 192.168.0.0/255.255.255.0
remoteip: 192.168.1.0/255.255.255.0
action: allow
direction: in
protocol: tcp
@ -214,7 +189,6 @@
action: allow
direction: in
protocol: tcp
force: yes
- name: Add same firewall rule when remoteip is IPv4 (again)
win_firewall_rule:
@ -232,3 +206,122 @@
assert:
that:
- add_firewall_rule_with_ipv4_remoteip_again.changed == false
- name: Add firewall rule when remoteip contains a netmask
win_firewall_rule:
name: http
enabled: yes
state: present
localport: 80
remoteip: 192.168.2.0/255.255.255.0
action: allow
direction: in
protocol: tcp
- name: Add same firewall rule when remoteip in CIDR notation
win_firewall_rule:
name: http
enabled: yes
state: present
localport: 80
remoteip: 192.168.2.0/24
action: allow
direction: in
protocol: tcp
register: add_same_firewall_rule_with_cidr_remoteip
- name: Check that creating same firewall rule succeeds without a change when remoteip contains a netmask or CIDR
assert:
that:
- add_same_firewall_rule_with_cidr_remoteip.changed == false
- name: Add firewall rule with multiple ports
win_firewall_rule:
name: http
enabled: yes
state: present
localport: '80,81'
action: allow
direction: in
protocol: tcp
register: add_firewall_rule_with_multiple_ports
- name: Check that creating firewall rule with multiple ports succeeds with a change
assert:
that:
- add_firewall_rule_with_multiple_ports.changed == true
- name: Add firewall rule with interface types
win_firewall_rule:
name: http
enabled: yes
state: present
localport: 80
action: allow
direction: in
protocol: tcp
interfacetypes: 'ras,lan,wireless'
register: add_firewall_rule_with_interface_types
- name: Check that creating firewall rule with interface types succeeds with a change
assert:
that:
- add_firewall_rule_with_interface_types.changed == true
- name: Add firewall rule with interface type 'any'
win_firewall_rule:
name: http
enabled: yes
state: present
localport: 80
action: allow
direction: in
protocol: tcp
interfacetypes: any
register: add_firewall_rule_with_interface_type_any
- name: Check that creating firewall rule with interface type 'any' succeeds with a change
assert:
that:
- add_firewall_rule_with_interface_type_any.changed == true
- name: Add firewall rule with edge traversal option 'deferapp'
win_firewall_rule:
name: http
enabled: yes
state: present
localport: 80
action: allow
direction: in
protocol: tcp
edge: deferapp
register: add_firewall_rule_with_edge_traversal
# Setup action creates ansible_distribution_version variable
- action: setup
- name: Check that creating firewall rule with enge traversal option 'deferapp' succeeds with a change
assert:
that:
- add_firewall_rule_with_edge_traversal.changed == true
# Works on windows >= Windows 7/Windows Server 2008 R2
when: ansible_distribution_version | version_compare('6.1', '>=')
- name: Add firewall rule with 'authenticate' secure flag
win_firewall_rule:
name: http
enabled: yes
state: present
localport: 80
action: allow
direction: in
protocol: tcp
security: authenticate
register: add_firewall_rule_with_secure_flags
- name: Check that creating firewall rule with secure flag 'authenticate' succeeds with a change
assert:
that:
- add_firewall_rule_with_secure_flags.changed == true
# Works on windows >= Windows 8/Windows Server 2012
when: ansible_distribution_version | version_compare('6.2', '>=')