mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-03-27 05:43:05 +00:00
Certificates given by ansible could have leading and trailing white space, but also multi line input is possible that also could have leading and training white space and newlines.
1612 lines
66 KiB
Python
1612 lines
66 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
# Authors:
|
|
# Thomas Woerner <twoerner@redhat.com>
|
|
#
|
|
# Copyright (C) 2019-2022 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/>.
|
|
|
|
from __future__ import (absolute_import, division, print_function)
|
|
|
|
__metaclass__ = type
|
|
|
|
ANSIBLE_METADATA = {
|
|
"metadata_version": "1.0",
|
|
"supported_by": "community",
|
|
"status": ["preview"],
|
|
}
|
|
|
|
DOCUMENTATION = """
|
|
---
|
|
module: ipahost
|
|
short_description: Manage FreeIPA hosts
|
|
description: Manage FreeIPA hosts
|
|
extends_documentation_fragment:
|
|
- ipamodule_base_docs
|
|
options:
|
|
name:
|
|
description: The full qualified domain name.
|
|
type: list
|
|
elements: str
|
|
aliases: ["fqdn"]
|
|
required: false
|
|
hosts:
|
|
description: The list of host dicts
|
|
required: false
|
|
type: list
|
|
elements: dict
|
|
suboptions:
|
|
name:
|
|
description: The host (internally uid).
|
|
type: str
|
|
aliases: ["fqdn"]
|
|
required: true
|
|
description:
|
|
description: The host description
|
|
type: str
|
|
required: false
|
|
locality:
|
|
description: Host locality (e.g. "Baltimore, MD")
|
|
type: str
|
|
required: false
|
|
location:
|
|
description: Host physical location hist (e.g. "Lab 2")
|
|
type: str
|
|
aliases: ["ns_host_location"]
|
|
required: false
|
|
platform:
|
|
description: Host hardware platform (e.g. "Lenovo T61")
|
|
type: str
|
|
aliases: ["ns_hardware_platform"]
|
|
required: false
|
|
os:
|
|
description: Host operating system and version (e.g. "Fedora 9")
|
|
type: str
|
|
aliases: ["ns_os_version"]
|
|
required: false
|
|
password:
|
|
description: Password used in bulk enrollment
|
|
type: str
|
|
aliases: ["user_password", "userpassword"]
|
|
required: false
|
|
random:
|
|
description:
|
|
Initiate the generation of a random password to be used in bulk
|
|
enrollment
|
|
type: bool
|
|
aliases: ["random_password"]
|
|
required: false
|
|
certificate:
|
|
description: List of base-64 encoded host certificates
|
|
type: list
|
|
elements: str
|
|
aliases: ["usercertificate"]
|
|
required: false
|
|
managedby_host:
|
|
description: List of hosts that can manage this host
|
|
type: list
|
|
elements: str
|
|
required: false
|
|
principal:
|
|
description: List of principal aliases for this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["principalname", "krbprincipalname"]
|
|
required: false
|
|
allow_create_keytab_user:
|
|
description: Users allowed to create a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_write_keys_user"]
|
|
required: false
|
|
allow_create_keytab_group:
|
|
description: Groups allowed to create a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_write_keys_group"]
|
|
required: false
|
|
allow_create_keytab_host:
|
|
description: Hosts allowed to create a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_write_keys_host"]
|
|
required: false
|
|
allow_create_keytab_hostgroup:
|
|
description: Hostgroups allowed to create a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_write_keys_hostgroup"]
|
|
required: false
|
|
allow_retrieve_keytab_user:
|
|
description: Users allowed to retrieve a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_read_keys_user"]
|
|
required: false
|
|
allow_retrieve_keytab_group:
|
|
description: Groups allowed to retrieve a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_read_keys_group"]
|
|
required: false
|
|
allow_retrieve_keytab_host:
|
|
description: Hosts allowed to retrieve a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_read_keys_host"]
|
|
required: false
|
|
allow_retrieve_keytab_hostgroup:
|
|
description: Hostgroups allowed to retrieve a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_read_keys_hostgroup"]
|
|
required: false
|
|
mac_address:
|
|
description: List of hardware MAC addresses.
|
|
type: list
|
|
elements: str
|
|
aliases: ["macaddress"]
|
|
required: false
|
|
sshpubkey:
|
|
description: List of SSH public keys
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipasshpubkey"]
|
|
required: false
|
|
userclass:
|
|
description:
|
|
Host category (semantics placed on this attribute are for local
|
|
interpretation)
|
|
type: list
|
|
elements: str
|
|
aliases: ["class"]
|
|
required: false
|
|
auth_ind:
|
|
description:
|
|
Defines an allow list for Authentication Indicators. Use 'otp'
|
|
to allow OTP-based 2FA authentications. Use 'radius' to allow
|
|
RADIUS-based 2FA authentications. Other values may be used
|
|
for custom configurations. Use empty string to reset auth_ind
|
|
to the initial value.
|
|
type: list
|
|
elements: str
|
|
aliases: ["krbprincipalauthind"]
|
|
choices: ["radius", "otp", "pkinit", "hardened", "idp", ""]
|
|
required: false
|
|
requires_pre_auth:
|
|
description: Pre-authentication is required for the service
|
|
type: bool
|
|
aliases: ["ipakrbrequirespreauth"]
|
|
required: false
|
|
ok_as_delegate:
|
|
description: Client credentials may be delegated to the service
|
|
type: bool
|
|
aliases: ["ipakrbokasdelegate"]
|
|
required: false
|
|
ok_to_auth_as_delegate:
|
|
description:
|
|
The service is allowed to authenticate on behalf of a client
|
|
type: bool
|
|
aliases: ["ipakrboktoauthasdelegate"]
|
|
required: false
|
|
force:
|
|
description: Force host name even if not in DNS
|
|
type: bool
|
|
required: false
|
|
reverse:
|
|
description: Reverse DNS detection
|
|
type: bool
|
|
required: false
|
|
ip_address:
|
|
description:
|
|
The host IP address list (IPv4 and IPv6). No IP address conflict
|
|
check will be done.
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaddress"]
|
|
required: false
|
|
update_dns:
|
|
description:
|
|
Controls the update of the DNS SSHFP records for existing hosts and
|
|
the removal of all DNS entries if a host gets removed with state
|
|
absent.
|
|
type: bool
|
|
aliases: ["updatedns"]
|
|
required: false
|
|
description:
|
|
description: The host description
|
|
type: str
|
|
required: false
|
|
locality:
|
|
description: Host locality (e.g. "Baltimore, MD")
|
|
type: str
|
|
required: false
|
|
location:
|
|
description: Host location (e.g. "Lab 2")
|
|
type: str
|
|
aliases: ["ns_host_location"]
|
|
required: false
|
|
platform:
|
|
description: Host hardware platform (e.g. "Lenovo T61")
|
|
type: str
|
|
aliases: ["ns_hardware_platform"]
|
|
required: false
|
|
os:
|
|
description: Host operating system and version (e.g. "Fedora 9")
|
|
type: str
|
|
aliases: ["ns_os_version"]
|
|
required: false
|
|
password:
|
|
description: Password used in bulk enrollment
|
|
type: str
|
|
aliases: ["user_password", "userpassword"]
|
|
required: false
|
|
random:
|
|
description:
|
|
Initiate the generation of a random password to be used in bulk
|
|
enrollment
|
|
type: bool
|
|
aliases: ["random_password"]
|
|
required: false
|
|
certificate:
|
|
description: List of base-64 encoded host certificates
|
|
type: list
|
|
elements: str
|
|
aliases: ["usercertificate"]
|
|
required: false
|
|
managedby_host:
|
|
description: List of hosts that can manage this host
|
|
type: list
|
|
elements: str
|
|
required: false
|
|
principal:
|
|
description: List of principal aliases for this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["principalname", "krbprincipalname"]
|
|
required: false
|
|
allow_create_keytab_user:
|
|
description: Users allowed to create a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_write_keys_user"]
|
|
required: false
|
|
allow_create_keytab_group:
|
|
description: Groups allowed to create a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_write_keys_group"]
|
|
required: false
|
|
allow_create_keytab_host:
|
|
description: Hosts allowed to create a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_write_keys_host"]
|
|
required: false
|
|
allow_create_keytab_hostgroup:
|
|
description: Hostgroups allowed to create a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_write_keys_hostgroup"]
|
|
required: false
|
|
allow_retrieve_keytab_user:
|
|
description: Users allowed to retrieve a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_read_keys_user"]
|
|
required: false
|
|
allow_retrieve_keytab_group:
|
|
description: Groups allowed to retrieve a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_read_keys_group"]
|
|
required: false
|
|
allow_retrieve_keytab_host:
|
|
description: Hosts allowed to retrieve a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_read_keys_host"]
|
|
required: false
|
|
allow_retrieve_keytab_hostgroup:
|
|
description: Hostgroups allowed to retrieve a keytab of this host
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaallowedtoperform_read_keys_hostgroup"]
|
|
required: false
|
|
mac_address:
|
|
description: List of hardware MAC addresses.
|
|
type: list
|
|
elements: str
|
|
aliases: ["macaddress"]
|
|
required: false
|
|
sshpubkey:
|
|
description: List of SSH public keys
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipasshpubkey"]
|
|
required: false
|
|
userclass:
|
|
description:
|
|
Host category (semantics placed on this attribute are for local
|
|
interpretation)
|
|
type: list
|
|
elements: str
|
|
aliases: ["class"]
|
|
required: false
|
|
auth_ind:
|
|
description:
|
|
Defines an allow list for Authentication Indicators. Use 'otp'
|
|
to allow OTP-based 2FA authentications. Use 'radius' to allow
|
|
RADIUS-based 2FA authentications. Other values may be used
|
|
for custom configurations. Use empty string to reset auth_ind
|
|
to the initial value.
|
|
type: list
|
|
elements: str
|
|
aliases: ["krbprincipalauthind"]
|
|
choices: ["radius", "otp", "pkinit", "hardened", "idp", ""]
|
|
required: false
|
|
requires_pre_auth:
|
|
description: Pre-authentication is required for the service
|
|
type: bool
|
|
aliases: ["ipakrbrequirespreauth"]
|
|
required: false
|
|
ok_as_delegate:
|
|
description: Client credentials may be delegated to the service
|
|
type: bool
|
|
aliases: ["ipakrbokasdelegate"]
|
|
required: false
|
|
ok_to_auth_as_delegate:
|
|
description:
|
|
The service is allowed to authenticate on behalf of a client
|
|
type: bool
|
|
aliases: ["ipakrboktoauthasdelegate"]
|
|
required: false
|
|
force:
|
|
description: Force host name even if not in DNS
|
|
type: bool
|
|
required: false
|
|
reverse:
|
|
description: Reverse DNS detection
|
|
type: bool
|
|
required: false
|
|
ip_address:
|
|
description:
|
|
The host IP address list (IPv4 and IPv6). No IP address conflict
|
|
check will be done.
|
|
type: list
|
|
elements: str
|
|
aliases: ["ipaddress"]
|
|
required: false
|
|
update_dns:
|
|
description:
|
|
Controls the update of the DNS SSHFP records for existing hosts and
|
|
the removal of all DNS entries if a host gets removed with state
|
|
absent.
|
|
type: bool
|
|
aliases: ["updatedns"]
|
|
required: false
|
|
update_password:
|
|
description:
|
|
Set password for a host in present state only on creation or always
|
|
type: str
|
|
choices: ["always", "on_create"]
|
|
action:
|
|
description: Work on host or member level
|
|
type: str
|
|
default: "host"
|
|
choices: ["member", "host"]
|
|
state:
|
|
description: State to ensure
|
|
type: str
|
|
default: present
|
|
choices: ["present", "absent",
|
|
"disabled"]
|
|
author:
|
|
- Thomas Woerner (@t-woerner)
|
|
"""
|
|
|
|
EXAMPLES = """
|
|
# Ensure host is present
|
|
- ipahost:
|
|
ipaadmin_password: SomeADMINpassword
|
|
name: host01.example.com
|
|
description: Example host
|
|
ip_address: 192.168.0.123
|
|
locality: Lab
|
|
ns_host_location: Lab
|
|
ns_os_version: CentOS 7
|
|
ns_hardware_platform: Lenovo T61
|
|
mac_address:
|
|
- "08:00:27:E3:B1:2D"
|
|
- "52:54:00:BD:97:1E"
|
|
state: present
|
|
|
|
# Ensure host is present without DNS
|
|
- ipahost:
|
|
ipaadmin_password: SomeADMINpassword
|
|
name: host02.example.com
|
|
description: Example host
|
|
force: yes
|
|
|
|
# Ensure multiple hosts are present with random passwords
|
|
- ipahost:
|
|
ipaadmin_password: SomeADMINpassword
|
|
hosts:
|
|
- name: host01.example.com
|
|
random: yes
|
|
- name: host02.example.com
|
|
random: yes
|
|
|
|
# Initiate generation of a random password for the host
|
|
- ipahost:
|
|
ipaadmin_password: SomeADMINpassword
|
|
name: host01.example.com
|
|
description: Example host
|
|
ip_address: 192.168.0.123
|
|
random: yes
|
|
|
|
# Ensure multiple hosts are present with principals
|
|
- ipahost:
|
|
ipaadmin_password: SomeADMINpassword
|
|
hosts:
|
|
- name: host01.example.com
|
|
principal:
|
|
- host/testhost01.example.com
|
|
- name: host02.example.com
|
|
principal:
|
|
- host/myhost01.example.com
|
|
action: member
|
|
|
|
# Ensure host is disabled
|
|
- ipahost:
|
|
ipaadmin_password: SomeADMINpassword
|
|
name: host01.example.com
|
|
update_dns: yes
|
|
state: disabled
|
|
|
|
# Ensure host is absent
|
|
- ipahost:
|
|
ipaadmin_password: SomeADMINpassword
|
|
name: host01.example.com
|
|
state: absent
|
|
"""
|
|
|
|
RETURN = """
|
|
host:
|
|
description: Host dict with random password
|
|
returned: If random is yes and host did not exist or update_password is yes
|
|
type: dict
|
|
contains:
|
|
randompassword:
|
|
description: The generated random password
|
|
type: str
|
|
returned: |
|
|
If only one host is handled by the module without using hosts parameter
|
|
name:
|
|
description: The host name of the host that got a new random password
|
|
returned: |
|
|
If several hosts are handled by the module with the hosts parameter
|
|
type: dict
|
|
contains:
|
|
randompassword:
|
|
description: The generated random password
|
|
type: str
|
|
returned: always
|
|
"""
|
|
|
|
from ansible.module_utils.ansible_freeipa_module import \
|
|
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, \
|
|
encode_certificate, is_ipv4_addr, is_ipv6_addr, ipalib_errors, \
|
|
gen_add_list, gen_intersection_list, normalize_sshpubkey, \
|
|
convert_input_certificates
|
|
from ansible.module_utils import six
|
|
if six.PY3:
|
|
unicode = str
|
|
|
|
|
|
def find_host(module, name):
|
|
_args = {
|
|
"all": True,
|
|
}
|
|
|
|
try:
|
|
_result = module.ipa_command("host_show", name, _args)
|
|
except ipalib_errors.NotFound as e:
|
|
msg = str(e)
|
|
if "host not found" in msg:
|
|
return None
|
|
module.fail_json(msg="host_show failed: %s" % msg)
|
|
|
|
_res = _result["result"]
|
|
certs = _res.get("usercertificate")
|
|
if certs is not None:
|
|
_res["usercertificate"] = [encode_certificate(cert) for
|
|
cert in certs]
|
|
# krbprincipalname is returned as ipapython.kerberos.Principal, convert
|
|
# to string
|
|
principals = _res.get("krbprincipalname")
|
|
if principals is not None:
|
|
_res["krbprincipalname"] = [str(princ) for princ in principals]
|
|
return _res
|
|
|
|
|
|
def find_dnsrecord(module, name):
|
|
"""
|
|
Search for a DNS record.
|
|
|
|
This function may raise ipalib_errors.NotFound in some cases,
|
|
and it should be handled by the caller.
|
|
"""
|
|
domain_name = name[name.find(".") + 1:]
|
|
host_name = name[:name.find(".")]
|
|
|
|
_args = {
|
|
"all": True,
|
|
"idnsname": host_name
|
|
}
|
|
|
|
_result = module.ipa_command("dnsrecord_show", domain_name, _args)
|
|
|
|
return _result["result"]
|
|
|
|
|
|
def show_host(module, name):
|
|
_result = module.ipa_command("host_show", name, {})
|
|
return _result["result"]
|
|
|
|
|
|
def gen_args(description, locality, location, platform, os, password, random,
|
|
mac_address, sshpubkey, userclass, auth_ind, requires_pre_auth,
|
|
ok_as_delegate, ok_to_auth_as_delegate, force, _reverse,
|
|
ip_address, update_dns):
|
|
# certificate, managedby_host, principal, create_keytab_* and
|
|
# allow_retrieve_keytab_* are not handled here
|
|
_args = {}
|
|
if description is not None:
|
|
_args["description"] = description
|
|
if locality is not None:
|
|
_args["l"] = locality
|
|
if location is not None:
|
|
_args["nshostlocation"] = location
|
|
if platform is not None:
|
|
_args["nshardwareplatform"] = platform
|
|
if os is not None:
|
|
_args["nsosversion"] = os
|
|
if password is not None:
|
|
_args["userpassword"] = password
|
|
if random is not None:
|
|
_args["random"] = random
|
|
if mac_address is not None:
|
|
_args["macaddress"] = mac_address
|
|
if sshpubkey is not None:
|
|
_args["ipasshpubkey"] = sshpubkey
|
|
if userclass is not None:
|
|
_args["userclass"] = userclass
|
|
if auth_ind is not None:
|
|
_args["krbprincipalauthind"] = auth_ind
|
|
if requires_pre_auth is not None:
|
|
_args["ipakrbrequirespreauth"] = requires_pre_auth
|
|
if ok_as_delegate is not None:
|
|
_args["ipakrbokasdelegate"] = ok_as_delegate
|
|
if ok_to_auth_as_delegate is not None:
|
|
_args["ipakrboktoauthasdelegate"] = ok_to_auth_as_delegate
|
|
if force is not None:
|
|
_args["force"] = force
|
|
if ip_address is not None:
|
|
# IP addresses are handed extra, therefore it is needed to set
|
|
# the force option here to make sure that host-add is able to
|
|
# add a host without IP address.
|
|
_args["force"] = True
|
|
if update_dns is not None:
|
|
_args["updatedns"] = update_dns
|
|
|
|
return _args
|
|
|
|
|
|
def gen_dnsrecord_args(module, ip_address, reverse):
|
|
_args = {}
|
|
if reverse is not None:
|
|
_args["a_extra_create_reverse"] = reverse
|
|
_args["aaaa_extra_create_reverse"] = reverse
|
|
if ip_address is not None:
|
|
for ip in ip_address:
|
|
if is_ipv4_addr(ip):
|
|
_args.setdefault("arecord", []).append(ip)
|
|
elif is_ipv6_addr(ip):
|
|
_args.setdefault("aaaarecord", []).append(ip)
|
|
else:
|
|
module.fail_json(msg="'%s' is not a valid IP address." % ip)
|
|
|
|
return _args
|
|
|
|
|
|
def check_parameters( # pylint: disable=unused-argument
|
|
module, state, action,
|
|
description, locality, location, platform, os, password, random,
|
|
certificate, managedby_host, principal, allow_create_keytab_user,
|
|
allow_create_keytab_group, allow_create_keytab_host,
|
|
allow_create_keytab_hostgroup, allow_retrieve_keytab_user,
|
|
allow_retrieve_keytab_group, allow_retrieve_keytab_host,
|
|
allow_retrieve_keytab_hostgroup, mac_address, sshpubkey,
|
|
userclass, auth_ind, requires_pre_auth, ok_as_delegate,
|
|
ok_to_auth_as_delegate, force, reverse, ip_address, update_dns,
|
|
update_password):
|
|
invalid = []
|
|
if state == "present":
|
|
if action == "member":
|
|
# certificate, managedby_host, principal,
|
|
# allow_create_keytab_*, allow_retrieve_keytab_*,
|
|
invalid = ["description", "locality", "location", "platform",
|
|
"os", "password", "random", "mac_address", "sshpubkey",
|
|
"userclass", "auth_ind", "requires_pre_auth",
|
|
"ok_as_delegate", "ok_to_auth_as_delegate", "force",
|
|
"reverse", "update_dns", "update_password"]
|
|
|
|
if state == "absent":
|
|
invalid = ["description", "locality", "location", "platform", "os",
|
|
"password", "random", "mac_address", "sshpubkey",
|
|
"userclass", "auth_ind", "requires_pre_auth",
|
|
"ok_as_delegate", "ok_to_auth_as_delegate", "force",
|
|
"reverse", "update_password"]
|
|
if action == "host":
|
|
invalid = [
|
|
"certificate", "managedby_host", "principal",
|
|
"allow_create_keytab_user", "allow_create_keytab_group",
|
|
"allow_create_keytab_host", "allow_create_keytab_hostgroup",
|
|
"allow_retrieve_keytab_user", "allow_retrieve_keytab_group",
|
|
"allow_retrieve_keytab_host",
|
|
"allow_retrieve_keytab_hostgroup"
|
|
]
|
|
|
|
module.params_fail_used_invalid(invalid, state, action)
|
|
|
|
|
|
def check_authind(module, auth_ind):
|
|
_invalid = module.ipa_command_invalid_param_choices(
|
|
"host_add", "krbprincipalauthind", auth_ind)
|
|
if _invalid:
|
|
module.fail_json(
|
|
msg="The use of krbprincipalauthind '%s' is not supported "
|
|
"by your IPA version" % "','".join(_invalid))
|
|
|
|
|
|
# pylint: disable=unused-argument
|
|
def result_handler(module, result, command, name, args, exit_args,
|
|
single_host):
|
|
if "random" in args and command in ["host_add", "host_mod"] \
|
|
and "randompassword" in result["result"]:
|
|
if single_host:
|
|
exit_args["randompassword"] = \
|
|
result["result"]["randompassword"]
|
|
else:
|
|
exit_args.setdefault(name, {})["randompassword"] = \
|
|
result["result"]["randompassword"]
|
|
|
|
|
|
def main():
|
|
host_spec = dict(
|
|
# present
|
|
description=dict(type="str", default=None),
|
|
locality=dict(type="str", default=None),
|
|
location=dict(type="str", aliases=["ns_host_location"],
|
|
default=None),
|
|
platform=dict(type="str", aliases=["ns_hardware_platform"],
|
|
default=None),
|
|
os=dict(type="str", aliases=["ns_os_version"], default=None),
|
|
password=dict(type="str",
|
|
aliases=["user_password", "userpassword"],
|
|
default=None, no_log=True),
|
|
random=dict(type="bool", aliases=["random_password"],
|
|
default=None),
|
|
certificate=dict(type="list", elements="str",
|
|
aliases=["usercertificate"], default=None),
|
|
managedby_host=dict(type="list", elements="str", default=None),
|
|
principal=dict(type="list", elements="str",
|
|
aliases=["principalname", "krbprincipalname"],
|
|
default=None),
|
|
allow_create_keytab_user=dict(
|
|
type="list", elements="str",
|
|
aliases=["ipaallowedtoperform_write_keys_user"],
|
|
default=None, no_log=False),
|
|
allow_create_keytab_group=dict(
|
|
type="list", elements="str",
|
|
aliases=["ipaallowedtoperform_write_keys_group"],
|
|
default=None, no_log=False),
|
|
allow_create_keytab_host=dict(
|
|
type="list", elements="str",
|
|
aliases=["ipaallowedtoperform_write_keys_host"],
|
|
default=None, no_log=False),
|
|
allow_create_keytab_hostgroup=dict(
|
|
type="list", elements="str",
|
|
aliases=["ipaallowedtoperform_write_keys_hostgroup"],
|
|
default=None, no_log=False),
|
|
allow_retrieve_keytab_user=dict(
|
|
type="list", elements="str",
|
|
aliases=["ipaallowedtoperform_read_keys_user"],
|
|
default=None, no_log=False),
|
|
allow_retrieve_keytab_group=dict(
|
|
type="list", elements="str",
|
|
aliases=["ipaallowedtoperform_read_keys_group"],
|
|
default=None, no_log=False),
|
|
allow_retrieve_keytab_host=dict(
|
|
type="list", elements="str",
|
|
aliases=["ipaallowedtoperform_read_keys_host"],
|
|
default=None, no_log=False),
|
|
allow_retrieve_keytab_hostgroup=dict(
|
|
type="list", elements="str",
|
|
aliases=["ipaallowedtoperform_read_keys_hostgroup"],
|
|
default=None, no_log=False),
|
|
mac_address=dict(type="list", elements="str", aliases=["macaddress"],
|
|
default=None),
|
|
sshpubkey=dict(type="list", elements="str", aliases=["ipasshpubkey"],
|
|
default=None),
|
|
userclass=dict(type="list", elements="str", aliases=["class"],
|
|
default=None),
|
|
auth_ind=dict(type='list', elements="str",
|
|
aliases=["krbprincipalauthind"], default=None,
|
|
choices=["radius", "otp", "pkinit", "hardened", "idp",
|
|
""]),
|
|
requires_pre_auth=dict(type="bool", aliases=["ipakrbrequirespreauth"],
|
|
default=None),
|
|
ok_as_delegate=dict(type="bool", aliases=["ipakrbokasdelegate"],
|
|
default=None),
|
|
ok_to_auth_as_delegate=dict(type="bool",
|
|
aliases=["ipakrboktoauthasdelegate"],
|
|
default=None),
|
|
force=dict(type='bool', default=None),
|
|
reverse=dict(type='bool', default=None),
|
|
ip_address=dict(type="list", elements="str", aliases=["ipaddress"],
|
|
default=None),
|
|
update_dns=dict(type="bool", aliases=["updatedns"],
|
|
default=None),
|
|
# no_members
|
|
|
|
# for update:
|
|
# krbprincipalname
|
|
)
|
|
|
|
ansible_module = IPAAnsibleModule(
|
|
argument_spec=dict(
|
|
# general
|
|
name=dict(type="list", elements="str", aliases=["fqdn"],
|
|
default=None, required=False),
|
|
|
|
hosts=dict(type="list", default=None,
|
|
options=dict(
|
|
# Here name is a simple string
|
|
name=dict(type="str", aliases=["fqdn"],
|
|
required=True),
|
|
# Add host specific parameters
|
|
**host_spec
|
|
),
|
|
elements='dict', required=False),
|
|
|
|
# mod
|
|
update_password=dict(type='str', default=None, no_log=False,
|
|
choices=['always', 'on_create']),
|
|
|
|
# general
|
|
action=dict(type="str", default="host",
|
|
choices=["member", "host"]),
|
|
state=dict(type="str", default="present",
|
|
choices=["present", "absent", "disabled"]),
|
|
|
|
# Add host specific parameters for simple use case
|
|
**host_spec
|
|
),
|
|
mutually_exclusive=[["name", "hosts"]],
|
|
required_one_of=[["name", "hosts"]],
|
|
supports_check_mode=True,
|
|
)
|
|
|
|
ansible_module._ansible_debug = True
|
|
|
|
# Get parameters
|
|
|
|
# general
|
|
names = ansible_module.params_get("name")
|
|
hosts = ansible_module.params_get("hosts")
|
|
|
|
# present
|
|
description = ansible_module.params_get("description")
|
|
locality = ansible_module.params_get("locality")
|
|
location = ansible_module.params_get("location")
|
|
platform = ansible_module.params_get("platform")
|
|
os = ansible_module.params_get("os")
|
|
password = ansible_module.params_get("password")
|
|
random = ansible_module.params_get("random")
|
|
certificate = ansible_module.params_get("certificate")
|
|
managedby_host = ansible_module.params_get("managedby_host")
|
|
principal = ansible_module.params_get("principal")
|
|
allow_create_keytab_user = ansible_module.params_get(
|
|
"allow_create_keytab_user")
|
|
allow_create_keytab_group = ansible_module.params_get(
|
|
"allow_create_keytab_group")
|
|
allow_create_keytab_host = ansible_module.params_get(
|
|
"allow_create_keytab_host")
|
|
allow_create_keytab_hostgroup = ansible_module.params_get(
|
|
"allow_create_keytab_hostgroup")
|
|
allow_retrieve_keytab_user = ansible_module.params_get(
|
|
"allow_retrieve_keytab_user")
|
|
allow_retrieve_keytab_group = ansible_module.params_get(
|
|
"allow_retrieve_keytab_group")
|
|
allow_retrieve_keytab_host = ansible_module.params_get(
|
|
"allow_retrieve_keytab_host")
|
|
allow_retrieve_keytab_hostgroup = ansible_module.params_get(
|
|
"allow_retrieve_keytab_hostgroup")
|
|
mac_address = ansible_module.params_get("mac_address")
|
|
sshpubkey = ansible_module.params_get(
|
|
"sshpubkey", allow_empty_list_item=True)
|
|
userclass = ansible_module.params_get("userclass")
|
|
auth_ind = ansible_module.params_get(
|
|
"auth_ind", allow_empty_list_item=True)
|
|
requires_pre_auth = ansible_module.params_get("requires_pre_auth")
|
|
ok_as_delegate = ansible_module.params_get("ok_as_delegate")
|
|
ok_to_auth_as_delegate = ansible_module.params_get(
|
|
"ok_to_auth_as_delegate")
|
|
force = ansible_module.params_get("force")
|
|
reverse = ansible_module.params_get("reverse")
|
|
ip_address = ansible_module.params_get("ip_address")
|
|
update_dns = ansible_module.params_get("update_dns")
|
|
update_password = ansible_module.params_get("update_password")
|
|
# general
|
|
action = ansible_module.params_get("action")
|
|
state = ansible_module.params_get("state")
|
|
|
|
# Check parameters
|
|
|
|
if (names is None or len(names) < 1) and \
|
|
(hosts is None or len(hosts) < 1):
|
|
ansible_module.fail_json(msg="One of name and hosts is required")
|
|
|
|
if state == "present":
|
|
if names is not None and len(names) != 1:
|
|
ansible_module.fail_json(
|
|
msg="Only one host can be added at a time.")
|
|
|
|
check_parameters(
|
|
ansible_module, state, action,
|
|
description, locality, location, platform, os, password, random,
|
|
certificate, managedby_host, principal, allow_create_keytab_user,
|
|
allow_create_keytab_group, allow_create_keytab_host,
|
|
allow_create_keytab_hostgroup, allow_retrieve_keytab_user,
|
|
allow_retrieve_keytab_group, allow_retrieve_keytab_host,
|
|
allow_retrieve_keytab_hostgroup, mac_address, sshpubkey, userclass,
|
|
auth_ind, requires_pre_auth, ok_as_delegate, ok_to_auth_as_delegate,
|
|
force, reverse, ip_address, update_dns, update_password)
|
|
|
|
certificate = convert_input_certificates(ansible_module, certificate,
|
|
state)
|
|
|
|
if sshpubkey is not None:
|
|
sshpubkey = [str(normalize_sshpubkey(key)) for key in sshpubkey]
|
|
|
|
# Use hosts if names is None
|
|
if hosts is not None:
|
|
names = hosts
|
|
|
|
# Init
|
|
|
|
changed = False
|
|
exit_args = {}
|
|
|
|
# Connect to IPA API
|
|
with ansible_module.ipa_connect():
|
|
|
|
# Check version specific settings
|
|
|
|
check_authind(ansible_module, auth_ind)
|
|
|
|
server_realm = ansible_module.ipa_get_realm()
|
|
|
|
commands = []
|
|
host_set = set()
|
|
|
|
for host in names:
|
|
if isinstance(host, dict):
|
|
name = host.get("name")
|
|
if name in host_set:
|
|
ansible_module.fail_json(
|
|
msg="host '%s' is used more than once" % name)
|
|
host_set.add(name)
|
|
description = host.get("description")
|
|
locality = host.get("locality")
|
|
location = host.get("location")
|
|
platform = host.get("platform")
|
|
os = host.get("os")
|
|
password = host.get("password")
|
|
random = host.get("random")
|
|
certificate = host.get("certificate")
|
|
managedby_host = host.get("managedby_host")
|
|
principal = host.get("principal")
|
|
allow_create_keytab_user = host.get(
|
|
"allow_create_keytab_user")
|
|
allow_create_keytab_group = host.get(
|
|
"allow_create_keytab_group")
|
|
allow_create_keytab_host = host.get(
|
|
"allow_create_keytab_host")
|
|
allow_create_keytab_hostgroup = host.get(
|
|
"allow_create_keytab_hostgroup")
|
|
allow_retrieve_keytab_user = host.get(
|
|
"allow_retrieve_keytab_user")
|
|
allow_retrieve_keytab_group = host.get(
|
|
"allow_retrieve_keytab_group")
|
|
allow_retrieve_keytab_host = host.get(
|
|
"allow_retrieve_keytab_host")
|
|
allow_retrieve_keytab_hostgroup = host.get(
|
|
"allow_retrieve_keytab_hostgroup")
|
|
mac_address = host.get("mac_address")
|
|
sshpubkey = host.get("sshpubkey")
|
|
userclass = host.get("userclass")
|
|
auth_ind = host.get("auth_ind")
|
|
check_authind(ansible_module, auth_ind)
|
|
requires_pre_auth = host.get("requires_pre_auth")
|
|
ok_as_delegate = host.get("ok_as_delegate")
|
|
ok_to_auth_as_delegate = host.get("ok_to_auth_as_delegate")
|
|
force = host.get("force")
|
|
reverse = host.get("reverse")
|
|
ip_address = host.get("ip_address")
|
|
update_dns = host.get("update_dns")
|
|
# update_password is not part of hosts structure
|
|
# action is not part of hosts structure
|
|
# state is not part of hosts structure
|
|
|
|
check_parameters(
|
|
ansible_module, state, action,
|
|
description, locality, location, platform, os, password,
|
|
random, certificate, managedby_host, principal,
|
|
allow_create_keytab_user, allow_create_keytab_group,
|
|
allow_create_keytab_host, allow_create_keytab_hostgroup,
|
|
allow_retrieve_keytab_user, allow_retrieve_keytab_group,
|
|
allow_retrieve_keytab_host,
|
|
allow_retrieve_keytab_hostgroup, mac_address, sshpubkey,
|
|
userclass, auth_ind, requires_pre_auth, ok_as_delegate,
|
|
ok_to_auth_as_delegate, force, reverse, ip_address,
|
|
update_dns, update_password)
|
|
|
|
certificate = convert_input_certificates(ansible_module,
|
|
certificate, state)
|
|
|
|
if sshpubkey is not None:
|
|
sshpubkey = [str(normalize_sshpubkey(key)) for
|
|
key in sshpubkey]
|
|
|
|
elif (
|
|
isinstance(host, (str, unicode)) # pylint: disable=W0012,E0606
|
|
):
|
|
name = host
|
|
else:
|
|
ansible_module.fail_json(msg="Host '%s' is not valid" %
|
|
repr(host))
|
|
|
|
# Make sure host exists
|
|
res_find = find_host(ansible_module, name)
|
|
try:
|
|
res_find_dnsrecord = find_dnsrecord(ansible_module, name)
|
|
except ipalib_errors.NotFound as e:
|
|
msg = str(e)
|
|
dns_not_configured = "DNS is not configured" in msg
|
|
dns_zone_not_found = "DNS zone not found" in msg
|
|
dns_res_not_found = "DNS resource record not found" in msg
|
|
if (
|
|
dns_res_not_found
|
|
or ip_address is None
|
|
and (dns_not_configured or dns_zone_not_found)
|
|
):
|
|
# IP address(es) not given and no DNS support in IPA
|
|
# -> Ignore failure
|
|
# IP address(es) not given and DNS zone is not found
|
|
# -> Ignore failure
|
|
res_find_dnsrecord = None
|
|
else:
|
|
ansible_module.fail_json(msg="%s: %s" % (host, msg))
|
|
|
|
# Create command
|
|
if state == "present":
|
|
# Generate args
|
|
args = gen_args(
|
|
description, locality, location, platform, os, password,
|
|
random, mac_address, sshpubkey, userclass, auth_ind,
|
|
requires_pre_auth, ok_as_delegate, ok_to_auth_as_delegate,
|
|
force, reverse, ip_address, update_dns)
|
|
dnsrecord_args = gen_dnsrecord_args(
|
|
ansible_module, ip_address, reverse)
|
|
|
|
if action == "host":
|
|
# Found the host
|
|
if res_find is not None:
|
|
# Ignore password with update_password == on_create
|
|
if update_password == "on_create":
|
|
# Ignore userpassword and random for existing
|
|
# host if update_password is "on_create"
|
|
if "userpassword" in args:
|
|
del args["userpassword"]
|
|
if "random" in args:
|
|
del args["random"]
|
|
elif "userpassword" in args or "random" in args:
|
|
# Allow an existing OTP to be reset but don't
|
|
# allow a OTP or to be added to an enrolled host.
|
|
# Also do not allow to change the password for an
|
|
# enrolled host.
|
|
|
|
if not res_find["has_password"] and \
|
|
res_find["has_keytab"]:
|
|
ansible_module.fail_json(
|
|
msg="%s: Password cannot be set on "
|
|
"enrolled host." % host
|
|
)
|
|
|
|
# Ignore force, ip_address and no_reverse for mod
|
|
for x in ["force", "ip_address", "no_reverse"]:
|
|
if x in args:
|
|
del args[x]
|
|
|
|
# Ignore auth_ind if it is empty (for resetting)
|
|
# and not set in for the host
|
|
if "krbprincipalauthind" not in res_find and \
|
|
"krbprincipalauthind" in args and \
|
|
args["krbprincipalauthind"] == ['']:
|
|
del args["krbprincipalauthind"]
|
|
|
|
# Ignore sshpubkey if it is empty (for resetting)
|
|
# and not set for the host
|
|
if "ipasshpubkey" not in res_find and \
|
|
"ipasshpubkey" in args and \
|
|
args["ipasshpubkey"] == []:
|
|
del args["ipasshpubkey"]
|
|
|
|
# Ignore updatedns if it is the only arg
|
|
if "updatedns" in args and len(args) == 1:
|
|
del args["updatedns"]
|
|
|
|
# For all settings is args, check if there are
|
|
# different settings in the find result.
|
|
# If yes: modify
|
|
if not compare_args_ipa(ansible_module, args,
|
|
res_find):
|
|
commands.append([name, "host_mod", args])
|
|
elif random and "userpassword" in res_find:
|
|
# Host exists and random is set, return
|
|
# userpassword
|
|
if len(names) == 1:
|
|
exit_args["userpassword"] = \
|
|
res_find["userpassword"]
|
|
else:
|
|
exit_args.setdefault("hosts", {})[name] = {
|
|
"userpassword": res_find["userpassword"]
|
|
}
|
|
|
|
else:
|
|
# Remove update_dns as it is not supported by host_add
|
|
if "updatedns" in args:
|
|
del args["updatedns"]
|
|
commands.append([name, "host_add", args])
|
|
|
|
# Handle members: certificate, managedby_host, principal,
|
|
# allow_create_keytab and allow_retrieve_keytab
|
|
if res_find is not None:
|
|
certificate_add, certificate_del = gen_add_del_lists(
|
|
certificate, res_find.get("usercertificate"))
|
|
managedby_host_add, managedby_host_del = \
|
|
gen_add_del_lists(managedby_host,
|
|
res_find.get("managedby_host"))
|
|
principal_add, principal_del = gen_add_del_lists(
|
|
principal, res_find.get("krbprincipalname"))
|
|
# Principals are not returned as utf8 for IPA using
|
|
# python2 using host_show, therefore we need to
|
|
# convert the principals that we should remove.
|
|
principal_del = [unicode(x) for x in principal_del]
|
|
|
|
(allow_create_keytab_user_add,
|
|
allow_create_keytab_user_del) = \
|
|
gen_add_del_lists(
|
|
allow_create_keytab_user,
|
|
res_find.get(
|
|
"ipaallowedtoperform_write_keys_user"))
|
|
(allow_create_keytab_group_add,
|
|
allow_create_keytab_group_del) = \
|
|
gen_add_del_lists(
|
|
allow_create_keytab_group,
|
|
res_find.get(
|
|
"ipaallowedtoperform_write_keys_group"))
|
|
(allow_create_keytab_host_add,
|
|
allow_create_keytab_host_del) = \
|
|
gen_add_del_lists(
|
|
allow_create_keytab_host,
|
|
res_find.get(
|
|
"ipaallowedtoperform_write_keys_host"))
|
|
(allow_create_keytab_hostgroup_add,
|
|
allow_create_keytab_hostgroup_del) = \
|
|
gen_add_del_lists(
|
|
allow_create_keytab_hostgroup,
|
|
res_find.get(
|
|
"ipaallowedtoperform_write_keys_"
|
|
"hostgroup"))
|
|
(allow_retrieve_keytab_user_add,
|
|
allow_retrieve_keytab_user_del) = \
|
|
gen_add_del_lists(
|
|
allow_retrieve_keytab_user,
|
|
res_find.get(
|
|
"ipaallowedtoperform_read_keys_user"))
|
|
(allow_retrieve_keytab_group_add,
|
|
allow_retrieve_keytab_group_del) = \
|
|
gen_add_del_lists(
|
|
allow_retrieve_keytab_group,
|
|
res_find.get(
|
|
"ipaallowedtoperform_read_keys_group"))
|
|
(allow_retrieve_keytab_host_add,
|
|
allow_retrieve_keytab_host_del) = \
|
|
gen_add_del_lists(
|
|
allow_retrieve_keytab_host,
|
|
res_find.get(
|
|
"ipaallowedtoperform_read_keys_host"))
|
|
(allow_retrieve_keytab_hostgroup_add,
|
|
allow_retrieve_keytab_hostgroup_del) = \
|
|
gen_add_del_lists(
|
|
allow_retrieve_keytab_hostgroup,
|
|
res_find.get(
|
|
"ipaallowedtoperform_read_keys_hostgroup"))
|
|
|
|
# IP addresses are not really a member of hosts, but
|
|
# we will simply treat it as this to enable the
|
|
# addition and removal of IPv4 and IPv6 addresses in
|
|
# a simple way.
|
|
_dnsrec = res_find_dnsrecord or {}
|
|
dnsrecord_a_add, dnsrecord_a_del = gen_add_del_lists(
|
|
dnsrecord_args.get("arecord"),
|
|
_dnsrec.get("arecord"))
|
|
dnsrecord_aaaa_add, dnsrecord_aaaa_del = \
|
|
gen_add_del_lists(
|
|
dnsrecord_args.get("aaaarecord"),
|
|
_dnsrec.get("aaaarecord"))
|
|
else:
|
|
certificate_add = certificate or []
|
|
certificate_del = []
|
|
managedby_host_add = managedby_host or []
|
|
managedby_host_del = []
|
|
principal_add = principal or []
|
|
principal_del = []
|
|
allow_create_keytab_user_add = \
|
|
allow_create_keytab_user or []
|
|
allow_create_keytab_user_del = []
|
|
allow_create_keytab_group_add = \
|
|
allow_create_keytab_group or []
|
|
allow_create_keytab_group_del = []
|
|
allow_create_keytab_host_add = \
|
|
allow_create_keytab_host or []
|
|
allow_create_keytab_host_del = []
|
|
allow_create_keytab_hostgroup_add = \
|
|
allow_create_keytab_hostgroup or []
|
|
allow_create_keytab_hostgroup_del = []
|
|
allow_retrieve_keytab_user_add = \
|
|
allow_retrieve_keytab_user or []
|
|
allow_retrieve_keytab_user_del = []
|
|
allow_retrieve_keytab_group_add = \
|
|
allow_retrieve_keytab_group or []
|
|
allow_retrieve_keytab_group_del = []
|
|
allow_retrieve_keytab_host_add = \
|
|
allow_retrieve_keytab_host or []
|
|
allow_retrieve_keytab_host_del = []
|
|
allow_retrieve_keytab_hostgroup_add = \
|
|
allow_retrieve_keytab_hostgroup or []
|
|
allow_retrieve_keytab_hostgroup_del = []
|
|
_dnsrec = res_find_dnsrecord or {}
|
|
dnsrecord_a_add = gen_add_list(
|
|
dnsrecord_args.get("arecord"),
|
|
_dnsrec.get("arecord"))
|
|
dnsrecord_a_del = []
|
|
dnsrecord_aaaa_add = gen_add_list(
|
|
dnsrecord_args.get("aaaarecord"),
|
|
_dnsrec.get("aaaarecord"))
|
|
dnsrecord_aaaa_del = []
|
|
|
|
else:
|
|
# action member
|
|
if res_find is None:
|
|
ansible_module.fail_json(
|
|
msg="No host '%s'" % name)
|
|
|
|
certificate_add = gen_add_list(
|
|
certificate, res_find.get("usercertificate"))
|
|
certificate_del = []
|
|
managedby_host_add = gen_add_list(
|
|
managedby_host, res_find.get("managedby_host"))
|
|
managedby_host_del = []
|
|
principal_add = gen_add_list(
|
|
principal, res_find.get("krbprincipalname"))
|
|
principal_del = []
|
|
allow_create_keytab_user_add = gen_add_list(
|
|
allow_create_keytab_user,
|
|
res_find.get(
|
|
"ipaallowedtoperform_write_keys_user"))
|
|
allow_create_keytab_user_del = []
|
|
allow_create_keytab_group_add = gen_add_list(
|
|
allow_create_keytab_group,
|
|
res_find.get(
|
|
"ipaallowedtoperform_write_keys_group"))
|
|
allow_create_keytab_group_del = []
|
|
allow_create_keytab_host_add = gen_add_list(
|
|
allow_create_keytab_host,
|
|
res_find.get(
|
|
"ipaallowedtoperform_write_keys_host"))
|
|
allow_create_keytab_host_del = []
|
|
allow_create_keytab_hostgroup_add = gen_add_list(
|
|
allow_create_keytab_hostgroup,
|
|
res_find.get(
|
|
"ipaallowedtoperform_write_keys_hostgroup"))
|
|
allow_create_keytab_hostgroup_del = []
|
|
allow_retrieve_keytab_user_add = gen_add_list(
|
|
allow_retrieve_keytab_user,
|
|
res_find.get(
|
|
"ipaallowedtoperform_read_keys_user"))
|
|
allow_retrieve_keytab_user_del = []
|
|
allow_retrieve_keytab_group_add = gen_add_list(
|
|
allow_retrieve_keytab_group,
|
|
res_find.get(
|
|
"ipaallowedtoperform_read_keys_group"))
|
|
allow_retrieve_keytab_group_del = []
|
|
allow_retrieve_keytab_host_add = gen_add_list(
|
|
allow_retrieve_keytab_host,
|
|
res_find.get(
|
|
"ipaallowedtoperform_read_keys_host"))
|
|
allow_retrieve_keytab_host_del = []
|
|
allow_retrieve_keytab_hostgroup_add = gen_add_list(
|
|
allow_retrieve_keytab_hostgroup,
|
|
res_find.get(
|
|
"ipaallowedtoperform_read_keys_hostgroup"))
|
|
allow_retrieve_keytab_hostgroup_del = []
|
|
_dnsrec = res_find_dnsrecord or {}
|
|
dnsrecord_a_add = gen_add_list(
|
|
dnsrecord_args.get("arecord"),
|
|
_dnsrec.get("arecord"))
|
|
dnsrecord_a_del = []
|
|
dnsrecord_aaaa_add = gen_add_list(
|
|
dnsrecord_args.get("aaaarecord"),
|
|
_dnsrec.get("aaaarecord"))
|
|
dnsrecord_aaaa_del = []
|
|
|
|
# Remove canonical principal from principal_del
|
|
canonical_principal = "host/" + name + "@" + server_realm
|
|
# canonical_principal is also in find_res["krbcanonicalname"]
|
|
if canonical_principal in principal_del and \
|
|
action == "host" and (principal is not None or
|
|
canonical_principal not in principal):
|
|
principal_del.remove(canonical_principal)
|
|
|
|
# Remove canonical managedby managedby_host_del for
|
|
# action host if managedby_host is set and the canonical
|
|
# managedby host is not in the managedby_host list.
|
|
canonical_managedby_host = name
|
|
if canonical_managedby_host in managedby_host_del and \
|
|
action == "host" and (managedby_host is None or
|
|
canonical_managedby_host not in
|
|
managedby_host):
|
|
managedby_host_del.remove(canonical_managedby_host)
|
|
|
|
# Certificates need to be added and removed one by one,
|
|
# because if entry already exists, the processing of
|
|
# the remaining enries is stopped. The same applies to
|
|
# the removal of non-existing entries.
|
|
|
|
# Add certificates
|
|
for _certificate in certificate_add:
|
|
commands.append([name, "host_add_cert",
|
|
{
|
|
"usercertificate":
|
|
_certificate,
|
|
}])
|
|
# Remove certificates
|
|
for _certificate in certificate_del:
|
|
commands.append([name, "host_remove_cert",
|
|
{
|
|
"usercertificate":
|
|
_certificate,
|
|
}])
|
|
|
|
# Managedby_Hosts need to be added and removed one by one,
|
|
# because if entry already exists, the processing of
|
|
# the remaining enries is stopped. The same applies to
|
|
# the removal of non-existing entries.
|
|
|
|
# Add managedby_hosts
|
|
for _managedby_host in managedby_host_add:
|
|
commands.append([name, "host_add_managedby",
|
|
{
|
|
"host":
|
|
_managedby_host,
|
|
}])
|
|
# Remove managedby_hosts
|
|
for _managedby_host in managedby_host_del:
|
|
commands.append([name, "host_remove_managedby",
|
|
{
|
|
"host":
|
|
_managedby_host,
|
|
}])
|
|
|
|
# Principals need to be added and removed one by one,
|
|
# because if entry already exists, the processing of
|
|
# the remaining enries is stopped. The same applies to
|
|
# the removal of non-existing entries.
|
|
|
|
# Add principals
|
|
for _principal in principal_add:
|
|
commands.append([name, "host_add_principal",
|
|
{
|
|
"krbprincipalname":
|
|
_principal,
|
|
}])
|
|
# Remove principals
|
|
for _principal in principal_del:
|
|
commands.append([name, "host_remove_principal",
|
|
{
|
|
"krbprincipalname":
|
|
_principal,
|
|
}])
|
|
|
|
# Allow create keytab
|
|
if len(allow_create_keytab_user_add) > 0 or \
|
|
len(allow_create_keytab_group_add) > 0 or \
|
|
len(allow_create_keytab_host_add) > 0 or \
|
|
len(allow_create_keytab_hostgroup_add) > 0:
|
|
commands.append(
|
|
[name, "host_allow_create_keytab",
|
|
{
|
|
"user": allow_create_keytab_user_add,
|
|
"group": allow_create_keytab_group_add,
|
|
"host": allow_create_keytab_host_add,
|
|
"hostgroup": allow_create_keytab_hostgroup_add,
|
|
}])
|
|
|
|
# Disallow create keytab
|
|
if len(allow_create_keytab_user_del) > 0 or \
|
|
len(allow_create_keytab_group_del) > 0 or \
|
|
len(allow_create_keytab_host_del) > 0 or \
|
|
len(allow_create_keytab_hostgroup_del) > 0:
|
|
commands.append(
|
|
[name, "host_disallow_create_keytab",
|
|
{
|
|
"user": allow_create_keytab_user_del,
|
|
"group": allow_create_keytab_group_del,
|
|
"host": allow_create_keytab_host_del,
|
|
"hostgroup": allow_create_keytab_hostgroup_del,
|
|
}])
|
|
|
|
# Allow retrieve keytab
|
|
if len(allow_retrieve_keytab_user_add) > 0 or \
|
|
len(allow_retrieve_keytab_group_add) > 0 or \
|
|
len(allow_retrieve_keytab_host_add) > 0 or \
|
|
len(allow_retrieve_keytab_hostgroup_add) > 0:
|
|
commands.append(
|
|
[name, "host_allow_retrieve_keytab",
|
|
{
|
|
"user": allow_retrieve_keytab_user_add,
|
|
"group": allow_retrieve_keytab_group_add,
|
|
"host": allow_retrieve_keytab_host_add,
|
|
"hostgroup": allow_retrieve_keytab_hostgroup_add,
|
|
}])
|
|
|
|
# Disallow retrieve keytab
|
|
if len(allow_retrieve_keytab_user_del) > 0 or \
|
|
len(allow_retrieve_keytab_group_del) > 0 or \
|
|
len(allow_retrieve_keytab_host_del) > 0 or \
|
|
len(allow_retrieve_keytab_hostgroup_del) > 0:
|
|
commands.append(
|
|
[name, "host_disallow_retrieve_keytab",
|
|
{
|
|
"user": allow_retrieve_keytab_user_del,
|
|
"group": allow_retrieve_keytab_group_del,
|
|
"host": allow_retrieve_keytab_host_del,
|
|
"hostgroup": allow_retrieve_keytab_hostgroup_del,
|
|
}])
|
|
|
|
if len(dnsrecord_a_add) > 0 or len(dnsrecord_aaaa_add) > 0:
|
|
domain_name = name[name.find(".") + 1:]
|
|
host_name = name[:name.find(".")]
|
|
|
|
_args = {"idnsname": host_name}
|
|
if len(dnsrecord_a_add) > 0:
|
|
_args["arecord"] = dnsrecord_a_add
|
|
if reverse is not None:
|
|
_args["a_extra_create_reverse"] = reverse
|
|
if len(dnsrecord_aaaa_add) > 0:
|
|
_args["aaaarecord"] = dnsrecord_aaaa_add
|
|
if reverse is not None:
|
|
_args["aaaa_extra_create_reverse"] = reverse
|
|
|
|
commands.append([domain_name,
|
|
"dnsrecord_add", _args])
|
|
|
|
if len(dnsrecord_a_del) > 0 or len(dnsrecord_aaaa_del) > 0:
|
|
domain_name = name[name.find(".") + 1:]
|
|
host_name = name[:name.find(".")]
|
|
|
|
# There seems to be an issue with dnsrecord_del (not
|
|
# for dnsrecord_add) if aaaarecord is an empty list.
|
|
# Therefore this is done differently here:
|
|
_args = {"idnsname": host_name}
|
|
if len(dnsrecord_a_del) > 0:
|
|
_args["arecord"] = dnsrecord_a_del
|
|
if len(dnsrecord_aaaa_del) > 0:
|
|
_args["aaaarecord"] = dnsrecord_aaaa_del
|
|
|
|
commands.append([domain_name,
|
|
"dnsrecord_del", _args])
|
|
|
|
elif state == "absent":
|
|
if action == "host":
|
|
|
|
if res_find is not None:
|
|
args = {}
|
|
if update_dns is not None:
|
|
args["updatedns"] = update_dns
|
|
commands.append([name, "host_del", args])
|
|
else:
|
|
|
|
# Certificates need to be added and removed one by one,
|
|
# because if entry already exists, the processing of
|
|
# the remaining enries is stopped. The same applies to
|
|
# the removal of non-existing entries.
|
|
|
|
# Remove certificates
|
|
certificate_del = gen_intersection_list(
|
|
certificate, res_find.get("usercertificate"))
|
|
if certificate_del is not None:
|
|
for _certificate in certificate_del:
|
|
commands.append([name, "host_remove_cert",
|
|
{
|
|
"usercertificate":
|
|
_certificate,
|
|
}])
|
|
|
|
# Managedby_Hosts need to be added and removed one by one,
|
|
# because if entry already exists, the processing of
|
|
# the remaining enries is stopped. The same applies to
|
|
# the removal of non-existing entries.
|
|
|
|
# Remove managedby_hosts
|
|
managedby_host_del = gen_intersection_list(
|
|
managedby_host, res_find.get("managedby_host"))
|
|
if managedby_host_del is not None:
|
|
for _managedby_host in managedby_host_del:
|
|
commands.append([name, "host_remove_managedby",
|
|
{
|
|
"host":
|
|
_managedby_host,
|
|
}])
|
|
|
|
# Principals need to be added and removed one by one,
|
|
# because if entry already exists, the processing of
|
|
# the remaining enries is stopped. The same applies to
|
|
# the removal of non-existing entries.
|
|
|
|
# Remove principals
|
|
principal_del = gen_intersection_list(
|
|
principal, res_find.get("krbprincipalname"))
|
|
if principal_del is not None:
|
|
for _principal in principal_del:
|
|
commands.append([name, "host_remove_principal",
|
|
{
|
|
"krbprincipalname":
|
|
_principal,
|
|
}])
|
|
|
|
# Disallow create keytab
|
|
allow_create_keytab_user_del = gen_intersection_list(
|
|
allow_create_keytab_user,
|
|
res_find.get("ipaallowedtoperform_write_keys_user"))
|
|
allow_create_keytab_group_del = gen_intersection_list(
|
|
allow_create_keytab_group,
|
|
res_find.get("ipaallowedtoperform_write_keys_group"))
|
|
allow_create_keytab_host_del = gen_intersection_list(
|
|
allow_create_keytab_host,
|
|
res_find.get("ipaallowedtoperform_write_keys_host"))
|
|
allow_create_keytab_hostgroup_del = gen_intersection_list(
|
|
allow_create_keytab_hostgroup,
|
|
res_find.get(
|
|
"ipaallowedtoperform_write_keys_hostgroup"))
|
|
if len(allow_create_keytab_user_del) > 0 or \
|
|
len(allow_create_keytab_group_del) > 0 or \
|
|
len(allow_create_keytab_host_del) > 0 or \
|
|
len(allow_create_keytab_hostgroup_del) > 0:
|
|
commands.append(
|
|
[name, "host_disallow_create_keytab",
|
|
{
|
|
"user": allow_create_keytab_user_del,
|
|
"group": allow_create_keytab_group_del,
|
|
"host": allow_create_keytab_host_del,
|
|
"hostgroup":
|
|
allow_create_keytab_hostgroup_del,
|
|
}])
|
|
|
|
# Disallow retrieve keytab
|
|
allow_retrieve_keytab_user_del = gen_intersection_list(
|
|
allow_retrieve_keytab_user,
|
|
res_find.get("ipaallowedtoperform_read_keys_user"))
|
|
allow_retrieve_keytab_group_del = gen_intersection_list(
|
|
allow_retrieve_keytab_group,
|
|
res_find.get("ipaallowedtoperform_read_keys_group"))
|
|
allow_retrieve_keytab_host_del = gen_intersection_list(
|
|
allow_retrieve_keytab_host,
|
|
res_find.get("ipaallowedtoperform_read_keys_host"))
|
|
allow_retrieve_keytab_hostgroup_del = \
|
|
gen_intersection_list(
|
|
allow_retrieve_keytab_hostgroup,
|
|
res_find.get(
|
|
"ipaallowedtoperform_read_keys_hostgroup"))
|
|
if len(allow_retrieve_keytab_user_del) > 0 or \
|
|
len(allow_retrieve_keytab_group_del) > 0 or \
|
|
len(allow_retrieve_keytab_host_del) > 0 or \
|
|
len(allow_retrieve_keytab_hostgroup_del) > 0:
|
|
commands.append(
|
|
[name, "host_disallow_retrieve_keytab",
|
|
{
|
|
"user": allow_retrieve_keytab_user_del,
|
|
"group": allow_retrieve_keytab_group_del,
|
|
"host": allow_retrieve_keytab_host_del,
|
|
"hostgroup":
|
|
allow_retrieve_keytab_hostgroup_del,
|
|
}])
|
|
|
|
if res_find_dnsrecord is not None:
|
|
dnsrecord_args = gen_dnsrecord_args(
|
|
ansible_module, ip_address, reverse)
|
|
|
|
# Only keep a and aaaa recrords that are part
|
|
# of res_find_dnsrecord.
|
|
for _type in ["arecord", "aaaarecord"]:
|
|
if _type in dnsrecord_args:
|
|
recs = gen_intersection_list(
|
|
dnsrecord_args[_type],
|
|
res_find_dnsrecord.get(_type))
|
|
if len(recs) > 0:
|
|
dnsrecord_args[_type] = recs
|
|
else:
|
|
del dnsrecord_args[_type]
|
|
|
|
if "arecord" in dnsrecord_args or \
|
|
"aaaarecord" in dnsrecord_args:
|
|
domain_name = name[name.find(".") + 1:]
|
|
host_name = name[:name.find(".")]
|
|
dnsrecord_args["idnsname"] = host_name
|
|
|
|
commands.append([domain_name, "dnsrecord_del",
|
|
dnsrecord_args])
|
|
|
|
elif state == "disabled":
|
|
if res_find is not None:
|
|
commands.append([name, "host_disable", {}])
|
|
else:
|
|
raise ValueError("No host '%s'" % name)
|
|
|
|
else:
|
|
ansible_module.fail_json(msg="Unkown state '%s'" % state)
|
|
|
|
del host_set
|
|
|
|
# Execute commands
|
|
|
|
changed = ansible_module.execute_ipa_commands(
|
|
commands, result_handler, batch=True, keeponly=["randompassword"],
|
|
exit_args=exit_args, single_host=hosts is None)
|
|
|
|
# Done
|
|
|
|
ansible_module.exit_json(changed=changed, host=exit_args)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|