Skip to content
Snippets Groups Projects
Unverified Commit cbcced34 authored by Sergio Oliveira's avatar Sergio Oliveira Committed by GitHub
Browse files

Merge pull request #213 from rjeffman/dnsconfig

New DNSConfig management module
parents 4828431f e22bf295
No related branches found
No related tags found
No related merge requests found
DNSConfig module
============
Description
-----------
The dnsconfig module allows to modify global DNS configuration.
Features
--------
* Global DNS configuration
Supported FreeIPA Versions
--------------------------
FreeIPA versions 4.4.0 and up are supported by the ipadnsconfig module.
Requirements
------------
**Controller**
* Ansible version: 2.8+
**Node**
* Supported FreeIPA version (see above)
Usage
=====
Example inventory file
```ini
[ipaserver]
ipaserver.test.local
```
Example playbook to set global DNS configuration:
```yaml
---
- name: Playbook to handle global DNS configuration
hosts: ipaserver
become: true
tasks:
# Set dnsconfig.
- ipadnsconfig:
forwarders:
- ip_address: 8.8.4.4
- ip_address: 2001:4860:4860::8888
port: 53
forward_policy: only
allow_sync_ptr: yes
```
Example playbook to ensure a global forwarder, with a custom port, is absent:
```yaml
---
- name: Playbook to handle global DNS configuration
hosts: ipaserver
become: true
tasks:
# Ensure global forwarder with a custom port is absent.
- ipadnsconfig:
forwarders:
- ip_address: 2001:4860:4860::8888
port: 53
state: absent
```
Example playbook to disable global forwarders:
```yaml
---
- name: Playbook to disable global DNS forwarders
hosts: ipaserver
become: true
tasks:
# Disable global forwarders.
- ipadnsconfig:
forward_policy: none
```
Example playbook to change global forward policy:
```yaml
---
- name: Playbook to change global forward policy
hosts: ipaserver
become: true
tasks:
# Disable global forwarders.
- ipadnsconfig:
forward_policy: first
```
Example playbook to disallow synchronization of forward (A, AAAA) and reverse (PTR) records:
```yaml
---
- name: Playbook to disallow reverse synchronization.
hosts: ipaserver
become: true
tasks:
# Disable global forwarders.
- ipadnsconfig:
allow_sync_ptr: no
```
Variables
=========
ipadnsconfig
------------
Variable | Description | Required
-------- | ----------- | --------
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
`forwarders` | The list of forwarders dicts. Each `forwarders` dict entry has:| no
  | `ip_address` - The IPv4 or IPv6 address of the DNS server. | yes
  | `port` - The custom port that should be used on this server. | no
