Compare commits

...

32 Commits

Author SHA1 Message Date
Thomas Woerner
6d328caa59 ipaserver_test: Treat host, domain and realm settings in the same was as the cli
The code for host_name, the domain_name and also the realm_name has been
adapted to the code in the command line installer. The _hostname_overridden
setting is now only true if the hostname has been changed.
2019-06-07 17:59:12 +02:00
Thomas Woerner
6fe001e804 ipaserver: Only use install checks in _prepare, not also in _test
The install checks have been done temporarily in _test and finally also
in _prepare. This is not needed and also not done this way in the command
line installers.
2019-06-07 17:57:17 +02:00
Thomas Woerner
e1aa9641a4 ipaserver: Add log, debug and info to AnsibleModuleLog
This makes AnsibleModuleLog compatible to the version in ipareplica role.
2019-06-07 17:48:19 +02:00
Thomas Woerner
7d43c861bb ipaserver: Add support for pki_config_override
The addtion is not oly adding the config setting, but also fixing the
deployment without the setting as functions and methods have been changed
for pki_config_override.

There is a new setting for the ipaserver role:

ipaserver_pki_config_override
2019-06-07 17:45:16 +02:00
Thomas Woerner
df65de902d ipaserver_setup_http: Only use tasks.restore_context for old releases
tasks.restore_context is only used in old releases. The existence of
paths.CACHE_IPA_SESSIONS is used to determine if the call needs to be
done or not.
2019-06-07 17:39:41 +02:00
Thomas Woerner
46925086b7 ipaserver: Remove old section for client side deployment using command line
The section is not used since a long time any more and can therefore be
removed.
2019-06-07 17:28:29 +02:00
Thomas Woerner
9a53e71de8 ipaclient_test: Use validate_hostname with constants.MAXHOSTNAMELEN
Run validate_hostname to check for valid host name if constants.MAXHOSTNAMELEN
is defined. The call has not been used in older FreeIPA versions.
2019-06-07 17:25:12 +02:00
Thomas Woerner
c82867585b Increase minimal Ansible version to 2.8
ansible-freeipa is a new Ansible Collection introduced with Ansible 2.8 and
Ansible Galaxy 3.2.
2019-06-05 17:55:21 +02:00
Thomas Woerner
2717fc6ca4 New galaxy.yml file for Ansible 2.8 and Ansible Galaxy 3.2
Dashes in names are not allowed in Galaxy and are automatically replaced
by underscores. Therefore the name in Galaxy is ansible_freeipa.
2019-06-05 17:50:38 +02:00
Thomas Woerner
62fd4cc157 New topology managament modules
There are now two topology management modules placed in the plugins folder:

  plugins/modules/ipatopologysegment.py
  plugins/modules/ipatopologysuffix.py

Topology segments can be added, removed and reinitialized with the
ipatopologysegment module. Also it is possible to verify topology suffixes
with the ipatopologysuffix module.

A new module_utils for plugins has been added:

  plugins/module_utils/ansible_freeipa_module.py

And documentation for the modules:

  README-topology.md

New sample playbooks are available in playbooks/topology:

  playbooks/topology/add-topologysegment.yml
  playbooks/topology/delete-topologysegment.yml
  playbooks/topology/reinitialize-topologysegment.yml
  playbooks/topology/verify-topologysuffix.yml

The plugins folder can be used with the new Ansible Collections supported
by Ansible 2.8 and Ansible galaxy 3.2.
2019-06-05 17:45:39 +02:00
Thomas Woerner
c822423b14 Move role documentation into the specific role locations as README.md
This will result in a better role documentation on galaxy.
2019-06-05 16:38:12 +02:00
Thomas Woerner
9c2b995724 New playbook folder for sample playbooks
The playbooks install-client.yml, install-cluster.yml, install-replica.yml,
install-server.yml, uninstall-client.yml, uninstall-cluster.yml,
uninstall-replica.yml and uninstall-server.yml have been moved into
the playbooks folder.
2019-06-05 15:47:21 +02:00
Thomas Woerner
b51397eb89 ipa[server,replica,client]: Deactivate Python2/3 test
This test is not properly working with EL-8 nodes as the default system
python is not located in /usr/bin. Additionally Ansible 2.8 is able to
detect the default python version on the system. As the installation
base for IPA 4.5.90 where the Python 3 bindings have not been working
properly should be really small or not existing any more the deactivation
of this test should be fine.
2019-06-04 11:58:52 +02:00
Thomas Woerner
2dc2799883 ipareplica: Use result from ipareplica_test for freeipa-trust enablement
The result from ipareplica_test should be used to enable freeipa-trust
in the firewall.
2019-06-04 11:47:11 +02:00
Thomas Woerner
5057b3cfe0 ipareplica: Add support for hidden replica
The hidden replica support introduced some incompatible changes to replica
deployment. The methods find_providing_server and find_providing_serves
have been moved from ipaserver.install.service to ipaserver.masters.
Additionally the host_name argument for find_providing_server is a list
now. This breaks existing ipareplica Ansible modules ipareplica_prepare
and ipareplica_enable_ipa.
2019-05-31 18:05:02 +02:00
Thomas Woerner
5951b954be ipa[server,replica]: Enable freeipa-trust service if adtrust is enabled
The freeipa-trust service has not been added if adtrust was enabled. For
ipareplica the addition of freeipa-replication has been removed as the
used port is not used anymore since some time.

Fixes: #83 (when installing with ipaserver_setup_adtrust: true the firewalld
service freeipa-trust is not added)
2019-05-31 18:04:07 +02:00
Thomas Woerner
69b894a7e5 ipareplica: Disable automatic removal of replication agreements in uninstall
Replication agreements are not removed with the command line tools.
2019-05-31 17:47:05 +02:00
Thomas Woerner
bb591f33dd roles/ipareplica/tasks/uninstall.yml: Add changed_when for uninstall
This calms down ansible-lint in Ansible galaxy.
2019-05-31 17:44:36 +02:00
Thomas Woerner
1a3f72b1f4 roles/ipareplica/tasks/install.yml: Drop unused ipareplica_backend_disconnect 2019-05-31 17:43:06 +02:00
Thomas Woerner
ab1b4bc6ba roles/ipareplica/library/ipareplica_prepare.py: Drop double sstore and fstore
sstore and fstore have been set twice.
2019-05-31 17:36:14 +02:00
Thomas Woerner
6b4f0f62de roles/ipareplica/library/ipareplica_enable_ipa.py: Do not use textwrap 2019-05-31 17:33:54 +02:00
Thomas Woerner
dd321b2065 ipa[server,replica]: Fix wrong ansible argment types
This fixes the type warnings while deploying server and replica.
2019-05-31 17:29:59 +02:00
Thomas Woerner
9397776501 ipaclient/tasks/install.yml: Save and restore ipaadmin_password with OTP
The generated OTP password is stored into ipaadmin_password. The original
password is now saved and restored later on again.

This fixes the failure with incorrect password while installing the client
part in a replica deployment.
2019-05-31 17:22:56 +02:00
Thomas Woerner
be04079fc7 ipaclient/tasks/install.yml: Disable One-Time Password for on_master
if _on_master is set, deactivate _get_otp as OTP is not needed at all
for the client side install part on a master.
2019-05-31 17:21:26 +02:00
Thomas Woerner
5bdaa9aa6f ipaclient/action_plugins/ipaclient_get_otp: Only require gssapi for keytab
gssapi is only needed for OTP if keytab is used. The common case with
password does not require gssapi.

This change also fixes the new ansible 2.8 failure if gssapi is not
installed on the controller. Ansible 2.8 seems to also transfer and load
action plugins to the node if they are not used.
2019-05-31 17:19:05 +02:00
Thomas Woerner
1b1198a091 Merge pull request #84 from obscureorganization/better-gitignore
Ignore "*.retry" and "*.pyc" files
2019-05-31 16:40:42 +02:00
Thomas Woerner
bdf3ad4a9c Merge pull request #81 from spoore1/length_fix
ipaclient install role length typo
2019-05-31 16:39:30 +02:00
Thomas Woerner
939f10eeff Merge pull request #80 from branic/fix_empty_ipaservers
Fix errors when ipaservers variable is not set
2019-05-31 16:39:09 +02:00
Richard Bullington-McGuire
eded3b4cfd Ignore "*.retry" and "*.pyc" files
These may get left behind by runtime processes and should never get
committed to the repository.
2019-05-27 20:44:52 +00:00
Thomas Woerner
58e1f03bcb Update README.md
Fixed wrong use of ipareplica name in ipaclient inventory examples.
Added tier1 and tier2 replica handling.
2019-05-14 17:38:20 +02:00
Scott Poore
e0c85c5af4 ipaclient install role length typo
Correcting small typo for lenth to length in a check
2019-05-13 11:07:06 -05:00
Brant Evans
34ce174d55 Fix errors when ipaservers variable is not set 2019-05-08 16:08:24 -06:00
53 changed files with 1088 additions and 281 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.pyc
*.retry

154
README-topology.md Normal file
View File

