ansible-role-bind icon indicating copy to clipboard operation
ansible-role-bind copied to clipboard

Feature Add: update-policy + tsig keys + dynamic updates

Open brunobenchimol opened this issue 2 years ago • 25 comments

Added the ability to use bind_tsig_keys to use with dynamics updates (useful cases: DHCP integration and Certbot DNS challenge automation). Changed documentation to explain how to use. Also added and changed templates to implement this feature. Changelog was not touched.

brunobenchimol avatar Nov 13 '21 04:11 brunobenchimol

when merged? thanks.

mikysal78 avatar Sep 15 '22 22:09 mikysal78

Added the ability to use bind_tsig_keys to use with dynamics updates (useful cases: DHCP integration and Certbot DNS challenge automation). Changed documentation to explain how to use. Also added and changed templates to implement this feature. Changelog was not touched.

Hi, @brunobenchimol Your pull is not yet merged. (I don't understand why). I am very interested in what you have done and want to use your roles. How do I integrate certboot with wildcard dns and make dynamic dns on a zone? Thanks.

mikysal78 avatar Sep 18 '22 17:09 mikysal78

Added the ability to use bind_tsig_keys to use with dynamics updates (useful cases: DHCP integration and Certbot DNS challenge automation). Changed documentation to explain how to use. Also added and changed templates to implement this feature. Changelog was not touched.

Hi, @brunobenchimol Your pull is not yet merged. (I don't understand why). I am very interested in what you have done and want to use your roles. How do I integrate certboot with wildcard dns and make dynamic dns on a zone? Thanks.

Hello @mikysal78.

Check on how to use tsig keys: https://github.com/brunobenchimol/ansible-role-bind#using-tsig-keys-for-dynamic-updates

Its about the same as dns keys, same syntax.

update_policy is the same as bind documentation....

about integration with certbot i did a PR (not merged) and i did a wrapper for that.

Pull Request on certbot: https://github.com/geerlingguy/ansible-role-certbot/pull/163

Wrapper i built: https://github.com/brunobenchimol/ansible-role-certbot-dns and module on ansible-galaxy - https://galaxy.ansible.com/brunobenchimol/certbot_dns

Hope it helps.

brunobenchimol avatar Sep 18 '22 18:09 brunobenchimol

@brunobenchimol i try your repo and i have this error:

TASK [bind : Dump/flush dynamic zone changes to disk/zone file] *************************************************************************************************************************************************************************
Tuesday 20 September 2022  00:40:43 +0200 (0:00:02.755)       0:01:17.515 ***** 
failed: [ns2-basilicata.ninux.org] (item={'path': '/var/cache/bind/managed-keys.bind.jnl', 'mode': '0644', 'isdir': False, 'ischr': False, 'isblk': False, 'isreg': True, 'isfifo': False, 'islnk': False, 'issock': False, 'uid': 108, 'gid': 114, 'size': 1426, 'inode': 266522, 'dev': 2049, 'nlink': 1, 'atime': 1662134588.362842, 'mtime': 1662134563.3624492, 'ctime': 1662134563.3624492, 'gr_name': 'bind', 'pw_name': 'bind', 'wusr': True, 'rusr': True, 'xusr': False, 'wgrp': False, 'rgrp': True, 'xgrp': False, 'woth': False, 'roth': True, 'xoth': False, 'isuid': False, 'isgid': False}) => changed=true 
  ansible_loop_var: item
  cmd:
  - rndc
  - sync
  - -clean
  - managed-keys.bind
  delta: '0:00:00.022929'
  end: '2022-09-19 22:40:45.325915'
  item:
    atime: 1662134588.362842
    ctime: 1662134563.3624492
    dev: 2049
    gid: 114
    gr_name: bind
    inode: 266522
    isblk: false
    ischr: false
    isdir: false
    isfifo: false
    isgid: false
    islnk: false
    isreg: true
    issock: false
    isuid: false
    mode: '0644'
    mtime: 1662134563.3624492
    nlink: 1
    path: /var/cache/bind/managed-keys.bind.jnl
    pw_name: bind
    rgrp: true
    roth: true
    rusr: true
    size: 1426
    uid: 108
    wgrp: false
    woth: false
    wusr: true
    xgrp: false
    xoth: false
    xusr: false
  msg: non-zero return code
  rc: 1
  start: '2022-09-19 22:40:45.302986'
  stderr: |-
    rndc: 'sync' failed: not found
    no matching zone 'managed-keys.bind' in any view
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>
failed: [ns1-basilicata.ninux.org] (item={'path': '/var/cache/bind/managed-keys.bind.jnl', 'mode': '0644', 'isdir': False, 'ischr': False, 'isblk': False, 'isreg': True, 'isfifo': False, 'islnk': False, 'issock': False, 'uid': 108, 'gid': 114, 'size': 1426, 'inode': 265496, 'dev': 2049, 'nlink': 1, 'atime': 1662134593.2810001, 'mtime': 1662134563.2809472, 'ctime': 1662134563.2809472, 'gr_name': 'bind', 'pw_name': 'bind', 'wusr': True, 'rusr': True, 'xusr': False, 'wgrp': False, 'rgrp': True, 'xgrp': False, 'woth': False, 'roth': True, 'xoth': False, 'isuid': False, 'isgid': False}) => changed=true 
  ansible_loop_var: item
  cmd:
  - rndc
  - sync
  - -clean
  - managed-keys.bind
  delta: '0:00:00.030124'
  end: '2022-09-19 22:40:45.451287'
  item:
    atime: 1662134593.2810001
    ctime: 1662134563.2809472
    dev: 2049
    gid: 114
    gr_name: bind
    inode: 265496
    isblk: false
    ischr: false
    isdir: false
    isfifo: false
    isgid: false
    islnk: false
    isreg: true
    issock: false
    isuid: false
    mode: '0644'
    mtime: 1662134563.2809472
    nlink: 1
    path: /var/cache/bind/managed-keys.bind.jnl
    pw_name: bind
    rgrp: true
    roth: true
    rusr: true
    size: 1426
    uid: 108
    wgrp: false
    woth: false
    wusr: true
    xgrp: false
    xoth: false
    xusr: false
  msg: non-zero return code
  rc: 1
  start: '2022-09-19 22:40:45.421163'
  stderr: |-
    rndc: 'sync' failed: not found
    no matching zone 'managed-keys.bind' in any view
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>

mikysal78 avatar Sep 19 '22 22:09 mikysal78

@brunobenchimol i try your repo and i have this error:

TASK [bind : Dump/flush dynamic zone changes to disk/zone file] *************************************************************************************************************************************************************************
Tuesday 20 September 2022  00:40:43 +0200 (0:00:02.755)       0:01:17.515 ***** 
failed: [ns2-basilicata.ninux.org] (item={'path': '/var/cache/bind/managed-keys.bind.jnl', 'mode': '0644', 'isdir': False, 'ischr': False, 'isblk': False, 'isreg': True, 'isfifo': False, 'islnk': False, 'issock': False, 'uid': 108, 'gid': 114, 'size': 1426, 'inode': 266522, 'dev': 2049, 'nlink': 1, 'atime': 1662134588.362842, 'mtime': 1662134563.3624492, 'ctime': 1662134563.3624492, 'gr_name': 'bind', 'pw_name': 'bind', 'wusr': True, 'rusr': True, 'xusr': False, 'wgrp': False, 'rgrp': True, 'xgrp': False, 'woth': False, 'roth': True, 'xoth': False, 'isuid': False, 'isgid': False}) => changed=true 
  ansible_loop_var: item
  cmd:
  - rndc
  - sync
  - -clean
  - managed-keys.bind
  delta: '0:00:00.022929'
  end: '2022-09-19 22:40:45.325915'
  item:
    atime: 1662134588.362842
    ctime: 1662134563.3624492
    dev: 2049
    gid: 114
    gr_name: bind
    inode: 266522
    isblk: false
    ischr: false
    isdir: false
    isfifo: false
    isgid: false
    islnk: false
    isreg: true
    issock: false
    isuid: false
    mode: '0644'
    mtime: 1662134563.3624492
    nlink: 1
    path: /var/cache/bind/managed-keys.bind.jnl
    pw_name: bind
    rgrp: true
    roth: true
    rusr: true
    size: 1426
    uid: 108
    wgrp: false
    woth: false
    wusr: true
    xgrp: false
    xoth: false
    xusr: false
  msg: non-zero return code
  rc: 1
  start: '2022-09-19 22:40:45.302986'
  stderr: |-
    rndc: 'sync' failed: not found
    no matching zone 'managed-keys.bind' in any view
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>
failed: [ns1-basilicata.ninux.org] (item={'path': '/var/cache/bind/managed-keys.bind.jnl', 'mode': '0644', 'isdir': False, 'ischr': False, 'isblk': False, 'isreg': True, 'isfifo': False, 'islnk': False, 'issock': False, 'uid': 108, 'gid': 114, 'size': 1426, 'inode': 265496, 'dev': 2049, 'nlink': 1, 'atime': 1662134593.2810001, 'mtime': 1662134563.2809472, 'ctime': 1662134563.2809472, 'gr_name': 'bind', 'pw_name': 'bind', 'wusr': True, 'rusr': True, 'xusr': False, 'wgrp': False, 'rgrp': True, 'xgrp': False, 'woth': False, 'roth': True, 'xoth': False, 'isuid': False, 'isgid': False}) => changed=true 
  ansible_loop_var: item
  cmd:
  - rndc
  - sync
  - -clean
  - managed-keys.bind
  delta: '0:00:00.030124'
  end: '2022-09-19 22:40:45.451287'
  item:
    atime: 1662134593.2810001
    ctime: 1662134563.2809472
    dev: 2049
    gid: 114
    gr_name: bind
    inode: 265496
    isblk: false
    ischr: false
    isdir: false
    isfifo: false
    isgid: false
    islnk: false
    isreg: true
    issock: false
    isuid: false
    mode: '0644'
    mtime: 1662134563.2809472
    nlink: 1
    path: /var/cache/bind/managed-keys.bind.jnl
    pw_name: bind
    rgrp: true
    roth: true
    rusr: true
    size: 1426
    uid: 108
    wgrp: false
    woth: false
    wusr: true
    xgrp: false
    xoth: false
    xusr: false
  msg: non-zero return code
  rc: 1
  start: '2022-09-19 22:40:45.421163'
  stderr: |-
    rndc: 'sync' failed: not found
    no matching zone 'managed-keys.bind' in any view
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>

Somehow the config is wrong, its picking up managed-keys.bind as zone name and is unable to sync. Double check your yaml files and post to make it easier to troubleshoot.

brunobenchimol avatar Sep 19 '22 23:09 brunobenchimol

My playbook is:

- hosts: dns_server
  become: "{{ sudo | default('yes') }}"
  roles:
    - bind
  vars:
    bind_statistics_channels: true
    bind_statistics_host: "{{ ansible_default_ipv4.address }}"
    #bind_statistics_host:  "10.27.253.1"
    bind_statistics_allow:
      - "10.27.253.0/24"

    bind_zone_dir: /var/local/named-zones
    bind_zone_file_mode: '0660'
    bind_allow_query:
      - any
    bind_listen_ipv4:
      - any
    bind_listen_ipv6:
      - any
    bind_acls:
      - name: ninux
        match_list:
          - localhost
          - localnets
          - 10.27.0.0/16
          - 141.95.18.146
          - 51.178.46.85
    bind_forwarders:
      - '8.8.8.8'
      - '8.8.4.4'
    bind_recursion: false
    bind_allow_recursion:
      - ninux
    bind_dns64: true
    bind_query_log: 'data/query.log'
    bind_check_names: 'master ignore'

    # SOA information
    bind_zone_ttl: "1W"
    bind_zone_time_to_refresh: "12H"
    bind_zone_time_to_retry: "1H"
    bind_zone_time_to_expire: "2W"
    bind_zone_minimum_ttl: "1D"

  pre_tasks:
    - name: Install python3-netaddr
      apt: pkg=python3-netaddr state=present
    - name: Install python3-ipaddr
      apt: pkg=python3-ipaddr state=present
    - name: Install python3-dns
      apt: pkg=python3-dns state=present
    - name: Install dns utils
      apt: pkg=dnsutils state=present
    - name: Install dns certbot
      apt: pkg=python3-certbot-dns-rfc2136 state=present
    - name: Get dict for each zone
      include_vars:
        dir: zones
    - name: Merge zone dicts
      set_fact:
        bind_zones:
          "{{ nnxx_ninux_org }} +
           {{ basilicata_ninux_org }} +
           {{ basilicata_nnxx }}"

Zone is (3 zones equal):

---
nnxx_ninux_org:
  - name: nnxx.ninux.org
    hostmaster_email: mikytux
    create_reverse_zones: true
    primaries:
      - 141.95.18.146
    name_servers:
      - ns1-basilicata.ninux.org.
      - ns2-basilicata.ninux.org.
    also_notify:
      - 51.178.46.85
    networks:
      - '141.95.18'
      - '51.178.46'
    ipv6_networks:
      - '2001:41d0:0701:1100::/56'
      - '2001:41d0:404:200::/56'
    mail_servers:
      - name: 'mail'
        preference: '10'
        ttl: 300
    hosts:
      - name: 'ns1-basilicata'
        ip: 141.95.18.146
        ipv6: 2001:41d0:701:1100::2cb2
        sshfp:   # Secure shell fingerprint
          - "3 1 9a37f73b78fff4772c0a9628c211e34d5b660fc6"
          - "3 2 1123b280c0a17a625cba59d89cf03c91bcb64e527199dc6b579e618a019dedde"
      - name: 'ns2-basilicata'
        ip: 51.178.46.85
        ipv6: 2001:41d0:404:200::5c77
        sshfp:   # Secure shell fingerprint
          - "3 1 b6bf5fbb1f7375cdfd41cf98543228a38d6c0638"
          - "3 2 ec42143de701eddeca68a42848ac85fb58ad543706104684361e1cb8ed286576"

      - name: '@'
        ip: 51.68.45.242
        ipv6: 2001:41d0:305:2100::63eb
        aliases:
          - www
          - downloads
      - name: 'controller'
        ip: 92.246.89.121
        sshfp:   # Secure shell fingerprint
          - "3 1 2a3874727c3d65949f105ca70acefefcf89e0589"
          - "3 2 130311b55cae5139f0c755ecb34207e4ed53e1472848156f5861ceea4a2e1327"
        aliases:
          - vpn-basilicata
          - openvpn
      - name: 'wifi'
        ip: 92.246.89.121
        aliases:
          - wifiauth
      - name: 'mail'
        ip: 51.68.45.242
        ipv6: 2001:41d0:305:2100::63eb
        aliases:
          - smtp
          - pop
          - pop3
          - imap
          - webmail
          - mailserver
          - ispmail
    text:
      - name: '@'
        text: 'v=spf1 mx a ip4:51.68.45.242 ip4:92.246.89.121 a:mail.basilicata.ninux.org mx:basilicata.ninux.org mx:mail.basilicata.ninux.org include:_spf.google.com ~all'
      - name: '_dmarc'
        text: 'v=DMARC1; p=quarantine; pct=100; rua=mailto:[email protected]'
      - name: '_smtp._tls'
        text: 'v=TLSRPTv1; [email protected]'

mikysal78 avatar Sep 20 '22 05:09 mikysal78

I believe you are missing some vars to use my PR. That may break, but i believe you found a bug.

on my code tasks/zones.yml on task "- name: Find zones which in need of flushing/dumping dynamic updates to zonefile" i should check if tsig keys are defined, if they are not it may fail to sync/flush zones.

Well, regarding to that you are missing some key vars:

on your vars you need to create a tsig key:

bind_tsig_keys:
  - name: "tsig_key."
    algorithm: hmac-sha256
    secret: "azertyAZERTY123456"

on your zone you need to add update_policy

      - bind_zones:
         # Example of a primary zone (hosts: and name_servers: ares defined)
         - name: example.com           # Domain name
         ....
           update_policy:
            - "grant {{ tsig_key_name }} zonesub A"
            - "grant {{ tsig_key_name }} zonesub TXT"
            - "grant local-ddns zonesub any"

Try to follow this documentation: https://github.com/brunobenchimol/ansible-role-bind#using-tsig-keys-for-dynamic-updates

If i remember you must also define a bind key (https://github.com/brunobenchimol/ansible-role-bind#binding-keys)... i am not quite sure but if you do not it wont enable configs that must be done.

If you cant make it run, let me know. I will try to set up a lab to test it but it would take some time.

brunobenchimol avatar Sep 20 '22 21:09 brunobenchimol

@brunobenchimol i try and i have this error:

TASK [Merge zone dicts] *****************************************************************************************************************************************************************************************************************
Wednesday 21 September 2022  21:27:47 +0200 (0:00:00.211)       0:00:15.996 *** 
fatal: [ns1-basilicata.ninux.org]: FAILED! => 
  msg: |-
    The task includes an option with an undefined variable. The error was: [{'name': 'nnxx.ninux.org', 'hostmaster_email': 'mikytux', 'create_reverse_zones': True, 'primaries': ['141.95.18.146'], 'name_servers': ['ns1-basilicata.ninux.org.', 'ns2-basilicata.ninux.org.'], 'also_notify': ['51.178.46.85'], 'networks': ['141.95.18', '51.178.46'], 'ipv6_networks': ['2001:41d0:0701:1100::/56', '2001:41d0:404:200::/56'], 'update_policy': ['grant {{ tsig_key }} zonesub A', 'grant {{ tsig_key }} zonesub TXT', 'grant local-ddns zonesub any'], 'mail_servers': [{'name': 'mail', 'preference': '10', 'ttl': 300}], 'hosts': [{'name': 'ns1-basilicata', 'ip': '141.95.18.146', 'ipv6': '2001:41d0:701:1100::2cb2', 'sshfp': ['3 1 9a37f73b78fff4772c0a9628c211e34d5b660fc6', '3 2 1123b280c0a17a625cba59d89cf03c91bcb64e527199dc6b579e618a019dedde']}, {'name': 'ns2-basilicata', 'ip': '51.178.46.85', 'ipv6': '2001:41d0:404:200::5c77', 'sshfp': ['3 1 b6bf5fbb1f7375cdfd41cf98543228a38d6c0638', '3 2 ec42143de701eddeca68a42848ac85fb58ad543706104684361e1cb8ed286576']}, {'name': '@', 'ip': '51.68.45.242', 'ipv6': '2001:41d0:305:2100::63eb', 'aliases': ['www', 'downloads']}, {'name': 'controller', 'ip': '92.246.89.121', 'sshfp': ['3 1 2a3874727c3d65949f105ca70acefefcf89e0589', '3 2 130311b55cae5139f0c755ecb34207e4ed53e1472848156f5861ceea4a2e1327'], 'aliases': ['vpn-basilicata', 'openvpn']}, {'name': 'wifi', 'ip': '92.246.89.121', 'aliases': ['wifiauth']}, {'name': 'mail', 'ip': '51.68.45.242', 'ipv6': '2001:41d0:305:2100::63eb', 'aliases': ['smtp', 'pop', 'pop3', 'imap', 'webmail', 'mailserver', 'ispmail']}], 'text': [{'name': '@', 'text': 'v=spf1 mx a ip4:51.68.45.242 ip4:92.246.89.121 a:mail.basilicata.ninux.org mx:basilicata.ninux.org mx:mail.basilicata.ninux.org include:_spf.google.com ~all'}, {'name': '_dmarc', 'text': 'v=DMARC1; p=quarantine; pct=100; rua=mailto:[email protected]'}, {'name': '_smtp._tls', 'text': 'v=TLSRPTv1; [email protected]'}]}]: 'tsig_key' is undefined
  
    The error appears to be in '/git/new-dns/server.yml': line 63, column 7, but may
    be elsewhere in the file depending on the exact syntax problem.
  
    The offending line appears to be:
  
            dir: zones
        - name: Merge zone dicts
          ^ here
fatal: [ns2-basilicata.ninux.org]: FAILED! => 
  msg: |-
    The task includes an option with an undefined variable. The error was: [{'name': 'nnxx.ninux.org', 'hostmaster_email': 'mikytux', 'create_reverse_zones': True, 'primaries': ['141.95.18.146'], 'name_servers': ['ns1-basilicata.ninux.org.', 'ns2-basilicata.ninux.org.'], 'also_notify': ['51.178.46.85'], 'networks': ['141.95.18', '51.178.46'], 'ipv6_networks': ['2001:41d0:0701:1100::/56', '2001:41d0:404:200::/56'], 'update_policy': ['grant {{ tsig_key }} zonesub A', 'grant {{ tsig_key }} zonesub TXT', 'grant local-ddns zonesub any'], 'mail_servers': [{'name': 'mail', 'preference': '10', 'ttl': 300}], 'hosts': [{'name': 'ns1-basilicata', 'ip': '141.95.18.146', 'ipv6': '2001:41d0:701:1100::2cb2', 'sshfp': ['3 1 9a37f73b78fff4772c0a9628c211e34d5b660fc6', '3 2 1123b280c0a17a625cba59d89cf03c91bcb64e527199dc6b579e618a019dedde']}, {'name': 'ns2-basilicata', 'ip': '51.178.46.85', 'ipv6': '2001:41d0:404:200::5c77', 'sshfp': ['3 1 b6bf5fbb1f7375cdfd41cf98543228a38d6c0638', '3 2 ec42143de701eddeca68a42848ac85fb58ad543706104684361e1cb8ed286576']}, {'name': '@', 'ip': '51.68.45.242', 'ipv6': '2001:41d0:305:2100::63eb', 'aliases': ['www', 'downloads']}, {'name': 'controller', 'ip': '92.246.89.121', 'sshfp': ['3 1 2a3874727c3d65949f105ca70acefefcf89e0589', '3 2 130311b55cae5139f0c755ecb34207e4ed53e1472848156f5861ceea4a2e1327'], 'aliases': ['vpn-basilicata', 'openvpn']}, {'name': 'wifi', 'ip': '92.246.89.121', 'aliases': ['wifiauth']}, {'name': 'mail', 'ip': '51.68.45.242', 'ipv6': '2001:41d0:305:2100::63eb', 'aliases': ['smtp', 'pop', 'pop3', 'imap', 'webmail', 'mailserver', 'ispmail']}], 'text': [{'name': '@', 'text': 'v=spf1 mx a ip4:51.68.45.242 ip4:92.246.89.121 a:mail.basilicata.ninux.org mx:basilicata.ninux.org mx:mail.basilicata.ninux.org include:_spf.google.com ~all'}, {'name': '_dmarc', 'text': 'v=DMARC1; p=quarantine; pct=100; rua=mailto:[email protected]'}, {'name': '_smtp._tls', 'text': 'v=TLSRPTv1; [email protected]'}]}]: 'tsig_key' is undefined
  
    The error appears to be in '/git/new-dns/server.yml': line 63, column 7, but may
    be elsewhere in the file depending on the exact syntax problem.
  
    The offending line appears to be:
  
            dir: zones
        - name: Merge zone dicts
          ^ here

PLAY RECAP ******************************************************************************************************************************************************************************************************************************
ns1-basilicata.ninux.org   : ok=6    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
ns2-basilicata.ninux.org   : ok=6    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

It seems like it can't read the yml files of the zones, i use the zones in separate files (order in the zones, I don't understand why in the master they put everything together which is confusing). Indent for name: Merge zone dicts is correct, with master role work fine.

if you want to try my playbook email me and I will send you the files. (mikysal78 @ gmail.com)

mikysal78 avatar Sep 21 '22 19:09 mikysal78

@mikysal78 I did not test multiples zones when testing this role. Try to test only one zone than try adding more zones to your yaml file. I believe something is wrong.

Check your error: 'tsig_key' is undefined

Variable is bind_tsig_key as per documentation. https://github.com/brunobenchimol/ansible-role-bind#using-tsig-keys-for-dynamic-updates

Does your config works without using my PR?

This PR, only adds two new variables: update_policy and bind_tsig_keys

brunobenchimol avatar Sep 21 '22 19:09 brunobenchimol

@mikysal78 I did not test multiples zones when testing this role. Try to test only one zone than try adding more zones to your yaml file. I believe something is wrong.

I can't remove the zone, the server is in production

Check your error: 'tsig_key' is undefined

Variable is bind_tsig_key as per documentation. https://github.com/brunobenchimol/ansible-role-bind#using-tsig-keys-for-dynamic-updates

ok, i fix vars bat i have first error:

TASK [bind : Dump/flush dynamic zone changes to disk/zone file] *************************************************************************************************************************************************************************
Wednesday 21 September 2022  22:12:50 +0200 (0:00:02.597)       0:01:14.723 *** 
failed: [ns2-basilicata.ninux.org] (item={'path': '/var/cache/bind/managed-keys.bind.jnl', 'mode': '0644', 'isdir': False, 'ischr': False, 'isblk': False, 'isreg': True, 'isfifo': False, 'islnk': False, 'issock': False, 'uid': 108, 'gid': 114, 'size': 1426, 'inode': 266522, 'dev': 2049, 'nlink': 1, 'atime': 1662134588.362842, 'mtime': 1662134563.3624492, 'ctime': 1662134563.3624492, 'gr_name': 'bind', 'pw_name': 'bind', 'wusr': True, 'rusr': True, 'xusr': False, 'wgrp': False, 'rgrp': True, 'xgrp': False, 'woth': False, 'roth': True, 'xoth': False, 'isuid': False, 'isgid': False}) => changed=true 
  ansible_loop_var: item
  cmd:
  - rndc
  - sync
  - -clean
  - managed-keys.bind
  delta: '0:00:00.024330'
  end: '2022-09-21 20:12:52.636533'
  item:
    atime: 1662134588.362842
    ctime: 1662134563.3624492
    dev: 2049
    gid: 114
    gr_name: bind
    inode: 266522
    isblk: false
    ischr: false
    isdir: false
    isfifo: false
    isgid: false
    islnk: false
    isreg: true
    issock: false
    isuid: false
    mode: '0644'
    mtime: 1662134563.3624492
    nlink: 1
    path: /var/cache/bind/managed-keys.bind.jnl
    pw_name: bind
    rgrp: true
    roth: true
    rusr: true
    size: 1426
    uid: 108
    wgrp: false
    woth: false
    wusr: true
    xgrp: false
    xoth: false
    xusr: false
  msg: non-zero return code
  rc: 1
  start: '2022-09-21 20:12:52.612203'
  stderr: |-
    rndc: 'sync' failed: not found
    no matching zone 'managed-keys.bind' in any view
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>
failed: [ns1-basilicata.ninux.org] (item={'path': '/var/cache/bind/managed-keys.bind.jnl', 'mode': '0644', 'isdir': False, 'ischr': False, 'isblk': False, 'isreg': True, 'isfifo': False, 'islnk': False, 'issock': False, 'uid': 108, 'gid': 114, 'size': 1426, 'inode': 265496, 'dev': 2049, 'nlink': 1, 'atime': 1662134593.2810001, 'mtime': 1662134563.2809472, 'ctime': 1662134563.2809472, 'gr_name': 'bind', 'pw_name': 'bind', 'wusr': True, 'rusr': True, 'xusr': False, 'wgrp': False, 'rgrp': True, 'xgrp': False, 'woth': False, 'roth': True, 'xoth': False, 'isuid': False, 'isgid': False}) => changed=true 
  ansible_loop_var: item
  cmd:
  - rndc
  - sync
  - -clean
  - managed-keys.bind
  delta: '0:00:00.027946'
  end: '2022-09-21 20:12:52.652431'
  item:
    atime: 1662134593.2810001
    ctime: 1662134563.2809472
    dev: 2049
    gid: 114
    gr_name: bind
    inode: 265496
    isblk: false
    ischr: false
    isdir: false
    isfifo: false
    isgid: false
    islnk: false
    isreg: true
    issock: false
    isuid: false
    mode: '0644'
    mtime: 1662134563.2809472
    nlink: 1
    path: /var/cache/bind/managed-keys.bind.jnl
    pw_name: bind
    rgrp: true
    roth: true
    rusr: true
    size: 1426
    uid: 108
    wgrp: false
    woth: false
    wusr: true
    xgrp: false
    xoth: false
    xusr: false
  msg: non-zero return code
  rc: 1
  start: '2022-09-21 20:12:52.624485'
  stderr: |-
    rndc: 'sync' failed: not found
    no matching zone 'managed-keys.bind' in any view
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>

PLAY RECAP ******************************************************************************************************************************************************************************************************************************
ns1-basilicata.ninux.org   : ok=24   changed=0    unreachable=0    failed=1    skipped=2    rescued=0    ignored=0   
ns2-basilicata.ninux.org   : ok=17   changed=0    unreachable=0    failed=1    skipped=2    rescued=0    ignored=0   

Does your config works without using my PR?

yes

This PR, only adds two new variables: update_policy and bind_tsig_keys

mikysal78 avatar Sep 21 '22 20:09 mikysal78

@mikysal78 I will post an example i did that worked. I tested with RHEL. Its only one zone by the way. Considering the error you got, thats maybe something related to Debian creating some .jnl files which are not meant to be... i may need to check it out.... could you upload your *.conf files from bind that were generated?

I also advice to set up a testbox for testing new things out. It is not recommended to try new things directly on production systems.

---
- hosts: dns
  become: true
  gather_facts: true
 
  vars:
   - dns_key_name: "certbot-sha256."
   - dns_key_algorithm: hmac-sha256
   - dns_key_secret: "xwOGjKnek3ec15X3pEsFF9Y7or8p3u1bO0FyrXw49TU="
  tasks:

   - name: Configure Firewalld to allow DNS
     firewalld:
      zone: public
      service: dns
      permanent: yes
      immediate: yes
      state: enabled

   - name: Configure DNS Servers
     import_role:
      name: "/home/bruno/projects/ansible-role-bind"
     vars:
      - bind_listen_ipv4: ['any']
      - bind_allow_query: ['any']
      - bind_acls:
         - name: ACL-allow-zone-transfers
           match_list:
            - 192.168.10.221/32
            - 192.168.10.222/32
      - bind_tsig_keys:
         - name: "{{tsig_key_name}}"
           algorithm: "{{tsig_key_algorithm}}"
           secret: "{{tsig_key_secret}}"
      - bind_zones:
         - name: testzone.local           # Domain name
           hostmaster_email: testmail
           bind_zone_ttl: 1H
           bind_zone_minimum_ttl: 1D
           bind_zone_time_to_expire: 1W
           bind_zone_time_to_refresh: 1D
           bind_zone_time_to_retry: 1D
           create_reverse_zones: true  # Skip creation of reverse zones, if false
           primaries:
            - 192.168.10.220                # Primary server(s) for this zone
           networks:
            - "192.168.10"
           name_servers:
            - ns1.testzone.local.
            - ns2.testzone.local.
           mail_servers:
            - name: mx
              preference: 10
           # allow_update:
           # - "10.254.227.252/32"
           # - "key {{ tsig_key_name }}"
           update_policy:
            - "grant {{ tsig_key_name }} zonesub A"
            - "grant {{ tsig_key_name }} zonesub TXT"
            - "grant local-ddns zonesub any"
           hosts:
            - name: '@'                # Enables "http://testzone.local/"
              ip:
               - 192.168.10.222            # Multiple IP addresses for a single host
               - 192.168.10.223            #   results in DNS round robin
              # ipv6:
              # - 2001:db8::5
              # - 2001:db8::6
              aliases:
               - mainapp
            - name: ns1
              ip: 192.168.10..220
              # ipv6: 2001:db8::1
              aliases:
               - dnstest-default-0
            - name: ns2
              ip: 192.168.10..221
              # ipv6: 2001:db8::2
              aliases:
               - dnstest-default-1
            - name: dnstest-default-4
              ip: 192.168.10.224
              aliases:
               - www
            - name: mx
              ip: 192.168.10.228
            - name: sample
              ip: 192.168.10.250

   - name: "Add or modify ansible.testzone.local A to 192.168.10.230 using TSIG"
     nsupdate:
      key_name: "{{ tsig_key_name }}"
      key_algorithm: "{{ tsig_key_algorithm }}"
      key_secret: "{{ tsig_key_secret }}"
      server: "192.168.10.220"
      zone: "testzone.local"
      record: "ansible"
      value: "192.168.10.230"
      state: present
     tags: never  # change tag or use --tags never when you want to only nsupdate instead of whole config
     run_once: true

brunobenchimol avatar Sep 22 '22 23:09 brunobenchimol

@mikysal78 I will post an example i did that worked. I tested with RHEL. Its only one zone by the way. Considering the error you got, thats maybe something related to Debian creating some .jnl files which are not meant to be... i may need to check it out.... could you upload your *.conf files from bind that were generated?

@brunobenchimol ,Hi, i compress file bind and zones genrate. This on generate from master roles var-cache-bind.tar.gz etc-bind.tar.gz

mikysal78 avatar Sep 23 '22 18:09 mikysal78

@mikysal78 i did a small fix on code, hope it fix your error. I changed how ansible read zone files (it will read from your config instead of server files).

Commit https://github.com/bertvv/ansible-role-bind/commit/0daf9d47ef4badbd72271f080a9f8ee435b2a6fd

brunobenchimol avatar Sep 23 '22 19:09 brunobenchimol

i did a small fix on code, hope it fix your error. I changed how ansible read zone files (it will read from your config instead of server files).

Commit 0daf9d4

update role and now is:

TASK [bind : Main BIND config file] *****************************************************************************************************************************************************************************************************
Friday 23 September 2022  21:25:32 +0200 (0:00:10.408)       0:02:27.219 ****** 
[DEPRECATION WARNING]: Use 'ansible.utils.ipaddr' module instead. This feature will be removed from ansible.netcommon in a release after 2024-01-01. Deprecation warnings can be disabled by setting deprecation_warnings=False in 
ansible.cfg.
[DEPRECATION WARNING]: Use 'ansible.utils.ipaddr' module instead. This feature will be removed from ansible.netcommon in a release after 2024-01-01. Deprecation warnings can be disabled by setting deprecation_warnings=False in 
ansible.cfg.
fatal: [ns2-basilicata.ninux.org]: FAILED! => changed=false 
  checksum: 4e06789dc9d1789c4df04d1edd1156942ae22e49
  exit_status: 1
  msg: failed to validate
  stderr: ''
  stderr_lines: <omitted>
  stdout: |-
    /root/.ansible/tmp/ansible-tmp-1663961132.472001-248026-163169885720072/source:31: option 'dnssec-enable' is obsolete and should be removed
    /etc/bind/tsig_keys.conf:3: unknown algorithm 'DH'
  stdout_lines: <omitted>
fatal: [ns1-basilicata.ninux.org]: FAILED! => changed=false 
  checksum: df2da592f214b4569eb430c6c30fc9e7d9a1fb81
  exit_status: 1
  msg: failed to validate
  stderr: ''
  stderr_lines: <omitted>
  stdout: |-
    /root/.ansible/tmp/ansible-tmp-1663961132.493875-248025-187990302811822/source:31: option 'dnssec-enable' is obsolete and should be removed
    /root/.ansible/tmp/ansible-tmp-1663961132.493875-248025-187990302811822/source:74: expected unquoted string near '{'
  stdout_lines: <omitted>

the command: dnssec-keygen -a HMAC-SHA256 -b 256 -n HOST tsig_key. output: dnssec-keygen: fatal: unknown algorithm HMAC-SHA256

i try with DH because HMAC-SHA256 not found:

root@ns1-basilicata:tmp # dnssec-keygen -h
Usage:
    dnssec-keygen [options] name

Version: 9.16.27-Debian
    name: owner of the key
Options:
    -K <directory>: write keys into directory
    -k <policy>: generate keys for dnssec-policy
    -l <file>: configuration file with dnssec-policy statement
    -a <algorithm>:
        RSASHA1 | NSEC3RSASHA1 |
        RSASHA256 | RSASHA512 |
        ECDSAP256SHA256 | ECDSAP384SHA384 |
        ED25519 | ED448 | DH
    -3: use NSEC3-capable algorithm
    -b <key size in bits>:
        RSASHA1:	[1024..4096]
        NSEC3RSASHA1:	[1024..4096]
        RSASHA256:	[1024..4096]
        RSASHA512:	[1024..4096]
        DH:		[128..4096]
        ECDSAP256SHA256:	ignored
        ECDSAP384SHA384:	ignored
        ED25519:	ignored
        ED448:	ignored
        (key size defaults are set according to
        algorithm and usage (ZSK or KSK)
    -n <nametype>: ZONE | HOST | ENTITY | USER |
    ```
    
   You  try to integrate in your PR this: issues #78 

mikysal78 avatar Sep 23 '22 19:09 mikysal78

@mikysal78 Thats quite Debian-related. I am more a RHEL guy. But checking Debians docs

https://manpages.debian.org/bullseye/bind9-utils/dnssec-keygen.8.en.html

[-a algorithm]
This option selects the cryptographic algorithm. For DNSSEC keys, the value of algorithm must be one of RSASHA1, NSEC3RSASHA1, RSASHA256, RSASHA512, ECDSAP256SHA256, ECDSAP384SHA384, ED25519, or ED448. For TKEY, the value must be DH (Diffie-Hellman); specifying this value automatically sets the -T KEY option as well.
These values are case-insensitive. In some cases, abbreviations are supported, such as ECDSA256 for ECDSAP256SHA256 and ECDSA384 for ECDSAP384SHA384. If RSASHA1 is specified along with the -3 option, NSEC3RSASHA1 is used instead.

This parameter must be specified except when using the -S option, which copies the algorithm from the predecessor key.

In prior releases, HMAC algorithms could be generated for use as TSIG keys, but that feature was removed in BIND 9.13.0. Use tsig-keygen to generate TSIG keys.

For TSIG keys, it must be generated with HMAC algorithms. According to this manpages you should try tsig-keygen. Check: https://manpages.debian.org/bullseye/bind9/tsig-keygen.8.en.html

Always check man pages if help command does not seems complete.

brunobenchimol avatar Sep 23 '22 20:09 brunobenchimol

For TSIG keys, it must be generated with HMAC algorithms. According to this manpages you should try tsig-keygen. Check: https://manpages.debian.org/bullseye/bind9/tsig-keygen.8.en.html

Always check man pages if help command does not seems complete.

ok, i generate key with tsig-keygen. Same playbook, only change role: with master is ok with your i have error and run the playbook with -vvv

TASK [bind : Main BIND config file] *****************************************************************************************************************************************************************************************************
task path: /git/new-dns/roles/bind/tasks/main.yml:112
Friday 23 September 2022  23:17:03 +0200 (0:00:07.119)       0:01:58.584 ****** 
[CUT]
fatal: [ns1-basilicata.ninux.org]: FAILED! => changed=false 
  checksum: c4109562edde64613abaad9ddb9de4efdee52976
  diff: []
  exit_status: 1
  invocation:
    module_args:
      _original_basename: etc_named.conf.j2
      attributes: null
      backup: false
      checksum: c4109562edde64613abaad9ddb9de4efdee52976
      content: null
      dest: /etc/bind/named.conf
      directory_mode: null
      follow: false
      force: true
      group: bind
      local_follow: null
      mode: 416
      owner: root
      remote_src: null
      selevel: null
      serole: null
      setype: named_conf_t
      seuser: null
      src: /root/.ansible/tmp/ansible-tmp-1663967823.2293131-259383-104189146121820/source
      unsafe_writes: false
      validate: named-checkconf %s
  msg: failed to validate
  stderr: ''
  stderr_lines: <omitted>
  stdout: |-
    /root/.ansible/tmp/ansible-tmp-1663967823.2293131-259383-104189146121820/source:31: option 'dnssec-enable' is obsolete and should be removed
    /root/.ansible/tmp/ansible-tmp-1663967823.2293131-259383-104189146121820/source:74: expected unquoted string near '{'
  stdout_lines: <omitted>

TASK [bind : Start BIND service] *******************************************

mikysal78 avatar Sep 23 '22 21:09 mikysal78

Thays wierd. Thia PR does not touch this part of original code.

I cant replicate your exact error. I Will try to help.

Upload your named.conf (original) Than update zones.yaml and comment validate line that creates files based on jinja etc_named.conf.j2.

After that check the New files created to compare.

Also use named-checkconf and see output. Should have no errors.

I believe your bind version is incompatible with some params. New version maybe

brunobenchimol avatar Sep 23 '22 21:09 brunobenchimol

Thays wierd. Thia PR does not touch this part of original code.

I cant replicate your exact error. I Will try to help.

Upload your named.conf (original) Than update zones.yaml and comment validate line that creates files based on jinja etc_named.conf.j2.

After that check the New files created to compare.

Also use named-checkconf and see output. Should have no errors.

I believe your bind version is incompatible with some params. New version maybe

try and with default vars " bind_dnssec_enable: true" with master i not have error, with your role i have error. i try disable vars and the error is:

fatal: [ns1-basilicata.ninux.org]: FAILED! => changed=false 
  checksum: b9d93f4ec11f5cc5deb95997052f645151eda92d
  diff: []
  exit_status: 1
  invocation:
    module_args:
      _original_basename: etc_named.conf.j2
      attributes: null
      backup: false
      checksum: b9d93f4ec11f5cc5deb95997052f645151eda92d
      content: null
      dest: /etc/bind/named.conf
      directory_mode: null
      follow: false
      force: true
      group: bind
      local_follow: null
      mode: 416
      owner: root
      remote_src: null
      selevel: null
      serole: null
      setype: named_conf_t
      seuser: null
      src: /root/.ansible/tmp/ansible-tmp-1663971087.1293068-263651-42369240590728/source
      unsafe_writes: false
      validate: named-checkconf %s
  msg: failed to validate
  stderr: ''
  stderr_lines: <omitted>
  stdout: |-
    /root/.ansible/tmp/ansible-tmp-1663971087.1293068-263651-42369240590728/source:74: expected unquoted string near '{'
  stdout_lines: <omitted>

not write file for check diff. bat ...expected unquoted string near '{' ??

mikysal78 avatar Sep 23 '22 22:09 mikysal78

With the new commits is perfect!

mikysal78 avatar Sep 24 '22 19:09 mikysal78

@bertvv You need to see and testing this PR! The PR author @brunobenchimol uses RedHat, I use Debian. It works just fine. In my opinion it is a PR to be placed in the mater role!

mikysal78 avatar Sep 28 '22 21:09 mikysal78

Hey @brunobenchimol,

I like your PR and need the ability to use dynamic DNS updates. ATM I loose all dynamic updates when Ansible runs.

And then I discovered an issue:

TASK [bind : Dump/flush dynamic zone changes to disk/zone file] *************************************************************************************************************************************
failed: [ns.local] (item={'name': 'ddns.ns.local', 'create_reverse_zones': False, 'primaries': ['127.0.0.1'], 'type': 'primary', 'name_servers': ['localhost.'], 'update_policy': ['grant clt1 zonesub
A', 'grant clt0 zonesub AAAA', 'grant clt1 zonesub A', 'grant clt1 zonesub AAAA', 'grant clt2 zonesub A', 'grant clt2 zonesub AAAA', 'grant clt3 zonesub A', 'grant clt3 zonesub AAAA']}) => changed=true
  ansible_loop_var: item
  cmd:
  - rndc
  - sync
  - -clean
  - ddns.ns.local
  item:
    create_reverse_zones: false
    name: ddns.ns.local
    name_servers:
      - localhost.
    primaries:
    - 127.0.0.1
    type: primary
    update_policy:
    - grant clt0 zonesub A
    - grant clt0 zonesub AAAA
    - grant clt1 zonesub A
    - grant clt1 zonesub AAAA
    - grant clt2 zonesub A
    - grant clt2 zonesub AAAA
    - grant clt3 zonesub A
    - grant clt3 zonesub AAAA
  msg: non-zero return code
  rc: 1
  stderr: |-
    rndc: 'sync' failed: not found
    no matching zone 'ddns.ns.local' in any view
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>

This NEW DNS zone needs to be crated - it does not exist. There is nothing to flush.

I got into this situation like so:

bind_zones:
  - name: 'ddns.ns.local'
    create_reverse_zones: False
    primaries:
      - '127.0.0.1'
    type: 'primary'
    name_servers:
      - "localhost."
    update_policy:
      - "grant {{ bind_tsig_keys[0].name }} zonesub A"
      - "grant {{ bind_tsig_keys[0].name }} zonesub AAAA"
      - "grant {{ bind_tsig_keys[1].name }} zonesub A"
      - "grant {{ bind_tsig_keys[1].name }} zonesub AAAA"
      - "grant {{ bind_tsig_keys[2].name }} zonesub A"
      - "grant {{ bind_tsig_keys[2].name }} zonesub AAAA"
      - "grant {{ bind_tsig_keys[3].name }} zonesub A"
      - "grant {{ bind_tsig_keys[3].name }} zonesub AAAA"

and then:

bind_zones:
  - name: 'ddns.ns.local'
    create_forward_zones: False # <---- note this "FORWARD": ``named.conf`` does not include this zone
    primaries:
      - '127.0.0.1'
    type: 'primary'
    name_servers:
      - "localhost."
    update_policy:
      - "grant {{ bind_tsig_keys[0].name }} zonesub A"
      - "grant {{ bind_tsig_keys[0].name }} zonesub AAAA"
      - "grant {{ bind_tsig_keys[1].name }} zonesub A"
      - "grant {{ bind_tsig_keys[1].name }} zonesub AAAA"
      - "grant {{ bind_tsig_keys[2].name }} zonesub A"
      - "grant {{ bind_tsig_keys[2].name }} zonesub AAAA"
      - "grant {{ bind_tsig_keys[3].name }} zonesub A"
      - "grant {{ bind_tsig_keys[3].name }} zonesub AAAA"

After that I replaced create_forward_zones again with create_reverse_zones.

I tried this create_forward_zones: false because Ansible always overrides the zone file (understandably). But this excludes it entirely from the named.conf.

Is there a way to:

  • NOT touch the zone file via Ansible if it exists? - need to force it?
  • Flush only if it exists.

EDIT1: workaround for the error - not the initial problem:

  • comment update_policy
  • run
  • uncomment

Kariton avatar Nov 06 '22 22:11 Kariton

Hello @Kariton

Is there a way to:

  • NOT touch the zone file via Ansible if it exists? - need to force it?

That is not based on my PR, but if i remember properly it needs to maintain all zones when using this role.

  • Flush only if it exists.

Flush is based on dynamic dns policies (update policy/allow updates)... if it has on config, it will sync flush. I could not find anyway to preserve previous dynamic updates and change bind files.... either dynamic goes away or new zone file does not get loaded.

Maybe, thats big one..it could be able to create a new variable to control when to sync flush zones. But it may lead to inconsistent state. It could be like "ansible_managed_dynamic_update = true/false" but it would cause confusion imho.

So if i got it properly, you are having issues on the first run of this role because it crashes because there is nothing to flush yet? Could try to implement to check if zone file exists before running sync.

I did a few changes on my previous commit https://github.com/brunobenchimol/ansible-role-bind/blob/master/tasks/zones.yml... i dont know if it "updated" this PR when i was fixing some bugs for @mikysal78 .

brunobenchimol avatar Nov 06 '22 23:11 brunobenchimol

Another one: First install fails with: rndc: connect failed: 127.0.0.1#953: connection refused caused by named initially not running. After Starting named manually I got the same error as above. (rndc: 'sync' failed: not found no matching zone 'ddns.ns.local' in any view)

Kariton avatar Nov 07 '22 07:11 Kariton

Hello @brunobenchimol, First of all: Thanks for your fast reply!

So if i got it properly, you are having issues on the first run of this role because it crashes because there is nothing to flush yet?

yep.

I have read your discussion with @mikysal78. It is clear that the find was not that good. But the current way is "not good enough".

It could be like "ansible_managed_dynamic_update = true/false" but it would cause confusion imho.

I thought about it a bit and also found nothing better. I think that a bool is the way it needs to be. Would name it ansible_managed_dynamic_zones rather than ansible_managed_dynamic_update.

From my understanding:

  • ansible_managed_dynamic_zones: False -> create file if missing - never touch it again
  • ansible_managed_dynamic_zones: True -> create and update file by ansible

i dont know if it "updated" this PR when i was fixing some bugs for @mikysal78.

It did. I merged your remote myself on top of @bertvv main.

Kariton avatar Nov 07 '22 07:11 Kariton

I was thinking on checking it using ignore_error or using failed_when when syncing a non existent zone... it may be a dirty fix, but it would work... It does no harm if it keeps running and this task 'fails'. I could try to code it on friday or weekend... it should be pretty easy to do.

brunobenchimol avatar Nov 07 '22 22:11 brunobenchimol