Skip to content
Snippets Groups Projects
Commit 3bd68ac0 authored by Rafael Guterres Jeffman's avatar Rafael Guterres Jeffman
Browse files

ipadnszone: Add support for per-zone privilege delegation

IPA DNS Zones management can be delegated by adding a "Manage DNS zone"
permission. The CLI commands that manage these permissions are
dnszone-add-permission and dnszone-remove-permission.

The ansible-freeipa module ipadnszone did not have this capability, and
it now support dnszone per-zone management delegation by setting the
module parameter 'permission'. If set to 'true' the permission will be
assigned to the zone, if set to false the permission will be removed.
parent 0f2c3761
No related branches found
No related tags found
No related merge requests found
......@@ -133,6 +133,22 @@ Example playbook to enable a zone:
state: enabled
```
Example playbook to allow per-zone privilege delegation:
``` yaml
---
- name: Playbook to enable per-zone privilege delegation
hosts: ipaserver
become: true
tasks:
- name: Enable privilege delegation.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name: testzone.local
permission: true
```
Example playbook to remove a zone:
```yaml
......@@ -223,6 +239,7 @@ Variable | Description | Required
`ttl`| Time to live for records at zone apex | no
`default_ttl`| Time to live for records without explicit TTL definition | no
`nsec3param_rec`| NSEC3PARAM record for zone in format: hash_algorithm flags iterations salt | no
`permission` \| `managedby` | Set per-zone access delegation permission. | no
`skip_overlap_check`| Force DNS zone creation even if it will overlap with an existing zone | no
`skip_nameserver_check` | Force DNS zone creation even if nameserver is not resolvable | no
......@@ -238,4 +255,6 @@ Variable | Description | Returned When
Authors
=======
Sergio Oliveira Campos
- Sergio Oliveira Campos
- Thomas Woerner
- Rafael Jeffman
......@@ -142,6 +142,11 @@ options:
salt.
required: false
type: str
permission:
description: Set per-zone access delegation permission.
required: false
type: bool
aliases: ["managedby"]
skip_overlap_check:
description: |
Force DNS zone creation even if it will overlap with an existing zone
......@@ -154,6 +159,7 @@ options:
author:
- Sergio Oliveira Campos (@seocam)
- Thomas Woerner (@t-woerner)
- Rafael Jeffman (@rjeffman)
""" # noqa: E501
EXAMPLES = """
......@@ -253,6 +259,9 @@ class DNSZoneModule(IPAAnsibleModule):
"idnsallowdynupdate": "dynamic_update",
"idnssecinlinesigning": "dnssec",
"idnsupdatepolicy": "update_policy",
# FreeIPA uses 'managedby' for dnszone and dnsforwardzone
# to manage 'permissions'.
"managedby": "permission",
# Mapping by method
"idnsforwarders": self.get_ipa_idnsforwarders,
"idnsallowtransfer": self.get_ipa_idnsallowtransfer,
......@@ -434,7 +443,7 @@ class DNSZoneModule(IPAAnsibleModule):
is_zone_active = False
else:
zone = response["result"]
# FreeIPA 4.9.10+ and 4.10 use proper mapping for boolean vaalues.
# FreeIPA 4.9.10+ and 4.10 use proper mapping for boolean values.
# See: https://github.com/freeipa/freeipa/pull/6294
is_zone_active = (
str(zone.get("idnszoneactive")[0]).upper() == "TRUE"
......@@ -462,18 +471,24 @@ class DNSZoneModule(IPAAnsibleModule):
self.fail_json(
msg="Either `name` or `name_from_ip` must be provided."
)
# check invalid parameters
invalid = []
if self.ipa_params.state != "present":
invalid = ["name_from_ip"]
invalid .extend(["name_from_ip"])
if self.ipa_params.state == "absent":
invalid.extend(["permission"])
self.params_fail_used_invalid(invalid, self.ipa_params.state)
def define_ipa_commands(self):
for zone_name in self.get_zone_names():
# Look for existing zone in IPA
zone, is_zone_active = self.get_zone(zone_name)
args = self.ipa_params.get_ipa_command_args(zone=zone)
if self.ipa_params.state in ["present", "enabled", "disabled"]:
args = self.ipa_params.get_ipa_command_args(zone=zone)
# We'll handle "managedby" after dnszone add/mod.
args.pop("managedby", None)
if not zone:
# Since the zone doesn't exist we just create it
# with given args
......@@ -487,6 +502,16 @@ class DNSZoneModule(IPAAnsibleModule):
if not compare_args_ipa(self, args, zone):
self.commands.append((zone_name, "dnszone_mod", args))
# Permissions must be set on existing zones.
if self.ipa_params.permission is not None:
is_managed = zone.get("managedby")
if self.ipa_params.permission and not is_managed:
self.commands.append(
(zone_name, "dnszone_add_permission", {}))
if not self.ipa_params.permission and is_managed:
self.commands.append(
(zone_name, "dnszone_remove_permission", {}))
if self.ipa_params.state == "enabled" and not is_zone_active:
self.commands.append((zone_name, "dnszone_enable", {}))
......@@ -555,6 +580,8 @@ def get_argument_spec():
ttl=dict(type="int", required=False, default=None),
default_ttl=dict(type="int", required=False, default=None),
nsec3param_rec=dict(type="str", required=False, default=None),
permission=dict(type="bool", required=False, default=None,
aliases=["managedby"]),
skip_nameserver_check=dict(type="bool", required=False, default=None),
skip_overlap_check=dict(type="bool", required=False, default=None),
)
......
......@@ -3,6 +3,10 @@
hosts: "{{ ipa_test_host | default('ipaserver') }}"
become: true
gather_facts: true
module_defaults:
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
tasks:
......@@ -13,8 +17,6 @@
# Tests
- name: Check if zone is present, when it shouldn't be.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
state: present
check_mode: yes
......@@ -23,8 +25,6 @@
- name: Check if zone is present again, when it shouldn't be.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
state: present
check_mode: yes
......@@ -33,8 +33,6 @@
- name: Ensure zone is present.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
state: present
register: result
......@@ -42,8 +40,6 @@
- name: Check if zone is present, when it should be.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
state: present
check_mode: yes
......@@ -52,8 +48,6 @@
- name: Ensure zone is present, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
state: present
register: result
......@@ -61,8 +55,6 @@
- name: Ensure zone is disabled.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
state: disabled
register: result
......@@ -70,8 +62,6 @@
- name: Ensure zone is disabled, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
state: disabled
register: result
......@@ -79,8 +69,6 @@
- name: Ensure zone is enabled.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
state: enabled
register: result
......@@ -88,8 +76,6 @@
- name: Ensure zone is enabled, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
state: enabled
register: result
......@@ -97,8 +83,6 @@
- name: Ensure forward_policy is none.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
forward_policy: none
register: result
......@@ -106,8 +90,6 @@
- name: Ensure forward_policy is none, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
forward_policy: none
register: result
......@@ -115,8 +97,6 @@
- name: Ensure forward_policy is first.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
forward_policy: first
register: result
......@@ -124,8 +104,6 @@
- name: Ensure forward_policy is first, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
forward_policy: first
register: result
......@@ -133,8 +111,6 @@
- name: Ensure first forwarder is set.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
forwarders:
- ip_address: 8.8.8.8
......@@ -144,8 +120,6 @@
- name: Ensure first and second forwarder are set.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
forwarders:
- ip_address: 8.8.8.8
......@@ -156,8 +130,6 @@
- name: Ensure first and second forwarder are set, again.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
forwarders:
- ip_address: 8.8.8.8
......@@ -168,8 +140,6 @@
- name: Ensure only second forwarder is set.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
forwarders:
- ip_address: 2001:4860:4860::8888
......@@ -178,16 +148,12 @@
- name: Nothing changes.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
register: result
failed_when: result.changed or result.failed
- name: Ensure no forwarders are set.
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testzone.local
forwarders: []
register: result
......@@ -195,56 +161,70 @@
- name: Create zones test1
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test1.testzone.local
register: result
failed_when: not result.changed or result.failed
- name: Create zones test1, again
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test1.testzone.local
register: result
failed_when: result.changed or result.failed
- name: Create zones test2
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test2.testzone.local
register: result
failed_when: not result.changed or result.failed
- name: Create zones test2, again
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test2.testzone.local
register: result
failed_when: result.changed or result.failed
- name: Create zones test3
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test3.testzone.local
register: result
failed_when: not result.changed or result.failed
- name: Create zones test3, again
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test3.testzone.local
register: result
failed_when: result.changed or result.failed
- name: Ensure zone test1.testzone.local has management permissioon
ipadnszone:
name: test1.testzone.local
permission: true
register: result
failed_when: not result.changed or result.failed
- name: Ensure zone test1.testzone.local has management permissioon
ipadnszone:
name: test1.testzone.local
permission: true
register: result
failed_when: result.changed or result.failed
- name: Ensure zone test1.testzone.local don't have management permissioon
ipadnszone:
name: test1.testzone.local
permission: false
register: result
failed_when: not result.changed or result.failed
- name: Ensure zone test1.testzone.local don't have management permissioon
ipadnszone:
name: test1.testzone.local
permission: false
register: result
failed_when: result.changed or result.failed
- name: Ensure multiple zones are absent
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name:
- test1.testzone.local
- test2.testzone.local
......@@ -255,8 +235,6 @@
- name: Ensure multiple zones are absent, again
ipadnszone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name:
- test1.testzone.local
- test2.testzone.local
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment