mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-04-04 01:33:05 +00:00
Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
513d5ee46b | ||
|
|
cd440a2049 | ||
|
|
e2317f304c | ||
|
|
7a23c668fc | ||
|
|
91d818b334 | ||
|
|
902d8b7238 | ||
|
|
d553f9a0b1 | ||
|
|
9cfe835b03 | ||
|
|
30c405cb36 | ||
|
|
7275bbf6a3 | ||
|
|
6df89ad7db | ||
|
|
c5fa54f2cf | ||
|
|
8e3102270d | ||
|
|
89cfb5f4c4 | ||
|
|
5fb22581bb | ||
|
|
6976ef57eb | ||
|
|
0d9b164358 | ||
|
|
8b03e4d007 | ||
|
|
ef73a85320 | ||
|
|
5b3a4729f0 | ||
|
|
7245339934 | ||
|
|
638422e113 | ||
|
|
432376524c | ||
|
|
86701caf8b | ||
|
|
d1857c18ac | ||
|
|
edbdd3af79 | ||
|
|
2d3da2d72c | ||
|
|
329c16f742 | ||
|
|
66c0be06d0 | ||
|
|
f04c90f4db | ||
|
|
dfa4bcb68f | ||
|
|
b1328ba7d5 | ||
|
|
fe58f3a8ba | ||
|
|
4dc6192640 | ||
|
|
e9435410b2 | ||
|
|
de6a0429a0 | ||
|
|
40d85f83e4 | ||
|
|
678927f35c | ||
|
|
f0e6d0c89f | ||
|
|
c095c24950 | ||
|
|
34dc75802c | ||
|
|
feb33e4e3a | ||
|
|
3c50a8121f | ||
|
|
e8688d4cf5 | ||
|
|
d540be425a | ||
|
|
c1d7ed1df6 | ||
|
|
0fc8ddf450 | ||
|
|
012f0deb00 | ||
|
|
f27b0e3011 | ||
|
|
8b4b22dd00 | ||
|
|
91c4b83311 | ||
|
|
6925503a10 | ||
|
|
0da0b22ae7 | ||
|
|
f5f454915c | ||
|
|
8581b79eba | ||
|
|
a9602431ce | ||
|
|
9195494f37 | ||
|
|
81abf6889b | ||
|
|
81906edec6 | ||
|
|
5071653db3 | ||
|
|
df4ec30a51 | ||
|
|
73160a037b | ||
|
|
b7ed9ecfd5 | ||
|
|
a4f608854d | ||
|
|
8e6c5e566d | ||
|
|
431dc8667a | ||
|
|
bc16ccaef7 | ||
|
|
227c95e62e | ||
|
|
5abb515c92 | ||
|
|
1c4b50fa51 | ||
|
|
8fc2de1673 | ||
|
|
8d74fe34ef | ||
|
|
87ad46f7a4 | ||
|
|
4c3f4e6f7d | ||
|
|
489f4d5784 | ||
|
|
29fc03c625 | ||
|
|
2dc1deeb87 | ||
|
|
82a53b9ae4 |
@@ -26,7 +26,7 @@ repos:
|
||||
- id: yamllint
|
||||
files: \.(yaml|yml)$
|
||||
- repo: https://github.com/pycqa/flake8
|
||||
rev: 7.0.0
|
||||
rev: 7.2.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/pycqa/pylint
|
||||
|
||||
@@ -20,4 +20,9 @@ rules:
|
||||
max: 160
|
||||
# Disabled rules
|
||||
indentation: disable
|
||||
comments: disable
|
||||
comments:
|
||||
min-spaces-from-content: 1
|
||||
comments-indentation: disable
|
||||
octal-values:
|
||||
forbid-implicit-octal: true
|
||||
forbid-explicit-octal: true
|
||||
|
||||
@@ -8,8 +8,12 @@ The group module allows to ensure presence and absence of groups and members of
|
||||
|
||||
The group module is as compatible as possible to the Ansible upstream `ipa_group` module, but additionally offers to add users to a group and also to remove users from a group.
|
||||
|
||||
## Note
|
||||
Ensuring presence (adding) of several groups with mixed types (`external`, `nonposix` and `posix`) requires a fix in FreeIPA. The module implements a workaround to automatically use `client` context if the fix is not present in the target node FreeIPA and if more than one group is provided to the task using the `groups` parameter. If `ipaapi_context` is forced to be `server`, the module will fail in this case.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
* Ensuring presence (adding) of several groups with mixed types (`external`, `nonposix` and `posix`) requires a fix in FreeIPA. The module implements a workaround to automatically use `client` context if the fix is not present in the target node FreeIPA and if more than one group is provided to the task using the `groups` parameter. If `ipaapi_context` is forced to be `server`, the module will fail in this case.
|
||||
* Using `externalmember` or `idoverrideuser` is only supported with `ipaapi_context: server`. With 'client' context, module execution will fail.
|
||||
|
||||
|
||||
Features
|
||||
@@ -213,7 +217,7 @@ Example playbook to add members from a trusted realm to an external group:
|
||||
---
|
||||
- name: Playbook to handle groups.
|
||||
hosts: ipaserver
|
||||
|
||||
|
||||
tasks:
|
||||
- name: Create an external group and add members from a trust to it.
|
||||
ipagroup:
|
||||
@@ -276,6 +280,7 @@ Example playbook to ensure groups are absent:
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Variables
|
||||
=========
|
||||
|
||||
@@ -299,8 +304,8 @@ Variable | Description | Required
|
||||
`service` | List of service name strings assigned to this group. Only usable with IPA versions 4.7 and up. | no
|
||||
`membermanager_user` | List of member manager users assigned to this group. Only usable with IPA versions 4.8.4 and up. | no
|
||||
`membermanager_group` | List of member manager groups assigned to this group. Only usable with IPA versions 4.8.4 and up. | no
|
||||
`externalmember` \| `ipaexternalmember` \| `external_member`| List of members of a trusted domain in DOM\\name or name@domain form. | no
|
||||
`idoverrideuser` | List of user ID overrides to manage. Only usable with IPA versions 4.8.7 and up.| no
|
||||
`externalmember` \| `ipaexternalmember` \| `external_member`| List of members of a trusted domain in DOM\\name or name@domain form. Requires "server" context. | no
|
||||
`idoverrideuser` | List of user ID overrides to manage. Only usable with IPA versions 4.8.7 and up. Requires "server" context. | no
|
||||
`rename` \| `new_name` | Rename the user object to the new name string. Only usable with `state: renamed`. | no
|
||||
`action` | Work on group or member level. It can be on of `member` or `group` and defaults to `group`. | no
|
||||
`state` | The state to ensure. It can be one of `present`, `absent` or `renamed`, default: `present`. | yes
|
||||
|
||||
@@ -68,23 +68,6 @@ Example playbook to ensure a local domain idrange is present:
|
||||
name: local_domain_id_range
|
||||
base_id: 150000
|
||||
range_size: 200000
|
||||
```
|
||||
|
||||
Example playbook to ensure a local domain idrange is present, with RID and secondary RID base values:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA idrange.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure local idrange is present
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: local_domain_id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
secondary_rid_base: 200000000
|
||||
```
|
||||
@@ -172,8 +155,8 @@ Variable | Description | Required
|
||||
`name` \| `cn` | The list of idrange name strings. | yes
|
||||
`base_id` \| `ipabaseid` | First Posix ID of the range. (int) | yes, if `state: present`
|
||||
`range_size` \| `ipaidrangesize` | Number of IDs in the range. (int) | yes, if `state: present`
|
||||
`rid_base` \| `ipabaserid` | First RID of the corresponding RID range. (int) | no
|
||||
`secondary_rid_base` \| `ipasecondarybaserid` | First RID of the secondary RID range. (int) | no
|
||||
`rid_base` \| `ipabaserid` | First RID of the corresponding RID range. (int) | yes, if `idrange_type: ipa-local` and `state: present` |
|
||||
`secondary_rid_base` \| `ipasecondarybaserid` | First RID of the secondary RID range. (int) | yes, if `idrange_type: ipa-local` and `state: present` |
|
||||
`dom_sid` \| `ipanttrusteddomainsid` | Domain SID of the trusted domain. | no
|
||||
`idrange_type` \| `iparangetype` | ID range type, one of `ipa-ad-trust`, `ipa-ad-trust-posix`, `ipa-local`. Only valid if idrange does not exist. | no
|
||||
`dom_name` \| `ipanttrusteddomainname` | Name of the trusted domain. Can only be used when `ipaapi_context: server`. | no
|
||||
|
||||
@@ -66,7 +66,7 @@ Supported Distributions
|
||||
-----------------------
|
||||
|
||||
* RHEL/CentOS 7.4+
|
||||
* Fedora 26+
|
||||
* Fedora 40+
|
||||
* Ubuntu
|
||||
* Debian 10+ (ipaclient only, no server or replica!)
|
||||
|
||||
@@ -125,7 +125,7 @@ ansible-freeipa/plugins/module_utils to ~/.ansible/plugins/
|
||||
|
||||
**RPM package**
|
||||
|
||||
There are RPM packages available for Fedora 29+. These are installing the roles and modules into the global Ansible directories for `roles`, `plugins/modules` and `plugins/module_utils` in the `/usr/share/ansible` directory. Therefore is it possible to use the roles and modules without adapting the names like it is done in the example playbooks.
|
||||
There are RPM packages available for Fedora. These are installing the roles and modules into the global Ansible directories for `roles`, `plugins/modules` and `plugins/module_utils` in the `/usr/share/ansible` directory. Therefore is it possible to use the roles and modules without adapting the names like it is done in the example playbooks.
|
||||
|
||||
**Ansible Galaxy**
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@ trigger:
|
||||
- master
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-20.04'
|
||||
vmImage: 'ubuntu-24.04'
|
||||
|
||||
variables:
|
||||
ansible_version: "-core >=2.16,<2.17"
|
||||
ansible_latest: "-core"
|
||||
ansible_minimum: "-core <2.16"
|
||||
distros: "fedora-latest,c9s,fedora-rawhide"
|
||||
distros: "fedora-latest,c9s,c10s,fedora-rawhide"
|
||||
|
||||
stages:
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ trigger: none
|
||||
pool:
|
||||
vmImage: 'ubuntu-24.04'
|
||||
|
||||
variables: { distros: "fedora-latest,fedora-rawhide,c9s" }
|
||||
variables: { distros: "fedora-latest,fedora-rawhide,c9s,c10s" }
|
||||
|
||||
stages:
|
||||
|
||||
|
||||
@@ -10,12 +10,12 @@ schedules:
|
||||
trigger: none
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-20.04'
|
||||
vmImage: 'ubuntu-24.04'
|
||||
|
||||
variables:
|
||||
# We need to have two sets, as c8s is not supported by all ansible versions
|
||||
recent_distros: "fedora-latest,fedora-rawhide,c9s"
|
||||
distros: "fedora-latest,fedora-rawhide,c9s,c8s"
|
||||
recent_distros: "fedora-latest,fedora-rawhide,c10s,c9s"
|
||||
distros: "fedora-latest,fedora-rawhide,c10s,c9s,c8s"
|
||||
ansible_latest: "-core"
|
||||
ansible_minimum: "-core <2.16"
|
||||
ansible_version: "-core >=2.16,<2.17"
|
||||
|
||||
@@ -3,10 +3,10 @@ trigger:
|
||||
- master
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-20.04'
|
||||
vmImage: 'ubuntu-24.04'
|
||||
|
||||
variables:
|
||||
distros: "fedora-latest,c9s,c8s,fedora-rawhide"
|
||||
distros: "fedora-latest,c10s,c9s,c8s,fedora-rawhide"
|
||||
ansible_version: "-core >=2.15,<2.16"
|
||||
|
||||
stages:
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
- script: ansible-galaxy collection install containers.podman
|
||||
displayName: Install Ansible Galaxy collections
|
||||
|
||||
- script: infra/image/build.sh -p -s ${{ parameters.distro }}
|
||||
- script: infra/image/build.sh -s ${{ parameters.distro }}
|
||||
displayName: Build ${{ parameters.distro }} base image
|
||||
env:
|
||||
ANSIBLE_ROLES_PATH: "${PWD}/roles"
|
||||
|
||||
21
infra/azure/templates/variables_c10s.yaml
Normal file
21
infra/azure/templates/variables_c10s.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# Variables must be defined as comma separated lists.
|
||||
# For easier management of items to enable/disable,
|
||||
# use one test/module on each line, followed by a comma.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# ipa_disabled_modules: >-
|
||||
# dnsconfig,
|
||||
# group,
|
||||
# hostgroup
|
||||
#
|
||||
# If no variables are set, set "empty: true" as at least
|
||||
# one item is needed in the set.
|
||||
---
|
||||
variables:
|
||||
empty: true
|
||||
# ipa_enabled_modules: >-
|
||||
# ipa_enabled_tests: >-
|
||||
# ipa_disabled_modules: >-
|
||||
# ipa_disabled_tests: >-
|
||||
@@ -15,7 +15,7 @@ valid_distro() {
|
||||
usage() {
|
||||
local prog="${0##*/}"
|
||||
cat << EOF
|
||||
usage: ${prog} [-h] [-p] [-n HOSTNAME] [-s] distro
|
||||
usage: ${prog} [-h] [-n HOSTNAME] [-s] distro
|
||||
${prog} build a container image to test ansible-freeipa.
|
||||
EOF
|
||||
}
|
||||
@@ -41,14 +41,14 @@ cpus="2"
|
||||
memory="3g"
|
||||
quayname="quay.io/ansible-freeipa/upstream-tests"
|
||||
deploy_server="N"
|
||||
privileged=""
|
||||
deploy_capabilities="SYS_ADMIN,SYSLOG"
|
||||
capabilities=""
|
||||
|
||||
while getopts ":hn:ps" option
|
||||
while getopts ":hn:s" option
|
||||
do
|
||||
case "${option}" in
|
||||
h) help && exit 0 ;;
|
||||
n) hostname="${OPTARG}" ;;
|
||||
p) privileged="privileged" ;;
|
||||
s) deploy_server="Y" ;;
|
||||
*) die -u "Invalid option: ${option}" ;;
|
||||
esac
|
||||
@@ -66,6 +66,8 @@ container_check
|
||||
|
||||
if [ "${deploy_server}" == "Y" ]
|
||||
then
|
||||
capabilities="${deploy_capabilities}"
|
||||
|
||||
[ -n "$(command -v "ansible-playbook")" ] || die "ansible-playbook is required to install FreeIPA."
|
||||
|
||||
deploy_playbook="${TOPDIR}/playbooks/install-server.yml"
|
||||
@@ -89,7 +91,7 @@ container_create "${name}" "${tag}" \
|
||||
"hostname=${hostname}" \
|
||||
"memory=${memory}" \
|
||||
"cpus=${cpus}" \
|
||||
"${privileged}"
|
||||
"${capabilities:+capabilities=$capabilities}"
|
||||
container_commit "${name}" "${quayname}:${tag}"
|
||||
|
||||
if [ "${deploy_server}" == "Y" ]
|
||||
@@ -117,13 +119,6 @@ then
|
||||
deployed=true
|
||||
fi
|
||||
echo
|
||||
|
||||
if $deployed; then
|
||||
log info "= Enabling services ="
|
||||
container_exec "${name}" systemctl enable fixnet
|
||||
container_exec "${name}" systemctl enable fixipaip
|
||||
echo
|
||||
fi
|
||||
|
||||
container_stop "${name}"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM quay.io/centos/centos:stream10-development
|
||||
FROM quay.io/centos/centos:stream10
|
||||
ENV container=podman
|
||||
|
||||
RUN rm -fv /var/cache/dnf/metadata_lock.pid; \
|
||||
@@ -9,7 +9,8 @@ dnf --assumeyes install \
|
||||
bash \
|
||||
systemd \
|
||||
procps-ng \
|
||||
iproute; \
|
||||
iproute \
|
||||
hostname; \
|
||||
rm -rf /var/cache/dnf/;
|
||||
|
||||
RUN (cd /lib/systemd/system/; \
|
||||
@@ -30,6 +31,8 @@ COPY system-service/fixipaip.sh /root/
|
||||
COPY system-service/fixnet.service /etc/systemd/system/
|
||||
COPY system-service/fixipaip.service /etc/systemd/system/
|
||||
RUN chmod +x /root/fixnet.sh /root/fixipaip.sh
|
||||
RUN systemctl enable fixnet.service
|
||||
RUN systemctl enable fixipaip.service
|
||||
|
||||
STOPSIGNAL RTMIN+3
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ COPY system-service/fixipaip.sh /root/
|
||||
COPY system-service/fixnet.service /etc/systemd/system/
|
||||
COPY system-service/fixipaip.service /etc/systemd/system/
|
||||
RUN chmod +x /root/fixnet.sh /root/fixipaip.sh
|
||||
RUN systemctl enable fixnet.service
|
||||
RUN systemctl enable fixipaip.service
|
||||
|
||||
STOPSIGNAL RTMIN+3
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ COPY system-service/fixipaip.sh /root/
|
||||
COPY system-service/fixnet.service /etc/systemd/system/
|
||||
COPY system-service/fixipaip.service /etc/systemd/system/
|
||||
RUN chmod +x /root/fixnet.sh /root/fixipaip.sh
|
||||
RUN systemctl enable fixnet.service
|
||||
RUN systemctl enable fixipaip.service
|
||||
|
||||
STOPSIGNAL RTMIN+3
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ COPY system-service/fixipaip.sh /root/
|
||||
COPY system-service/fixnet.service /etc/systemd/system/
|
||||
COPY system-service/fixipaip.service /etc/systemd/system/
|
||||
RUN chmod +x /root/fixnet.sh /root/fixipaip.sh
|
||||
RUN systemctl enable fixnet.service
|
||||
RUN systemctl enable fixipaip.service
|
||||
|
||||
STOPSIGNAL RTMIN+3
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ COPY system-service/fixipaip.sh /root/
|
||||
COPY system-service/fixnet.service /etc/systemd/system/
|
||||
COPY system-service/fixipaip.service /etc/systemd/system/
|
||||
RUN chmod +x /root/fixnet.sh /root/fixipaip.sh
|
||||
RUN systemctl enable fixnet.service
|
||||
RUN systemctl enable fixipaip.service
|
||||
|
||||
STOPSIGNAL RTMIN+3
|
||||
|
||||
|
||||
@@ -4,13 +4,20 @@
|
||||
SCRIPTDIR="$(dirname -- "$(readlink -f "${BASH_SOURCE[0]}")")"
|
||||
TOPDIR="$(readlink -f "${SCRIPTDIR}/../..")"
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
. "${SCRIPTDIR}/shdefaults"
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
. "${TOPDIR}/utils/shfun"
|
||||
|
||||
container_create() {
|
||||
local name=${1}
|
||||
local image=${2}
|
||||
shift 2
|
||||
declare -a extra_opts=()
|
||||
declare -a extra_opts
|
||||
readarray -t extra_opts < \
|
||||
<(sed -e "s/-/--cap-drop=/g" -e "s/+/--cap-add=/g" \
|
||||
<<< "$(printf '%s\n' "${CAP_DEFAULTS[@]}")")
|
||||
for opt in "$@"
|
||||
do
|
||||
[ -z "${opt}" ] && continue
|
||||
@@ -18,7 +25,8 @@ container_create() {
|
||||
hostname=*) extra_opts+=("--${opt}") ;;
|
||||
cpus=*) extra_opts+=("--${opt}") ;;
|
||||
memory=*) extra_opts+=("--${opt}") ;;
|
||||
privileged) extra_opts+=("--${opt}") ;;
|
||||
capabilities=*) extra_opts+=("--cap-add=${opt##*=}") ;;
|
||||
volume=*) extra_opts+=("--volume=${opt##*=}") ;;
|
||||
*) log error "container_create: Invalid option: ${opt}" ;;
|
||||
esac
|
||||
done
|
||||
@@ -47,6 +55,19 @@ container_start() {
|
||||
|
||||
log info "= Starting ${name} ="
|
||||
podman start "${name}"
|
||||
# Add host entry to /etc/hosts
|
||||
ip=$(podman inspect "${name}" --format "{{.NetworkSettings.IPAddress}}")
|
||||
hostname=$(podman inspect "${name}" --format "{{.Config.Hostname}}")
|
||||
if [ -n "${ip}" ] && [ -n "${hostname}" ]; then
|
||||
cmd=$(cat <<EOF
|
||||
sed -i -E "/\s+${hostname}(\s|$)/d" /etc/hosts
|
||||
echo -e "$ip\t${hostname} ${hostname%%.*}" >> /etc/hosts
|
||||
EOF
|
||||
)
|
||||
podman exec "${name}" bash -c "$cmd"
|
||||
fi
|
||||
# Ensure /etc/shadow is readable
|
||||
podman exec "${name}" bash -c "chmod u+r /etc/shadow"
|
||||
echo
|
||||
}
|
||||
|
||||
@@ -175,3 +196,35 @@ container_image_list() {
|
||||
container_check() {
|
||||
[ -n "$(command -v "podman")" ] || die "podman is required."
|
||||
}
|
||||
|
||||
container_copy() {
|
||||
local name="${1}"
|
||||
local source="${2}"
|
||||
local destination="${3}"
|
||||
|
||||
log info "= Copying ${source} to ${name}:${destination} ="
|
||||
podman cp "${source}" "${name}:${destination}"
|
||||
echo
|
||||
}
|
||||
|
||||
container_fetch() {
|
||||
local name="${1}"
|
||||
local source="${2}"
|
||||
local destination="${3}"
|
||||
|
||||
log info "= Copying ${name}:${source} to ${destination} ="
|
||||
podman cp "${name}:${source}" "${destination}"
|
||||
echo
|
||||
}
|
||||
|
||||
container_tee() {
|
||||
local name=${1}
|
||||
local destination=${2}
|
||||
tmpfile=$(mktemp /tmp/container-temp.XXXXXX)
|
||||
|
||||
log info "= Creating ${name}:${destination} from stdin ="
|
||||
cat - > "${tmpfile}"
|
||||
podman cp "${tmpfile}" "${name}:${destination}"
|
||||
rm "${tmpfile}"
|
||||
echo
|
||||
}
|
||||
|
||||
9
infra/image/shdefaults
Normal file
9
infra/image/shdefaults
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash -eu
|
||||
# This file is meant to be source'd by other scripts
|
||||
|
||||
# Set default capabilities options for freeipa containers.
|
||||
# Use +CAP to add the capability and -CAP to drop the capability.
|
||||
CAP_DEFAULTS=(
|
||||
"+DAC_READ_SEARCH" # Required for SSSD
|
||||
"+SYS_PTRACE" # Required for debugging
|
||||
)
|
||||
@@ -1,6 +1,7 @@
|
||||
[Unit]
|
||||
Description=Fix IPA server IP in IPA Server
|
||||
After=ipa.service
|
||||
PartOf=ipa.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
@@ -9,4 +10,4 @@ StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
WantedBy=ipa.service
|
||||
|
||||
@@ -50,9 +50,9 @@ if [ -z "${FORWARDER}" ] || [ "${FORWARDER}" == "127.0.0.1" ]; then
|
||||
fi
|
||||
|
||||
echo "Fix IPA:"
|
||||
echo " HOSTNAME: '${HOSTNAME}'"
|
||||
echo " IP: '${IP}'"
|
||||
echo " PTR: '${PTR}'"
|
||||
echo " HOSTNAME: '${HOSTNAME}'"
|
||||
echo " IP: '${IP}'"
|
||||
echo " PTR: '${PTR}'"
|
||||
echo " FORWARDER: '${FORWARDER}'"
|
||||
|
||||
ZONES=$(ipa -e in_server=true dnszone-find --name-from-ip="${HOSTNAME}." \
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
[Unit]
|
||||
Description=Fix server IP in IPA Server
|
||||
Wants=network.target
|
||||
After=network.target
|
||||
Before=ipa.service
|
||||
Description=Fix /etc/hosts and with local DNS also /etc/resolv.conf
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
@@ -11,4 +8,4 @@ StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=ipa.service
|
||||
WantedBy=container-ipa.target
|
||||
|
||||
@@ -39,26 +39,35 @@ if [ -z "${IP}" ] || ! valid_ipv4 "${IP}" ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DOMAIN=${HOSTNAME#*.}
|
||||
|
||||
echo "Fix NET:"
|
||||
echo " HOSTNAME: '${HOSTNAME}'"
|
||||
echo " IP: '${IP}'"
|
||||
echo " DOMAIN: '${DOMAIN}'"
|
||||
echo " IP: '${IP}'"
|
||||
echo
|
||||
|
||||
if grep -qE "^[^(#\s*)][0-9\.]+\s$HOSTNAME(\s|$)" /etc/hosts
|
||||
then
|
||||
sed -i.bak -e "s/.*${HOSTNAME}/${IP}\t${HOSTNAME}/" /etc/hosts
|
||||
else
|
||||
echo -e "$IP\t${HOSTNAME} ${HOSTNAME%%.*}" >> /etc/hosts
|
||||
fi
|
||||
# /etc/hosts
|
||||
|
||||
cp -a /etc/resolv.conf /etc/resolv.conf.fixnet
|
||||
cat > /etc/resolv.conf <<EOF
|
||||
search ${HOSTNAME#*.}
|
||||
nameserver 127.0.0.1
|
||||
EOF
|
||||
sed -i -E "/\s+${HOSTNAME}(\s|$)/d" /etc/hosts
|
||||
echo -e "$IP\t${HOSTNAME} ${HOSTNAME%%.*}" >> /etc/hosts
|
||||
|
||||
echo "/etc/hosts:"
|
||||
cat "/etc/hosts"
|
||||
|
||||
# /etc/resolv.conf
|
||||
|
||||
# If bind is not installed, exit
|
||||
[ -f "/etc/named.conf" ] || exit 0
|
||||
# If dyndb is not enabled for bind, exit
|
||||
grep -q '^dyndb "ipa"' "/etc/named.conf" || exit 0
|
||||
|
||||
cp -a /etc/resolv.conf /etc/resolv.conf.fixnet
|
||||
cat > /etc/resolv.conf <<EOF
|
||||
search ${DOMAIN}
|
||||
nameserver 127.0.0.1
|
||||
EOF
|
||||
|
||||
echo
|
||||
echo "/etc/resolv.conf:"
|
||||
cat "/etc/resolv.conf"
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
- ip_address: 8.8.8.8
|
||||
- ip_address: 8.8.4.4
|
||||
port: 52
|
||||
#serial: 1234
|
||||
# serial: 1234
|
||||
refresh: 3600
|
||||
retry: 900
|
||||
expire: 1209600
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
dest: "{{ ansible_facts['env'].HOME }}/password.txt"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ ansible_user }}"
|
||||
mode: 0600
|
||||
mode: "0600"
|
||||
- name: Ensure symmetric vault exists with password from file.
|
||||
ipavault:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
dest: "{{ ansible_facts['env'].HOME }}/public.pem"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ ansible_user }}"
|
||||
mode: 0600
|
||||
mode: "0600"
|
||||
- name: Ensure asymmetric vault exists with public key from file.
|
||||
ipavault:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
|
||||
@@ -589,6 +589,20 @@ def ensure_fqdn(name, domain):
|
||||
return name
|
||||
|
||||
|
||||
def convert_to_sid(items):
|
||||
"""Convert all items to SID, if possible."""
|
||||
def get_sid(data):
|
||||
try:
|
||||
return get_trusted_domain_object_sid(data)
|
||||
except ipalib_errors.NotFound:
|
||||
return data
|
||||
if items is None:
|
||||
return None
|
||||
if not isinstance(items, (list, tuple)):
|
||||
items = [items]
|
||||
return [get_sid(item) for item in items]
|
||||
|
||||
|
||||
def api_get_realm():
|
||||
return api.env.realm
|
||||
|
||||
@@ -903,6 +917,13 @@ def get_trusted_domain_sid_from_name(dom_name):
|
||||
return unicode(sid) if sid is not None else None
|
||||
|
||||
|
||||
def get_trusted_domain_object_sid(object_name):
|
||||
"""Given an object name, returns de object SID."""
|
||||
domain_validator = __get_domain_validator()
|
||||
sid = domain_validator.get_trusted_domain_object_sid(object_name)
|
||||
return unicode(sid) if sid is not None else None
|
||||
|
||||
|
||||
class IPAParamMapping(Mapping):
|
||||
"""
|
||||
Provides IPA API mapping to playbook parameters or computed values.
|
||||
|
||||
@@ -106,7 +106,7 @@ RETURN = '''
|
||||
'''
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import (
|
||||
IPAAnsibleModule, compare_args_ipa
|
||||
IPAAnsibleModule, compare_args_ipa, ipalib_errors
|
||||
)
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ class AutomountMap(IPAAnsibleModule):
|
||||
location,
|
||||
{"automountmapname": name, "all": True}
|
||||
)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
return None
|
||||
return response["result"]
|
||||
|
||||
@@ -132,7 +132,7 @@ class AutomountMap(IPAAnsibleModule):
|
||||
"""Check if 'name' is an indirect map for 'parentmap'."""
|
||||
try:
|
||||
maps = self.ipa_command("automountmap_find", location, {})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
return []
|
||||
|
||||
result = []
|
||||
|
||||
@@ -487,6 +487,8 @@ def main():
|
||||
|
||||
# revoked
|
||||
reason = ansible_module.params_get("revocation_reason")
|
||||
if reason is not None:
|
||||
reason = get_revocation_reason(ansible_module, reason)
|
||||
|
||||
# general
|
||||
serial_number = ansible_module.params.get("serial_number")
|
||||
@@ -521,6 +523,9 @@ def main():
|
||||
invalid.append("revocation_reason")
|
||||
if state == "revoked":
|
||||
invalid.extend(["certificate_out", "chain"])
|
||||
# Reason 8 (revomeFromCRL) is the same as release hold
|
||||
if reason == 8:
|
||||
state = "released"
|
||||
elif state == "held":
|
||||
reason = 6 # certificateHold
|
||||
|
||||
|
||||
@@ -356,7 +356,7 @@ def config_show(module):
|
||||
def get_netbios_name(module):
|
||||
try:
|
||||
_result = module.ipa_command_no_name("trustconfig_show", {"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
return None
|
||||
return _result["result"]["ipantflatname"][0]
|
||||
|
||||
|
||||
@@ -124,14 +124,14 @@ RETURN = """
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa
|
||||
IPAAnsibleModule, compare_args_ipa, ipalib_errors
|
||||
|
||||
|
||||
def find_delegation(module, name):
|
||||
"""Find if a delegation with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("delegation_show", name, {"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if delegation name is not found.
|
||||
return None
|
||||
return _result["result"]
|
||||
|
||||
@@ -113,13 +113,14 @@ options:
|
||||
externalmember:
|
||||
description:
|
||||
- List of members of a trusted domain in DOM\\name or name@domain form.
|
||||
Requires "server" context.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaexternalmember", "external_member"]
|
||||
idoverrideuser:
|
||||
description:
|
||||
- User ID overrides to add
|
||||
- User ID overrides to add. Requires "server" context.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
@@ -188,13 +189,14 @@ options:
|
||||
externalmember:
|
||||
description:
|
||||
- List of members of a trusted domain in DOM\\name or name@domain form.
|
||||
Requires "server" context.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaexternalmember", "external_member"]
|
||||
idoverrideuser:
|
||||
description:
|
||||
- User ID overrides to add
|
||||
- User ID overrides to add. Requires "server" context.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
@@ -297,6 +299,7 @@ EXAMPLES = """
|
||||
posix: yes
|
||||
|
||||
# Create an external group and add members from a trust to it.
|
||||
# Module will fail if running under 'client' context.
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: extgroup
|
||||
@@ -327,7 +330,8 @@ RETURN = """
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, \
|
||||
gen_add_list, gen_intersection_list, api_check_param
|
||||
gen_add_list, gen_intersection_list, api_check_param, \
|
||||
convert_to_sid
|
||||
from ansible.module_utils import six
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
@@ -562,21 +566,29 @@ def main():
|
||||
# The simple solution is to switch to client context for ensuring
|
||||
# several groups simply if the user was not explicitly asking for
|
||||
# the server context no matter if mixed types are used.
|
||||
context = None
|
||||
context = ansible_module.params_get("ipaapi_context")
|
||||
if state == "present" and groups is not None and len(groups) > 1 \
|
||||
and not FIX_6741_DEEPCOPY_OBJECTCLASSES:
|
||||
_context = ansible_module.params_get("ipaapi_context")
|
||||
if _context is None:
|
||||
if context is None:
|
||||
context = "client"
|
||||
ansible_module.debug(
|
||||
"Switching to client context due to an unfixed issue in "
|
||||
"your IPA version: https://pagure.io/freeipa/issue/9349")
|
||||
elif _context == "server":
|
||||
elif context == "server":
|
||||
ansible_module.fail_json(
|
||||
msg="Ensuring several groups with server context is not "
|
||||
"supported by your IPA version: "
|
||||
"https://pagure.io/freeipa/issue/9349")
|
||||
|
||||
if (
|
||||
(externalmember is not None
|
||||
or idoverrideuser is not None)
|
||||
and context == "client"
|
||||
):
|
||||
ansible_module.fail_json(
|
||||
msg="Cannot use externalmember in client context."
|
||||
)
|
||||
|
||||
# Use groups if names is None
|
||||
if groups is not None:
|
||||
names = groups
|
||||
@@ -676,6 +688,23 @@ def main():
|
||||
# Make sure group exists
|
||||
res_find = find_group(ansible_module, name)
|
||||
|
||||
# external members must de handled as SID
|
||||
externalmember = convert_to_sid(externalmember)
|
||||
|
||||
# idoverrides need to be compared through SID
|
||||
idoverrideuser_sid = convert_to_sid(idoverrideuser)
|
||||
res_idoverrideuser_sid = convert_to_sid(
|
||||
(res_find or {}).get("member_idoverrideuser", []))
|
||||
idoverride_set = dict(
|
||||
list(zip(idoverrideuser_sid or [], idoverrideuser or [])) +
|
||||
list(
|
||||
zip(
|
||||
res_idoverrideuser_sid or [],
|
||||
(res_find or {}).get("member_idoverrideuser", [])
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
user_add, user_del = [], []
|
||||
group_add, group_del = [], []
|
||||
service_add, service_del = [], []
|
||||
@@ -723,11 +752,12 @@ def main():
|
||||
res_find = {}
|
||||
|
||||
# if we just created/modified the group, update res_find
|
||||
res_find.setdefault("objectclass", [])
|
||||
classes = list(res_find.setdefault("objectclass", []))
|
||||
if external and not is_external_group(res_find):
|
||||
res_find["objectclass"].append("ipaexternalgroup")
|
||||
classes.append("ipaexternalgroup")
|
||||
if posix and not is_posix_group(res_find):
|
||||
res_find["objectclass"].append("posixgroup")
|
||||
classes.append("posixgroup")
|
||||
res_find["objectclass"] = classes
|
||||
|
||||
member_args = gen_member_args(
|
||||
user, group, service, externalmember, idoverrideuser
|
||||
@@ -746,13 +776,25 @@ def main():
|
||||
|
||||
(externalmember_add,
|
||||
externalmember_del) = gen_add_del_lists(
|
||||
externalmember, res_find.get("member_external"))
|
||||
externalmember, (
|
||||
list(res_find.get("member_external", []))
|
||||
+ list(res_find.get("ipaexternalmember", []))
|
||||
)
|
||||
)
|
||||
|
||||
# There are multiple ways to name an AD User, and any
|
||||
# can be used in idoverrides, so we create the add/del
|
||||
# lists based on SID, and then use the given user name
|
||||
# to the idoverride.
|
||||
(idoverrides_add,
|
||||
idoverrides_del) = gen_add_del_lists(
|
||||
idoverrideuser,
|
||||
res_find.get("member_idoverrideuser")
|
||||
)
|
||||
idoverrideuser_sid, res_idoverrideuser_sid)
|
||||
idoverrides_add = [
|
||||
idoverride_set[sid] for sid in set(idoverrides_add)
|
||||
]
|
||||
idoverrides_del = [
|
||||
idoverride_set[sid] for sid in set(idoverrides_del)
|
||||
]
|
||||
|
||||
membermanager_user_add, membermanager_user_del = \
|
||||
gen_add_del_lists(
|
||||
@@ -780,9 +822,16 @@ def main():
|
||||
service_add = gen_add_list(
|
||||
service, res_find.get("member_service"))
|
||||
externalmember_add = gen_add_list(
|
||||
externalmember, res_find.get("member_external"))
|
||||
externalmember, (
|
||||
list(res_find.get("member_external", []))
|
||||
+ list(res_find.get("ipaexternalmember", []))
|
||||
)
|
||||
)
|
||||
idoverrides_add = gen_add_list(
|
||||
idoverrideuser, res_find.get("member_idoverrideuser"))
|
||||
idoverrideuser_sid, res_idoverrideuser_sid)
|
||||
idoverrides_add = [
|
||||
idoverride_set[sid] for sid in set(idoverrides_add)
|
||||
]
|
||||
|
||||
membermanager_user_add = gen_add_list(
|
||||
membermanager_user,
|
||||
@@ -815,9 +864,16 @@ def main():
|
||||
service_del = gen_intersection_list(
|
||||
service, res_find.get("member_service"))
|
||||
externalmember_del = gen_intersection_list(
|
||||
externalmember, res_find.get("member_external"))
|
||||
externalmember, (
|
||||
list(res_find.get("member_external", []))
|
||||
+ list(res_find.get("ipaexternalmember", []))
|
||||
)
|
||||
)
|
||||
idoverrides_del = gen_intersection_list(
|
||||
idoverrideuser, res_find.get("member_idoverrideuser"))
|
||||
idoverrideuser_sid, res_idoverrideuser_sid)
|
||||
idoverrides_del = [
|
||||
idoverride_set[sid] for sid in set(idoverrides_del)
|
||||
]
|
||||
|
||||
membermanager_user_del = gen_intersection_list(
|
||||
membermanager_user, res_find.get("membermanager_user"))
|
||||
@@ -860,7 +916,7 @@ def main():
|
||||
if len(externalmember_del) > 0:
|
||||
del_member_args["ipaexternalmember"] = \
|
||||
externalmember_del
|
||||
elif externalmember or external:
|
||||
elif externalmember:
|
||||
ansible_module.fail_json(
|
||||
msg="Cannot add external members to a "
|
||||
"non-external group."
|
||||
|
||||
@@ -155,7 +155,7 @@ RETURN = """
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa
|
||||
IPAAnsibleModule, compare_args_ipa, ipalib_errors
|
||||
from ansible.module_utils import six
|
||||
|
||||
if six.PY3:
|
||||
@@ -168,7 +168,7 @@ def find_idoverridegroup(module, idview, anchor):
|
||||
_result = module.ipa_command("idoverridegroup_show", idview,
|
||||
{"ipaanchoruuid": anchor,
|
||||
"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if idoverridegroup anchor is not found.
|
||||
return None
|
||||
return _result["result"]
|
||||
|
||||
@@ -315,7 +315,8 @@ RETURN = """
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, gen_add_list, \
|
||||
gen_intersection_list, encode_certificate, convert_input_certificates
|
||||
gen_intersection_list, encode_certificate, convert_input_certificates, \
|
||||
ipalib_errors
|
||||
from ansible.module_utils import six
|
||||
|
||||
if six.PY3:
|
||||
@@ -328,7 +329,7 @@ def find_idoverrideuser(module, idview, anchor):
|
||||
_result = module.ipa_command("idoverrideuser_show", idview,
|
||||
{"ipaanchoruuid": anchor,
|
||||
"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if idoverrideuser anchor is not found.
|
||||
return None
|
||||
|
||||
|
||||
@@ -184,7 +184,8 @@ RETURN = """
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, template_str, urlparse
|
||||
IPAAnsibleModule, compare_args_ipa, template_str, urlparse, \
|
||||
ipalib_errors
|
||||
from ansible.module_utils import six
|
||||
from copy import deepcopy
|
||||
import string
|
||||
@@ -269,7 +270,7 @@ def find_idp(module, name):
|
||||
"""Find if a idp with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("idp_show", name, {"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if idp name is not found.
|
||||
return None
|
||||
|
||||
|
||||
@@ -143,7 +143,8 @@ RETURN = """
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, get_trusted_domain_sid_from_name
|
||||
IPAAnsibleModule, compare_args_ipa, get_trusted_domain_sid_from_name, \
|
||||
ipalib_errors
|
||||
from ansible.module_utils import six
|
||||
|
||||
if six.PY3:
|
||||
@@ -154,7 +155,7 @@ def find_idrange(module, name):
|
||||
"""Find if a idrange with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("idrange_show", name, {"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if idrange name is not found.
|
||||
return None
|
||||
return _result["result"]
|
||||
@@ -280,6 +281,14 @@ def main():
|
||||
|
||||
# Connect to IPA API
|
||||
with ansible_module.ipa_connect():
|
||||
# set required fields
|
||||
required = ["base_id", "range_size"]
|
||||
requires_baserid = (
|
||||
ansible_module.ipa_command_param_exists("config_mod", "enable_sid")
|
||||
and idrange_type in [None, "ipa-local"]
|
||||
)
|
||||
if requires_baserid:
|
||||
required.extend(["rid_base", "secondary_rid_base"])
|
||||
|
||||
commands = []
|
||||
for name in names:
|
||||
@@ -320,6 +329,18 @@ def main():
|
||||
del args["iparangetype"]
|
||||
commands.append([name, "idrange_mod", args])
|
||||
else:
|
||||
# Check if required parameters were given
|
||||
missing_params = [
|
||||
pname for pname in required
|
||||
if ansible_module.params_get(pname) is None
|
||||
]
|
||||
if missing_params:
|
||||
ansible_module.fail_json(
|
||||
msg=(
|
||||
"Missing required parameters: %s"
|
||||
% (", ".join(missing_params))
|
||||
)
|
||||
)
|
||||
commands.append([name, "idrange_add", args])
|
||||
|
||||
elif state == "absent":
|
||||
|
||||
@@ -138,7 +138,7 @@ def find_idview(module, name):
|
||||
"""Find if a idview with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("idview_show", name, {"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if idview name is not found.
|
||||
return None
|
||||
return _result["result"]
|
||||
|
||||
@@ -76,14 +76,14 @@ RETURN = """
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa
|
||||
IPAAnsibleModule, compare_args_ipa, ipalib_errors
|
||||
|
||||
|
||||
def find_location(module, name):
|
||||
"""Find if a location with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("location_show", name, {"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if location name is not found.
|
||||
return None
|
||||
return _result["result"]
|
||||
|
||||
@@ -154,14 +154,14 @@ RETURN = """
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, to_text
|
||||
IPAAnsibleModule, compare_args_ipa, to_text, ipalib_errors
|
||||
|
||||
|
||||
def find_permission(module, name):
|
||||
"""Find if a permission with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("permission_show", name, {"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if permission name is not found.
|
||||
return None
|
||||
_res = _result["result"]
|
||||
|
||||
@@ -124,7 +124,7 @@ RETURN = """
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, gen_add_list, \
|
||||
gen_intersection_list
|
||||
gen_intersection_list, ipalib_errors
|
||||
from ansible.module_utils import six
|
||||
|
||||
if six.PY3:
|
||||
@@ -135,7 +135,7 @@ def find_privilege(module, name):
|
||||
"""Find if a privilege with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("privilege_show", name, {"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if privilege name is not found.
|
||||
return None
|
||||
return _result["result"]
|
||||
|
||||
@@ -129,7 +129,7 @@ EXAMPLES = """
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, gen_add_del_lists, compare_args_ipa, \
|
||||
gen_intersection_list, ensure_fqdn
|
||||
gen_intersection_list, ensure_fqdn, ipalib_errors
|
||||
from ansible.module_utils import six
|
||||
|
||||
if six.PY3:
|
||||
@@ -140,7 +140,7 @@ def find_role(module, name):
|
||||
"""Find if a role with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("role_show", name, {"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if role name is not found.
|
||||
return None
|
||||
return _result["result"]
|
||||
|
||||
@@ -113,14 +113,14 @@ RETURN = """
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa
|
||||
IPAAnsibleModule, compare_args_ipa, ipalib_errors
|
||||
|
||||
|
||||
def find_selfservice(module, name):
|
||||
"""Find if a selfservice with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("selfservice_show", name, {"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if selfservice name is not found.
|
||||
return None
|
||||
return _result["result"]
|
||||
|
||||
@@ -192,14 +192,14 @@ RETURN = """
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, DNSName
|
||||
IPAAnsibleModule, compare_args_ipa, DNSName, ipalib_errors
|
||||
|
||||
|
||||
def find_server(module, name):
|
||||
"""Find if a server with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("server_show", name, {"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if server name is not found.
|
||||
return None
|
||||
return _result["result"]
|
||||
@@ -214,7 +214,7 @@ def server_role_status(module, name):
|
||||
"include_master": True,
|
||||
"raw": True,
|
||||
"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if server name is not found.
|
||||
return None
|
||||
return _result["result"][0]
|
||||
|
||||
@@ -142,7 +142,7 @@ def find_servicedelegationrule(module, name):
|
||||
try:
|
||||
_result = module.ipa_command("servicedelegationrule_show", name,
|
||||
{"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if servicedelegationrule name is not found.
|
||||
return None
|
||||
return _result["result"]
|
||||
|
||||
@@ -106,7 +106,7 @@ RETURN = """
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, gen_add_del_lists, gen_add_list, gen_intersection_list, \
|
||||
servicedelegation_normalize_principals
|
||||
servicedelegation_normalize_principals, ipalib_errors
|
||||
from ansible.module_utils import six
|
||||
|
||||
if six.PY3:
|
||||
@@ -118,7 +118,7 @@ def find_servicedelegationtarget(module, name):
|
||||
try:
|
||||
_result = module.ipa_command("servicedelegationtarget_show", name,
|
||||
{"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if servicedelegationtarget name is not found.
|
||||
return None
|
||||
return _result["result"]
|
||||
|
||||
@@ -710,7 +710,11 @@ def main():
|
||||
|
||||
# Generate addition and removal lists
|
||||
host_add, host_del = gen_add_del_lists(
|
||||
entry.host, res_find.get('memberhost_host', []))
|
||||
entry.host, (
|
||||
list(res_find.get('memberhost_host', []))
|
||||
+ list(res_find.get('externalhost', []))
|
||||
)
|
||||
)
|
||||
|
||||
hostgroup_add, hostgroup_del = gen_add_del_lists(
|
||||
entry.hostgroup,
|
||||
@@ -721,7 +725,11 @@ def main():
|
||||
entry.hostmask, res_find.get('hostmask', []))
|
||||
|
||||
user_add, user_del = gen_add_del_lists(
|
||||
entry.user, res_find.get('memberuser_user', []))
|
||||
entry.user, (
|
||||
list(res_find.get('memberuser_user', []))
|
||||
+ list(res_find.get('externaluser', []))
|
||||
)
|
||||
)
|
||||
|
||||
group_add, group_del = gen_add_del_lists(
|
||||
entry.group, res_find.get('memberuser_group', []))
|
||||
@@ -751,8 +759,7 @@ def main():
|
||||
# the provided list against both users and external
|
||||
# users list.
|
||||
runasuser_add, runasuser_del = gen_add_del_lists(
|
||||
entry.runasuser,
|
||||
(
|
||||
entry.runasuser, (
|
||||
list(res_find.get('ipasudorunas_user', []))
|
||||
+ list(res_find.get('ipasudorunasextuser', []))
|
||||
)
|
||||
@@ -785,7 +792,11 @@ def main():
|
||||
# the sudorule already
|
||||
if entry.host is not None:
|
||||
host_add = gen_add_list(
|
||||
entry.host, res_find.get("memberhost_host"))
|
||||
entry.host, (
|
||||
list(res_find.get("memberhost_host", []))
|
||||
+ list(res_find.get("externalhost", []))
|
||||
)
|
||||
)
|
||||
if entry.hostgroup is not None:
|
||||
hostgroup_add = gen_add_list(
|
||||
entry.hostgroup,
|
||||
@@ -796,7 +807,11 @@ def main():
|
||||
entry.hostmask, res_find.get("hostmask"))
|
||||
if entry.user is not None:
|
||||
user_add = gen_add_list(
|
||||
entry.user, res_find.get("memberuser_user"))
|
||||
entry.user, (
|
||||
list(res_find.get('memberuser_user', []))
|
||||
+ list(res_find.get('externaluser', []))
|
||||
)
|
||||
)
|
||||
if entry.group is not None:
|
||||
group_add = gen_add_list(
|
||||
entry.group, res_find.get("memberuser_group"))
|
||||
@@ -862,7 +877,11 @@ def main():
|
||||
# in sudorule
|
||||
if entry.host is not None:
|
||||
host_del = gen_intersection_list(
|
||||
entry.host, res_find.get("memberhost_host"))
|
||||
entry.host, (
|
||||
list(res_find.get("memberhost_host", []))
|
||||
+ list(res_find.get("externalhost", []))
|
||||
)
|
||||
)
|
||||
|
||||
if entry.hostgroup is not None:
|
||||
hostgroup_del = gen_intersection_list(
|
||||
@@ -876,7 +895,11 @@ def main():
|
||||
|
||||
if entry.user is not None:
|
||||
user_del = gen_intersection_list(
|
||||
entry.user, res_find.get("memberuser_user"))
|
||||
entry.user, (
|
||||
list(res_find.get('memberuser_user', []))
|
||||
+ list(res_find.get('externaluser', []))
|
||||
)
|
||||
)
|
||||
|
||||
if entry.group is not None:
|
||||
group_del = gen_intersection_list(
|
||||
@@ -911,8 +934,7 @@ def main():
|
||||
# users list.
|
||||
if entry.runasuser is not None:
|
||||
runasuser_del = gen_intersection_list(
|
||||
entry.runasuser,
|
||||
(
|
||||
entry.runasuser, (
|
||||
list(res_find.get('ipasudorunas_user', []))
|
||||
+ list(res_find.get('ipasudorunasextuser', []))
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
-r requirements-tests.txt
|
||||
ipdb==0.13.4
|
||||
pre-commit==2.20.0
|
||||
flake8==7.0.0
|
||||
flake8
|
||||
flake8-bugbear
|
||||
pylint>=3.2
|
||||
wrapt==1.14.1
|
||||
|
||||
@@ -34,7 +34,7 @@ Supported Distributions
|
||||
|
||||
* RHEL/CentOS 7.6+
|
||||
* CentOS Stream 8+
|
||||
* Fedora 26+
|
||||
* Fedora 40+
|
||||
* Ubuntu 16.04 and 18.04
|
||||
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ Supported Distributions
|
||||
|
||||
* RHEL/CentOS 7.4+
|
||||
* CentOS Stream 8+
|
||||
* Fedora 26+
|
||||
* Fedora 40+
|
||||
* Ubuntu
|
||||
* Debian
|
||||
|
||||
@@ -202,6 +202,8 @@ Variable | Description | Required
|
||||
`ipaclient_request_cert` | The bool value defines if the certificate for the machine wil be requested. The certificate will be stored in /etc/ipa/nssdb under the nickname "Local IPA host". . `ipaclient_request_cert` defaults to `no`. The option is deprecated and will be removed in a future release. | no
|
||||
`ipaclient_keytab` | The string value contains the path on the node of a backup host keytab from a previous enrollment. | no
|
||||
`ipaclient_automount_location` | Automount location | no
|
||||
`ipaclient_dns_over_tls` | Configure DNS over TLS. Requires FreeIPA version 4.12.5 or later. (bool, default: false) | no
|
||||
`ipaclient_no_dnssec_validation` | Disable DNSSEC validation for DNS over TLS. This turns off DNSSEC validation for unbound. Ignored if `ipaserver_dns_over_tls` is not enabled. (bool, default: false) | no
|
||||
|
||||
|
||||
Server Variables
|
||||
|
||||
@@ -26,6 +26,8 @@ ipasssd_enable_dns_updates: no
|
||||
ipasssd_no_krb5_offline_passwords: no
|
||||
ipasssd_preserve_sssd: no
|
||||
ipaclient_request_cert: no
|
||||
ipaclient_dns_over_tls: no
|
||||
ipaclient_no_dnssec_validation: no
|
||||
|
||||
### packages ###
|
||||
ipaclient_install_packages: yes
|
||||
|
||||
@@ -86,6 +86,16 @@ options:
|
||||
type: bool
|
||||
required: no
|
||||
default: no
|
||||
dns_over_tls:
|
||||
description: Configure DNS over TLS
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
no_dnssec_validation:
|
||||
description: Disable DNSSEC validation for DNS over TLS
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
enable_dns_updates:
|
||||
description: |
|
||||
Configures the machine to attempt dns updates when the ip address
|
||||
@@ -212,7 +222,9 @@ def main():
|
||||
mkhomedir=dict(required=False, type='bool'),
|
||||
on_master=dict(required=False, type='bool'),
|
||||
dnsok=dict(required=False, type='bool', default=False),
|
||||
|
||||
dns_over_tls=dict(required=False, type='bool', default=False),
|
||||
no_dnssec_validation=dict(required=False, type='bool',
|
||||
default=False),
|
||||
enable_dns_updates=dict(required=False, type='bool'),
|
||||
all_ip_addresses=dict(required=False, type='bool', default=False),
|
||||
ip_addresses=dict(required=False, type='list', elements='str',
|
||||
@@ -249,6 +261,8 @@ def main():
|
||||
options.mkhomedir = module.params.get('mkhomedir')
|
||||
options.on_master = module.params.get('on_master')
|
||||
dnsok = module.params.get('dnsok')
|
||||
options.dns_over_tls = module.params.get('dns_over_tls')
|
||||
options.no_dnssec_validation = module.params.get('no_dnssec_validation')
|
||||
|
||||
fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
|
||||
statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE)
|
||||
@@ -256,6 +270,7 @@ def main():
|
||||
os.environ['KRB5CCNAME'] = paths.IPA_DNS_CCACHE
|
||||
|
||||
options.dns_updates = module.params.get('enable_dns_updates')
|
||||
options.dns_over_tls = module.params.get('dns_over_tls')
|
||||
options.all_ip_addresses = module.params.get('all_ip_addresses')
|
||||
options.ip_addresses = ansible_module_get_parsed_ip_addresses(module)
|
||||
options.request_cert = module.params.get('request_cert')
|
||||
@@ -279,6 +294,7 @@ def main():
|
||||
options.no_sssd = False
|
||||
options.sssd = not options.no_sssd
|
||||
options.no_ac = False
|
||||
options.dns_over_tls = module.params.get('dns_over_tls')
|
||||
nosssd_files = module.params.get('nosssd_files')
|
||||
selinux_works = module.params.get('selinux_works')
|
||||
krb_name = module.params.get('krb_name')
|
||||
@@ -339,17 +355,19 @@ def main():
|
||||
ca_subject)
|
||||
ca_certs_trust = [(c, n,
|
||||
certstore.key_policy_to_trust_flags(t, True, u))
|
||||
for (c, n, t, u) in ca_certs]
|
||||
for (c, n, t, u) in [x[0:4] for x in ca_certs]]
|
||||
|
||||
if hasattr(paths, "KDC_CA_BUNDLE_PEM"):
|
||||
x509.write_certificate_list(
|
||||
[c for c, n, t, u in ca_certs if t is not False],
|
||||
[c for c, n, t, u in [x[0:4] for x in ca_certs]
|
||||
if t is not False],
|
||||
paths.KDC_CA_BUNDLE_PEM,
|
||||
# mode=0o644
|
||||
)
|
||||
if hasattr(paths, "CA_BUNDLE_PEM"):
|
||||
x509.write_certificate_list(
|
||||
[c for c, n, t, u in ca_certs if t is not False],
|
||||
[c for c, n, t, u in [x[0:4] for x in ca_certs]
|
||||
if t is not False],
|
||||
paths.CA_BUNDLE_PEM,
|
||||
# mode=0o644
|
||||
)
|
||||
@@ -376,7 +394,12 @@ def main():
|
||||
ssh_config_dir = paths.SSH_CONFIG_DIR
|
||||
else:
|
||||
ssh_config_dir = services.knownservices.sshd.get_config_dir()
|
||||
update_ssh_keys(hostname, ssh_config_dir, options.create_sshfp)
|
||||
argspec_update_ssh_keys = getargspec(update_ssh_keys)
|
||||
# Hotfix for https://github.com/freeipa/freeipa/pull/7343
|
||||
if "options" in argspec_update_ssh_keys.args:
|
||||
update_ssh_keys(hostname, ssh_config_dir, options, cli_server[0])
|
||||
else:
|
||||
update_ssh_keys(hostname, ssh_config_dir, options.create_sshfp)
|
||||
|
||||
try:
|
||||
os.remove(CCACHE_FILE)
|
||||
|
||||
@@ -91,6 +91,11 @@ options:
|
||||
changes
|
||||
type: bool
|
||||
required: no
|
||||
dns_over_tls:
|
||||
description: Configure DNS over TLS
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
preserve_sssd:
|
||||
description: Preserve old SSSD configuration if possible
|
||||
type: bool
|
||||
@@ -140,6 +145,7 @@ def main():
|
||||
fixed_primary=dict(required=False, type='bool'),
|
||||
permit=dict(required=False, type='bool'),
|
||||
enable_dns_updates=dict(required=False, type='bool'),
|
||||
dns_over_tls=dict(required=False, type='bool', default=False),
|
||||
preserve_sssd=dict(required=False, type='bool'),
|
||||
no_krb5_offline_passwords=dict(required=False, type='bool'),
|
||||
),
|
||||
@@ -169,11 +175,13 @@ def main():
|
||||
options.primary = module.params.get('fixed_primary')
|
||||
options.permit = module.params.get('permit')
|
||||
options.dns_updates = module.params.get('enable_dns_updates')
|
||||
options.dns_over_tls = module.params.get('dns_over_tls')
|
||||
options.preserve_sssd = module.params.get('preserve_sssd')
|
||||
|
||||
options.no_krb5_offline_passwords = module.params.get(
|
||||
'no_krb5_offline_passwords')
|
||||
options.krb5_offline_passwords = not options.no_krb5_offline_passwords
|
||||
options.dns_over_tls = False
|
||||
|
||||
fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
|
||||
client_domain = hostname[hostname.find(".") + 1:]
|
||||
|
||||
@@ -124,6 +124,16 @@ options:
|
||||
type: bool
|
||||
required: no
|
||||
default: no
|
||||
dns_over_tls:
|
||||
description: Configure DNS over TLS
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
no_dnssec_validation:
|
||||
description: Disable DNSSEC validation for DNS over TLS
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
enable_dns_updates:
|
||||
description:
|
||||
Configures the machine to attempt dns updates when the ip address
|
||||
@@ -248,7 +258,8 @@ from ansible.module_utils.ansible_ipa_client import (
|
||||
CLIENT_INSTALL_ERROR, tasks, check_ldap_conf, timeconf, constants,
|
||||
validate_hostname, nssldap_exists, gssapi, remove_file,
|
||||
check_ip_addresses, ipadiscovery, print_port_conf_info,
|
||||
IPA_PYTHON_VERSION, getargspec
|
||||
IPA_PYTHON_VERSION, getargspec, services,
|
||||
CLIENT_SUPPORTS_NO_DNSSEC_VALIDATION
|
||||
)
|
||||
|
||||
|
||||
@@ -328,6 +339,9 @@ def main():
|
||||
default=None),
|
||||
all_ip_addresses=dict(required=False, type='bool', default=False),
|
||||
on_master=dict(required=False, type='bool', default=False),
|
||||
dns_over_tls=dict(required=False, type='bool', default=False),
|
||||
no_dnssec_validation=dict(required=False, type='bool',
|
||||
default=False),
|
||||
# sssd
|
||||
enable_dns_updates=dict(required=False, type='bool',
|
||||
default=False),
|
||||
@@ -356,6 +370,8 @@ def main():
|
||||
options.ip_addresses = module.params.get('ip_addresses')
|
||||
options.all_ip_addresses = module.params.get('all_ip_addresses')
|
||||
options.on_master = module.params.get('on_master')
|
||||
options.dns_over_tls = module.params.get('dns_over_tls')
|
||||
options.no_dnssec_validation = module.params.get('no_dnssec_validation')
|
||||
options.enable_dns_updates = module.params.get('enable_dns_updates')
|
||||
|
||||
# Get domain from first server if domain is not set, but if there are
|
||||
@@ -365,6 +381,16 @@ def main():
|
||||
options.domain_name = options.servers[0][
|
||||
options.servers[0].find(".") + 1:]
|
||||
|
||||
if options.dns_over_tls \
|
||||
and not services.knownservices["unbound"].is_installed():
|
||||
module.fail_json(
|
||||
msg="To enable DNS over TLS, package ipa-client-encrypted-dns "
|
||||
"must be installed.")
|
||||
if options.dns_over_tls and not CLIENT_SUPPORTS_NO_DNSSEC_VALIDATION:
|
||||
module.fail_json(
|
||||
msg="Important patches for DNS over TLS are missing in your IPA "
|
||||
"version.")
|
||||
|
||||
try:
|
||||
self = options
|
||||
|
||||
|
||||
@@ -231,8 +231,6 @@ try:
|
||||
cli_realm, cli_domain, cli_server, cli_kdc, dnsok,
|
||||
filename, client_domain, client_hostname, force=False,
|
||||
configure_sssd=True):
|
||||
# pylint: disable=global-variable-not-assigned
|
||||
global options
|
||||
options.force = force
|
||||
options.sssd = configure_sssd
|
||||
return ipa_client_install.configure_krb5_conf(
|
||||
@@ -312,6 +310,15 @@ try:
|
||||
except ImportError:
|
||||
configure_selinux_for_client = None
|
||||
|
||||
try:
|
||||
CLIENT_SUPPORTS_NO_DNSSEC_VALIDATION = False
|
||||
from ipaclient.install.client import ClientInstallInterface
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
if hasattr(ClientInstallInterface, "no_dnssec_validation"):
|
||||
CLIENT_SUPPORTS_NO_DNSSEC_VALIDATION = True
|
||||
|
||||
logger = logging.getLogger("ipa-client-install")
|
||||
root_logger = logger
|
||||
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
---
|
||||
# tasks file for ipaclient
|
||||
|
||||
- name: Install - Ensure that IPA client packages are installed
|
||||
ansible.builtin.package:
|
||||
name: "{{ ipaclient_packages }}"
|
||||
state: present
|
||||
- name: Install - Package installation
|
||||
when: ipaclient_install_packages | bool
|
||||
block:
|
||||
|
||||
- name: Install - Set packages for installation
|
||||
ansible.builtin.set_fact:
|
||||
_ipapackages: "{{ ipaclient_packages }}"
|
||||
|
||||
- name: Install - Set packages for installlation, add DOT
|
||||
ansible.builtin.set_fact:
|
||||
_ipapackages: "{{ _ipapackages + ipaclient_packages_dot }}"
|
||||
when: ipaclient_dns_over_tls | bool
|
||||
|
||||
- name: Install - Ensure that packages are installed
|
||||
ansible.builtin.package:
|
||||
name: "{{ _ipapackages }}"
|
||||
state: present
|
||||
|
||||
- name: Install - Set ipaclient_servers
|
||||
ansible.builtin.set_fact:
|
||||
@@ -38,7 +50,7 @@
|
||||
msg: "ipaclient_domain or ipaserver_domain is required for ipaclient_configure_dns_resolver"
|
||||
when: ipaserver_domain is not defined and ipaclient_domain is not defined
|
||||
|
||||
- name: Install - Fail on missing ipaclient_servers
|
||||
- name: Install - Fail on missing ipaclient_dns_servers
|
||||
ansible.builtin.fail:
|
||||
msg: "ipaclient_dns_servers is required for ipaclient_configure_dns_resolver"
|
||||
when: ipaclient_dns_servers is not defined
|
||||
@@ -69,9 +81,10 @@
|
||||
ip_addresses: "{{ ipaclient_ip_addresses | default(omit) }}"
|
||||
all_ip_addresses: "{{ ipaclient_all_ip_addresses }}"
|
||||
on_master: "{{ ipaclient_on_master }}"
|
||||
dns_over_tls: "{{ ipaclient_dns_over_tls }}"
|
||||
no_dnssec_validation: "{{ ipaclient_no_dnssec_validation }}"
|
||||
### sssd ###
|
||||
enable_dns_updates: "{{ ipassd_enable_dns_updates
|
||||
| default(ipasssd_enable_dns_updates) }}"
|
||||
enable_dns_updates: "{{ ipasssd_enable_dns_updates }}"
|
||||
register: result_ipaclient_test
|
||||
|
||||
- name: Install - Client deployment
|
||||
@@ -152,7 +165,7 @@
|
||||
ansible.builtin.copy:
|
||||
src: "{{ ipaadmin_keytab }}"
|
||||
dest: "{{ keytab_temp.path }}"
|
||||
mode: 0600
|
||||
mode: "0600"
|
||||
delegate_to: "{{ result_ipaclient_test.servers[0] }}"
|
||||
when: ipaadmin_keytab is defined
|
||||
|
||||
@@ -321,16 +334,12 @@
|
||||
no_sshd: "{{ ipaclient_no_sshd }}"
|
||||
no_sudo: "{{ ipaclient_no_sudo }}"
|
||||
all_ip_addresses: "{{ ipaclient_all_ip_addresses }}"
|
||||
fixed_primary: "{{ ipassd_fixed_primary
|
||||
| default(ipasssd_fixed_primary) }}"
|
||||
permit: "{{ ipassd_permit | default(ipasssd_permit) }}"
|
||||
enable_dns_updates: "{{ ipassd_enable_dns_updates
|
||||
| default(ipasssd_enable_dns_updates) }}"
|
||||
preserve_sssd: "{{ ipassd_preserve_sssd
|
||||
| default(ipasssd_preserve_sssd) }}"
|
||||
no_krb5_offline_passwords:
|
||||
"{{ ipassd_no_krb5_offline_passwords
|
||||
| default(ipasssd_no_krb5_offline_passwords) }}"
|
||||
fixed_primary: "{{ ipasssd_fixed_primary }}"
|
||||
permit: "{{ ipasssd_permit }}"
|
||||
enable_dns_updates: "{{ ipasssd_enable_dns_updates }}"
|
||||
dns_over_tls: "{{ ipaclient_dns_over_tls }}"
|
||||
preserve_sssd: "{{ ipasssd_preserve_sssd }}"
|
||||
no_krb5_offline_passwords: "{{ ipasssd_no_krb5_offline_passwords }}"
|
||||
|
||||
- name: Install - IPA API calls for remaining enrollment parts
|
||||
ipaclient_api:
|
||||
@@ -365,23 +374,20 @@
|
||||
ca_enabled: "{{ result_ipaclient_api.ca_enabled }}"
|
||||
on_master: "{{ ipaclient_on_master }}"
|
||||
dnsok: "{{ result_ipaclient_test.dnsok }}"
|
||||
enable_dns_updates: "{{ ipassd_enable_dns_updates
|
||||
| default(ipasssd_enable_dns_updates) }}"
|
||||
enable_dns_updates: "{{ ipasssd_enable_dns_updates }}"
|
||||
dns_over_tls: "{{ ipaclient_dns_over_tls }}"
|
||||
no_dnssec_validation: "{{ ipaclient_no_dnssec_validation }}"
|
||||
all_ip_addresses: "{{ ipaclient_all_ip_addresses }}"
|
||||
ip_addresses: "{{ ipaclient_ip_addresses | default(omit) }}"
|
||||
request_cert: "{{ ipaclient_request_cert }}"
|
||||
preserve_sssd: "{{ ipassd_preserve_sssd
|
||||
| default(ipasssd_preserve_sssd) }}"
|
||||
preserve_sssd: "{{ ipasssd_preserve_sssd }}"
|
||||
no_ssh: "{{ ipaclient_no_ssh }}"
|
||||
no_sshd: "{{ ipaclient_no_sshd }}"
|
||||
no_sudo: "{{ ipaclient_no_sudo }}"
|
||||
subid: "{{ ipaclient_subid }}"
|
||||
fixed_primary: "{{ ipassd_fixed_primary
|
||||
| default(ipasssd_fixed_primary) }}"
|
||||
permit: "{{ ipassd_permit | default(ipasssd_permit) }}"
|
||||
no_krb5_offline_passwords:
|
||||
"{{ ipassd_no_krb5_offline_passwords
|
||||
| default(ipasssd_no_krb5_offline_passwords) }}"
|
||||
fixed_primary: "{{ ipasssd_fixed_primary }}"
|
||||
permit: "{{ ipasssd_permit }}"
|
||||
no_krb5_offline_passwords: "{{ ipasssd_no_krb5_offline_passwords }}"
|
||||
no_dns_sshfp: "{{ ipaclient_no_dns_sshfp }}"
|
||||
nosssd_files: "{{ result_ipaclient_test.nosssd_files }}"
|
||||
selinux_works: "{{ result_ipaclient_test.selinux_works }}"
|
||||
|
||||
@@ -15,8 +15,3 @@
|
||||
ipaclient_configure_dns_resolver:
|
||||
state: absent
|
||||
when: ipaclient_cleanup_dns_resolver | bool
|
||||
|
||||
#- name: Remove IPA client package
|
||||
# ansible.builtin.package:
|
||||
# name: "{{ ipaclient_packages }}"
|
||||
# state: absent
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
# vars/Debian.yml
|
||||
ipaclient_packages: [ "freeipa-client" ]
|
||||
ipaclient_packages_dot: [ ]
|
||||
# Debian Buster must use python2 as Python interpreter due
|
||||
# to the way freeipa-client package is defined.
|
||||
# You must install package python2.7 before executing this role.
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
# vars/Debian.yml
|
||||
---
|
||||
ipaclient_packages: [ "freeipa-client" ]
|
||||
ipaclient_packages_dot: [ ]
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# defaults file for ipaclient
|
||||
# vars/Fedora-25.yml
|
||||
---
|
||||
ipaclient_packages: [ "ipa-client", "libselinux-python" ]
|
||||
#ansible_python_interpreter: '/usr/bin/python2'
|
||||
@@ -1,5 +0,0 @@
|
||||
# defaults file for ipaclient
|
||||
# vars/Fedora-26.yml
|
||||
---
|
||||
ipaclient_packages: [ "ipa-client", "libselinux-python" ]
|
||||
#ansible_python_interpreter: '/usr/bin/python2'
|
||||
@@ -1,5 +0,0 @@
|
||||
# defaults file for ipaclient
|
||||
# vars/RedHat-7.3.yml
|
||||
---
|
||||
ipaclient_packages: [ "ipa-client", "ipa-admintools", "libselinux-python" ]
|
||||
#ansible_python_interpreter: '/usr/bin/python2'
|
||||
@@ -2,4 +2,4 @@
|
||||
# vars/RedHat-7
|
||||
---
|
||||
ipaclient_packages: [ "ipa-client", "libselinux-python" ]
|
||||
#ansible_python_interpreter: '/usr/bin/python2'
|
||||
ipaclient_packages_dot: [ ]
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
# vars/RedHat-8.yml
|
||||
---
|
||||
ipaclient_packages: [ "@idm:DL1/client" ]
|
||||
ipaclient_packages_dot: [ ]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# vars/Ubuntu-18.04.yml
|
||||
---
|
||||
ipaclient_packages: [ "freeipa-client" ]
|
||||
ipaclient_packages_dot: [ ]
|
||||
# Ubuntu Bionic Beaver must use python2 as Python interpreter due
|
||||
# to the way python-ipalib package is defined.
|
||||
# Package python2.7 must be installed before executing this role.
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
# vars/default.yml
|
||||
---
|
||||
ipaclient_packages: [ "ipa-client", "python3-libselinux" ]
|
||||
#ansible_python_interpreter: '/usr/bin/python3'
|
||||
ipaclient_packages_dot: [ "ipa-client-encrypted-dns" ]
|
||||
|
||||
@@ -28,7 +28,7 @@ Supported Distributions
|
||||
|
||||
* RHEL/CentOS 7.6+
|
||||
* CentOS Stream 8+
|
||||
* Fedora 26+
|
||||
* Fedora 40+
|
||||
* Ubuntu 16.04 and 18.04
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ Variable | Description | Required
|
||||
`ipaservers` | This group with the IPA master full qualified hostnames. (list of strings) | mostly
|
||||
`ipareplicas` | Group of IPA replica hostnames. (list of strings) | yes
|
||||
`ipaadmin_password` | The password for the IPA admin user (string) | mostly
|
||||
`ipareplica_ip_addresses` | The list of master server IP addresses. (list of strings) | no
|
||||
`ipareplica_ip_addresses` | The list of IPA replica IP addresses. (list of strings) | no
|
||||
`ipareplica_domain` | The primary DNS domain of an existing IPA deployment. (string) | no
|
||||
`ipaserver_realm` | The Kerberos realm of an existing IPA deployment. (string) | no
|
||||
`ipaserver_hostname` | Fully qualified name of the server. (string) | no
|
||||
@@ -270,6 +270,11 @@ Variable | Description | Required
|
||||
`ipareplica_auto_forwarders` | Add DNS forwarders configured in /etc/resolv.conf to the list of forwarders used by IPA DNS. (bool, default: false) | no
|
||||
`ipareplica_forward_policy` | DNS forwarding policy for global forwarders specified using other options. (choice: first,only) | no
|
||||
`ipareplica_no_dnssec_validation` | Disable DNSSEC validation on this server. (bool, default: false) | no
|
||||
`ipareplica_dot_forwarders` | List of DNS over TLS forwarders. Required if `ipareplica_dns_over_tls` is enabled. (list of strings) | no
|
||||
`ipareplica_dns_over_tls` \| `ipaclient_dns_over_tls` | Configure DNS over TLS. Requires FreeIPA version 4.12.5 or later. (bool, default: false) | no
|
||||
`ipareplica_dns_over_tls_cert` | Certificate to use for DNS over TLS. If empty, a new certificate will be requested from IPA CA. (string) | no
|
||||
`ipareplica_dns_over_tls_key` | Key for certificate specified in `ipareplica_dns_over_tls_cert`. (string) | no
|
||||
`ipareplica_dns_policy` | Encrypted DNS policy. Only usable if `ipareplica_dns_over_tls` is enabled. (choice: relaxed, enforced, default: relaxed) | no
|
||||
|
||||
AD trust Variables
|
||||
------------------
|
||||
|
||||
@@ -17,10 +17,10 @@ ipareplica_no_ui_redirect: no
|
||||
ipaclient_mkhomedir: no
|
||||
ipaclient_force_join: no
|
||||
ipaclient_no_ntp: no
|
||||
#ipaclient_ssh_trust_dns: no
|
||||
#ipaclient_no_ssh: no
|
||||
#ipaclient_no_sshd: no
|
||||
#ipaclient_no_dns_sshfp: no
|
||||
# ipaclient_ssh_trust_dns: no
|
||||
# ipaclient_no_ssh: no
|
||||
# ipaclient_no_sshd: no
|
||||
# ipaclient_no_dns_sshfp: no
|
||||
ipaclient_ssh_trust_dns: no
|
||||
### certificate system ###
|
||||
ipareplica_skip_schema_check: no
|
||||
|
||||
@@ -47,7 +47,7 @@ options:
|
||||
type: str
|
||||
required: no
|
||||
ip_addresses:
|
||||
description: List of Master Server IP Addresses
|
||||
description: List of IPA replica IP addresses
|
||||
type: list
|
||||
elements: str
|
||||
required: no
|
||||
|
||||
@@ -47,7 +47,7 @@ options:
|
||||
type: str
|
||||
required: no
|
||||
ip_addresses:
|
||||
description: List of Master Server IP Addresses
|
||||
description: List of IPA replica IP addresses
|
||||
type: list
|
||||
elements: str
|
||||
required: no
|
||||
|
||||
@@ -49,7 +49,7 @@ options:
|
||||
type: str
|
||||
required: no
|
||||
ip_addresses:
|
||||
description: List of Master Server IP Addresses
|
||||
description: List of IPA replica IP addresses
|
||||
type: list
|
||||
elements: str
|
||||
required: no
|
||||
@@ -224,6 +224,32 @@ options:
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
dot_forwarders:
|
||||
description: List of DNS over TLS forwarders
|
||||
type: list
|
||||
elements: str
|
||||
default: []
|
||||
required: no
|
||||
dns_over_tls:
|
||||
description: Configure DNS over TLS
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
dns_over_tls_cert:
|
||||
description:
|
||||
Certificate to use for DNS over TLS. If empty, a new
|
||||
certificate will be requested from IPA CA
|
||||
type: str
|
||||
required: no
|
||||
dns_over_tls_key:
|
||||
description: Key for certificate specified in dns_over_tls_cert
|
||||
type: str
|
||||
required: no
|
||||
dns_policy:
|
||||
description: Encrypted DNS policy
|
||||
type: str
|
||||
choices: ['relaxed', 'enforced']
|
||||
default: 'relaxed'
|
||||
enable_compat:
|
||||
description: Enable support for trusted domains for old clients
|
||||
type: bool
|
||||
@@ -354,6 +380,15 @@ def main():
|
||||
choices=['first', 'only'], default=None),
|
||||
no_dnssec_validation=dict(required=False, type='bool',
|
||||
default=False),
|
||||
dot_forwarders=dict(required=False, type='list', elements='str',
|
||||
default=[]),
|
||||
dns_over_tls=dict(required=False, type='bool',
|
||||
default=False),
|
||||
dns_over_tls_cert=dict(required=False, type='str'),
|
||||
dns_over_tls_key=dict(required=False, type='str'),
|
||||
dns_policy=dict(required=False, type='str',
|
||||
choices=['relaxed', 'enforced'],
|
||||
default='relaxed'),
|
||||
# ad trust
|
||||
enable_compat=dict(required=False, type='bool', default=False),
|
||||
netbios_name=dict(required=False, type='str'),
|
||||
@@ -430,6 +465,11 @@ def main():
|
||||
options.forward_policy = ansible_module.params.get('forward_policy')
|
||||
options.no_dnssec_validation = ansible_module.params.get(
|
||||
'no_dnssec_validation')
|
||||
options.dot_forwarders = ansible_module.params.get('dot_forwarders')
|
||||
options.dns_over_tls = ansible_module.params.get('dns_over_tls')
|
||||
options.dns_over_tls_cert = ansible_module.params.get('dns_over_tls_cert')
|
||||
options.dns_over_tls_key = ansible_module.params.get('dns_over_tls_key')
|
||||
options.dns_policy = ansible_module.params.get('dns_policy')
|
||||
# ad trust
|
||||
options.enable_compat = ansible_module.params.get('enable_compat')
|
||||
options.netbios_name = ansible_module.params.get('netbios_name')
|
||||
|
||||
@@ -72,6 +72,32 @@ options:
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
dot_forwarders:
|
||||
description: List of DNS over TLS forwarders
|
||||
type: list
|
||||
elements: str
|
||||
default: []
|
||||
required: no
|
||||
dns_over_tls:
|
||||
description: Configure DNS over TLS
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
dns_over_tls_cert:
|
||||
description:
|
||||
Certificate to use for DNS over TLS. If empty, a new
|
||||
certificate will be requested from IPA CA
|
||||
type: str
|
||||
required: no
|
||||
dns_over_tls_key:
|
||||
description: Key for certificate specified in dns_over_tls_cert
|
||||
type: str
|
||||
required: no
|
||||
dns_policy:
|
||||
description: Encrypted DNS policy
|
||||
type: str
|
||||
choices: ['relaxed', 'enforced']
|
||||
default: 'relaxed'
|
||||
dns_ip_addresses:
|
||||
description: The dns ip_addresses setting
|
||||
type: list
|
||||
@@ -117,6 +143,9 @@ from ansible.module_utils.ansible_ipa_replica import (
|
||||
gen_ReplicaConfig, gen_remote_api, api, redirect_stdout, dns,
|
||||
ansible_module_get_parsed_ip_addresses
|
||||
)
|
||||
# pylint: disable=unused-import
|
||||
from ansible.module_utils.ansible_ipa_replica import bindinstance # noqa: F401
|
||||
# pylint: enable=unused-import
|
||||
|
||||
|
||||
def main():
|
||||
@@ -135,6 +164,14 @@ def main():
|
||||
choices=['first', 'only'], default=None),
|
||||
no_dnssec_validation=dict(required=False, type='bool',
|
||||
default=False),
|
||||
dot_forwarders=dict(required=False, type='list', elements='str',
|
||||
default=[]),
|
||||
dns_over_tls=dict(required=False, type='bool', default=False),
|
||||
dns_over_tls_cert=dict(required=False, type='str'),
|
||||
dns_over_tls_key=dict(required=False, type='str'),
|
||||
dns_policy=dict(required=False, type='str',
|
||||
choices=['relaxed', 'enforced'],
|
||||
default='relaxed'),
|
||||
# additional
|
||||
dns_ip_addresses=dict(required=True, type='list', elements='str'),
|
||||
dns_reverse_zones=dict(required=True, type='list', elements='str'),
|
||||
@@ -167,6 +204,11 @@ def main():
|
||||
options.forward_policy = ansible_module.params.get('forward_policy')
|
||||
options.no_dnssec_validation = ansible_module.params.get(
|
||||
'no_dnssec_validation')
|
||||
options.dot_forwarders = ansible_module.params.get('dot_forwarders')
|
||||
options.dns_over_tls = ansible_module.params.get('dns_over_tls')
|
||||
options.dns_over_tls_cert = ansible_module.params.get('dns_over_tls_cert')
|
||||
options.dns_over_tls_key = ansible_module.params.get('dns_over_tls_key')
|
||||
options.dns_policy = ansible_module.params.get('dns_policy')
|
||||
# additional
|
||||
dns.ip_addresses = ansible_module_get_parsed_ip_addresses(
|
||||
ansible_module, 'dns_ip_addresses')
|
||||
|
||||
@@ -47,7 +47,7 @@ options:
|
||||
type: str
|
||||
required: no
|
||||
ip_addresses:
|
||||
description: List of Master Server IP Addresses
|
||||
description: List of IPA replica IP addresses
|
||||
type: list
|
||||
elements: str
|
||||
required: no
|
||||
|
||||
@@ -47,7 +47,7 @@ options:
|
||||
type: str
|
||||
required: no
|
||||
ip_addresses:
|
||||
description: List of Master Server IP Addresses
|
||||
description: List of IPA replica IP addresses
|
||||
type: list
|
||||
elements: str
|
||||
required: no
|
||||
|
||||
@@ -38,7 +38,7 @@ short_description: IPA replica deployment tests
|
||||
description: IPA replica deployment tests
|
||||
options:
|
||||
ip_addresses:
|
||||
description: List of Master Server IP Addresses
|
||||
description: List of IPA replica IP addresses
|
||||
type: list
|
||||
elements: str
|
||||
required: no
|
||||
@@ -181,6 +181,32 @@ options:
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
dot_forwarders:
|
||||
description: List of DNS over TLS forwarders
|
||||
type: list
|
||||
elements: str
|
||||
default: []
|
||||
required: no
|
||||
dns_over_tls:
|
||||
description: Configure DNS over TLS
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
dns_over_tls_cert:
|
||||
description:
|
||||
Certificate to use for DNS over TLS. If empty, a new
|
||||
certificate will be requested from IPA CA
|
||||
type: str
|
||||
required: no
|
||||
dns_over_tls_key:
|
||||
description: Key for certificate specified in dns_over_tls_cert
|
||||
type: str
|
||||
required: no
|
||||
dns_policy:
|
||||
description: Encrypted DNS policy
|
||||
type: str
|
||||
choices: ['relaxed', 'enforced']
|
||||
default: 'relaxed'
|
||||
author:
|
||||
- Thomas Woerner (@t-woerner)
|
||||
'''
|
||||
@@ -199,7 +225,8 @@ from ansible.module_utils.ansible_ipa_replica import (
|
||||
paths, sysrestore, ansible_module_get_parsed_ip_addresses, service,
|
||||
redirect_stdout, create_ipa_conf, ipautil,
|
||||
x509, validate_domain_name, common_check,
|
||||
IPA_PYTHON_VERSION, getargspec, adtrustinstance, install_ca_cert
|
||||
IPA_PYTHON_VERSION, getargspec, adtrustinstance, install_ca_cert,
|
||||
services, CLIENT_SUPPORTS_NO_DNSSEC_VALIDATION
|
||||
)
|
||||
|
||||
|
||||
@@ -250,6 +277,14 @@ def main():
|
||||
choices=['first', 'only'], default=None),
|
||||
no_dnssec_validation=dict(required=False, type='bool',
|
||||
default=False),
|
||||
dot_forwarders=dict(required=False, type='list', elements='str',
|
||||
default=[]),
|
||||
dns_over_tls=dict(required=False, type='bool', default=False),
|
||||
dns_over_tls_cert=dict(required=False, type='str'),
|
||||
dns_over_tls_key=dict(required=False, type='str'),
|
||||
dns_policy=dict(required=False, type='str',
|
||||
choices=['relaxed', 'enforced'],
|
||||
default='relaxed'),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -298,6 +333,11 @@ def main():
|
||||
options.forward_policy = ansible_module.params.get('forward_policy')
|
||||
options.no_dnssec_validation = ansible_module.params.get(
|
||||
'no_dnssec_validation')
|
||||
options.dot_forwarders = ansible_module.params.get('dot_forwarders')
|
||||
options.dns_over_tls = ansible_module.params.get('dns_over_tls')
|
||||
options.dns_over_tls_cert = ansible_module.params.get('dns_over_tls_cert')
|
||||
options.dns_over_tls_key = ansible_module.params.get('dns_over_tls_key')
|
||||
options.dns_policy = ansible_module.params.get('dns_policy')
|
||||
|
||||
##########################################################################
|
||||
# replica init ###########################################################
|
||||
@@ -419,6 +459,14 @@ def main():
|
||||
ansible_module.fail_json(
|
||||
msg="You cannot specify a --no-dnssec-validation option "
|
||||
"without the --setup-dns option")
|
||||
if installer.dns_over_tls_cert:
|
||||
ansible_module.fail_json(
|
||||
msg="You cannot specify a --dns-over-tls-cert option "
|
||||
"without the --setup-dns option")
|
||||
if installer.dns_over_tls_key:
|
||||
ansible_module.fail_json(
|
||||
msg="You cannot specify a --dns-over-tls-key option "
|
||||
"without the --setup-dns option")
|
||||
elif installer.forwarders and installer.no_forwarders:
|
||||
ansible_module.fail_json(
|
||||
msg="You cannot specify a --forwarder option together with "
|
||||
@@ -435,6 +483,31 @@ def main():
|
||||
ansible_module.fail_json(
|
||||
msg="You cannot specify a --auto-reverse option together with "
|
||||
"--no-reverse")
|
||||
elif installer.dot_forwarders and not installer.dns_over_tls:
|
||||
ansible_module.fail_json(
|
||||
msg="You cannot specify a --dot-forwarder option "
|
||||
"without the --dns-over-tls option")
|
||||
elif (installer.dns_over_tls
|
||||
and not services.knownservices["unbound"].is_installed()):
|
||||
ansible_module.fail_json(
|
||||
msg="To enable DNS over TLS, package ipa-server-encrypted-dns "
|
||||
"must be installed.")
|
||||
elif installer.dns_policy == "enforced" and not installer.dns_over_tls:
|
||||
ansible_module.fail_json(
|
||||
msg="You cannot specify a --dns-policy option "
|
||||
"without the --dns-over-tls option")
|
||||
elif installer.dns_over_tls_cert and not installer.dns_over_tls:
|
||||
ansible_module.fail_json(
|
||||
msg="You cannot specify a --dns-over-tls-cert option "
|
||||
"without the --dns-over-tls option")
|
||||
elif installer.dns_over_tls_key and not installer.dns_over_tls:
|
||||
ansible_module.fail_json(
|
||||
msg="You cannot specify a --dns-over-tls-key option "
|
||||
"without the --dns-over-tls option")
|
||||
elif bool(installer.dns_over_tls_key) != bool(installer.dns_over_tls_cert):
|
||||
ansible_module.fail_json(
|
||||
msg="You cannot specify a --dns-over-tls-key option "
|
||||
"without the --dns-over-tls-cert option and vice versa")
|
||||
|
||||
# replica installers
|
||||
if installer.servers and not installer.domain_name:
|
||||
@@ -449,6 +522,10 @@ def main():
|
||||
ansible_module.fail_json(
|
||||
msg="You must specify at least one of --forwarder, "
|
||||
"--auto-forwarders, or --no-forwarders options")
|
||||
if installer.dns_over_tls and not installer.dot_forwarders:
|
||||
ansible_module.fail_json(
|
||||
msg="You must specify --dot-forwarder "
|
||||
"when enabling DNS over TLS")
|
||||
|
||||
if installer.dirsrv_config_file is not None and \
|
||||
not os.path.exists(installer.dirsrv_config_file):
|
||||
@@ -486,6 +563,11 @@ def main():
|
||||
if installer.domain_name is not None:
|
||||
validate_domain_name(installer.domain_name)
|
||||
|
||||
if installer.dns_over_tls and not CLIENT_SUPPORTS_NO_DNSSEC_VALIDATION:
|
||||
ansible_module.fail_json(
|
||||
msg="Important patches for DNS over TLS are missing in your "
|
||||
"IPA version.")
|
||||
|
||||
##########################################################################
|
||||
# replica promote_check excerpts #########################################
|
||||
##########################################################################
|
||||
|
||||
@@ -80,6 +80,13 @@ except ImportError:
|
||||
try:
|
||||
from contextlib import contextmanager as contextlib_contextmanager
|
||||
from ipapython.version import NUM_VERSION, VERSION
|
||||
try:
|
||||
from ipapython.version import parse_version
|
||||
except ImportError:
|
||||
# In IPA we either need pkg_resources or packaging Version
|
||||
# class to compare versions with check_remote_version, so
|
||||
# we let an exception to be raised if neither is available.
|
||||
from pkg_resources import parse_version
|
||||
|
||||
if NUM_VERSION < 30201:
|
||||
# See ipapython/version.py
|
||||
@@ -99,8 +106,6 @@ try:
|
||||
import dns.resolver as dnsresolver
|
||||
import dns.reversename as dnsreversename
|
||||
|
||||
from pkg_resources import parse_version
|
||||
|
||||
from ipaclient.install.ipachangeconf import IPAChangeConf
|
||||
from ipalib.install import certstore, sysrestore
|
||||
from ipapython.ipautil import ipa_generate_password
|
||||
@@ -182,6 +187,14 @@ try:
|
||||
from ipaserver.install import ntpinstance
|
||||
time_service = "ntpd" # pylint: disable=invalid-name
|
||||
|
||||
try:
|
||||
CLIENT_SUPPORTS_NO_DNSSEC_VALIDATION = False
|
||||
from ipaclient.install.client import ClientInstallInterface
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
if hasattr(ClientInstallInterface, "no_dnssec_validation"):
|
||||
CLIENT_SUPPORTS_NO_DNSSEC_VALIDATION = True
|
||||
else:
|
||||
# IPA version < 4.6
|
||||
raise RuntimeError("freeipa version '%s' is too old" % VERSION)
|
||||
@@ -208,11 +221,13 @@ def setup_logging():
|
||||
|
||||
@contextlib_contextmanager
|
||||
def redirect_stdout(stream):
|
||||
old_stdout = sys.stdout
|
||||
|
||||
sys.stdout = stream
|
||||
try:
|
||||
yield stream
|
||||
finally:
|
||||
sys.stdout = sys.__stdout__
|
||||
sys.stdout = old_stdout
|
||||
|
||||
|
||||
class AnsibleModuleLog():
|
||||
@@ -331,6 +346,7 @@ options.add_agents = False
|
||||
# ServerReplicaInstall
|
||||
options.subject_base = None
|
||||
options.ca_subject = None
|
||||
|
||||
# pylint: enable=attribute-defined-outside-init
|
||||
|
||||
|
||||
|
||||
@@ -1,33 +1,43 @@
|
||||
---
|
||||
# tasks file for ipareplica
|
||||
|
||||
- name: Package installation
|
||||
- name: Install - Set ipareplica__dns_over_lts
|
||||
ansible.builtin.set_fact:
|
||||
ipareplica__dns_over_tls: "{{ ipareplica_dns_over_tls | default(ipaclient_dns_over_tls) | default(False) }}"
|
||||
|
||||
- name: Install - Package installation
|
||||
when: ipareplica_install_packages | bool
|
||||
block:
|
||||
|
||||
- name: Install - Ensure IPA replica packages are installed
|
||||
ansible.builtin.package:
|
||||
name: "{{ ipareplica_packages }}"
|
||||
state: present
|
||||
- name: Install - Set packages for installation
|
||||
ansible.builtin.set_fact:
|
||||
_ipapackages: "{{ ipareplica_packages }}"
|
||||
|
||||
- name: Install - Ensure IPA replica packages for dns are installed
|
||||
ansible.builtin.package:
|
||||
name: "{{ ipareplica_packages_dns }}"
|
||||
state: present
|
||||
- name: Install - Set packages for installlation, add DNS
|
||||
ansible.builtin.set_fact:
|
||||
_ipapackages: "{{ _ipapackages + ipareplica_packages_dns }}"
|
||||
when: ipareplica_setup_dns | bool
|
||||
|
||||
- name: Install - Ensure IPA replica packages for adtrust are installed
|
||||
ansible.builtin.package:
|
||||
name: "{{ ipareplica_packages_adtrust }}"
|
||||
state: present
|
||||
- name: Install - Set packages for installlation, add DOT
|
||||
ansible.builtin.set_fact:
|
||||
_ipapackages: "{{ _ipapackages + ipareplica_packages_dot }}"
|
||||
when: ipareplica__dns_over_tls | bool
|
||||
|
||||
- name: Install - Set packages for installlation, add adtrust
|
||||
ansible.builtin.set_fact:
|
||||
_ipapackages: "{{ _ipapackages + ipareplica_packages_adtrust }}"
|
||||
when: ipareplica_setup_adtrust | bool
|
||||
|
||||
- name: Install - Ensure that firewall packages installed
|
||||
ansible.builtin.package:
|
||||
name: "{{ ipareplica_packages_firewalld }}"
|
||||
state: present
|
||||
- name: Install - Set packages for installlation, add firewalld
|
||||
ansible.builtin.set_fact:
|
||||
_ipapackages: "{{ _ipapackages + ipareplica_packages_firewalld }}"
|
||||
when: ipareplica_setup_firewalld | bool
|
||||
|
||||
- name: Install - Ensure that packages are installed
|
||||
ansible.builtin.package:
|
||||
name: "{{ _ipapackages }}"
|
||||
state: present
|
||||
|
||||
- name: Firewall configuration
|
||||
when: ipareplica_setup_firewalld | bool
|
||||
block:
|
||||
@@ -104,6 +114,11 @@
|
||||
auto_forwarders: "{{ ipareplica_auto_forwarders }}"
|
||||
forward_policy: "{{ ipareplica_forward_policy | default(omit) }}"
|
||||
no_dnssec_validation: "{{ ipareplica_no_dnssec_validation }}"
|
||||
dot_forwarders: "{{ ipareplica_dot_forwarders | default([]) }}"
|
||||
dns_over_tls: "{{ ipareplica__dns_over_tls }}"
|
||||
dns_over_tls_cert: "{{ ipareplica_dns_over_tls_cert | default(omit) }}"
|
||||
dns_over_tls_key: "{{ ipareplica_dns_over_tls_key | default(omit) }}"
|
||||
dns_policy: "{{ ipareplica_dns_policy | default(omit) }}"
|
||||
register: result_ipareplica_test
|
||||
|
||||
- name: Install - Deploy replica
|
||||
@@ -125,7 +140,10 @@
|
||||
ipaclient_realm: "{{ result_ipareplica_test.realm | default(omit) }}"
|
||||
ipaclient_servers: "{{ ipareplica_servers | default(omit) }}"
|
||||
ipaclient_hostname: "{{ result_ipareplica_test.hostname }}"
|
||||
ipaclient_ip_addresses: "{{ ipareplica_ip_addresses | default(omit) }}"
|
||||
ipaclient_install_packages: "{{ ipareplica_install_packages }}"
|
||||
ipaclient_dns_over_tls: "{{ ipareplica__dns_over_tls }}"
|
||||
ipaclient_no_dnssec_validation: "{{ ipareplica_no_dnssec_validation }}"
|
||||
when: not result_ipareplica_test.client_enrolled
|
||||
|
||||
- name: Install - Configure firewalld
|
||||
@@ -139,6 +157,8 @@
|
||||
{{ "--add-service=freeipa-trust" if result_ipareplica_test.setup_adtrust
|
||||
else "" }}
|
||||
{{ "--add-service=dns" if ipareplica_setup_dns | bool else "" }}
|
||||
{{ "--add-service=dns-over-tls" if ipareplica__dns_over_tls | bool
|
||||
else "" }}
|
||||
{{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }}
|
||||
when: ipareplica_setup_firewalld | bool
|
||||
|
||||
@@ -152,6 +172,8 @@
|
||||
{{ "--add-service=freeipa-trust" if result_ipareplica_test.setup_adtrust
|
||||
else "" }}
|
||||
{{ "--add-service=dns" if ipareplica_setup_dns | bool else "" }}
|
||||
{{ "--add-service=dns-over-tls" if ipareplica__dns_over_tls | bool
|
||||
else "" }}
|
||||
{{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }}
|
||||
when: ipareplica_setup_firewalld | bool
|
||||
|
||||
@@ -200,6 +222,11 @@
|
||||
auto_forwarders: "{{ ipareplica_auto_forwarders }}"
|
||||
forward_policy: "{{ ipareplica_forward_policy | default(omit) }}"
|
||||
no_dnssec_validation: "{{ ipareplica_no_dnssec_validation }}"
|
||||
dot_forwarders: "{{ ipareplica_dot_forwarders | default([]) }}"
|
||||
dns_over_tls: "{{ ipareplica__dns_over_tls }}"
|
||||
dns_over_tls_cert: "{{ ipareplica_dns_over_tls_cert | default(omit) }}"
|
||||
dns_over_tls_key: "{{ ipareplica_dns_over_tls_key | default(omit) }}"
|
||||
dns_policy: "{{ ipareplica_dns_policy | default(omit) }}"
|
||||
### ad trust ###
|
||||
enable_compat: "{{ ipareplica_enable_compat }}"
|
||||
netbios_name: "{{ ipareplica_netbios_name | default(omit) }}"
|
||||
@@ -716,6 +743,11 @@
|
||||
result_ipareplica_prepare.forward_policy is
|
||||
not none else omit }}"
|
||||
no_dnssec_validation: "{{ ipareplica_no_dnssec_validation }}"
|
||||
dot_forwarders: "{{ ipareplica_dot_forwarders | default([]) }}"
|
||||
dns_over_tls: "{{ ipareplica__dns_over_tls }}"
|
||||
dns_over_tls_cert: "{{ ipareplica_dns_over_tls_cert | default(omit) }}"
|
||||
dns_over_tls_key: "{{ ipareplica_dns_over_tls_key | default(omit) }}"
|
||||
dns_policy: "{{ ipareplica_dns_policy | default(omit) }}"
|
||||
### additional ###
|
||||
dns_ip_addresses: "{{ result_ipareplica_prepare.dns_ip_addresses }}"
|
||||
dns_reverse_zones: "{{ result_ipareplica_prepare.dns_reverse_zones }}"
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# defaults file for ipareplica
|
||||
# vars/Fedora-25.yml
|
||||
---
|
||||
ipareplica_packages: [ "ipa-server", "libselinux-python" ]
|
||||
ipareplica_packages_dns: [ "ipa-server-dns" ]
|
||||
ipareplica_packages_adtrust: [ "ipa-server-trust-ad" ]
|
||||
ipareplica_packages_firewalld: [ "firewalld" ]
|
||||
@@ -1,7 +0,0 @@
|
||||
# defaults file for ipareplica
|
||||
# vars/Fedora-26.yml
|
||||
---
|
||||
ipareplica_packages: [ "ipa-server", "libselinux-python" ]
|
||||
ipareplica_packages_dns: [ "ipa-server-dns" ]
|
||||
ipareplica_packages_adtrust: [ "ipa-server-trust-ad" ]
|
||||
ipareplica_packages_firewalld: [ "firewalld" ]
|
||||
@@ -1,7 +0,0 @@
|
||||
# defaults file for ipareplica
|
||||
# vars/Fedora-27.yml
|
||||
---
|
||||
ipareplica_packages: [ "ipa-server", "libselinux-python" ]
|
||||
ipareplica_packages_dns: [ "ipa-server-dns" ]
|
||||
ipareplica_packages_adtrust: [ "ipa-server-trust-ad" ]
|
||||
ipareplica_packages_firewalld: [ "firewalld" ]
|
||||
@@ -3,5 +3,6 @@
|
||||
---
|
||||
ipareplica_packages: [ "freeipa-server", "python3-libselinux" ]
|
||||
ipareplica_packages_dns: [ "freeipa-server-dns" ]
|
||||
ipareplica_packages_dot: [ "freeipa-server-encrypted-dns" ]
|
||||
ipareplica_packages_adtrust: [ "freeipa-server-trust-ad" ]
|
||||
ipareplica_packages_firewalld: [ "firewalld" ]
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
---
|
||||
ipareplica_packages: [ "ipa-server", "libselinux-python" ]
|
||||
ipareplica_packages_dns: [ "ipa-server-dns" ]
|
||||
ipareplica_packages_dot: [ ]
|
||||
ipareplica_packages_adtrust: [ "ipa-server-trust-ad" ]
|
||||
ipareplica_packages_firewalld: [ "firewalld" ]
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
---
|
||||
ipareplica_packages: [ "@idm:DL1/server" ]
|
||||
ipareplica_packages_dns: [ "@idm:DL1/dns" ]
|
||||
ipareplica_packages_dot: [ ]
|
||||
ipareplica_packages_adtrust: [ "@idm:DL1/adtrust" ]
|
||||
ipareplica_packages_firewalld: [ "firewalld" ]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
---
|
||||
ipareplica_packages: [ "freeipa-server" ]
|
||||
ipareplica_packages_dns: [ "freeipa-server-dns" ]
|
||||
ipareplica_packages_dot: [ ]
|
||||
ipareplica_packages_adtrust: [ "freeipa-server-trust-ad" ]
|
||||
ipareplica_packages_firewalld: [ "firewalld" ]
|
||||
# Ubuntu Bionic Beaver must use python2 as Python interpreter due
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
---
|
||||
ipareplica_packages: [ "freeipa-server" ]
|
||||
ipareplica_packages_dns: [ "freeipa-server-dns" ]
|
||||
ipareplica_packages_dot: [ ]
|
||||
ipareplica_packages_adtrust: [ "freeipa-server-trust-ad" ]
|
||||
ipareplica_packages_firewalld: [ "firewalld" ]
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# defaults file for ipareplica
|
||||
# vars/default.yml
|
||||
---
|
||||
ipareplica_packages: [ "freeipa-server", "python3-libselinux" ]
|
||||
ipareplica_packages_dns: [ "freeipa-server-dns" ]
|
||||
ipareplica_packages_adtrust: [ "freeipa-server-trust-ad" ]
|
||||
ipareplica_packages: [ "ipa-server", "python3-libselinux" ]
|
||||
ipareplica_packages_dns: [ "ipa-server-dns" ]
|
||||
ipareplica_packages_dot: [ "ipa-server-encrypted-dns" ]
|
||||
ipareplica_packages_adtrust: [ "ipa-server-trust-ad" ]
|
||||
ipareplica_packages_firewalld: [ "firewalld" ]
|
||||
|
||||
@@ -25,7 +25,7 @@ Supported Distributions
|
||||
|
||||
* RHEL/CentOS 7.6+
|
||||
* CentOS Stream 8+
|
||||
* Fedora 26+
|
||||
* Fedora 40+
|
||||
* Ubuntu 16.04 and 18.04
|
||||
|
||||
|
||||
@@ -343,6 +343,12 @@ Variable | Description | Required
|
||||
`ipaserver_auto_forwarders` | Add DNS forwarders configured in /etc/resolv.conf to the list of forwarders used by IPA DNS. (bool, default: false) | no
|
||||
`ipaserver_forward_policy` | DNS forwarding policy for global forwarders specified using other options. (choice: first, only) | no
|
||||
`ipaserver_no_dnssec_validation` | Disable DNSSEC validation on this server. (bool, default: false) | no
|
||||
`ipaserver_dot_forwarders` | List of DNS over TLS forwarders. Required if `ipaserver_dns_over_tls` is enabled. (list of strings) | no
|
||||
`ipaserver_dns_over_tls` \| `ipaclient_dns_over_tls` | Configure DNS over TLS. Requires FreeIPA version 4.12.5 or later. (bool, default: false) | no
|
||||
`ipaserver_dns_over_tls_cert` | Certificate to use for DNS over TLS. If empty, a new certificate will be requested from IPA CA. (string) | no
|
||||
`ipaserver_dns_over_tls_key` | Key for certificate specified in `ipaserver_dns_over_tls_cert`. (string) | no
|
||||
`ipaserver_dns_policy` | Encrypted DNS policy. Only usable if `ipaserver_dns_over_tls` is enabled. (choice: relaxed, enforced, default: relaxed) | no
|
||||
|
||||
|
||||
AD trust Variables
|
||||
------------------
|
||||
|
||||
@@ -16,10 +16,10 @@ ipaserver_random_serial_numbers: false
|
||||
### client ###
|
||||
ipaclient_mkhomedir: no
|
||||
ipaclient_no_ntp: no
|
||||
#ipaclient_ssh_trust_dns: no
|
||||
#ipaclient_no_ssh: no
|
||||
#ipaclient_no_sshd: no
|
||||
#ipaclient_no_dns_sshfp: no
|
||||
# ipaclient_ssh_trust_dns: no
|
||||
# ipaclient_no_ssh: no
|
||||
# ipaclient_no_sshd: no
|
||||
# ipaclient_no_dns_sshfp: no
|
||||
### certificate system ###
|
||||
ipaserver_external_ca: no
|
||||
### dns ###
|
||||
|
||||
@@ -174,6 +174,32 @@ options:
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
dot_forwarders:
|
||||
description: List of DNS over TLS forwarders
|
||||
type: list
|
||||
elements: str
|
||||
default: []
|
||||
required: no
|
||||
dns_over_tls:
|
||||
description: Configure DNS over TLS
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
dns_over_tls_cert:
|
||||
description:
|
||||
Certificate to use for DNS over TLS. If empty, a new
|
||||
certificate will be requested from IPA CA
|
||||
type: str
|
||||
required: no
|
||||
dns_over_tls_key:
|
||||
description: Key for certificate specified in dns_over_tls_cert
|
||||
type: str
|
||||
required: no
|
||||
dns_policy:
|
||||
description: Encrypted DNS policy
|
||||
type: str
|
||||
choices: ['relaxed', 'enforced']
|
||||
default: 'relaxed'
|
||||
enable_compat:
|
||||
description: Enable support for trusted domains for old clients
|
||||
type: bool
|
||||
@@ -280,6 +306,15 @@ def main():
|
||||
choices=['first', 'only'], default=None),
|
||||
no_dnssec_validation=dict(required=False, type='bool',
|
||||
default=False),
|
||||
dot_forwarders=dict(required=False, type='list', elements='str',
|
||||
default=[]),
|
||||
dns_over_tls=dict(required=False, type='bool',
|
||||
default=False),
|
||||
dns_over_tls_cert=dict(required=False, type='str'),
|
||||
dns_over_tls_key=dict(required=False, type='str'),
|
||||
dns_policy=dict(required=False, type='str',
|
||||
choices=['relaxed', 'enforced'],
|
||||
default='relaxed'),
|
||||
# ad trust
|
||||
enable_compat=dict(required=False, type='bool', default=False),
|
||||
netbios_name=dict(required=False, type='str'),
|
||||
@@ -360,6 +395,11 @@ def main():
|
||||
options.forward_policy = ansible_module.params.get('forward_policy')
|
||||
options.no_dnssec_validation = ansible_module.params.get(
|
||||
'no_dnssec_validation')
|
||||
options.dot_forwarders = ansible_module.params.get('dot_forwarders')
|
||||
options.dns_over_tls = ansible_module.params.get('dns_over_tls')
|
||||
options.dns_over_tls_cert = ansible_module.params.get('dns_over_tls_cert')
|
||||
options.dns_over_tls_key = ansible_module.params.get('dns_over_tls_key')
|
||||
options.dns_policy = ansible_module.params.get('dns_policy')
|
||||
# ad trust
|
||||
options.enable_compat = ansible_module.params.get('enable_compat')
|
||||
options.netbios_name = ansible_module.params.get('netbios_name')
|
||||
|
||||
@@ -83,6 +83,32 @@ options:
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
dot_forwarders:
|
||||
description: List of DNS over TLS forwarders
|
||||
type: list
|
||||
elements: str
|
||||
default: []
|
||||
required: no
|
||||
dns_over_tls:
|
||||
description: Configure DNS over TLS
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
dns_over_tls_cert:
|
||||
description:
|
||||
Certificate to use for DNS over TLS. If empty, a new
|
||||
certificate will be requested from IPA CA
|
||||
type: str
|
||||
required: no
|
||||
dns_over_tls_key:
|
||||
description: Key for certificate specified in dns_over_tls_cert
|
||||
type: str
|
||||
required: no
|
||||
dns_policy:
|
||||
description: Encrypted DNS policy
|
||||
type: str
|
||||
choices: ['relaxed', 'enforced']
|
||||
default: 'relaxed'
|
||||
dns_ip_addresses:
|
||||
description: The dns ip_addresses setting
|
||||
type: list
|
||||
@@ -107,9 +133,13 @@ from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.ansible_ipa_server import (
|
||||
check_imports, AnsibleModuleLog, setup_logging, options, paths, dns,
|
||||
ansible_module_get_parsed_ip_addresses, sysrestore, api_Backend_ldap2,
|
||||
redirect_stdout, bindinstance
|
||||
redirect_stdout
|
||||
)
|
||||
|
||||
# pylint: disable=unused-import
|
||||
from ansible.module_utils.ansible_ipa_server import bindinstance # noqa: F401
|
||||
# pylint: enable=unused-import
|
||||
|
||||
|
||||
def main():
|
||||
ansible_module = AnsibleModule(
|
||||
@@ -130,6 +160,14 @@ def main():
|
||||
default='first'),
|
||||
no_dnssec_validation=dict(required=False, type='bool',
|
||||
default=False),
|
||||
dot_forwarders=dict(required=False, type='list', elements='str',
|
||||
default=[]),
|
||||
dns_over_tls=dict(required=False, type='bool', default=False),
|
||||
dns_over_tls_cert=dict(required=False, type='str'),
|
||||
dns_over_tls_key=dict(required=False, type='str'),
|
||||
dns_policy=dict(required=False, type='str',
|
||||
choices=['relaxed', 'enforced'],
|
||||
default='relaxed'),
|
||||
# additional
|
||||
dns_ip_addresses=dict(required=True, type='list', elements='str'),
|
||||
dns_reverse_zones=dict(required=True, type='list', elements='str'),
|
||||
@@ -158,6 +196,11 @@ def main():
|
||||
options.forward_policy = ansible_module.params.get('forward_policy')
|
||||
options.no_dnssec_validation = ansible_module.params.get(
|
||||
'no_dnssec_validation')
|
||||
options.dot_forwarders = ansible_module.params.get('dot_forwarders')
|
||||
options.dns_over_tls = ansible_module.params.get('dns_over_tls')
|
||||
options.dns_over_tls_cert = ansible_module.params.get('dns_over_tls_cert')
|
||||
options.dns_over_tls_key = ansible_module.params.get('dns_over_tls_key')
|
||||
options.dns_policy = ansible_module.params.get('dns_policy')
|
||||
# additional
|
||||
dns.ip_addresses = ansible_module_get_parsed_ip_addresses(
|
||||
ansible_module, 'dns_ip_addresses')
|
||||
@@ -165,25 +208,16 @@ def main():
|
||||
|
||||
# init ##################################################################
|
||||
|
||||
fstore = sysrestore.FileStore(paths.SYSRESTORE)
|
||||
# pylint: disable=unused-variable
|
||||
fstore = sysrestore.FileStore(paths.SYSRESTORE) # noqa: F841
|
||||
# pylint: enable=unused-variable
|
||||
|
||||
api_Backend_ldap2(options.host_name, options.setup_ca, connect=True)
|
||||
|
||||
# setup dns #############################################################
|
||||
|
||||
with redirect_stdout(ansible_log):
|
||||
if options.setup_dns:
|
||||
dns.install(False, False, options)
|
||||
else:
|
||||
# Create a BIND instance
|
||||
bind = bindinstance.BindInstance(fstore)
|
||||
bind.set_output(ansible_log)
|
||||
bind.setup(options.host_name, options.ip_addresses,
|
||||
options.realm_name,
|
||||
options.domain_name, (), 'first', (),
|
||||
zonemgr=options.zonemgr,
|
||||
no_dnssec_validation=options.no_dnssec_validation)
|
||||
bind.create_file_with_system_records()
|
||||
dns.install(False, False, options)
|
||||
|
||||
# done ##################################################################
|
||||
|
||||
|
||||
@@ -265,6 +265,32 @@ options:
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
dot_forwarders:
|
||||
description: List of DNS over TLS forwarders
|
||||
type: list
|
||||
elements: str
|
||||
default: []
|
||||
required: no
|
||||
dns_over_tls:
|
||||
description: Configure DNS over TLS
|
||||
type: bool
|
||||
default: no
|
||||
required: no
|
||||
dns_over_tls_cert:
|
||||
description:
|
||||
Certificate to use for DNS over TLS. If empty, a new
|
||||
certificate will be requested from IPA CA
|
||||
type: str
|
||||
required: no
|
||||
dns_over_tls_key:
|
||||
description: Key for certificate specified in dns_over_tls_cert
|
||||
type: str
|
||||
required: no
|
||||
dns_policy:
|
||||
description: Encrypted DNS policy
|
||||
type: str
|
||||
choices: ['relaxed', 'enforced']
|
||||
default: 'relaxed'
|
||||
enable_compat:
|
||||
description: Enable support for trusted domains for old clients
|
||||
type: bool
|
||||
@@ -312,7 +338,8 @@ from ansible.module_utils.ansible_ipa_server import (
|
||||
check_dirsrv, ScriptError, get_fqdn, verify_fqdn, BadHostError,
|
||||
validate_domain_name, load_pkcs12, IPA_PYTHON_VERSION,
|
||||
encode_certificate, check_available_memory, getargspec, adtrustinstance,
|
||||
get_min_idstart, SerialNumber
|
||||
get_min_idstart, SerialNumber, services, service,
|
||||
CLIENT_SUPPORTS_NO_DNSSEC_VALIDATION
|
||||
)
|
||||
from ansible.module_utils import six
|
||||
|
||||
@@ -396,6 +423,14 @@ def main():
|
||||
choices=['first', 'only'], default=None),
|
||||
no_dnssec_validation=dict(required=False, type='bool',
|
||||
default=False),
|
||||
dot_forwarders=dict(required=False, type='list', elements='str',
|
||||
default=[]),
|
||||
dns_over_tls=dict(required=False, type='bool', default=False),
|
||||
dns_over_tls_cert=dict(required=False, type='str'),
|
||||
dns_over_tls_key=dict(required=False, type='str'),
|
||||
dns_policy=dict(required=False, type='str',
|
||||
choices=['relaxed', 'enforced'],
|
||||
default='relaxed'),
|
||||
# ad trust
|
||||
enable_compat=dict(required=False, type='bool', default=False),
|
||||
netbios_name=dict(required=False, type='str'),
|
||||
@@ -482,6 +517,11 @@ def main():
|
||||
options.forward_policy = ansible_module.params.get('forward_policy')
|
||||
options.no_dnssec_validation = ansible_module.params.get(
|
||||
'no_dnssec_validation')
|
||||
options.dot_forwarders = ansible_module.params.get('dot_forwarders')
|
||||
options.dns_over_tls = ansible_module.params.get('dns_over_tls')
|
||||
options.dns_over_tls_cert = ansible_module.params.get('dns_over_tls_cert')
|
||||
options.dns_over_tls_key = ansible_module.params.get('dns_over_tls_key')
|
||||
options.dns_policy = ansible_module.params.get('dns_policy')
|
||||
# ad trust
|
||||
options.enable_compat = ansible_module.params.get('enable_compat')
|
||||
options.netbios_name = ansible_module.params.get('netbios_name')
|
||||
@@ -603,6 +643,14 @@ def main():
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --no-dnssec-validation option "
|
||||
"without the --setup-dns option")
|
||||
if self.dns_over_tls_cert:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --dns-over-tls-cert option "
|
||||
"without the --setup-dns option")
|
||||
if self.dns_over_tls_key:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --dns-over-tls-key option "
|
||||
"without the --setup-dns option")
|
||||
elif self.forwarders and self.no_forwarders:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --forwarder option together with "
|
||||
@@ -619,7 +667,31 @@ def main():
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --auto-reverse option together with "
|
||||
"--no-reverse")
|
||||
|
||||
elif self.dot_forwarders and not self.dns_over_tls:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --dot-forwarder option "
|
||||
"without the --dns-over-tls option")
|
||||
elif (self.dns_over_tls
|
||||
and not services.knownservices["unbound"].is_installed()):
|
||||
raise RuntimeError(
|
||||
"To enable DNS over TLS, package ipa-server-encrypted-dns "
|
||||
"must be installed.")
|
||||
elif self.dns_policy == "enforced" and not self.dns_over_tls:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --dns-policy option "
|
||||
"without the --dns-over-tls option")
|
||||
elif self.dns_over_tls_cert and not self.dns_over_tls:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --dns-over-tls-cert option "
|
||||
"without the --dns-over-tls option")
|
||||
elif self.dns_over_tls_key and not self.dns_over_tls:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --dns-over-tls-key option "
|
||||
"without the --dns-over-tls option")
|
||||
elif bool(self.dns_over_tls_key) != bool(self.dns_over_tls_cert):
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --dns-over-tls-key option "
|
||||
"without the --dns-over-tls-cert option and vice versa")
|
||||
if not self.setup_adtrust:
|
||||
if self.add_agents:
|
||||
raise RuntimeError(
|
||||
@@ -677,6 +749,10 @@ def main():
|
||||
raise RuntimeError(
|
||||
"You must specify at least one of --forwarder, "
|
||||
"--auto-forwarders, or --no-forwarders options")
|
||||
if self.dns_over_tls and not self.dot_forwarders:
|
||||
raise RuntimeError(
|
||||
"You must specify --dot-forwarder "
|
||||
"when enabling DNS over TLS")
|
||||
|
||||
any_ignore_option_true = any(
|
||||
[self.ignore_topology_disconnect, self.ignore_last_of_role])
|
||||
@@ -719,6 +795,19 @@ def main():
|
||||
|
||||
# #######################################################################
|
||||
|
||||
if options.dns_over_tls and not CLIENT_SUPPORTS_NO_DNSSEC_VALIDATION:
|
||||
ansible_module.fail_json(
|
||||
msg="Important patches for DNS over TLS are missing in your "
|
||||
"IPA version.")
|
||||
|
||||
client_dns_over_tls = self.dns_over_tls
|
||||
if self.dns_over_tls and not self.setup_dns:
|
||||
service.print_msg("Warning: --dns-over-tls option "
|
||||
"specified without --setup-dns, ignoring")
|
||||
client_dns_over_tls = False
|
||||
|
||||
# #######################################################################
|
||||
|
||||
# If any of the key file options are selected, all are required.
|
||||
cert_file_req = (options.dirsrv_cert_files, options.http_cert_files)
|
||||
cert_file_opt = (options.pkinit_cert_files,)
|
||||
@@ -1208,6 +1297,7 @@ def main():
|
||||
domainlevel=options.domainlevel,
|
||||
sid_generation_always=sid_generation_always,
|
||||
random_serial_numbers=options._random_serial_numbers,
|
||||
client_dns_over_tls=client_dns_over_tls
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
__metaclass__ = type # pylint: disable=invalid-name
|
||||
# pylint: disable=invalid-name
|
||||
__metaclass__ = type
|
||||
# pylint: enable=invalid-name
|
||||
|
||||
__all__ = ["IPAChangeConf", "certmonger", "sysrestore", "root_logger",
|
||||
"ipa_generate_password", "run", "ScriptError", "services",
|
||||
@@ -214,6 +216,14 @@ try:
|
||||
except ImportError:
|
||||
SerialNumber = None
|
||||
|
||||
try:
|
||||
CLIENT_SUPPORTS_NO_DNSSEC_VALIDATION = False
|
||||
from ipaclient.install.client import ClientInstallInterface
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
if hasattr(ClientInstallInterface, "no_dnssec_validation"):
|
||||
CLIENT_SUPPORTS_NO_DNSSEC_VALIDATION = True
|
||||
else:
|
||||
# IPA version < 4.5
|
||||
raise RuntimeError("freeipa version '%s' is too old" % VERSION)
|
||||
@@ -239,11 +249,13 @@ def setup_logging():
|
||||
|
||||
@contextlib_contextmanager
|
||||
def redirect_stdout(stream):
|
||||
old_stdout = sys.stdout
|
||||
|
||||
sys.stdout = stream
|
||||
try:
|
||||
yield stream
|
||||
finally:
|
||||
sys.stdout = sys.__stdout__
|
||||
sys.stdout = old_stdout
|
||||
|
||||
|
||||
class AnsibleModuleLog():
|
||||
|
||||
@@ -1,32 +1,42 @@
|
||||
---
|
||||
# tasks file for ipaserver
|
||||
|
||||
- name: Install - Set ipaserver__dns_over_lts
|
||||
ansible.builtin.set_fact:
|
||||
ipaserver__dns_over_tls: "{{ ipaserver_dns_over_tls | default(ipaclient_dns_over_tls) | default(False) }}"
|
||||
|
||||
- name: Install - Package installation
|
||||
when: ipaserver_install_packages | bool
|
||||
block:
|
||||
- name: Install - Ensure that IPA server packages are installed
|
||||
ansible.builtin.package:
|
||||
name: "{{ ipaserver_packages }}"
|
||||
state: present
|
||||
|
||||
- name: Install - Ensure that IPA server packages for dns are installed
|
||||
ansible.builtin.package:
|
||||
name: "{{ ipaserver_packages_dns }}"
|
||||
state: present
|
||||
- name: Install - Set packages for installation
|
||||
ansible.builtin.set_fact:
|
||||
_ipapackages: "{{ ipaserver_packages }}"
|
||||
|
||||
- name: Install - Set packages for installlation, add DNS
|
||||
ansible.builtin.set_fact:
|
||||
_ipapackages: "{{ _ipapackages + ipaserver_packages_dns }}"
|
||||
when: ipaserver_setup_dns | bool
|
||||
|
||||
- name: Install - Ensure that IPA server packages for adtrust are installed
|
||||
ansible.builtin.package:
|
||||
name: "{{ ipaserver_packages_adtrust }}"
|
||||
state: present
|
||||
- name: Install - Set packages for installlation, add DOT
|
||||
ansible.builtin.set_fact:
|
||||
_ipapackages: "{{ _ipapackages + ipaserver_packages_dot }}"
|
||||
when: ipaserver__dns_over_tls | bool
|
||||
|
||||
- name: Install - Set packages for installlation, add adtrust
|
||||
ansible.builtin.set_fact:
|
||||
_ipapackages: "{{ _ipapackages + ipaserver_packages_adtrust }}"
|
||||
when: ipaserver_setup_adtrust | bool
|
||||
|
||||
- name: Install - Ensure that firewall packages installed
|
||||
ansible.builtin.package:
|
||||
name: "{{ ipaserver_packages_firewalld }}"
|
||||
state: present
|
||||
- name: Install - Set packages for installlation, add firewalld
|
||||
ansible.builtin.set_fact:
|
||||
_ipapackages: "{{ _ipapackages + ipaserver_packages_firewalld }}"
|
||||
when: ipaserver_setup_firewalld | bool
|
||||
|
||||
- name: Install - Ensure that packages are installed
|
||||
ansible.builtin.package:
|
||||
name: "{{ _ipapackages }}"
|
||||
state: present
|
||||
|
||||
- name: Install - Firewall configuration
|
||||
when: ipaserver_setup_firewalld | bool
|
||||
@@ -121,6 +131,11 @@
|
||||
auto_forwarders: "{{ ipaserver_auto_forwarders }}"
|
||||
forward_policy: "{{ ipaserver_forward_policy | default(omit) }}"
|
||||
no_dnssec_validation: "{{ ipaserver_no_dnssec_validation }}"
|
||||
dot_forwarders: "{{ ipaserver_dot_forwarders | default([]) }}"
|
||||
dns_over_tls: "{{ ipaserver__dns_over_tls }}"
|
||||
dns_over_tls_cert: "{{ ipaserver_dns_over_tls_cert | default(omit) }}"
|
||||
dns_over_tls_key: "{{ ipaserver_dns_over_tls_key | default(omit) }}"
|
||||
dns_policy: "{{ ipaserver_dns_policy | default(omit) }}"
|
||||
### ad trust ###
|
||||
enable_compat: "{{ ipaserver_enable_compat }}"
|
||||
netbios_name: "{{ ipaserver_netbios_name | default(omit) }}"
|
||||
@@ -192,6 +207,11 @@
|
||||
auto_forwarders: "{{ ipaserver_auto_forwarders }}"
|
||||
forward_policy: "{{ ipaserver_forward_policy | default(omit) }}"
|
||||
no_dnssec_validation: "{{ ipaserver_no_dnssec_validation }}"
|
||||
dot_forwarders: "{{ ipaserver_dot_forwarders | default([]) }}"
|
||||
dns_over_tls: "{{ ipaserver__dns_over_tls }}"
|
||||
dns_over_tls_cert: "{{ ipaserver_dns_over_tls_cert | default(omit) }}"
|
||||
dns_over_tls_key: "{{ ipaserver_dns_over_tls_key | default(omit) }}"
|
||||
dns_policy: "{{ ipaserver_dns_policy | default(omit) }}"
|
||||
### ad trust ###
|
||||
enable_compat: "{{ ipaserver_enable_compat }}"
|
||||
netbios_name: "{{ ipaserver_netbios_name | default(omit) }}"
|
||||
@@ -381,6 +401,11 @@
|
||||
forward_policy: "{{ result_ipaserver_prepare.forward_policy }}"
|
||||
zonemgr: "{{ ipaserver_zonemgr | default(omit) }}"
|
||||
no_dnssec_validation: "{{ result_ipaserver_prepare.no_dnssec_validation }}"
|
||||
dot_forwarders: "{{ ipaserver_dot_forwarders | default([]) }}"
|
||||
dns_over_tls: "{{ ipaserver__dns_over_tls }}"
|
||||
dns_over_tls_cert: "{{ ipaserver_dns_over_tls_cert | default(omit) }}"
|
||||
dns_over_tls_key: "{{ ipaserver_dns_over_tls_key | default(omit) }}"
|
||||
dns_policy: "{{ ipaserver_dns_policy | default(omit) }}"
|
||||
### additional ###
|
||||
dns_ip_addresses: "{{ result_ipaserver_prepare.dns_ip_addresses }}"
|
||||
dns_reverse_zones: "{{ result_ipaserver_prepare.dns_reverse_zones }}"
|
||||
@@ -432,6 +457,7 @@
|
||||
ipaclient_no_ntp:
|
||||
"{{ 'true' if result_ipaserver_test.ipa_python_version >= 40690
|
||||
else 'false' }}"
|
||||
ipaclient_dns_over_tls: "{{ result_ipaserver_test.client_dns_over_tls }}"
|
||||
ipaclient_install_packages: no
|
||||
|
||||
- name: Install - Enable IPA
|
||||
@@ -452,6 +478,8 @@
|
||||
{{ "--add-service=freeipa-trust" if ipaserver_setup_adtrust | bool
|
||||
else "" }}
|
||||
{{ "--add-service=dns" if ipaserver_setup_dns | bool else "" }}
|
||||
{{ "--add-service=dns-over-tls" if ipaserver__dns_over_tls | bool
|
||||
else "" }}
|
||||
{{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }}
|
||||
when: ipaserver_setup_firewalld | bool
|
||||
|
||||
@@ -465,6 +493,8 @@
|
||||
{{ "--add-service=freeipa-trust" if ipaserver_setup_adtrust | bool
|
||||
else "" }}
|
||||
{{ "--add-service=dns" if ipaserver_setup_dns | bool else "" }}
|
||||
{{ "--add-service=dns-over-tls" if ipaserver__dns_over_tls | bool
|
||||
else "" }}
|
||||
{{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }}
|
||||
when: ipaserver_setup_firewalld | bool
|
||||
|
||||
|
||||
@@ -54,8 +54,3 @@
|
||||
# 1 means that uninstall failed because IPA server was not configured
|
||||
failed_when: uninstall.rc != 0 and uninstall.rc != 1
|
||||
changed_when: uninstall.rc == 0
|
||||
|
||||
#- name: Remove IPA server packages
|
||||
# ansible.builtin.package:
|
||||
# name: "{{ ipaserver_packages }}"
|
||||
# state: absent
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# defaults file for ipaserver
|
||||
# vars/Fedora-25.yml
|
||||
---
|
||||
ipaserver_packages: [ "ipa-server", "libselinux-python" ]
|
||||
ipaserver_packages_dns: [ "ipa-server-dns" ]
|
||||
ipaserver_packages_adtrust: [ "ipa-server-trust-ad" ]
|
||||
ipaserver_packages_firewalld: [ "firewalld" ]
|
||||
@@ -1,7 +0,0 @@
|
||||
# defaults file for ipaserver
|
||||
# vars/Fedora-26.yml
|
||||
---
|
||||
ipaserver_packages: [ "ipa-server", "libselinux-python" ]
|
||||
ipaserver_packages_dns: [ "ipa-server-dns" ]
|
||||
ipaserver_packages_adtrust: [ "ipa-server-trust-ad" ]
|
||||
ipaserver_packages_firewalld: [ "firewalld" ]
|
||||
@@ -1,7 +0,0 @@
|
||||
# defaults file for ipaserver
|
||||
# vars/Fedora-27.yml
|
||||
---
|
||||
ipaserver_packages: [ "ipa-server", "libselinux-python" ]
|
||||
ipaserver_packages_dns: [ "ipa-server-dns" ]
|
||||
ipaserver_packages_adtrust: [ "ipa-server-trust-ad" ]
|
||||
ipaserver_packages_firewalld: [ "firewalld" ]
|
||||
@@ -3,5 +3,6 @@
|
||||
---
|
||||
ipaserver_packages: [ "freeipa-server", "python3-libselinux" ]
|
||||
ipaserver_packages_dns: [ "freeipa-server-dns" ]
|
||||
ipaserver_packages_dot: [ "freeipa-server-encrypted-dns" ]
|
||||
ipaserver_packages_adtrust: [ "freeipa-server-trust-ad" ]
|
||||
ipaserver_packages_firewalld: [ "firewalld" ]
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
---
|
||||
ipaserver_packages: [ "ipa-server", "libselinux-python" ]
|
||||
ipaserver_packages_dns: [ "ipa-server-dns" ]
|
||||
ipaserver_packages_dot: [ ]
|
||||
ipaserver_packages_adtrust: [ "ipa-server-trust-ad" ]
|
||||
ipaserver_packages_firewalld: [ "firewalld" ]
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
---
|
||||
ipaserver_packages: [ "@idm:DL1/server" ]
|
||||
ipaserver_packages_dns: [ "@idm:DL1/dns" ]
|
||||
ipaserver_packages_dot: [ ]
|
||||
ipaserver_packages_adtrust: [ "@idm:DL1/adtrust" ]
|
||||
ipaserver_packages_firewalld: [ "firewalld" ]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
---
|
||||
ipaserver_packages: [ "freeipa-server" ]
|
||||
ipaserver_packages_dns: [ "freeipa-server-dns" ]
|
||||
ipaserver_packages_dot: [ ]
|
||||
ipaserver_packages_adtrust: [ "freeipa-server-trust-ad" ]
|
||||
ipaserver_packages_firewalld: [ "firewalld" ]
|
||||
# Ubuntu Bionic Beaver must use python2 as Python interpreter due
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user