Skip to content

Commit

Permalink
ci: Add full integration test for dyndns
Browse files Browse the repository at this point in the history
Modify the role so dyndns_auth can be actually configured.
Add handling of client hostname not being fqdn.
Add integration test for dyndns with actual AD.
  • Loading branch information
jakub-vavra-cz authored and richm committed Nov 8, 2023
1 parent 2cfcb60 commit 8dd4cbf
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 3 deletions.
1 change: 1 addition & 0 deletions .ansible-lint
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ exclude_paths:
mock_modules:
- win_domain_group
- win_domain_user
- ini_file
mock_roles:
- linux-system-roles.ad_integration
6 changes: 4 additions & 2 deletions defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,12 @@ ad_dyndns_update_ptr: true
# Only applicable if `ad_dyndns_update` is true
ad_dyndns_force_tcp: false

# Optional. If true, GSS-TSIG authentication will be used for secure updates
# Optional. GSS-TSIG authentication is used for secure updates
# with the DNS server when updating A and AAAA records.
# Valid values are "GSS-TSIG" or "none" allowing unsecure updates.
# The default value in sssd is 'GSS-TSIG'.
# Only applicable if `ad_dyndns_update` is true
ad_dyndns_auth: true
ad_dyndns_auth: null

# Optional. DNS server to use when performing a DNS update when autodetection
# settings fail.
Expand Down
8 changes: 7 additions & 1 deletion tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,16 @@
- key: dyndns_force_tcp
value: "{{ ad_dyndns_force_tcp | string }}"
- key: dyndns_auth
value: "{{ 'GSS-TSIG' if ad_dyndns_auth else 'none' }}"
value: "{{ ad_dyndns_auth | string if ad_dyndns_auth else '' }}"
- key: dyndns_server
value: "{{ ad_dyndns_server | string
if ad_dyndns_server is not none else '' }}"
# For dynamic dns to work the machine either needs fqdn in hostname
# or ad_hostname needs to be defined.
- key: ad_hostname
value: "{{ ansible_hostname + '.' + ad_integration_realm | lower
| string if '.' not in ansible_hostname else '' }}"

when:
- ad_dyndns_update | bool
- item.value is not none
Expand Down
1 change: 1 addition & 0 deletions tests/collection-requirements.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
collections:
- community.windows
- ansible.windows
- community.general
1 change: 1 addition & 0 deletions tests/tests_dyndns.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
vars:
ad_dyndns_iface: "TESTING"
ad_dyndns_server: 127.0.0.1
ad_dyndns_auth: "GSS-TSIG"

- name: Test - Verify sssd.conf options were written
block:
Expand Down
189 changes: 189 additions & 0 deletions tests/tests_full_integration_dyndns.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# SPDX-License-Identifier: MIT
---

# To run this test, AD (ad1) needs to be present in the inventory
# AD should be pre-configured as a dns for the client machine.
# AD's DNS service should be configured with both forward and reverse zones
# and the DNS records from any previous runs removed.
# Note that both for client and ad the ansible_host should
# contain the ip4 address to make this work properly.
# There is expectation that both client and ad are on the
# same network with mask 255.255.255.0.

# Example inventory:
# [client]
# client1 ansible_host=<CLIENT IP>\
# ad_integration_password=Secret123 ad_integration_realm="domain.com" \
# ad_dyndns_update=true
# [ad]
# ad1 ansible_host=<AD IP> ansible_connection=winrm\
# ansible_password=Secret123 ansible_port=5986 ansible_user=Administrator\
# ansible_winrm_server_cert_validation=ignore

- name: Set variables
hosts: client
tasks:
- name: Set ad_integration_realm if it is not defined or is empty
set_fact:
ad_integration_realm: domain.com
when: ad_integration_realm is not defined or not ad_integration_realm

- name: Configure DynDNS on AD
hosts: ad
gather_facts: true
tasks:
- name: Get AD address
set_fact:
ad_address: "{{ hostvars[inventory_hostname].ansible_host }}"
- name: Get network for zone
set_fact:
network_ad: >-
{{ ad_address.split('.')[-2::-1] | join('.') }}.in-addr.arpa
- name: Show AD network
debug:
msg: "AD network: {{ network_ad }}"
- name: Create reverse zone
ansible.windows.win_command: >-
dnscmd.exe /zoneadd {{ network_ad }} /primary
register: res
failed_when:
- res.rc != 0 and "DNS_ERROR_ZONE_ALREADY_EXISTS" not in res.stdout
- name: Allow updates in the zone
ansible.windows.win_command: >-
dnscmd.exe /config
{{ hostvars[groups['client'][0]].ad_integration_realm }}
/allowupdate 1
- name: Allow updates in the reverse zone
ansible.windows.win_command: >-
dnscmd.exe /config {{ network_ad }} /allowupdate 1
- name: Disable dns forwarders
ansible.windows.win_command: dnscmd.exe /config /norecursion 1