@@ -0,0 +1,154 @@
Topology modules
================
Description
-----------
These modules allow to manage the topology. That means that topology segments can be added, removed and reinitialized. Also it is possible to verify topology suffixes.
Features
--------
* Topology management
Supported FreeIPA Versions
--------------------------
FreeIPA versions 4.4.0 and up are supported by the ipatopologysegment and ipatopologysuffix modules.
Requirements
------------
**Controller**
* Ansible version: 2.8+
**Node**
* Supported FreeIPA version (see above)
Usage
=====
Example inventory file
```ini
[ipaserver]
ipaserver.test.local
```
Example playbook to add a topology segment wiht default name (cn):
```yaml
---
- name: Playbook to handle topologysegment
hosts: ipaserver
become: true
tasks:
- name: Add topology segment
ipatopologysegment:
password: MyPassword123
suffix: domain
left: ipareplica1.test.local
right: ipareplica2.test.local
state: present
```
The name (cn) can also be set if it should not be the default `{left}-to-{rkight}`.
Example playbook to delete a topology segment:
```yaml
---
- name: Playbook to handle topologysegment
hosts: ipaserver
become: true
tasks:
- name: Delete topology segment
ipatopologysegment:
password: MyPassword123
suffix: domain
left: ipareplica1.test.local
right: ipareplica2.test.local
state: absent
```
It is possible to either use the name (cn) or left and right nodes. If left and right nodes are used, then the name will be searched and used internally.
Example playbook to reinitialize a topology segment:
```yaml
---
- name: Playbook to handle topologysegment
hosts: ipaserver
become: true
tasks:
- name: Reinitialize topology segment
ipatopologysegment:
password: MyPassword123
suffix: domain
left: ipareplica1.test.local
right: ipareplica2.test.local
direction: left-to-right
state: reinitialized
```
It is possible to either use the name (cn) or left and right nodes. If left and right nodes are used, then the name will be searched and used internally.
Example playbook to verify a topology suffix:
```yaml
---
- name: Playbook to handle topologysuffix
hosts: ipaserver
become: true
tasks:
- name: Verify topology suffix
ipatopologysuffix:
password: MyPassword123
suffix: domain
state: verified
```
Variables
=========
ipatopologysegment
------------------
Variable | Description | Required
-------- | ----------- | --------
`principal` | The admin principal is a string and defaults to `admin` | no
`password` | The admin password is a string and is required if there is no admin ticket available on the node | no
`suffix` | The topology suffix to be used, this can either be `domain` or `ca` | yes
`name` \| `cn` | The topology segment name (cn) is the unique identifier for a segment. | no
`left` \| `leftnode` | The left replication node string - an IPA server | no
`right` \| `rightnode` | The right replication node string - an IPA server | no
`direction` | The direction a segment will be reinitialized. It can either be `left-to-right` or `right-to-left` and only used with `state: reinitialized` |
`state` | The state to ensure. It can be one of `present`, `absent`, `enabled`, `disabled` or `reinitialized` | yes
ipatopologysuffix
-----------------
Verify FreeIPA topology suffix
Variable | Description | Required
-------- | ----------- | --------
`principal` | The admin principal is a string and defaults to `admin` | no
`password` | The admin password is a string and is required if there is no admin ticket available on the node | no
`suffix` | The topology suffix to be used, this can either be `domain` or `ca` | yes
`state` | The state to ensure. It can only be `verified` | yes
Authors
=======
Thomas Woerner

View File

@@ -11,6 +11,7 @@ Features
* Cluster deployments: Server, replicas and clients in one playbook
* One-time-password (OTP) support for client installation
* Repair mode for clients
* Modules for topology management
Supported FreeIPA Versions
--------------------------
@@ -30,8 +31,8 @@ Requirements
------------
**Controller**
* Ansible version: 2.5+
* python3-gssapi is required on the controller if a one time password (OTP) is used to install the client.
* Ansible version: 2.8+ (ansible-freeipa is an Ansible Collection)
* python3-gssapi is required on the controller if a one time password (OTP) is used with keytab to install the client.
**Node**
* Supported FreeIPA version (see above)
@@ -121,12 +122,34 @@ This will create a chain from ```ipaserver.test.local <- ipareplica1.test.local
If you need to set more than one server for a replica (for fallbacks etc.), simply use a comma separated list for ```ipareplica_servers```:
```yaml
[ipareplicas]
[ipareplicas_tier1]
ipareplica1.test.local
[ipareplicas_tier2]
ipareplica2.test.local ipareplica_servers=ipareplica1.test.local,ipaserver.test.local
```
The first entry in ```ipareplica_servers``` will be used as the master.
In this case you need to have separate tasks in the playbook to first deploy replicas from tier1 and then replicas from tier2:
```yaml
---
- name: Playbook to configure IPA replicas (tier1)
hosts: ipareplicas_tier1
become: true
roles:
- role: ipareplica
state: present
- name: Playbook to configure IPA replicas (tier2)
hosts: ipareplicas_tier2
become: true
roles:
- role: ipareplica
state: present
```
You can add settings for replica deployment:
```yaml
[ipareplicas:vars]
@@ -179,7 +202,7 @@ If you need to set more than one server for a client (for fallbacks etc.), simpl
You can add settings for client deployment:
```yaml
[ipareplicas:vars]
[ipaclients:vars]
ipaadmin_password=ADMPassword1
ipaserver_domain=test.local
ipaserver_realm=TEST.LOCAL
@@ -188,7 +211,7 @@ ipaserver_realm=TEST.LOCAL
For enhanced security it is possible to use a auto-generated one-time-password (OTP). This will be generated on the controller using the (first) server. It is needed to have the Python gssapi bindings installed on the controller for this.
To enable the generation of the one-time-password:
```yaml
[ipareplicas:vars]
[ipaclients:vars]
ipaclient_use_otp=yes
```
@@ -214,16 +237,17 @@ All these settings will be available in the ```[ipaserver]```, ```[ipareplicas]`
Playbooks
=========
The playbooks needed to deploy or undeploy server, replicas and clients are part of the repository. There are also playbooks to deploy and undeploy clusters. With them it is only needed to add an inventory file:
The playbooks needed to deploy or undeploy server, replicas and clients are part of the repository and placed in the playbooks folder. There are also playbooks to deploy and undeploy clusters. With them it is only needed to add an inventory file:
```
install-client.yml
install-cluster.yml
install-replica.yml
install-server.yml
uninstall-client.yml
uninstall-cluster.yml
uninstall-replica.yml
uninstall-server.yml
playbooks\
install-client.yml
install-cluster.yml
install-replica.yml
install-server.yml
uninstall-client.yml
uninstall-cluster.yml
uninstall-replica.yml
uninstall-server.yml
```
How to deploy a master server
@@ -281,6 +305,12 @@ This will deploy the server, replicas and clients defined in the inventory file.
Roles
=====
* [Server](SERVER.md)
* [Replica](REPLICA.md)
* [Client](CLIENT.md)
* [Server](roles/ipaserver/README.md)
* [Replica](roles/ipareplica/README.md)
* [Client](roles/ipaclient/README.md)
Plugins in plugin/modules
=========================
* [ipatopologysegment](README-topology.md)
* [ipatopologysuffix](README-topology.md)

25
galaxy.yml Normal file
View File

@@ -0,0 +1,25 @@
namespace: "freeipa"
name: "ansible_freeipa"
version: "0.1.1"
description: ""
authors:
- "Thomas Woerner <twoerner@redhat.com>"
repository: "https://github.com/freeipa/ansible-freeipa"
documentation: "https://github.com/freeipa/ansible-freeipa/blob/master/README.md"
homepage: "https://github.com/freeipa/ansible-freeipa"
issues: "https://github.com/freeipa/ansible-freeipa/issues"
dependencies: {}
readme: "README.md"
license: "GPL-3.0-or-later"
license_file: "COPYING"
tags:
- "identity"
- "ipa"
- "freeipa"
- "cluster"
- "collection"

View File

@@ -0,0 +1,13 @@
---
- name: Playbook to handle topologysegment
hosts: ipaserver
become: true
tasks:
- name: Add topology segment
ipatopologysegment:
password: MyPassword123
suffix: domain
left: ipareplica1.test.local
right: ipareplica2.test.local
state: present

View File

@@ -0,0 +1,13 @@
---
- name: Playbook to handle topologysegment
hosts: ipaserver
become: true
tasks:
- name: Delete topology segment
ipatopologysegment:
password: MyPassword123
suffix: domain
left: ipareplica1.test.local
right: ipareplica2.test.local
state: absent

View File

@@ -0,0 +1,14 @@
---
- name: Playbook to handle topologysegment
hosts: ipaserver
become: true
tasks:
- name: Reinitialize topology segment
ipatopologysegment:
password: MyPassword123
suffix: domain
left: ipareplica1.test.local
right: ipareplica2.test.local
direction: left-to-right
state: reinitialized

View File

@@ -0,0 +1,11 @@
---
- name: Playbook to handle topologysuffix
hosts: ipaserver
become: true
tasks:
- name: Verify topology suffix
ipatopologysuffix:
password: MyPassword123
suffix: domain
state: verified

View File

@@ -0,0 +1,122 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# Copyright (C) 2019 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import tempfile
import shutil
from ipalib import api, errors
from ipalib.config import Env
from ipalib.constants import DEFAULT_CONFIG
try:
from ipalib.install.kinit import kinit_password
except ImportError:
from ipapython.ipautil import kinit_password
from ipapython.ipautil import run
from ipaplatform.paths import paths
from ipalib.krb_utils import get_credentials_if_valid
def valid_creds(principal):
"""
Get valid credintials matching the princial
"""
creds = get_credentials_if_valid()
if creds and \
creds.lifetime > 0 and \
"%s@" % principal in creds.name.display_as(creds.name.name_type):
return True
return False
def temp_kinit(principal, password):
"""
kinit with password using a temporary ccache
"""
if not password:
raise RuntimeError("The password is not set")
if not principal:
principal = "admin"
ccache_dir = tempfile.mkdtemp(prefix='krbcc')
ccache_name = os.path.join(ccache_dir, 'ccache')
try:
kinit_password(principal, password, ccache_name)
except RuntimeError as e:
raise RuntimeError("Kerberos authentication failed: {}".format(e))
return ccache_dir, ccache_name
def temp_kdestroy(ccache_dir, ccache_name):
"""
Destroy temporary ticket and remove temporary ccache
"""
if ccache_name is not None:
run([paths.KDESTROY, '-c', ccache_name], raiseonerr=False)
if ccache_dir is not None:
shutil.rmtree(ccache_dir, ignore_errors=True)
def api_connect():
"""
Create environment, initialize api and connect to ldap2
"""
env = Env()
env._bootstrap()
env._finalize_core(**dict(DEFAULT_CONFIG))
api.bootstrap(context='server', debug=env.debug, log=None)
api.finalize()
api.Backend.ldap2.connect()
def api_command(module, command, name, args):
"""
Call ipa.Command, use AnsibleModule.fail_json for error handling
"""
try:
return api.Command[command](name, **args)
except Exception as e:
module.fail_json(msg="%s: %s" % (command, e))
def execute_api_command(module, principal, password, command, name, args):
"""
Get KRB ticket if not already there, initialize api, connect,
execute command and destroy ticket again if it has been created also.
"""
ccache_dir = None
ccache_name = None
try:
if not valid_creds(principal):
ccache_dir, ccache_name = temp_kinit(principal, password)
api_connect()
return api_command(module, command, name, args)
except Exception as e:
module.fail_json(msg=str(e))
finally:
temp_kdestroy(ccache_dir, ccache_name)

View File

@@ -0,0 +1,288 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# Copyright (C) 2019 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
ANSIBLE_METADATA = {
"metadata_version": "1.0",
"supported_by": "community",
"status": ["preview"],
}
DOCUMENTATION = """
---
module: ipatopologysegment
short description: Manage FreeIPA topology segments
description: Manage FreeIPA topology segments
options:
principal:
description: The admin principal
default: admin
password:
description: The admin password
required: false
suffix:
description: Topology suffix
required: true
choices: ["domain", "ca"]
name:
description: Topology segment name, unique identifier.
required: false
aliases: ["cn"]
left:
description: Left replication node - an IPA server
aliases: ["leftnode"]
right:
description: Right replication node - an IPA server
aliases: ["rightnode"]
direction:
description: The direction a segment will be reinitialized
required: false
choices: ["left-to-right", "right-to-left"]
state:
description: State to ensure
default: present
choices: ["present", "absent", "enabled", "disabled", "reinitialized"]
author:
- Thomas Woerner
"""
EXAMPLES = """
- ipatopologysegment:
suffix: domain
left: ipaserver.test.local
right: ipareplica1.test.local
state: present
- ipatopologysegment:
suffix: domain
name: ipaserver.test.local-to-replica1.test.local
state: absent
- ipatopologysegment:
suffix: domain
left: ipaserver.test.local
right: ipareplica1.test.local
state: absent
- ipatopologysegment:
suffix: ca
name: ipaserver.test.local-to-replica1.test.local
direction: left-to-right
state: reinitialized
"""
RETURN = """
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_bytes, to_native, to_text
from ansible.module_utils.ansible_freeipa_module import temp_kinit, \
temp_kdestroy, valid_creds, api_connect, api_command
def find_left_right(module, suffix, left, right):
_args = {
"iparepltoposegmentleftnode": to_text(left),
"iparepltoposegmentrightnode": to_text(right),
}
_result = api_command(module, "topologysegment_find",
to_text(suffix), _args)
if len(_result["result"]) > 1:
module.fail_json(
msg="Combination of left node '%s' and right node '%s' is "
"not unique for suffix '%s'" % (left, right, suffix))
elif len(_result["result"]) == 1:
return _result["result"][0]
else:
return None
def find_cn(module, suffix, name):
_args = {
"cn": to_text(name),
}
_result = api_command(module, "topologysegment_find",
to_text(suffix), _args)
if len(_result["result"]) > 1:
module.fail_json(
msg="CN '%s' is not unique for suffix '%s'" % (name, suffix))
elif len(_result["result"]) == 1:
return _result["result"][0]
else:
return None
def main():
ansible_module = AnsibleModule(
argument_spec=dict(
principal=dict(type="str", default="admin"),
password=dict(type="str", required=False, no_log=True),
suffix=dict(choices=["domain", "ca"], required=True),
name=dict(type="str", aliases=["cn"], default=None),
left=dict(type="str", aliases=["leftnode"], default=None),
right=dict(type="str", aliases=["rightnode"], default=None),
direction=dict(type="str", default=None,
choices=["left-to-right", "right-to-left"]),
state=dict(type="str", default="present",
choices=["present", "absent", "enabled", "disabled",
"reinitialized"]),
),
supports_check_mode=True,
)
ansible_module._ansible_debug = True
# Get parameters
principal = ansible_module.params.get("principal")
password = ansible_module.params.get("password")
suffix = ansible_module.params.get("suffix")
name = ansible_module.params.get("name")
left = ansible_module.params.get("left")
right = ansible_module.params.get("right")
direction = ansible_module.params.get("direction")
state = ansible_module.params.get("state")
# Check parameters
if state != "reinitialized" and direction is not None:
ansible_module.fail_json(
msg="Direction is not supported in this mode.")
# Init
changed = False
ccache_dir = None
ccache_name = None
try:
if not valid_creds(principal):
ccache_dir, ccache_name = temp_kinit(principal, password)
api_connect()
command = None
# Get name (cn) from left and right node if set for absent, disabled
# or reinitialized.
if state in ["absent", "disabled", "reinitialized"]:
if left is not None and right is not None:
left_right = find_left_right(ansible_module, suffix,
left, right)
if left_right is not None:
if name is not None and \
left_right["cn"][0] != to_text(name):
ansible_module.fail_json(
msg="Left and right nodes do not match "
"given name name (cn) '%s'" % name)
args = {
"cn": left_right["cn"][0]
}
# else: Nothing to change
elif name is not None:
result = find_cn(ansible_module, suffix, name)
if result is not None:
args = {
"cn": result["cn"][0]
}
# else: Nothing to change
else:
ansible_module.fail_json(
msg="Either left and right or name need to be set.")
# Create command
if state in ["present", "enabled"]:
# Make sure topology segment exists
if left is None or right is None:
ansible_module.fail_json(
msg="Left and right need to be set.")
args = {
"iparepltoposegmentleftnode": to_text(left),
"iparepltoposegmentrightnode": to_text(right),
}
if name is not None:
args["cn"] = to_text(name)
res_left_right = find_left_right(ansible_module, suffix,
left, right)
if res_left_right is not None:
if name is not None and \
res_left_right["cn"][0] != to_text(name):
ansible_module.fail_json(
msg="Left and right nodes already used with "
"different name (cn) '%s'" % res_left_right["cn"])
# Left and right nodes and also the name can not be
# changed
for key in [ "iparepltoposegmentleftnode",
"iparepltoposegmentrightnode" ]:
if key in args:
del args[key]
if len(args) > 1:
# cn needs to be in args always
command = "topologysegment_mod"
# else: Nothing to change
else:
if name is None:
args["cn"] = to_text("%s-to-%s" % (left, right))
command = "topologysegment_add"
elif state in ["absent", "disabled"]:
# Make sure topology segment does not exist
if len(args) > 0:
# Either name defined or found name from left and right node
command = "topologysegment_del"
elif state == "reinitialized":
# Reinitialize segment
if len(args) > 0:
# Either name defined or found name from left and right node
command = "topologysegment_reinitialize"
if direction == "left-to-right":
args["left"] = True
elif direction == "right-to-left":
args["right"] = True
else:
ansible_module.fail_json(msg="Unknown direction '%s'" %
direction)
else:
ansible_module.fail_json(msg="Unkown state '%s'" % state)
# Execute command
if command is not None:
result = api_command(ansible_module, command,
to_text(suffix), args)
changed = True
except Exception as e:
ansible_module.fail_json(msg=str(e))
finally:
temp_kdestroy(ccache_dir, ccache_name)
# Done
ansible_module.exit_json(changed=changed)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,109 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# Copyright (C) 2019 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
ANSIBLE_METADATA = {
"metadata_version": "1.0",
"supported_by": "community",
"status": ["preview"],
}
DOCUMENTATION = """
---
module: ipatopologysuffix
short description: Verify FreeIPA topology suffix
description: Verify FreeIPA topology suffix
options:
principal:
description: The admin principal
default: admin
password:
description: The admin password
required: false
suffix:
description: Topology suffix
required: true
choices: ["domain", "ca"]
state:
description: State to ensure
default: verified
choices: ["verified"]
author:
- Thomas Woerner
"""
EXAMPLES = """
- ipatopologysuffix:
suffix: domain
state: verified
"""
RETURN = """
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_bytes, to_native, to_text
from ansible.module_utils.ansible_freeipa_module import execute_api_command
def main():
ansible_module = AnsibleModule(
argument_spec=dict(
principal=dict(type="str", default="admin"),
password=dict(type="str", required=False, no_log=True),
suffix=dict(choices=["domain", "ca"], required=True),
state=dict(type="str", default="verified",
choices=["verified"]),
),
supports_check_mode=True,
)
ansible_module._ansible_debug = True
# Get parameters
principal = ansible_module.params.get("principal")
password = ansible_module.params.get("password")
suffix = ansible_module.params.get("suffix")
state = ansible_module.params.get("state")
# Check parameters
# Init
# Create command
if state in ["verified"]:
command = "topologysuffix_verify"
args = {}
else:
ansible_module.fail_json(msg="Unkown state '%s'" % state)
# Execute command
execute_api_command(ansible_module, principal, password,
command, to_text(suffix), args)
# Done
ansible_module.exit_json(changed=True)
if __name__ == "__main__":
main()

View File

@@ -1 +1 @@
ansible>=2.5.0
ansible>=2.8.0

View File

@@ -17,7 +17,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import gssapi
try:
import gssapi
except ImportError:
gssapi = None
import os
import shutil
import subprocess
@@ -76,6 +79,9 @@ def kinit_keytab(principal, keytab, ccache_name, config):
Perform kinit using principal/keytab, with the specified config file
and store the TGT in ccache_name.
"""
if gssapi is None:
raise ImportError("gssapi is not available")
old_config = os.environ.get('KRB5_CONFIG')
os.environ['KRB5_CONFIG'] = config
try:

View File

@@ -306,8 +306,9 @@ def main():
# Get domain from first server if domain is not set, but if there are
# servers
if options.domain_name is None and len(options.servers) > 0:
options.domain_name = options.servers[0][options.servers[0].find(".")+1:]
if options.domain_name is None and options.servers is not None:
if len(options.servers) > 0:
options.domain_name = options.servers[0][options.servers[0].find(".")+1:]
try:
self = options
@@ -324,7 +325,8 @@ def main():
### ServiceInstallInterface ###
validate_domain_name(options.domain_name)
if options.domain_name:
validate_domain_name(options.domain_name)
if options.realm_name:
argspec = inspect.getargspec(validate_domain_name)
@@ -527,6 +529,14 @@ def main():
"Invalid hostname, '{}' must not be used.".format(hostname),
rval=CLIENT_INSTALL_ERROR)
if hasattr(constants, "MAXHOSTNAMELEN"):
try:
validate_hostname(hostname, maxlen=constants.MAXHOSTNAMELEN)
except ValueError as e:
raise ScriptError(
'invalid hostname: {}'.format(e),
rval=CLIENT_INSTALL_ERROR)
if hasattr(tasks, "is_nosssd_supported"):
# --no-sssd is not supported any more for rhel-based distros
if not tasks.is_nosssd_supported() and not options.sssd:

View File

@@ -5,7 +5,7 @@ galaxy_info:
description: A role to join a machine to an IPA domain
company: Red Hat, Inc
license: GPLv3
min_ansible_version: 2.5.0
min_ansible_version: 2.8
platforms:
- name: Fedora
versions:
@@ -13,7 +13,7 @@ galaxy_info:
- name: EL
versions:
- 7
# - 8
- 8
galaxy_tags:
- identity
- ipa

View File

@@ -81,6 +81,7 @@ if NUM_VERSION >= 40400:
except ImportError:
from ipaclient import ipadiscovery
from ipalib import api, errors, x509
from ipalib import constants
try:
from ipalib.install import sysrestore
except ImportError:
@@ -97,7 +98,8 @@ if NUM_VERSION >= 40400:
from ipapython import certdb, ipautil
from ipapython.admintool import ScriptError
from ipapython.ipautil import CheckedIPAddress
from ipalib.util import validate_domain_name, normalize_hostname
from ipalib.util import validate_domain_name, normalize_hostname, \
validate_hostname
from ipaplatform import services
from ipaplatform.paths import paths
from ipaplatform.tasks import tasks

View File

@@ -8,8 +8,8 @@
with_items: "{{ ipaclient_packages }}"
when: ipaclient_install_packages | bool
- name: Install - Include Python2/3 import test
import_tasks: "{{ role_path }}/tasks/python_2_3_test.yml"
#- name: Install - Include Python2/3 import test
# import_tasks: "{{ role_path }}/tasks/python_2_3_test.yml"
- name: Install - Set ipaclient_servers
set_fact:
@@ -73,6 +73,11 @@
servers: "{{ result_ipaclient_test.servers }}"
domain: "{{ result_ipaclient_test.domain }}"
- name: Install - Disable One-Time Password for on_master
set_fact:
ipaclient_use_otp: "no"
when: ipaclient_use_otp | bool and ipaclient_on_master | bool
- name: Install - Test if IPA client has working krb5.keytab
ipaclient_test_keytab:
servers: "{{ result_ipaclient_test.servers }}"
@@ -106,9 +111,9 @@
set_fact:
ipaclient_ansible_python_interpreter: "{{ ansible_python_interpreter }}"
- name: Install - Include Python2/3 import test
import_tasks: "{{ role_path }}/tasks/python_2_3_test.yml"
delegate_to: "{{ result_ipaclient_test.servers[0] }}"
#- name: Install - Include Python2/3 import test
# import_tasks: "{{ role_path }}/tasks/python_2_3_test.yml"
# delegate_to: "{{ result_ipaclient_test.servers[0] }}"
- name: Install - Get One-Time Password for client enrollment
no_log: yes
@@ -133,6 +138,7 @@
- name: Install - Store the previously obtained OTP
no_log: yes
set_fact:
ipaadmin_orig_password: "{{ ipaadmin_password }}"
ipaadmin_password: "{{ result_ipaclient_get_otp.host.randompassword
if result_ipaclient_get_otp.host is defined }}"
@@ -160,7 +166,7 @@
fail: msg="At least one of password or keytab must be specified"
when: not result_ipaclient_test_keytab.krb5_keytab_ok and
(ipaadmin_password is undefined or ipaadmin_password|length == 0)
and (ipaclient_keytab is undefined or ipaclient_keytab|lenth == 0)
and (ipaclient_keytab is undefined or ipaclient_keytab|length == 0)
when: not ipaclient_on_master | bool
- name: Install - Purge {{ result_ipaclient_test.realm }} from host keytab
@@ -342,6 +348,12 @@
not ipaclient_allow_repair | bool and not ipaclient_force_join | bool)
always:
- name: Install - Restore original admin password if overwritten by OTP
no_log: yes
set_fact:
ipaadmin_password: "{{ ipaadmin_orig_password }}"
when: ipaclient_use_otp | bool and ipaadmin_orig_password is defined
- name: Cleanup leftover ccache
file:
path: "/etc/ipa/.dns_ccache"

View File

@@ -4,6 +4,7 @@
### basic ###
ipareplica_no_host_dns: no
ipareplica_skip_conncheck: no
ipareplica_hidden_replica: no
### server ###
ipareplica_setup_adtrust: no
ipareplica_setup_ca: no

View File

@@ -180,7 +180,7 @@ def main():
_http_pkcs12_info = dict(required=False),
_pkinit_pkcs12_info = dict(required=False),
_top_dir = dict(required=True),
_add_to_ipaservers = dict(required=True),
_add_to_ipaservers = dict(required=True, type='bool'),
_ca_subject=dict(required=True),
_subject_base=dict(required=True),

View File

@@ -107,7 +107,7 @@ def main():
_pkinit_pkcs12_info = dict(required=False),
_top_dir = dict(required=True),
dirman_password=dict(required=True, no_log=True),
config_setup_ca=dict(required=True),
config_setup_ca=dict(required=True, type='bool'),
config_master_host_name=dict(required=True),
config_ca_host_name=dict(required=True),
),

View File

@@ -69,13 +69,14 @@ def main():
ansible_module = AnsibleModule(
argument_spec = dict(
hostname=dict(required=False),
hidden_replica=dict(required=False, type='bool', default=False),
### server ###
### certificate system ###
subject_base=dict(required=True),
### additional ###
ccache=dict(required=True),
_top_dir = dict(required=True),
setup_ca=dict(required=True),
setup_ca=dict(required=True, type='bool'),
config_master_host_name=dict(required=True),
),
supports_check_mode = True,
@@ -88,6 +89,7 @@ def main():
options = installer
options.host_name = ansible_module.params.get('hostname')
options.hidden_replica = ansible_module.params.get('hidden_replica')
### server ###
### certificate system ###
options.subject_base = ansible_module.params.get('subject_base')
@@ -112,6 +114,7 @@ def main():
env = gen_env_boostrap_finalize_core(paths.ETC_IPA,
constants.DEFAULT_CONFIG)
api_bootstrap_finalize(env)
config = gen_ReplicaConfig()
remote_api = gen_remote_api(config_master_host_name, paths.ETC_IPA)
installer._remote_api = remote_api
@@ -122,11 +125,16 @@ def main():
api.Backend.ldap2.connect()
with redirect_stdout(ansible_log):
# Enable configured services and update DNS SRV records
service.enable_services(options.host_name)
if options.hidden_replica:
# Set services to hidden
service.hide_services(config.host_name)
else:
# Enable configured services
service.enable_services(config.host_name)
# update DNS SRV records. Although it's only really necessary in
# enabled-service case, also perform update in hidden replica case.
api.Command.dns_update_system_records()
ca_servers = service.find_providing_servers('CA', api.Backend.ldap2,
api)
ca_servers = find_providing_servers('CA', api.Backend.ldap2, api=api)
api.Backend.ldap2.disconnect()
# Everything installed properly, activate ipa service.
@@ -134,12 +142,12 @@ def main():
# Print a warning if CA role is only installed on one server
if len(ca_servers) == 1:
msg = textwrap.dedent(u'''
msg = u'''
WARNING: The CA service is only installed on one server ({}).
It is strongly recommended to install it on another server.
Run ipa-ca-install(1) on another master to accomplish this.
'''.format(ca_servers[0]))
ansible_module.warn(msg)
'''.format(ca_servers[0])
ansible_module.debug(msg)
# done #

View File

@@ -134,11 +134,11 @@ def main():
_http_pkcs12_info = dict(required=False),
_pkinit_pkcs12_info = dict(required=False),
_top_dir = dict(required=True),
_add_to_ipaservers = dict(required=True),
_add_to_ipaservers = dict(required=True, type='bool'),
_ca_subject=dict(required=True),
_subject_base=dict(required=True),
dirman_password=dict(required=True, no_log=True),
config_setup_ca=dict(required=True),
config_setup_ca=dict(required=True, type='bool'),
config_master_host_name=dict(required=True),
config_ca_host_name=dict(required=True),
config_ips=dict(required=False, type='list', default=[]),

View File

@@ -278,9 +278,6 @@ def main():
## check selinux status, http and DS ports, NTP conflicting services
#common_check(options.no_ntp)
sstore = sysrestore.StateFile(paths.SYSRESTORE)
fstore = sysrestore.FileStore(paths.SYSRESTORE)
installer._enrollment_performed = False
installer._top_dir = tempfile.mkdtemp("ipa")
@@ -296,10 +293,14 @@ def main():
# pylint: disable=no-member
xmlrpc_uri = 'https://{}/ipa/xml'.format(ipautil.format_netloc(env.host))
if hasattr(ipaldap, "realm_to_ldapi_uri"):
realm_to_ldapi_uri = ipaldap.realm_to_ldapi_uri
else:
realm_to_ldapi_uri = installutils.realm_to_ldapi_uri
api.bootstrap(in_server=True,
context='installer',
confdir=paths.ETC_IPA,
ldap_uri=installutils.realm_to_ldapi_uri(env.realm),
ldap_uri=realm_to_ldapi_uri(env.realm),
xmlrpc_uri=xmlrpc_uri)
# pylint: enable=no-member
api.finalize()
@@ -311,13 +312,19 @@ def main():
config.host_name = api.env.host
config.domain_name = api.env.domain
config.master_host_name = api.env.server
config.ca_host_name = api.env.ca_host
if not api.env.ca_host or api.env.ca_host == api.env.host:
# ca_host has not been configured explicitly, prefer source master
config.ca_host_name = api.env.server
else:
# default to ca_host from IPA config
config.ca_host_name = api.env.ca_host
config.kra_host_name = config.ca_host_name
config.ca_ds_port = 389
config.setup_ca = options.setup_ca
config.setup_kra = options.setup_kra
config.dir = installer._top_dir
config.basedn = api.env.basedn
#config.hidden_replica = options.hidden_replica
# load and check certificates #
@@ -553,8 +560,11 @@ def main():
ansible_log.debug("-- SEARCH FOR CA --")
# Find if any server has a CA
ca_host = service.find_providing_server(
'CA', conn, config.ca_host_name)
if not hasattr(service, "find_providing_server"):
_host = [config.ca_host_name]
else:
_host = config.ca_host_name
ca_host = find_providing_server('CA', conn, _host)
if ca_host is not None:
config.ca_host_name = ca_host
ca_enabled = True
@@ -577,14 +587,17 @@ def main():
ansible_log.debug("-- SEARCH FOR KRA --")
kra_host = service.find_providing_server(
'KRA', conn, config.kra_host_name)
if not hasattr(service, "find_providing_server"):
_host = [config.kra_host_name]
else:
_host = config.kra_host_name
kra_host = find_providing_server('KRA', conn, _host)
if kra_host is not None:
config.kra_host_name = kra_host
kra_enabled = True
else:
if options.setup_kra:
logger.error("There is no KRA server in the domain, "
logger.error("There is no active KRA server in the domain, "
"can't setup a KRA clone")
raise ScriptError(rval=3)
kra_enabled = False
@@ -676,6 +689,10 @@ def main():
if add_to_ipaservers:
os.environ['KRB5CCNAME'] = ccache
if hasattr(tasks, "configure_pkcs11_modules"):
if tasks.configure_pkcs11_modules(fstore):
ansible_log.info("Disabled p11-kit-proxy")
installer._ca_enabled = ca_enabled
installer._kra_enabled = kra_enabled
installer._ca_file = cafile

View File

@@ -78,7 +78,7 @@ def main():
### additional ###
ccache=dict(required=True),
_top_dir = dict(required=True),
config_setup_ca=dict(required=True),
config_setup_ca=dict(required=True, type='bool'),
config_master_host_name=dict(required=True),
),
supports_check_mode = True,

View File

@@ -78,7 +78,7 @@ def main():
### additional ###
ccache=dict(required=True),
_top_dir = dict(required=True),
config_setup_ca=dict(required=True),
config_setup_ca=dict(required=True, type='bool'),
config_master_host_name=dict(required=True),
),
supports_check_mode = True,

View File

@@ -124,7 +124,7 @@ def main():
_ca_subject=dict(required=True),
_subject_base=dict(required=True),
dirman_password=dict(required=True, no_log=True),
config_setup_ca=dict(required=True),
config_setup_ca=dict(required=True, type='bool'),
config_master_host_name=dict(required=True),
config_ca_host_name=dict(required=True),
config_ips=dict(required=False, type='list', default=[]),

View File

@@ -88,7 +88,7 @@ def main():
### additional ###
ccache=dict(required=True),
_top_dir = dict(required=True),
setup_ca=dict(required=True),
setup_ca=dict(required=True, type='bool'),
config_master_host_name=dict(required=True),
),
supports_check_mode = True,

View File

@@ -181,11 +181,11 @@ def main():
_http_pkcs12_info = dict(required=False),
_pkinit_pkcs12_info = dict(required=False),
_top_dir = dict(required=True),
_add_to_ipaservers = dict(required=True),
_add_to_ipaservers = dict(required=True, type='bool'),
_ca_subject=dict(required=True),
_subject_base=dict(required=True),
dirman_password=dict(required=True, no_log=True),
config_setup_ca=dict(required=True),
config_setup_ca=dict(required=True, type='bool'),
config_master_host_name=dict(required=True),
config_ca_host_name=dict(required=True),
config_ips=dict(required=False, type='list', default=[]),

View File

@@ -119,7 +119,7 @@ def main():
_http_pkcs12_info = dict(required=False),
_pkinit_pkcs12_info = dict(required=False),
_top_dir = dict(required=True),
_add_to_ipaservers = dict(required=True),
_add_to_ipaservers = dict(required=True, type='bool'),
_ca_subject=dict(required=True),
_subject_base=dict(required=True),
),

View File

@@ -64,6 +64,7 @@ def main():
realm=dict(required=False),
hostname=dict(required=False),
ca_cert_files=dict(required=False, type='list', default=[]),
hidden_replica=dict(required=False, type='bool', default=False),
### server ###
setup_adtrust=dict(required=False, type='bool', default=False),
setup_kra=dict(required=False, type='bool', default=False),
@@ -106,6 +107,7 @@ def main():
options.realm_name = ansible_module.params.get('realm')
options.host_name = ansible_module.params.get('hostname')
options.ca_cert_files = ansible_module.params.get('ca_cert_files')
options.hidden_replica = ansible_module.params.get('hidden_replica')
### server ###
options.setup_adtrust = ansible_module.params.get('setup_adtrust')
options.setup_kra = ansible_module.params.get('setup_kra')
@@ -173,6 +175,10 @@ def main():
# # options.setup_kra = False
# # ansible_module.warn(msg="kra is not supported, disabling")
if options.hidden_replica and not hasattr(service, "hide_services"):
ansible_module.fail_json(
msg="Hidden replica is not supported in this version.")
# From ipa installer classes
# pkinit is not supported on DL0, don't allow related options

View File

@@ -1,12 +1,11 @@
# dependencies:
# - role: t_woerner.ipaclient
dependencies: []
galaxy_info:
author: Thomas Woerner
description: A role to setup an IPA domain replica
company: Red Hat, Inc
license: GPLv3
min_ansible_version: 2.5
min_ansible_version: 2.8
platforms:
- name: Fedora
versions:
@@ -14,7 +13,7 @@ galaxy_info:
- name: EL
versions:
- 7
# - 8
- 8
galaxy_tags:
- identity
- ipa

View File

@@ -79,6 +79,12 @@ if NUM_VERSION >= 40600:
adtrust, bindinstance, ca, certs, dns, dsinstance, httpinstance,
installutils, kra, krbinstance,
otpdinstance, custodiainstance, service, upgradeinstance)
try:
from ipaserver.masters import (
find_providing_servers, find_providing_server)
except ImportError:
from ipaserver.install.service import (
find_providing_servers, find_providing_server)
from ipaserver.install.installutils import (
ReplicaConfig, load_pkcs12, is_ipa_configured)
from ipaserver.install.replication import (
@@ -162,6 +168,9 @@ class AnsibleModuleLog():
def debug(self, msg):
self.module.debug(msg)
def info(self, msg):
self.module.debug(msg)
def write(self, msg):
self.module.debug(msg)
#self.module.warn(msg)

View File

@@ -25,8 +25,8 @@
when: ipareplica_install_packages | bool
- name: Install - Include Python2/3 import test
import_tasks: "{{ role_path }}/tasks/python_2_3_test.yml"
#- name: Install - Include Python2/3 import test
# import_tasks: "{{ role_path }}/tasks/python_2_3_test.yml"
- name: Install - Set default principal if no keytab is given
set_fact:
@@ -46,6 +46,7 @@
realm: "{{ ipareplica_realm | default(omit) }}"
hostname: "{{ ipareplica_hostname | default(ansible_fqdn) }}"
ca_cert_files: "{{ ipareplica_ca_cert_files | default([]) }}"
hidden_replica: "{{ ipareplica_hidden_replica }}"
### server ###
setup_adtrust: "{{ ipareplica_setup_adtrust }}"
setup_kra: "{{ ipareplica_setup_kra }}"
@@ -96,7 +97,8 @@
--permanent
--add-service=freeipa-ldap
--add-service=freeipa-ldaps
--add-service=freeipa-replication
{{ "--add-service=freeipa-trust" if result_ipareplica_test.setup_adtrust
else "" }}
{{ "--add-service=dns" if ipareplica_setup_dns | bool else "" }}
{{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }}
when: ipareplica_setup_firewalld | bool
@@ -106,7 +108,8 @@
firewall-cmd
--add-service=freeipa-ldap
--add-service=freeipa-ldaps
--add-service=freeipa-replication
{{ "--add-service=freeipa-trust" if result_ipareplica_test.setup_adtrust
else "" }}
{{ "--add-service=dns" if ipareplica_setup_dns | bool else "" }}
{{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }}
when: ipareplica_setup_firewalld | bool
@@ -632,12 +635,11 @@
"{{ result_ipareplica_prepare.adtrust_reset_netbios_name }}"
when: result_ipareplica_test.setup_adtrust
# - name: Install - Disconnect backend
# ipareplica_backend_disconnect:
- name: Install - Enable IPA
ipareplica_enable_ipa:
hostname: "{{ result_ipareplica_test.hostname }}"
hidden_replica: "{{ ipareplica_hidden_replica }}"
### server ###
### certificate system ###
subject_base: "{{ result_ipareplica_prepare.subject_base }}"
### additional ###

View File

@@ -19,20 +19,20 @@
has no attribute 'basedn'" not in result_uninstall.stderr
# IPA server is not configured on this system" not in
# result_uninstall.stdout_lines
# changed_when: result_uninstall.rc == 0
changed_when: result_uninstall.rc == 0
# until: result_uninstall.rc == 0
retries: 2
delay: 1
- name: Uninstall - Remove all replication agreements and data about replica
command: >
/usr/sbin/ipa-replica-manage
del
{{ ipareplica_hostname | default(ansible_fqdn) }}
--force
--password={{ ipadm_password }}
failed_when: False
delegate_to: "{{ groups.ipaserver[0] | default(fail) }}"
#- name: Uninstall - Remove all replication agreements and data about replica
# command: >
# /usr/sbin/ipa-replica-manage
# del
# {{ ipareplica_hostname | default(ansible_fqdn) }}
# --force
# --password={{ ipadm_password }}
# failed_when: False
# delegate_to: "{{ groups.ipaserver[0] | default(fail) }}"
# - name: Remove IPA replica packages
# package:

View File

@@ -129,6 +129,9 @@ Variables
**ipaserver_no_host_dns** - Do not use DNS for hostname lookup during installation.
(bool, optional)
**ipaserver_pki_config_override** - Path to ini file with config overrides.
(string, optional)
**ipaserver_no_dnssec_validation** - Disable DNSSEC validation on this server.
(bool, optional)

View File

@@ -109,7 +109,7 @@ def main():
forwarders=dict(required=False, type='list', default=[]),
no_forwarders=dict(required=False, type='bool', default=False),
auto_forwarders=dict(required=False, type='bool', default=False),
forward_policy=dict(required=False),
forward_policy=dict(default=None, choices=['first', 'only']),
no_dnssec_validation=dict(required=False, type='bool',
default=False),
### ad trust ###
@@ -181,6 +181,15 @@ def main():
fstore = sysrestore.FileStore(paths.SYSRESTORE)
sstore = sysrestore.StateFile(paths.SYSRESTORE)
# subject_base
if not options.subject_base:
options.subject_base = str(default_subject_base(options.realm_name))
# set options.subject for old ipa releases
options.subject = options.subject_base
if not options.ca_subject:
options.ca_subject = str(default_ca_subject_dn(options.subject_base))
# Configuration for ipalib, we will bootstrap and finalize later, after
# we are sure we have the configuration file ready.
cfg = dict(
@@ -268,7 +277,29 @@ def main():
if _update_hosts_file:
update_hosts_file(ip_addresses, options.host_name, fstore)
ansible_module.exit_json(changed=True)
if hasattr(tasks, "configure_pkcs11_modules"):
if tasks.configure_pkcs11_modules(fstore):
ansible_log.info("Disabled p11-kit-proxy")
ansible_module.exit_json(changed=True,
### basic ###
ip_addresses=[ str(ip) for ip in ip_addresses ],
### certificate system ###
subject_base=options.subject_base,
_subject_base=options._subject_base,
ca_subject=options.ca_subject,
_ca_subject=options._ca_subject,
### dns ###
reverse_zones=options.reverse_zones,
forward_policy=options.forward_policy,
forwarders=options.forwarders,
no_dnssec_validation=options.no_dnssec_validation,
### additional ###
dns_ip_addresses=[ str(ip) for ip
in dns.ip_addresses ],
dns_reverse_zones=dns.reverse_zones,
adtrust_netbios_name=adtrust.netbios_name,
adtrust_reset_netbios_name=adtrust.reset_netbios_name)
if __name__ == '__main__':
main()

View File

@@ -91,6 +91,7 @@ def main():
realm=dict(required=True),
hostname=dict(required=False),
no_host_dns=dict(required=False, type='bool', default=False),
pki_config_override=dict(required=False),
### server ###
setup_adtrust=dict(required=False, type='bool', default=False),
setup_kra=dict(required=False, type='bool', default=False),
@@ -101,7 +102,7 @@ def main():
no_hbac_allow=dict(required=False, type='bool', default=False),
no_pkinit=dict(required=False, type='bool', default=False),
dirsrv_config_file=dict(required=False),
dirsrv_cert_files=dict(required=False),
dirsrv_cert_files=dict(required=False, type='list'),
_dirsrv_pkcs12_info=dict(required=False),
### certificate system ###
external_ca=dict(required=False, type='bool', default=False),
@@ -136,6 +137,8 @@ def main():
options.realm_name = ansible_module.params.get('realm')
options.host_name = ansible_module.params.get('hostname')
options.no_host_dns = ansible_module.params.get('no_host_dns')
options.pki_config_override = ansible_module.params.get(
'pki_config_override')
### server ###
options.setup_adtrust = ansible_module.params.get('setup_adtrust')
options.setup_kra = ansible_module.params.get('setup_kra')

View File

@@ -183,7 +183,8 @@ def main():
subject_base=options.subject_base,
auto_redirect=not options.no_ui_redirect,
ca_is_configured=options.setup_ca)
tasks.restore_context(paths.CACHE_IPA_SESSIONS)
if hasattr(paths, "CACHE_IPA_SESSIONS"):
tasks.restore_context(paths.CACHE_IPA_SESSIONS)
ca.set_subject_base_in_config(options.subject_base)

View File

@@ -58,6 +58,7 @@ def main():
setup_ca=dict(required=True, type='bool'),
setup_kra=dict(required=True, type='bool'),
realm=dict(required=True),
pki_config_override=dict(required=False),
),
)
@@ -71,6 +72,8 @@ def main():
options.setup_ca = ansible_module.params.get('setup_ca')
options.setup_kra = ansible_module.params.get('setup_kra')
options.realm_name = ansible_module.params.get('realm')
options.pki_config_override = ansible_module.params.get(
'pki_config_override')
options.promote = False # first master, no promotion
# init ##########################################################

View File

@@ -60,12 +60,12 @@ def main():
dm_password=dict(required=True, no_log=True),
password=dict(required=True, no_log=True),
master_password=dict(required=False, no_log=True),
ip_addresses=dict(required=False, type='list', default=[]),
domain=dict(required=False),
realm=dict(required=False),
hostname=dict(required=False),
ca_cert_files=dict(required=False, type='list', default=[]),
no_host_dns=dict(required=False, type='bool', default=False),
pki_config_override=dict(required=False),
### server ###
setup_adtrust=dict(required=False, type='bool', default=False),
setup_kra=dict(required=False, type='bool', default=False),
@@ -134,13 +134,13 @@ def main():
options.dm_password = ansible_module.params.get('dm_password')
options.admin_password = ansible_module.params.get('password')
options.master_password = ansible_module.params.get('master_password')
options.ip_addresses = ansible_module_get_parsed_ip_addresses(
ansible_module)
options.domain_name = ansible_module.params.get('domain')
options.realm_name = ansible_module.params.get('realm')
options.host_name = ansible_module.params.get('hostname')
options.ca_cert_files = ansible_module.params.get('ca_cert_files')
options.no_host_dns = ansible_module.params.get('no_host_dns')
options.pki_config_override = ansible_module.params.get(
'pki_config_override')
### server ###
options.setup_adtrust = ansible_module.params.get('setup_adtrust')
options.setup_dns = ansible_module.params.get('setup_dns')
@@ -213,6 +213,19 @@ def main():
# options.setup_kra = False
# ansible_module.warn(msg="kra is not supported, disabling")
if options.pki_config_override is not None:
if PKIIniLoader is None:
ansible_module.warn("The use of pki_config_override is not "
"supported for this IPA version")
else:
# From DogtagInstallInterface @pki_config_override.validator
try:
PKIIniLoader.verify_pki_config_override(
options.pki_config_override)
except ValueError as e:
ansible_module.fail_json(
msg="pki_config_override: %s" % str(e))
# validation #############################################################
if options.dm_password is None:
@@ -544,33 +557,39 @@ def main():
# host name
if options.host_name:
options.host_default = options.host_name
host_default = options.host_name
else:
options.host_default = get_fqdn()
host_default = get_fqdn()
try:
verify_fqdn(options.host_default, options.no_host_dns)
options.host_name = options.host_default
verify_fqdn(host_default, options.no_host_dns)
host_name = host_default
except BadHostError as e:
ansible_module.fail_json(msg=e)
options.host_name = options.host_name.lower()
host_name = host_name.lower()
if not options.domain_name:
options.domain_name = options.host_name[options.host_name.find(".")+1:]
domain_name = host_name[host_name.find(".")+1:]
try:
validate_domain_name(options.domain_name)
validate_domain_name(domain_name)
except ValueError as e:
ansible_module.fail_json(msg="Invalid domain name: %s" % unicode(e))
options.domain_name = options.domain_name.lower()
else:
domain_name = options.domain_name
domain_name = domain_name.lower()
if not options.realm_name:
options.realm_name = options.domain_name
options.realm_name = options.realm_name.upper()
realm_name = domain_name.upper()
else:
realm_name = options.realm_name.upper()
argspec = inspect.getargspec(validate_domain_name)
if "entity" in argspec.args:
# NUM_VERSION >= 40690:
try:
validate_domain_name(options.realm_name, entity="realm")
validate_domain_name(realm_name, entity="realm")
except ValueError as e:
raise ScriptError("Invalid realm name: {}".format(unicode(e)))
@@ -578,7 +597,7 @@ def main():
# If domain name and realm does not match, IPA server will not be able
# to establish trust with Active Directory. Fail.
if options.domain_name.upper() != options.realm_name:
if domain_name.upper() != realm_name:
ansible_module.warn(
"Realm name does not match the domain name: "
"You will not be able to establish trusts with Active "
@@ -605,7 +624,7 @@ def main():
key_password=options.http_pin,
key_nickname=options.http_cert_name,
ca_cert_files=options.ca_cert_files,
host_name=options.host_name)
host_name=host_name)
http_pkcs12_info = (http_pkcs12_file.name, options.http_pin)
if options.dirsrv_cert_files:
@@ -617,7 +636,7 @@ def main():
key_password=options.dirsrv_pin,
key_nickname=options.dirsrv_cert_name,
ca_cert_files=options.ca_cert_files,
host_name=options.host_name)
host_name=host_name)
dirsrv_pkcs12_info = (dirsrv_pkcs12_file.name, options.dirsrv_pin)
if options.pkinit_cert_files:
@@ -629,7 +648,7 @@ def main():
key_password=options.pkinit_pin,
key_nickname=options.pkinit_cert_name,
ca_cert_files=options.ca_cert_files,
realm_name=options.realm_name)
realm_name=realm_name)
pkinit_pkcs12_info = (pkinit_pkcs12_file.name, options.pkinit_pin)
if (options.http_cert_files and options.dirsrv_cert_files and
@@ -644,114 +663,15 @@ def main():
"Apache Server SSL certificate and PKINIT KDC "
"certificate are not signed by the same CA certificate")
# subject_base
if not options.subject_base:
options.subject_base = str(default_subject_base(options.realm_name))
# set options.subject for old ipa releases
options.subject = options.subject_base
if not options.ca_subject:
options.ca_subject = str(default_ca_subject_dn(options.subject_base))
# temporary ipa configuration ###########################################
ipa_tempdir = tempfile.mkdtemp(prefix="ipaconf")
try:
# Configuration for ipalib, we will bootstrap and finalize later, after
# we are sure we have the configuration file ready.
cfg = dict(
context='installer',
confdir=ipa_tempdir,
in_server=True,
# make sure host name specified by user is used instead of default
host=options.host_name,
)
if options.setup_ca:
# we have an IPA-integrated CA
cfg['ca_host'] = options.host_name
# Create the management framework config file and finalize api
target_fname = "%s/default.conf" % ipa_tempdir
fd = open(target_fname, "w")
fd.write("[global]\n")
fd.write("host=%s\n" % options.host_name)
fd.write("basedn=%s\n" % ipautil.realm_to_suffix(options.realm_name))
fd.write("realm=%s\n" % options.realm_name)
fd.write("domain=%s\n" % options.domain_name)
fd.write("xmlrpc_uri=https://%s/ipa/xml\n" % ipautil.format_netloc(options.host_name))
fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" %
installutils.realm_to_serverid(options.realm_name))
if options.setup_ca:
fd.write("enable_ra=True\n")
fd.write("ra_plugin=dogtag\n")
fd.write("dogtag_version=10\n")
else:
fd.write("enable_ra=False\n")
fd.write("ra_plugin=none\n")
fd.write("mode=production\n")
fd.close()
# Must be readable for everyone
os.chmod(target_fname, 0o644)
api.bootstrap(**cfg)
api.finalize()
# install checks ####################################################
if options.setup_ca:
ca.install_check(False, None, options)
if options.setup_kra:
kra.install_check(api, None, options)
if options.setup_dns:
with redirect_stdout(ansible_log):
dns.install_check(False, api, False, options, options.host_name)
ip_addresses = dns.ip_addresses
else:
ip_addresses = get_server_ip_address(options.host_name,
False, False,
options.ip_addresses)
# check addresses here, dns ansible_module is doing own check
no_matching_interface_for_ip_address_warning(ip_addresses)
options.ip_addresses = ip_addresses
options.reverse_zones = dns.reverse_zones
instance_name = "-".join(options.realm_name.split("."))
dirsrv = services.knownservices.dirsrv
if (options.external_cert_files
and dirsrv.is_installed(instance_name)
and not dirsrv.is_running(instance_name)):
logger.debug('Starting Directory Server')
services.knownservices.dirsrv.start(instance_name)
if options.setup_adtrust:
adtrust.install_check(False, options, api)
except (RuntimeError, ValueError, ScriptError) as e:
ansible_module.fail_json(msg=str(e))
finally:
try:
shutil.rmtree(ipa_tempdir, ignore_errors=True)
except OSError:
ansible_module.fail_json(msg="Could not remove %s" % ipa_tempdir)
# Always set _host_name_overridden
options._host_name_overridden = bool(options.host_name)
# done ##################################################################
ansible_module.exit_json(changed=False,
ipa_python_version=IPA_PYTHON_VERSION,
### basic ###
domain=options.domain_name,
realm=options.realm_name,
ip_addresses=[ str(ip) for ip in ip_addresses ],
hostname=options.host_name,
_hostname_overridden=options._host_name_overridden,
realm=realm_name,
hostname=host_name,
_hostname_overridden=bool(options.host_name),
no_host_dns=options.no_host_dns,
### server ###
setup_adtrust=options.setup_adtrust,
@@ -770,27 +690,12 @@ def main():
_pkinit_pkcs12_file=pkinit_pkcs12_file,
_pkinit_pkcs12_info=pkinit_pkcs12_info,
_pkinit_ca_cert=pkinit_ca_cert,
### certificate system ###
subject_base=options.subject_base,
_subject_base=options._subject_base,
ca_subject=options.ca_subject,
_ca_subject=options._ca_subject,
### dns ###
reverse_zones=options.reverse_zones,
forward_policy=options.forward_policy,
forwarders=options.forwarders,
no_dnssec_validation=options.no_dnssec_validation,
### ad trust ###
rid_base=options.rid_base,
secondary_rid_base=options.secondary_rid_base,
### additional ###
_installation_cleanup=_installation_cleanup,
domainlevel=options.domainlevel,
dns_ip_addresses=[ str(ip) for ip
in dns.ip_addresses ],
dns_reverse_zones=dns.reverse_zones,
adtrust_netbios_name=adtrust.netbios_name,
adtrust_reset_netbios_name=adtrust.reset_netbios_name)
domainlevel=options.domainlevel)
if __name__ == '__main__':
main()

View File

@@ -1,12 +1,11 @@
# dependencies:
# - role: t_woerner.ipaclient
dependencies: []
galaxy_info:
author: Thomas Woerner
description: A role to setup an iPA domain server
company: Red Hat, Inc
license: GPLv3
min_ansible_version: 2.5
min_ansible_version: 2.8
platforms:
- name: Fedora
versions:
@@ -14,7 +13,7 @@ galaxy_info:
- name: EL
versions:
- 7
# - 8
- 8
galaxy_tags:
- identity
- ipa

View File

@@ -101,6 +101,10 @@ if NUM_VERSION >= 40500:
from ipaserver.install.server.install import (
check_dirsrv, validate_admin_password, validate_dm_password,
write_cache)
try:
from ipaserver.install.dogtaginstance import PKIIniLoader
except ImportError:
PKIIniLoader = None
try:
from ipaserver.install.installutils import default_subject_base
except ImportError:
@@ -167,6 +171,16 @@ class AnsibleModuleLog():
def flush(self):
pass
def log(self, msg):
#self.write(msg+"\n")
self.write(msg)
def debug(self, msg):
self.module.debug(msg)
def info(self, msg):
self.module.debug(msg)
def write(self, msg):
self.module.debug(msg)
#self.module.warn(msg)

View File

@@ -24,8 +24,8 @@
when: ipaserver_install_packages | bool
- name: Install - Include Python2/3 import test
import_tasks: "{{ role_path }}/tasks/python_2_3_test.yml"
#- name: Install - Include Python2/3 import test
# import_tasks: "{{ role_path }}/tasks/python_2_3_test.yml"
- name: Install - Server installation test
ipaserver_test:
@@ -33,12 +33,12 @@
dm_password: "{{ ipadm_password }}"
password: "{{ ipaadmin_password }}"
master_password: "{{ ipaserver_master_password | default(omit) }}"
ip_addresses: "{{ ipaserver_ip_addresses | default([]) }}"
domain: "{{ ipaserver_domain | default(omit) }}"
realm: "{{ ipaserver_realm | default(omit) }}"
hostname: "{{ ipaserver_hostname | default(ansible_fqdn) }}"
ca_cert_files: "{{ ipaserver_ca_cert_files | default(omit) }}"
no_host_dns: "{{ ipaserver_no_host_dns }}"
pki_config_override: "{{ ipaserver_pki_config_override | default(omit) }}"
### server ###
setup_adtrust: "{{ ipaserver_setup_adtrust }}"
setup_kra: "{{ ipaserver_setup_kra }}"
@@ -121,34 +121,36 @@
### basic ###
dm_password: "{{ ipadm_password }}"
password: "{{ ipaadmin_password }}"
# ip_addresses: "{{ result_ipaserver_test.ip_addresses }}"
ip_addresses: "{{ ipaserver_ip_addresses | default([]) }}"
domain: "{{ result_ipaserver_test.domain }}"
realm: "{{ result_ipaserver_test.realm }}"
hostname: "{{ result_ipaserver_test.hostname }}"
no_host_dns: "{{ result_ipaserver_test.no_host_dns }}"
### server ###
setup_adtrust: "{{ result_ipaserver_test.setup_adtrust }}"
setup_kra: "{{ result_ipaserver_test.setup_kra }}"
setup_adtrust: "{{ ipaserver_setup_adtrust }}"
setup_kra: "{{ ipaserver_setup_kra }}"
setup_dns: "{{ ipaserver_setup_dns }}"
### certificate system ###
# external_ca
# external_cert_files
subject_base: "{{ result_ipaserver_test.subject_base }}"
ca_subject: "{{ result_ipaserver_test.ca_subject }}"
subject_base: "{{ ipaserver_subject_base | default(omit) }}"
ca_subject: "{{ ipaserver_ca_subject | default(omit) }}"
### dns ###
allow_zone_overlap: "{{ ipaserver_allow_zone_overlap }}"
reverse_zones: "{{ result_ipaserver_test.reverse_zones }}"
reverse_zones: "{{ ipaserver_reverse_zones | default([]) }}"
no_reverse: "{{ ipaserver_no_reverse }}"
auto_reverse: "{{ ipaserver_auto_reverse }}"
zonemgr: "{{ ipaserver_zonemgr | default(omit) }}"
forwarders: "{{ ipaserver_forwarders | default([]) }}"
no_forwarders: "{{ ipaserver_no_forwarders }}"
auto_forwarders: "{{ ipaserver_auto_forwarders }}"
no_dnssec_validation: "{{ result_ipaserver_test.no_dnssec_validation }}"
forward_policy: "{{ ipaserver_forward_policy | default(omit) }}"
no_dnssec_validation: "{{ ipaserver_no_dnssec_validation }}"
### ad trust ###
enable_compat: "{{ ipaserver_enable_compat }}"
netbios_name: "{{ ipaserver_netbios_name | default(omit) }}"
# rid_base
# secondary_rid_base
rid_base: "{{ ipaserver_rid_base | default(omit) }}"
secondary_rid_base: "{{ ipaserver_secondary_rid_base | default(omit) }}"
### additional ###
setup_ca: "{{ result_ipaserver_test.setup_ca }}"
_hostname_overridden: "{{ result_ipaserver_test._hostname_overridden }}"
@@ -167,8 +169,8 @@
domain: "{{ result_ipaserver_test.domain }}"
realm: "{{ result_ipaserver_test.realm | default(omit) }}"
hostname: "{{ result_ipaserver_test.hostname }}"
# ip_addresses: "{{ result_ipaserver_test.ip_addresses }}"
# reverse_zones: "{{ result_ipaserver_test.reverse_zones }}"
# ip_addresses: "{{ result_ipaserver_prepare.ip_addresses }}"
# reverse_zones: "{{ result_ipaserver_prepare.reverse_zones }}"
# setup_adtrust: "{{ result_ipaserver_test.setup_adtrust }}"
# setup_kra: "{{ result_ipaserver_test.setup_kra }}"
# setup_dns: "{{ ipaserver_setup_dns }}"
@@ -177,8 +179,8 @@
dirsrv_config_file: "{{ ipaserver_dirsrv_config_file | default(omit) }}"
dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default([]) }}"
external_cert_files: "{{ ipaserver_external_cert_files | default([]) }}"
subject_base: "{{ result_ipaserver_test.subject_base }}"
ca_subject: "{{ result_ipaserver_test.ca_subject }}"
subject_base: "{{ result_ipaserver_prepare.subject_base }}"
ca_subject: "{{ result_ipaserver_prepare.ca_subject }}"
# no_reverse: "{{ ipaserver_no_reverse }}"
# auto_forwarders: "{{ ipaserver_auto_forwarders }}"
no_pkinit: "{{ result_ipaserver_test.no_pkinit }}"
@@ -194,16 +196,16 @@
domain: "{{ result_ipaserver_test.domain }}"
realm: "{{ result_ipaserver_test.realm }}"
hostname: "{{ result_ipaserver_test.hostname }}"
# ip_addresses: "{{ result_ipaserver_test.ip_addresses }}"
reverse_zones: "{{ result_ipaserver_test.reverse_zones }}"
# ip_addresses: "{{ result_ipaserver_prepare.ip_addresses }}"
reverse_zones: "{{ result_ipaserver_prepare.reverse_zones }}"
setup_adtrust: "{{ result_ipaserver_test.setup_adtrust }}"
setup_kra: "{{ result_ipaserver_test.setup_kra }}"
setup_dns: "{{ ipaserver_setup_dns }}"
setup_ca: "{{ result_ipaserver_test.setup_ca }}"
no_host_dns: "{{ result_ipaserver_test.no_host_dns }}"
external_cert_files: "{{ ipaserver_external_cert_files | default([]) }}"
subject_base: "{{ result_ipaserver_test.subject_base }}"
ca_subject: "{{ result_ipaserver_test.ca_subject }}"
subject_base: "{{ result_ipaserver_prepare.subject_base }}"
ca_subject: "{{ result_ipaserver_prepare.ca_subject }}"
no_reverse: "{{ ipaserver_no_reverse }}"
auto_forwarders: "{{ ipaserver_auto_forwarders }}"
no_pkinit: "{{ result_ipaserver_test.no_pkinit }}"
@@ -223,11 +225,13 @@
dm_password: "{{ ipadm_password }}"
password: "{{ ipaadmin_password }}"
master_password: "{{ ipaserver_master_password }}"
# ip_addresses: "{{ result_ipaserver_test.ip_addresses }}"
# ip_addresses: "{{ result_ipaserver_prepare.ip_addresses }}"
domain: "{{ result_ipaserver_test.domain }}"
realm: "{{ result_ipaserver_test.realm }}"
hostname: "{{ result_ipaserver_test.hostname }}"
no_host_dns: "{{ result_ipaserver_test.no_host_dns }}"
pki_config_override: "{{ ipaserver_pki_config_override |
default(omit) }}"
setup_adtrust: "{{ result_ipaserver_test.setup_adtrust }}"
setup_kra: "{{ result_ipaserver_test.setup_kra }}"
setup_dns: "{{ ipaserver_setup_dns }}"
@@ -241,13 +245,13 @@
_dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info }}"
external_ca: "{{ ipaserver_external_ca }}"
external_cert_files: "{{ ipaserver_external_cert_files | default([]) }}"
subject_base: "{{ result_ipaserver_test.subject_base }}"
_subject_base: "{{ result_ipaserver_test._subject_base }}"
ca_subject: "{{ result_ipaserver_test.ca_subject }}"
_ca_subject: "{{ result_ipaserver_test._ca_subject }}"
subject_base: "{{ result_ipaserver_prepare.subject_base }}"
_subject_base: "{{ result_ipaserver_prepare._subject_base }}"
ca_subject: "{{ result_ipaserver_prepare.ca_subject }}"
_ca_subject: "{{ result_ipaserver_prepare._ca_subject }}"
ca_signing_algorithm: "{{ ipaserver_ca_signing_algorithm |
default(omit) }}"
reverse_zones: "{{ result_ipaserver_test.reverse_zones }}"
reverse_zones: "{{ result_ipaserver_prepare.reverse_zones }}"
no_reverse: "{{ ipaserver_no_reverse }}"
auto_forwarders: "{{ ipaserver_auto_forwarders }}"
@@ -265,8 +269,8 @@
domain: "{{ result_ipaserver_test.domain }}"
realm: "{{ result_ipaserver_test.realm }}"
hostname: "{{ result_ipaserver_test.hostname }}"
# ip_addresses: "{{ result_ipaserver_test.ip_addresses }}"
reverse_zones: "{{ result_ipaserver_test.reverse_zones }}"
# ip_addresses: "{{ result_ipaserver_prepare.ip_addresses }}"
reverse_zones: "{{ result_ipaserver_prepare.reverse_zones }}"
setup_adtrust: "{{ result_ipaserver_test.setup_adtrust }}"
setup_kra: "{{ result_ipaserver_test.setup_kra }}"
setup_dns: "{{ ipaserver_setup_dns }}"
@@ -274,10 +278,10 @@
no_host_dns: "{{ result_ipaserver_test.no_host_dns }}"
dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default([]) }}"
external_cert_files: "{{ ipaserver_external_cert_files | default([]) }}"
subject_base: "{{ result_ipaserver_test.subject_base }}"
_subject_base: "{{ result_ipaserver_test._subject_base }}"
ca_subject: "{{ result_ipaserver_test.ca_subject }}"
_ca_subject: "{{ result_ipaserver_test._ca_subject }}"
subject_base: "{{ result_ipaserver_prepare.subject_base }}"
_subject_base: "{{ result_ipaserver_prepare._subject_base }}"
ca_subject: "{{ result_ipaserver_prepare.ca_subject }}"
_ca_subject: "{{ result_ipaserver_prepare._ca_subject }}"
no_reverse: "{{ ipaserver_no_reverse }}"
auto_forwarders: "{{ ipaserver_auto_forwarders }}"
no_pkinit: "{{ result_ipaserver_test.no_pkinit }}"
@@ -294,6 +298,8 @@
dm_password: "{{ ipadm_password }}"
setup_kra: "{{ result_ipaserver_test.setup_kra }}"
realm: "{{ result_ipaserver_test.realm }}"
pki_config_override: "{{ ipaserver_pki_config_override |
default(omit) }}"
when: result_ipaserver_test.setup_kra | bool
- name: Install - Setup DNS
@@ -301,13 +307,13 @@
hostname: "{{ result_ipaserver_test.hostname }}"
setup_ca: "{{ result_ipaserver_test.setup_ca }}"
setup_dns: "{{ ipaserver_setup_dns }}"
forwarders: "{{ result_ipaserver_test.forwarders }}"
forward_policy: "{{ result_ipaserver_test.forward_policy }}"
forwarders: "{{ result_ipaserver_prepare.forwarders }}"
forward_policy: "{{ result_ipaserver_prepare.forward_policy }}"
zonemgr: "{{ ipaserver_zonemgr | default(omit) }}"
no_dnssec_validation: "{{ result_ipaserver_test.no_dnssec_validation }}"
no_dnssec_validation: "{{ result_ipaserver_prepare.no_dnssec_validation }}"
### additional ###
dns_ip_addresses: "{{ result_ipaserver_test.dns_ip_addresses }}"
dns_reverse_zones: "{{ result_ipaserver_test.dns_reverse_zones }}"
dns_ip_addresses: "{{ result_ipaserver_prepare.dns_ip_addresses }}"
dns_reverse_zones: "{{ result_ipaserver_prepare.dns_reverse_zones }}"
when: ipaserver_setup_dns | bool
- name: Install - Setup ADTRUST
@@ -320,9 +326,9 @@
rid_base: "{{ result_ipaserver_test.rid_base }}"
secondary_rid_base: "{{ result_ipaserver_test.secondary_rid_base }}"
### additional ###
adtrust_netbios_name: "{{ result_ipaserver_test.adtrust_netbios_name }}"
adtrust_netbios_name: "{{ result_ipaserver_prepare.adtrust_netbios_name }}"
adtrust_reset_netbios_name:
"{{ result_ipaserver_test.adtrust_reset_netbios_name }}"
"{{ result_ipaserver_prepare.adtrust_reset_netbios_name }}"
when: result_ipaserver_test.setup_adtrust
- name: Install - Set DS password
@@ -333,8 +339,8 @@
realm: "{{ result_ipaserver_test.realm }}"
hostname: "{{ result_ipaserver_test.hostname }}"
setup_ca: "{{ result_ipaserver_test.setup_ca }}"
subject_base: "{{ result_ipaserver_test.subject_base }}"
ca_subject: "{{ result_ipaserver_test.ca_subject }}"
subject_base: "{{ result_ipaserver_prepare.subject_base }}"
ca_subject: "{{ result_ipaserver_prepare.ca_subject }}"
no_pkinit: "{{ result_ipaserver_test.no_pkinit }}"
no_hbac_allow: "{{ ipaserver_no_hbac_allow }}"
idstart: "{{ result_ipaserver_test.idstart }}"
@@ -357,21 +363,6 @@
else 'false' }}"
ipaclient_install_packages: "{{ ipaserver_install_packages }}"
# - name: Install - Setup client
# command: >
# /usr/sbin/ipa-client-install
# --unattended
# --on-master
# --domain "{{ result_ipaserver_test.domain }}"
# --realm "{{ result_ipaserver_test.realm }}"
# --server "{{ result_ipaserver_test.hostname }}"
# --hostname "{{ result_ipaserver_test.hostname }}"
# {{ "--mkhomedir" if ipaclient_mkhomedir | bool else "" }}
# # {{ "--no-dns-sshfp" if ipaclient_no_dns_sshfp | bool else "" }}
# # {{ "--ssh-trust-dns" if ipaclient_ssh_trust_dns | bool else "" }}
# # {{ "--no-ssh" if ipaclient_no_ssh | bool else "" }}
# # {{ "--no-sshd" if ipaclient_no_sshd | bool else "" }}
- name: Install - Enable IPA
ipaserver_enable_ipa:
hostname: "{{ result_ipaserver_test.hostname }}"
@@ -391,6 +382,8 @@
--permanent
--add-service=freeipa-ldap
--add-service=freeipa-ldaps
{{ "--add-service=freeipa-trust" if ipaserver_setup_adtrust | bool
else "" }}
{{ "--add-service=dns" if ipaserver_setup_dns | bool else "" }}
{{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }}
when: ipaserver_setup_firewalld | bool
@@ -400,6 +393,8 @@
firewall-cmd
--add-service=freeipa-ldap
--add-service=freeipa-ldaps
{{ "--add-service=freeipa-trust" if ipaserver_setup_adtrust | bool
else "" }}
{{ "--add-service=dns" if ipaserver_setup_dns | bool else "" }}
{{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }}
when: ipaserver_setup_firewalld | bool