[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 #!powershell
# # Copyright (c) 2017 Artem Zinenko <zinenkoartem@gmail.com>
# (c) 2014, Timothy Vandenbrande <timothy.vandenbrande@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)
# 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/>.
#
# WANT_JSON # WANT_JSON
# POWERSHELL_COMMON # 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" $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 = @{ $result = @{
changed = $false changed = $false
fwsettings = @{}
msg = @()
} }
$params = Parse-Args $args -supports_check_mode $true $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" $localport = Get-AnsibleParam -obj $params -name "localport" -type "str"
$remoteport = Get-AnsibleParam -obj $params -name "remoteport" -type "str" $remoteport = Get-AnsibleParam -obj $params -name "remoteport" -type "str"
$protocol = Get-AnsibleParam -obj $params -name "protocol" -type "str" -default "any" $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" $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" $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 $force = Get-AnsibleParam -obj $params -name "force" -type "bool" -default $false
# Check the arguments if ($diff_support) {
if ($enabled) { $result.diff = @{}
$result.fwsettings.Add("Enabled", "Yes") $result.diff.prepared = ""
} else {
$result.fwsettings.Add("Enabled", "No")
} }
$result.fwsettings.Add("Rule Name", $name) try {
#$result.fwsettings.Add("displayname", $name) $fw = New-Object -ComObject HNetCfg.FwPolicy2
if ($state -eq "present") { $existingRule = $fw.Rules | Where { $_.Name -eq $name }
$result.fwsettings.Add("Direction", $(ConvertTo-TitleCase($direction)))
$result.fwsettings.Add("Action", $(ConvertTo-TitleCase $action))
}
if ($description -ne $null) { if ($existingRule -is [System.Array]) {
$result.fwsettings.Add("Description", $description) Fail-Json $result "Multiple firewall rules with name '$name' found."
} }
if ($program -ne $null) { $rule = New-FWRule -name $name `
$result.fwsettings.Add("Program", $program) -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) $fwPropertiesToCompare = @('Name','Description','Direction','Action','ApplicationName','ServiceName','Enabled','Profiles','LocalAddresses','RemoteAddresses','LocalPorts','RemotePorts','Protocol','InterfaceTypes', 'EdgeTraversalOptions', 'SecureFlags')
$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
if ($state -eq "absent") {
if ($existingRule -eq $null) {
$result.msg = "Firewall rule '$name' does not exist."
} else { } 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") if (-not $check_mode) {
Fail-Json $result $result.msg $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 ($result.changed) {
$result.msg = "Firewall rule '$name' changed."
if ($get.exists) { } else {
$result.msg = "Firewall rule '$name' already 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
} }
$result.changed = $true
} else {
$result.msg += @("Firewall rule '$name' did not exist")
} }
} catch [Exception] {
Fail-Json $result $_.Exception.Message
} }
Exit-Json $result Exit-Json $result

View file

@ -1,21 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# Copyright (c) 2017 Artem Zinenko <zinenkoartem@gmail.com>
# (c) 2014, Timothy Vandenbrande <timothy.vandenbrande@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)
# 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/>.
ANSIBLE_METADATA = {'metadata_version': '1.1', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'], 'status': ['preview'],
@ -26,80 +12,70 @@ DOCUMENTATION = r'''
--- ---
module: win_firewall_rule module: win_firewall_rule
version_added: "2.0" version_added: "2.0"
author: Timothy Vandenbrande author:
- Artem Zinenko (@ar7z1)
- Timothy Vandenbrande (@TimothyVandenbrande)
short_description: Windows firewall automation short_description: Windows firewall automation
description: description:
- Allows you to create/remove/update firewall rules - Allows you to create/remove/update firewall rules.
options: options:
enabled: 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']
description: description:
description: - Is this firewall rule enabled or disabled.
- Description for the firewall rule type: bool
localip: default: 'yes'
description: aliases: [ 'enable' ]
- The local ip address this rule applies to state:
default: 'any' description:
remoteip: - Should this rule be added or removed.
description: default: "present"
- The remote ip address/range this rule applies to choices: ['present', 'absent']
default: 'any' name:
localport: description:
description: - The rules name
- The local port this rule applies to required: true
remoteport: direction:
description: description:
- The remote port this rule applies to - Is this rule for inbound or outbound traffic.
program: required: true
description: choices: ['in', 'out']
- The program this rule applies to action:
service: description:
description: - What to do with the items this rule is for.
- The service this rule applies to required: true
protocol: choices: ['allow', 'block', 'bypass']
description: description:
- The protocol this rule applies to description:
default: 'any' - Description for the firewall rule.
profiles: localip:
description: description:
- The profile this rule applies to - The local ip address this rule applies to.
default: 'domain,private,public' default: 'any'
aliases: [ 'profile' ] remoteip:
force: description:
description: - The remote ip address/range this rule applies to.
- Replace any existing rule by removing it first. default: 'any'
default: 'no' localport:
choices: [ 'no', 'yes' ] description:
notes: - The local port this rule applies to.
- The implementation uses C(netsh advfirewall) underneath, a pure-Powershell remoteport:
reimplementation would be more powerful. description:
- Modifying existing firewall rules is not possible, the module does allow - The remote port this rule applies to.
replacing complete rules based on name, but that works by removing the program:
existing rule completely, and recreating it with provided information description:
(when using C(force)). - 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''' EXAMPLES = r'''

View file

@ -2,11 +2,8 @@
win_firewall_rule: win_firewall_rule:
name: http name: http
state: absent state: absent
action: "{{ item }}" action: allow
direction: in direction: in
with_items:
- allow
- block
- name: Add firewall rule - name: Add firewall rule
win_firewall_rule: win_firewall_rule:
@ -82,7 +79,7 @@
direction: in direction: in
protocol: tcp protocol: tcp
- name: Add different firewall rule - name: Change firewall rule
win_firewall_rule: win_firewall_rule:
name: http name: http
enabled: yes enabled: yes
@ -91,31 +88,12 @@
action: block action: block
direction: in direction: in
protocol: tcp protocol: tcp
ignore_errors: yes register: change_firewall_rule
register: add_different_firewall_rule_without_force
- name: Check that creating different firewall rule without enabling force setting fails - name: Check that changing firewall rule succeeds
assert: assert:
that: that:
- add_different_firewall_rule_without_force.failed == true - change_firewall_rule.changed == 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
- name: Add firewall rule when remoteip is range - name: Add firewall rule when remoteip is range
win_firewall_rule: win_firewall_rule:
@ -127,7 +105,6 @@
action: allow action: allow
direction: in direction: in
protocol: tcp protocol: tcp
force: yes
- name: Add same firewall rule when remoteip is range (again) - name: Add same firewall rule when remoteip is range (again)
win_firewall_rule: win_firewall_rule:
@ -156,7 +133,6 @@
action: allow action: allow
direction: in direction: in
protocol: tcp protocol: tcp
force: yes
- name: Add same firewall rule when remoteip in CIDR notation (again) - name: Add same firewall rule when remoteip in CIDR notation (again)
win_firewall_rule: win_firewall_rule:
@ -181,11 +157,10 @@
enabled: yes enabled: yes
state: present state: present
localport: 80 localport: 80
remoteip: 192.168.0.0/255.255.255.0 remoteip: 192.168.1.0/255.255.255.0
action: allow action: allow
direction: in direction: in
protocol: tcp protocol: tcp
force: yes
- name: Add same firewall rule when remoteip contains a netmask (again) - name: Add same firewall rule when remoteip contains a netmask (again)
win_firewall_rule: win_firewall_rule:
@ -193,7 +168,7 @@
enabled: yes enabled: yes
state: present state: present
localport: 80 localport: 80
remoteip: 192.168.0.0/255.255.255.0 remoteip: 192.168.1.0/255.255.255.0
action: allow action: allow
direction: in direction: in
protocol: tcp protocol: tcp
@ -214,7 +189,6 @@
action: allow action: allow
direction: in direction: in
protocol: tcp protocol: tcp
force: yes
- name: Add same firewall rule when remoteip is IPv4 (again) - name: Add same firewall rule when remoteip is IPv4 (again)
win_firewall_rule: win_firewall_rule:
@ -232,3 +206,122 @@
assert: assert:
that: that:
- add_firewall_rule_with_ipv4_remoteip_again.changed == false - 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', '>=')