ansible-collections / community.windows

Windows community collection for Ansible
https://galaxy.ansible.com/community/windows
GNU General Public License v3.0
205 stars 159 forks source link

win_firewall_rule: Rule Not Added #154

Open jimbo8098 opened 4 years ago

jimbo8098 commented 4 years ago

I have written an Ansible playbook with the intention of building a docker cluster, however, I am having some issues wherein the win_firewall_rule doesn't result in the inbound rules (specifically) being added. Inbound rules are added perfectly fine. Here is my task list.

These rules should allow access on all profiles on:

Now I've done some digging in /usr/lib/python3/dist-packages/ansible/modules/windows/win_firewall_rule.ps1 on the host and found that the creation depends on New-Object -ComObject HNetCfg.FWRule. To emulate that I tried to add a new rule manually using the following object, based on New-Object -ComObject HNetCfg.FWRule:

PS C:\> $newrule

Name                        : Test
Description                 :
ApplicationName             :
serviceName                 :
Protocol                    : 6
LocalPorts                  : 2376
RemotePorts                 : *
LocalAddresses              : *
RemoteAddresses             : *
IcmpTypesAndCodes           :
Direction                   : 1
Interfaces                  :
InterfaceTypes              : All
Enabled                     : True
Grouping                    :
Profiles                    : 1
EdgeTraversal               : False
Action                      : 1
EdgeTraversalOptions        : 0
LocalAppPackageId           :
LocalUserOwner              :
LocalUserAuthorizedList     :
RemoteUserAuthorizedList    :
RemoteMachineAuthorizedList :
SecureFlags                 : 0
ISSUE TYPE
COMPONENT NAME

win_firewall_rule

ANSIBLE VERSION
ansible 2.9.6
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/jimspeir/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.8.5 (default, Jul 28 2020, 12:59:40) [GCC 9.3.0]
CONFIGURATION
<blank>
OS / ENVIRONMENT
uname -a
Linux master 5.4.0-52-generic #57-Ubuntu SMP Thu Oct 15 10:57:00 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

On the server I'm running the script on: image

STEPS TO REPRODUCE

Using the following task list, the issue is apparent with all inbound rules.

- name: Add docker port to firewall (2376)
  win_firewall_rule:
    action: allow
    name: Docker Client Communication
    protocol: tcp
    localport: 2376
    direction: "{{ item }}"
  register: test
  become: yes
  loop:
    - in
    - out
- debug:
    var: test
- name: Add docker port to firewall (2377 inbound)
  win_firewall_rule:
    action: allow
    name: Docker Swarm Communication
    protocol: tcp
    localport: 2377
    direction: "{{ item }}"
  loop:
    - in
    - out
- name: Add docker port to firewall (7946)
  win_firewall_rule:
    action: allow
    name: Docker Node Communication (Network Discovery)
    protocol: "{{ item.protocol }}"
    localport: 7946
    direction: "{{ item.direction }}"
  loop:
    - { protocol: "udp", direction: "in" }
    - { protocol: "udp", direction: "out" }
    - { protocol: "tcp", direction: "in" }
    - { protocol: "tcp", direction: "out" }
- name: Add docker port to firewall (4789)
  win_firewall_rule:
    action: allow
    name: Docker Node Communication (Ingress)
    protocol: udp
    localport: 4789
    direction: "{{ item }}"
  loop:
    - in
    - out
EXPECTED RESULTS

Get-NetFirewallRule -DisplayName "Docker*"

Should show the newly added firewall rule alongside the inbound rules showing in the firewall control panel for Windows.

ACTUAL RESULTS

Windows Defender Firewall and Get-NetFirewallRule do not show the inbound rules.

PS C:\> Get-NetFirewallRule -DisplayName "Docker*"

Name                  : {9562FC2B-EC40-4DD5-8AA3-F2DE04CF5B3F}
DisplayName           : Docker Client Communication
Description           :
DisplayGroup          :
Group                 :
Enabled               : True
Profile               : Domain
Platform              : {}
Direction             : Outbound
Action                : Allow
EdgeTraversalPolicy   : Block
LooseSourceMapping    : False
LocalOnlyMapping      : False
Owner                 :
PrimaryStatus         : OK
Status                : The rule was parsed successfully from the store. (65536)
EnforcementStatus     : NotApplicable
PolicyStoreSource     : PersistentStore
PolicyStoreSourceType : Local

Name                  : {0278C31B-2F3B-4803-B5AB-DB3C7C8A0C5F}
DisplayName           : Docker Node Communication (Network Discovery)
Description           :
DisplayGroup          :
Group                 :
Enabled               : True
Profile               : Domain
Platform              : {}
Direction             : Outbound
Action                : Allow
EdgeTraversalPolicy   : Block
LooseSourceMapping    : False
LocalOnlyMapping      : False
Owner                 :
PrimaryStatus         : OK
Status                : The rule was parsed successfully from the store. (65536)
EnforcementStatus     : NotApplicable
PolicyStoreSource     : PersistentStore
PolicyStoreSourceType : Local