`forward_policy` | The global forwarding policy. It can be one of `only`, `first`, or `none`. | no
`allow_sync_ptr` | Allow synchronization of forward (A, AAAA) and reverse (PTR) records (bool). | yes
`state` | The state to ensure. It can be one of `present` or `absent`, default: `present`. | yes
Authors
=======
Rafael Guterres Jeffman
...@@ -407,6 +407,7 @@ Roles ...@@ -407,6 +407,7 @@ Roles
Modules in plugin/modules Modules in plugin/modules
========================= =========================
* [ipadnsconfig](README-dnsconfig.md)
* [ipagroup](README-group.md) * [ipagroup](README-group.md)
* [ipahbacrule](README-hbacrule.md) * [ipahbacrule](README-hbacrule.md)
* [ipahbacsvc](README-hbacsvc.md) * [ipahbacsvc](README-hbacsvc.md)
......
---
- name: Playbook to disable global DNS forwarders
hosts: ipaserver
become: true
tasks:
- name: Disable global forwarders.
ipadnsconfig:
forward_policy: none
---
- name: Playbook to disallow reverse record synchronization.
hosts: ipaserver
become: true
tasks:
- name: Disallow reverse record synchronization.
ipadnsconfig:
allow_sync_ptr: no
---
- name: Playbook to handle global DNS configuration
hosts: ipaserver
become: true
tasks:
- name: Set dnsconfig.
ipadnsconfig:
forwarders:
- ip_address: 8.8.4.4
- ip_address: 2001:4860:4860::8888
port: 53
state: absent
---
- name: Playbook to handle global DNS configuration
hosts: ipaserver
become: true
tasks:
- name: Set dnsconfig.
ipadnsconfig:
forwarders:
- ip_address: 8.8.4.4
- ip_address: 2001:4860:4860::8888
port: 53
forward_policy: only
allow_sync_ptr: yes
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Authors:
# Rafael Guterres Jeffman <rjeffman@redhat.com>
#
# Copyright (C) 2019 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program 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.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
ANSIBLE_METADATA = {
"metadata_version": "1.0",
"supported_by": "community",
"status": ["preview"],
}
DOCUMENTATION = """
---
module: ipadnsconfig
short description: Manage FreeIPA dnsconfig
description: Manage FreeIPA dnsconfig
options:
ipaadmin_principal:
description: The admin principal
default: admin
ipaadmin_password:
description: The admin password
required: false
forwarders:
description: The list of global DNS forwarders.
required: false
options:
ip_address:
description: The forwarder nameserver IP address list (IPv4 and IPv6).
required: true
port:
description: The port to forward requests to.
required: false
forward_policy:
description:
Global forwarding policy. Set to "none" to disable any configured
global forwarders.
required: false
choices: ['only', 'first', 'none']
allow_sync_ptr:
description:
Allow synchronization of forward (A, AAAA) and reverse (PTR) records.
required: false
type: bool
state:
description: State to ensure
default: present
choices: ["present", "absent"]
"""
EXAMPLES = """
# Ensure global DNS forward configuration, allowing PTR record synchronization.
- ipadnsconfig:
forwarders:
- ip_address: 8.8.4.4
- ip_address: 2001:4860:4860::8888
port: 53
forward_policy: only
allow_sync_ptr: yes
# Ensure forwarder is absent.
- ipadnsconfig:
forwarders:
- ip_address: 2001:4860:4860::8888
port: 53
state: absent
# Disable PTR record synchronization.
- ipadnsconfig:
allow_sync_ptr: no
# Disable global forwarders.
- ipadnsconfig:
forward_policy: none
"""
RETURN = """
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_text
from ansible.module_utils.ansible_freeipa_module import temp_kinit, \
temp_kdestroy, valid_creds, api_connect, api_command, \
api_command_no_name, compare_args_ipa, module_params_get, \
gen_add_del_lists, is_ipv4_addr, is_ipv6_addr, ipalib_errors
def find_dnsconfig(module):
_args = {
"all": True,
}
_result = api_command_no_name(module, "dnsconfig_show", _args)
if "result" in _result:
if _result["result"].get('idnsforwarders', None) is None:
_result["result"]['idnsforwarders'] = ['']
return _result["result"]
else:
module.fail("Could not retrieve current DNS configuration.")
return None
def gen_args(module, state, dnsconfig, forwarders, forward_policy,
allow_sync_ptr):
_args = {}
if forwarders:
_forwarders = []
for forwarder in forwarders:
ip_address = forwarder.get('ip_address')
port = forwarder.get('port')
if not (is_ipv4_addr(ip_address) or is_ipv6_addr(ip_address)):
module.fail(
msg="Invalid IP for DNS forwarder: %s" % ip_address)
if port is None:
_forwarders.append(ip_address)
else:
_forwarders.append('%s port %d' % (ip_address, port))
global_forwarders = dnsconfig.get('idnsforwarders', [])
if state == 'absent':
_args['idnsforwarders'] = [
fwd for fwd in global_forwarders if fwd not in _forwarders]
# When all forwarders should be excluded, use an empty string ('').
if not _args['idnsforwarders']:
_args['idnsforwarders'] = ['']
elif state == 'present':
_args['idnsforwarders'] = [
fwd for fwd in _forwarders if fwd not in global_forwarders]
# If no forwarders should be added, remove argument.
if not _args['idnsforwarders']:
del _args['idnsforwarders']
else:
# shouldn't happen, but let's be paranoid.
module.fail(msg="Invalid state: %s" % state)
if forward_policy is not None:
_args['idnsforwardpolicy'] = forward_policy
if allow_sync_ptr is not None:
_args['idnsallowsyncptr'] = 'TRUE' if allow_sync_ptr else 'FALSE'
return _args
def main():
forwarder_spec = dict(
ip_address=dict(type=str, required=True),
port=dict(type=int, required=False, default=None)
)
ansible_module = AnsibleModule(
argument_spec=dict(
# general
ipaadmin_principal=dict(type='str', default='admin'),
ipaadmin_password=dict(type='str', no_log=True),
# dnsconfig
forwarders=dict(type='list', default=None, required=False,
options=dict(**forwarder_spec)),
forward_policy=dict(type='str', required=False, default=None,
choices=['only', 'first', 'none']),
allow_sync_ptr=dict(type='bool', required=False, default=None),
# general
state=dict(type="str", default="present",
choices=["present", "absent"]),
)
)
ansible_module._ansible_debug = True
# general
ipaadmin_principal = module_params_get(ansible_module,
"ipaadmin_principal")
ipaadmin_password = module_params_get(ansible_module,
"ipaadmin_password")
forwarders = module_params_get(ansible_module, 'forwarders') or []
forward_policy = module_params_get(ansible_module, 'forward_policy')
allow_sync_ptr = module_params_get(ansible_module, 'allow_sync_ptr')
state = module_params_get(ansible_module, 'state')
# Check parameters.
invalid = []
if state == 'absent':
invalid = ['forward_policy', 'allow_sync_ptr']
for x in invalid:
if vars()[x] is not None:
ansible_module.fail_json(
msg="Argument '%s' can not be used with state '%s'" %
(x, state))
# Init
changed = False
ccache_dir = None
ccache_name = None
try:
if not valid_creds(ansible_module, ipaadmin_principal):
ccache_dir, ccache_name = temp_kinit(ipaadmin_principal,
ipaadmin_password)
api_connect()
res_find = find_dnsconfig(ansible_module)
args = gen_args(ansible_module, state, res_find, forwarders,
forward_policy, allow_sync_ptr)
# Execute command only if configuration changes.
if not compare_args_ipa(ansible_module, args, res_find):
try:
api_command_no_name(ansible_module, 'dnsconfig_mod', args)
# If command did not fail, something changed.
changed = True
except Exception as e:
msg = str(e)
ansible_module.fail_json(msg="dnsconfig_mod: %s" % msg)
except Exception as e:
ansible_module.fail_json(msg=str(e))
finally:
temp_kdestroy(ccache_dir, ccache_name)
# Done
ansible_module.exit_json(changed=changed)
if __name__ == "__main__":
main()
---
- name: Test dnsconfig
hosts: ipaserver
become: true
gather_facts: true
tasks:
# Setup.
- name: Ensure forwarders are absent.
ipadnsconfig:
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4
- ip_address: 2001:4860:4860::8888
- ip_address: 2001:4860:4860::8888
port: 53
state: absent
# Tests.
- name: Set dnsconfig.
ipadnsconfig:
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4
- ip_address: 2001:4860:4860::8888
port: 53
forward_policy: only
allow_sync_ptr: yes
register: result
failed_when: not result.changed
- name: Set dnsconfig, with the same values.
ipadnsconfig:
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4
- ip_address: 2001:4860:4860::8888
port: 53
forward_policy: only
allow_sync_ptr: yes
register: result
failed_when: result.changed
- name: Ensure forwarder is absent.
ipadnsconfig:
forwarders:
- ip_address: 8.8.8.8
state: absent
register: result
failed_when: not result.changed
- name: Ensure forwarder is absent, again.
ipadnsconfig:
forwarders:
- ip_address: 8.8.8.8
state: absent
register: result
failed_when: result.changed
- name: Disable global forwarders.
ipadnsconfig:
forward_policy: none
register: result
failed_when: not result.changed
- name: Disable global forwarders, again.
ipadnsconfig:
forward_policy: none
register: result
failed_when: result.changed
- name: Re-enable global forwarders.
ipadnsconfig:
forward_policy: first
register: result
failed_when: not result.changed
- name: Re-enable global forwarders, again.
ipadnsconfig:
forward_policy: first
register: result
failed_when: result.changed
- name: Disable PTR record synchronization.
ipadnsconfig:
allow_sync_ptr: no
register: result
failed_when: not result.changed
- name: Disable PTR record synchronization, again.
ipadnsconfig:
allow_sync_ptr: no
register: result
failed_when: result.changed
- name: Re-enable PTR record synchronization.
ipadnsconfig:
allow_sync_ptr: yes
register: result
failed_when: not result.changed
- name: Re-enable PTR record synchronization, again.
ipadnsconfig:
allow_sync_ptr: yes
register: result
failed_when: result.changed
- name: Ensure all forwarders are absent.
ipadnsconfig:
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4
- ip_address: 2001:4860:4860::8888
port: 53
state: absent
register: result
failed_when: not result.changed
- name: Ensure all forwarders are absent, again.
ipadnsconfig:
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4
- ip_address: 2001:4860:4860::8888
port: 53
state: absent
register: result
failed_when: result.changed
# Cleanup.
- name: Ensure forwarders are absent.
ipadnsconfig:
forwarders:
- ip_address: 8.8.8.8
- ip_address: 8.8.4.4
- ip_address: 2001:4860:4860::8888
- ip_address: 2001:4860:4860::8888
port: 53
state: absent
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment