# Quick Start Guide - nsupdate_zone Module ## Installation The module is part of the `community.general` collection: ```bash ansible-galaxy collection install community.general ``` Install Python dependencies: ```bash pip install dnspython ``` ## Minimal Example ```yaml - name: Update DNS zone community.general.nsupdate_zone: key_name: "nsupdate" key_secret: "your-tsig-key-here==" zones: - name: example.com dns_server: ns1.example.com records: - record: 'example.com.' type: A value: 192.168.1.1 - record: www type: A value: 192.168.1.10 ``` **Note**: By default, SOA and DNSSEC records are ignored, and record validation is enabled. **Tip**: Run with `-v` flag to see detailed per-record actions. ## DNS Server Setup (BIND Example) 1. **Generate TSIG key:** ```bash tsig-keygen -a hmac-sha256 nsupdate ``` 2. **Configure BIND (`/etc/named.conf`):** ``` key "nsupdate" { algorithm hmac-sha256; secret "generated-secret-here=="; }; zone "example.com" { type master; file "/var/named/example.com.zone"; allow-update { key nsupdate; }; allow-transfer { key nsupdate; }; }; ``` 3. **Reload BIND:** ```bash sudo systemctl reload named ``` ## First Playbook Create `update-dns.yml`: ```yaml --- - name: Manage DNS zones hosts: localhost gather_facts: false tasks: - name: Update example.com zone community.general.nsupdate_zone: key_name: "nsupdate" key_secret: "{{ lookup('env', 'DNS_KEY') }}" key_algorithm: hmac-sha256 protocol: tcp zones: - name: example.com dns_server: ns1.example.com records: # Zone apex - record: 'example.com.' type: A value: 192.168.1.1 ttl: 3600 # Web server - record: www type: A value: - 192.168.1.10 - 192.168.1.11 ttl: 300 # Email - record: 'example.com.' type: MX value: - "10 mail.example.com." - record: mail type: A value: 192.168.1.20 register: result - name: Show what changed debug: msg: "Zone {{ item.zone }}: {{ item.changes.adds }} adds, {{ item.changes.deletes }} deletes, {{ item.changes.updates }} updates" loop: "{{ result.results }}" ``` Run it: ```bash export DNS_KEY="your-tsig-key-here==" ansible-playbook update-dns.yml ``` ## Verify It Works Check mode (dry run): ```bash ansible-playbook update-dns.yml --check ``` Verify DNS records: ```bash dig @ns1.example.com example.com A dig @ns1.example.com www.example.com A dig @ns1.example.com example.com MX ``` ## Common Use Cases ### 1. Load Zone from Variable File **zones/example.com.yml:** ```yaml --- - record: 'example.com.' type: A value: 192.168.1.1 - record: www type: A value: 192.168.1.10 ``` **Playbook:** ```yaml - name: Load and apply zone hosts: localhost vars_files: - zones/example.com.yml tasks: - name: Update zone community.general.nsupdate_zone: key_name: "nsupdate" key_secret: "{{ vault_dns_key }}" zones: - name: example.com dns_server: ns1.example.com records: "{{ zones }}" ``` ### 2. Ignore Dynamic Records and Use Global Server ```yaml - name: Update zone (ignore ACME challenges, use global server) community.general.nsupdate_zone: key_name: "nsupdate" key_secret: "{{ vault_dns_key }}" dns_server: ns1.dns.com # Global server for all zones # SOA and DNSSEC records are ignored by default ignore_record_patterns: - '^_acme-challenge\..*' zones: - name: example.com records: "{{ static_records }}" ``` ### 3. Multiple Zones with Shared Server ```yaml - name: Update all zones community.general.nsupdate_zone: key_name: "nsupdate" key_secret: "{{ vault_dns_key }}" dns_server: ns1.dns.com # Shared server for all zones zones: - name: example.com records: "{{ example_com_records }}" - name: example.org records: "{{ example_org_records }}" ``` ## Troubleshooting ### "AXFR failed: connection timeout" - Check firewall allows port 53 - Verify `allow-transfer` in BIND config - Test manually: `dig @ns1.example.com example.com AXFR` ### "UPDATE failed: REFUSED" - Check `allow-update` in BIND config - Verify TSIG key matches - Check zone name is correct ### "TSIG key error" - Verify key_secret is base64-encoded - Check key_algorithm matches server config - Ensure key_name matches server key name ### "CNAME conflict" - Cannot have CNAME with other record types at same name - Remove conflicting records from YAML - Or use different subdomain ## Best Practices 1. **Use ansible-vault for keys:** ```bash ansible-vault encrypt_string 'your-key' --name dns_key ``` 2. **Use TCP protocol:** ```yaml protocol: tcp # More reliable for large zones ``` 3. **Leverage defaults:** ```yaml # SOA and DNSSEC records are ignored by default # Record validation is enabled by default # Just add patterns for dynamic records ignore_record_patterns: - '^_acme-challenge\..*' ``` 4. **Use verbose mode for visibility:** ```yaml verbose: true # See Added, Removed, Changed, Skipped for each record ``` 5. **Test with check and diff mode:** ```bash ansible-playbook playbook.yml --check --diff ``` 6. **Use global dns_server:** ```yaml dns_server: ns1.dns.com # Applies to all zones without dns_server ``` ## Next Steps - Read full documentation: `docs/nsupdate_zone_guide.md` - See examples: `examples/nsupdate_zone_example.yml` - Check sample zone: `examples/sample_zone_format.yml` ## Support For issues and questions: - GitHub: https://github.com/ansible-collections/community.general - Docs: https://docs.ansible.com/