Name                  : {F692E217-5325-4C6B-B454-2446BB7D1E60}
DisplayName           : Docker Node Communication (Ingress)
Description           :
DisplayGroup          :
Group                 :
Enabled               : True
Profile               : Domain
Platform              : {}
Direction             : Outbound
Action                : Allow
EdgeTraversalPolicy   : Block
LooseSourceMapping    : False
LocalOnlyMapping      : False
Owner                 :
PrimaryStatus         : OK
Status                : The rule was parsed successfully from the store. (65536)
EnforcementStatus     : NotApplicable
PolicyStoreSource     : PersistentStore
PolicyStoreSourceType : Local

Name                  : {5AFD4605-4E43-4A84-8E72-7DA728858EF3}
DisplayName           : Docker Swarm Communication
Description           :
DisplayGroup          :
Group                 :
Enabled               : True
Profile               : Domain
Platform              : {}
Direction             : Outbound
Action                : Allow
EdgeTraversalPolicy   : Block
LooseSourceMapping    : False
LocalOnlyMapping      : False
Owner                 :
PrimaryStatus         : OK
Status                : The rule was parsed successfully from the store. (65536)
EnforcementStatus     : NotApplicable
PolicyStoreSource     : PersistentStore
PolicyStoreSourceType : Local
jimbo8098 commented 4 years ago

Just in case anyone else is affected by this, here's the task I used as a workaround:

- name: Open necessary ports
  win_shell: |
    Import-Module NetSecurity
    $prot = "{{ item.protocol }}"
    $port = "{{ item.port }}"
    [Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetSecurity.Profile] $profile = "{{ item.profile }}"
    [Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetSecurity.Direction] $direction = "{{ item.direction }}"
    $name = "{{ item.name }}"

    [Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetSecurity.Direction] $inbound = "Inbound"
    [bool] $found = $false

    $portfilters = (Get-NetFirewallPortFilter | Where-Object {$_.LocalPort -eq $port})
    foreach($portfilter in $portfilters)
    {
        $rule = ($portfilter | Get-NetFirewallRule)
        if(
            $rule.DisplayName -eq $name -And
            $rule.Enabled -eq $true -And
            $rule.Action -eq "Allow" -And
            $rule.Direction.CompareTo($direction) -eq 0 -And
            $rule.Profile.CompareTo($profile) -eq 0
        )
        {
            $found = $true
        }
    }

    if(!$found)
    {
        echo "${direction} ${port}/${prot} ${profile}: Not found, adding!"
        New-NetFirewallRule -DisplayName $name -LocalPort $port -Profile $profile -Direction $direction -Protocol $prot
        $res = $?
        if($res -eq $true)
        {
          exit 0
        }
        else
        {
          exit 2
        }
    }
    else
    {
        echo "${direction} ${port}/${prot} ${profile}: Found!"
        exit 1
    }
  loop:
    - { port: 2376, protocol: "TCP", profile: "Domain", direction: "Inbound", name: "Docker TLS port"}
    - { port: 2377, protocol: "TCP", profile: "Domain", direction: "Inbound", name: "Docker cluster management communications"}
    - { port: 7946, protocol: "TCP", profile: "Domain", direction: "Inbound", name: "Docker node communications (TCP)" }
    - { port: 7946, protocol: "UDP", profile: "Domain", direction: "Inbound", name: "Docker node communications (UDP)" }
    - { port: 4789, protocol: "UDP", profile: "Domain", direction: "Inbound", name: "Docker overlay network traffic" }
    - { port: 2376, protocol: "TCP", profile: "Domain", direction: "Outbound", name: "Docker TLS port"}
    - { port: 2377, protocol: "TCP", profile: "Domain", direction: "Outbound", name: "Docker cluster management communications"}
    - { port: 7946, protocol: "TCP", profile: "Domain", direction: "Outbound", name: "Docker node communications (TCP)" }
    - { port: 7946, protocol: "UDP", profile: "Domain", direction: "Outbound", name: "Docker node communications (UDP)" }
    - { port: 4789, protocol: "UDP", profile: "Domain", direction: "Outbound", name: "Docker overlay network traffic" }
  changed_when: firewall_res.rc == 0
  failed_when: firewall_res.rc == 2
  register: firewall_res
jborean93 commented 3 years ago

So does the module fail when you are adding these rules or it just continues through. Is it idempotent, i.e. does it report a change on subsequent reruns? Can you see the rules in the Windows Advanced Firewall control panel in the GUI?