Skip to content

Commit

Permalink
ipadnszone: Add support for per-zone privilege delegation
Browse files Browse the repository at this point in the history
IPA DNS Zones management can be delegated by adding a "Manage DNS zone"
permission. The CLI commands that manage these permissions are
dnszone-add-delegation and dnszone-remove-delegation.

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.
  • Loading branch information
rjeffman committed Oct 20, 2023
1 parent ba7bf0f commit 59ff223
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 60 deletions.
21 changes: 20 additions & 1 deletion README-dnszone.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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` | 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

Expand All @@ -238,4 +255,6 @@ Variable | Description | Returned When
Authors
=======

Sergio Oliveira Campos
- Sergio Oliveira Campos
- Thomas Woerner
- Rafael Jeffman
33 changes: 28 additions & 5 deletions plugins/modules/ipadnszone.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@
salt.
required: false
type: str
permission:
description: Set per-zone access delegation permission.
required: false
type: bool
skip_overlap_check:
description: |
Force DNS zone creation even if it will overlap with an existing zone
Expand All @@ -154,6 +158,7 @@
author:
- Sergio Oliveira Campos (@seocam)
- Thomas Woerner (@t-woerner)
- Rafael Jeffman (@rjeffman)
""" # noqa: E501

EXAMPLES = """
Expand Down Expand Up @@ -253,6 +258,7 @@ def __init__(self, *args, **kwargs):
"idnsallowdynupdate": "dynamic_update",
"idnssecinlinesigning": "dnssec",
"idnsupdatepolicy": "update_policy",
"managedby": "permission",
# Mapping by method
"idnsforwarders": self.get_ipa_idnsforwarders,
"idnsallowtransfer": self.get_ipa_idnsallowtransfer,
Expand Down Expand Up @@ -434,7 +440,7 @@ def get_zone(self, zone_name):
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"
Expand Down Expand Up @@ -462,18 +468,24 @@ def check_ipa_params(self):
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"]

self.params_fail_used_invalid(invalid, self.ipa_params.state)
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
Expand All @@ -487,6 +499,16 @@ def define_ipa_commands(self):
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", {}))

Expand Down Expand Up @@ -555,6 +577,7 @@ 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),
skip_nameserver_check=dict(type="bool", required=False, default=None),
skip_overlap_check=dict(type="bool", required=False, default=None),
)
Expand Down
Loading

0 comments on commit 59ff223

Please sign in to comment.