- name: Ensure that the role configures dynamic dns
hosts: client
tasks:
- name: Run the integration
when: "'ad' in groups and groups['ad']"
block:
- name: Debug dyndns settings
debug:
msg: >-
Interface {{ _ad_dyndns_iface | default('eth0') }} and server
: {{ hostvars[groups['ad'][0]].ansible_host }}
- name: Run the system role with proper config
include_role:
name: linux-system-roles.ad_integration
vars:
ad_dyndns_server: "{{ hostvars[groups['ad'][0]].ansible_host }}"
ad_dyndns_iface: "{{ _ad_dyndns_iface | default('eth0') }}"
ad_dyndns_auth: "none"
ad_dyndns_update: true
ad_dyndns_refresh_interval: 60
- name: Apply additional changes on sssd
ini_file:
path: /etc/sssd/sssd.conf
state: present
section: "domain/{{ ad_integration_realm | lower }}"
option: "{{ item.key }}"
value: "{{ item.value }}"
create: true
owner: root
group: root
mode: 0600
loop:
- key: debug_level
value: 9
- name: Clean sssd log
command: >-
truncate -s 0 /var/log/sssd/sssd_{{ ad_integration_realm }}.log
changed_when: true
failed_when: false
- name: Restart sssd
service:
name: sssd
state: restarted
- name: Pause for 5 to give sssd chance to refresh dn record on AD
ansible.builtin.pause:
minutes: 5
- name: Check sssd log fo dydndns update info
command: >-
grep -A 20 "nsupdate"
/var/log/sssd/sssd_{{ ad_integration_realm }}.log
changed_when: false
failed_when: false
- name: Grab sssd.conf contents
command: cat /etc/sssd/sssd.conf
changed_when: false
- name: Get IP for host's FQDN
command: >-
dig +short {{ ansible_fqdn }}.{{
hostvars[groups['client'][0]].ad_integration_realm }} A
register: dig_hostname
changed_when: false
failed_when: false
- name: Get hostname for host's IP address
command: "dig +short -x {{ ansible_default_ipv4.address }} PTR"
register: dig_ip
changed_when: false
failed_when: false
- name: Print to console dig outputs
debug:
msg:
- "Dig hostname: {{ dig_hostname.stdout }}"
- "Dig ip: {{ dig_ip.stdout }}"

- name: Check hosts on AD
hosts: ad
gather_facts: true
tasks:
- name: Get network for zone
set_fact:
network_ad: >-
{{ ad_address.split('.')[-2::-1] | join('.') }}.in-addr.arpa
client_ip_part: >-
{{ hostvars[groups['client'][0]].ansible_host.split('.')[-1] }}
- name: Show network information
debug:
msg: >-
AD network: {{ network_ad }}, Client IP:
{{ hostvars[groups['client'][0]].ansible_host }}
- name: List all AD zones
ansible.windows.win_command: dnscmd.exe /EnumZones
register: zones
failed_when: false
- name: Grab AD zone
# noqa: command-instead-of-shell
ansible.windows.win_shell: >-
dnscmd.exe /zoneprint
{{ hostvars[groups["client"][0]].ad_integration_realm }} |
findstr /c:"client"
register: zone_ad
failed_when: false
- name: Grab AD reverse zone
# noqa: command-instead-of-shell
ansible.windows.win_shell: >-
dnscmd.exe /zoneprint {{ network_ad }} | findstr /c:"client"
register: reverse_zone_ad
failed_when: false
- name: Show AD zones
debug:
msg:
- "Zones:"
- "{{ zones }}"
- "Zone:"
- "{{ zone_ad }}"
- "Reverse zone:"
- "{{ reverse_zone_ad }}"
- name: Test - client is in AD both in forward and reverse zones
assert:
that:
- hostvars[groups["client"][0]].ansible_host in zone_ad.stdout
- client_ip_part in reverse_zone_ad.stdout

- name: Leave realm
hosts: client
tasks:
- name: Teardown - Leave realm
command: realm leave
ignore_errors: true # noqa ignore-errors
changed_when: false

0 comments on commit 8dd4cbf

Please sign in to comment.