mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-03-26 21:33:05 +00:00
Modify ipahost module: the authentication is done locally on the controller
node and the credential cache is copied to the managed node ipahost module is also using facts gathered from the server to find the domain and realm.
This commit is contained in:
@@ -17,61 +17,226 @@
|
||||
# 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
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
from jinja2 import Template
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils._text import to_native
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
try:
|
||||
from __main__ import display
|
||||
except ImportError:
|
||||
from ansible.utils.display import Display
|
||||
display = Display()
|
||||
|
||||
def run_cmd(args, stdin=None):
|
||||
"""
|
||||
Execute an external command.
|
||||
"""
|
||||
p_in = None
|
||||
p_out = subprocess.PIPE
|
||||
p_err = subprocess.PIPE
|
||||
|
||||
if stdin:
|
||||
p_in = subprocess.PIPE
|
||||
|
||||
p = subprocess.Popen(args, stdin=p_in, stdout=p_out, stderr=p_err,
|
||||
close_fds=True)
|
||||
stdout, stderr = p.communicate(stdin)
|
||||
|
||||
return p.returncode
|
||||
|
||||
|
||||
def kinit_password(principal, password, ccache_name, config):
|
||||
"""
|
||||
Perform kinit using principal/password, with the specified config file
|
||||
and store the TGT in ccache_name.
|
||||
"""
|
||||
args = [ "/usr/bin/kinit", principal, '-c', ccache_name]
|
||||
old_config = os.environ.get('KRB5_CONFIG')
|
||||
os.environ['KRB5_CONFIG'] = config
|
||||
|
||||
try:
|
||||
result = run_cmd(args, stdin=password)
|
||||
return result
|
||||
finally:
|
||||
if old_config is not None:
|
||||
os.environ['KRB5_CONFIG'] = old_config
|
||||
else:
|
||||
os.environ.pop('KRB5_CONFIG', None)
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
old_config = os.environ.get('KRB5_CONFIG')
|
||||
os.environ['KRB5_CONFIG'] = config
|
||||
try:
|
||||
name = gssapi.Name(principal, gssapi.NameType.kerberos_principal)
|
||||
store = {'ccache': ccache_name,
|
||||
'client_keytab': keytab}
|
||||
cred = gssapi.Credentials(name=name, store=store, usage='initiate')
|
||||
return cred
|
||||
finally:
|
||||
if old_config is not None:
|
||||
os.environ['KRB5_CONFIG'] = old_config
|
||||
else:
|
||||
os.environ.pop('KRB5_CONFIG', None)
|
||||
|
||||
|
||||
KRB5CONF_TEMPLATE = """
|
||||
[logging]
|
||||
default = FILE:/var/log/krb5libs.log
|
||||
kdc = FILE:/var/log/krb5kdc.log
|
||||
admin_server = FILE:/var/log/kadmind.log
|
||||
|
||||
[libdefaults]
|
||||
default_realm = {{ ipa_realm }}
|
||||
dns_lookup_realm = false
|
||||
dns_lookup_kdc = true
|
||||
rdns = false
|
||||
ticket_lifetime = {{ ipa_lifetime }}
|
||||
forwardable = true
|
||||
udp_preference_limit = 0
|
||||
default_ccache_name = KEYRING:persistent:%{uid}
|
||||
|
||||
[realms]
|
||||
{{ ipa_realm }} = {
|
||||
kdc = {{ ipa_server }}:88
|
||||
master_kdc = {{ ipa_server }}:88
|
||||
admin_server = {{ ipa_server }}:749
|
||||
default_domain = {{ ipa_domain }}
|
||||
}
|
||||
|
||||
[domain_realm]
|
||||
.{{ ipa_domain }} = {{ ipa_realm }}
|
||||
{{ ipa_domain }} = {{ ipa_realm}}
|
||||
"""
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
"""
|
||||
handler for file transfer operations
|
||||
handler for credential cache transfer
|
||||
|
||||
ipa* commands can either provide a password or a keytab file
|
||||
in order to authenticate on the managed node with Kerberos.
|
||||
When a keytab is provided, it needs to be copied from the control
|
||||
node to the managed node.
|
||||
This Action Module performs the copy when needed.
|
||||
The module is using these credentials to obtain a TGT locally on the
|
||||
control node:
|
||||
- need to create a krb5.conf Kerberos client configuration that is
|
||||
using IPA server
|
||||
- set the environment variable KRB5_CONFIG to point to this conf file
|
||||
- set the environment variable KRB5CCNAME to use a specific cache
|
||||
- perform kinit on the control node
|
||||
This command creates the credential cache file
|
||||
- copy the credential cache file on the managed node
|
||||
|
||||
Then the IPA commands can use this credential cache file.
|
||||
"""
|
||||
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
principal = self._task.args.get('principal', None)
|
||||
keytab = self._task.args.get('keytab', None)
|
||||
password = self._task.args.get('password', None)
|
||||
lifetime = self._task.args.get('lifetime', '1h')
|
||||
|
||||
if (keytab is None and password is None):
|
||||
if (not keytab and not password):
|
||||
result['failed'] = True
|
||||
result['msg'] = "keytab or password is required"
|
||||
return result
|
||||
|
||||
# If password is supplied, just need to execute the module
|
||||
if password:
|
||||
result.update(self._execute_module(task_vars=task_vars))
|
||||
return result
|
||||
|
||||
# Password not supplied, need to transfer the keytab file
|
||||
# Check if the source keytab exists
|
||||
try:
|
||||
keytab = self._find_needle('files', keytab)
|
||||
except AnsibleError as e:
|
||||
if not principal:
|
||||
result['failed'] = True
|
||||
result['msg'] = to_native(e)
|
||||
result['msg'] = "principal is required"
|
||||
return result
|
||||
|
||||
# Create the remote tmp dir
|
||||
tmp = self._make_tmp_path()
|
||||
tmp_keytab = self._connection._shell.join_path(
|
||||
tmp, os.path.basename(keytab))
|
||||
self._transfer_file(keytab, tmp_keytab)
|
||||
self._fixup_perms2((tmp, tmp_keytab))
|
||||
data = self._execute_module(module_name='ipa_facts', module_args=dict(),
|
||||
task_vars=None)
|
||||
try:
|
||||
domain = data['ansible_facts']['ipa']['domain']
|
||||
realm = data['ansible_facts']['ipa']['realm']
|
||||
except KeyError:
|
||||
result['failed'] = True
|
||||
result['msg'] = "The host is not an IPA server"
|
||||
return result
|
||||
|
||||
new_module_args = self._task.args.copy()
|
||||
new_module_args.update(dict(keytab=tmp_keytab))
|
||||
items = principal.split('@')
|
||||
if len(items) < 2:
|
||||
principal = str('%s@%s' % (principal, realm))
|
||||
|
||||
# Execute module
|
||||
result.update(self._execute_module(module_args=new_module_args, task_vars=task_vars))
|
||||
self._remove_tmp_path(tmp)
|
||||
return result
|
||||
# Locally create a temp directory to store krb5.conf and ccache
|
||||
local_temp_dir = tempfile.mkdtemp()
|
||||
krb5conf_name = os.path.join(local_temp_dir, 'krb5.conf')
|
||||
ccache_name = os.path.join(local_temp_dir, 'ccache')
|
||||
|
||||
# Create the krb5.conf from the template
|
||||
template = Template(KRB5CONF_TEMPLATE)
|
||||
content = template.render(dict(
|
||||
ipa_server=task_vars['ansible_host'],
|
||||
ipa_domain=domain,
|
||||
ipa_realm=realm,
|
||||
ipa_lifetime=lifetime))
|
||||
|
||||
with open(krb5conf_name, 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
if password:
|
||||
# perform kinit -c ccache_name -l 1h principal
|
||||
res = kinit_password(principal, password, ccache_name,
|
||||
krb5conf_name)
|
||||
if res:
|
||||
result['failed'] = True
|
||||
result['msg'] = 'kinit %s with password failed' % principal
|
||||
return result
|
||||
|
||||
else:
|
||||
# Password not supplied, need to use the keytab file
|
||||
# Check if the source keytab exists
|
||||
try:
|
||||
keytab = self._find_needle('files', keytab)
|
||||
except AnsibleError as e:
|
||||
result['failed'] = True
|
||||
result['msg'] = to_native(e)
|
||||
return result
|
||||
# perform kinit -kt keytab
|
||||
try:
|
||||
kinit_keytab(principal, keytab, ccache_name, krb5conf_name)
|
||||
except Exception as e:
|
||||
result['failed'] = True
|
||||
result['msg'] = 'kinit %s with keytab %s failed' % (principal, keytab)
|
||||
return result
|
||||
|
||||
try:
|
||||
# Create the remote tmp dir
|
||||
tmp = self._make_tmp_path()
|
||||
tmp_ccache = self._connection._shell.join_path(
|
||||
tmp, os.path.basename(ccache_name))
|
||||
|
||||
# Copy the ccache to the remote tmp dir
|
||||
self._transfer_file(ccache_name, tmp_ccache)
|
||||
self._fixup_perms2((tmp, tmp_ccache))
|
||||
|
||||
new_module_args = self._task.args.copy()
|
||||
new_module_args.pop('password', None)
|
||||
new_module_args.pop('keytab', None)
|
||||
new_module_args.pop('lifetime', None)
|
||||
new_module_args.update(ccache=tmp_ccache)
|
||||
|
||||
# Execute module
|
||||
result.update(self._execute_module(module_args=new_module_args,
|
||||
task_vars=task_vars))
|
||||
return result
|
||||
finally:
|
||||
# delete the local temp directory
|
||||
shutil.rmtree(local_temp_dir, ignore_errors=True)
|
||||
run_cmd(['/usr/bin/kdestroy', '-c', tmp_ccache])
|
||||
|
||||
Binary file not shown.
@@ -9,7 +9,13 @@ ipaclient_domain=ipadomain.com
|
||||
ipaclient_realm=IPADOMAIN.COM
|
||||
ipaclient_server=ipaserver.ipadomain.com
|
||||
ipaclient_extraargs=[ '--kinit-attempts=3', '--mkhomedir']
|
||||
# if neither ipaclient_password nor ipaclient_keytab is defined,
|
||||
# the enrollement will create a OneTime Password and enroll with this OTP
|
||||
# In this case ipaserver_password or ipaserver_keytab is required
|
||||
#ipaclient_principal=admin
|
||||
#ipaclient_password=SecretPassword123
|
||||
#ipaclient_keytab=/tmp/krb5.keytab
|
||||
ipaserver_principal=admin
|
||||
#ipaserver_password=SecretPassword123
|
||||
ipaserver_keytab=files/admin.keytab
|
||||
|
||||
[ipaservers:vars]
|
||||
ipa_admin=admin
|
||||
ipa_password=MySecretPassword123
|
||||
|
||||
175
library/ipa_facts.py
Normal file
175
library/ipa_facts.py
Normal file
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import re
|
||||
import six
|
||||
from six.moves.configparser import RawConfigParser
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
try:
|
||||
from ipalib import api
|
||||
except ImportError:
|
||||
HAS_IPALIB = False
|
||||
else:
|
||||
HAS_IPALIB = True
|
||||
from ipaplatform.paths import paths
|
||||
try:
|
||||
# FreeIPA >= 4.5
|
||||
from ipalib.install import sysrestore
|
||||
except ImportError:
|
||||
# FreeIPA 4.4 and older
|
||||
from ipapython import sysrestore
|
||||
|
||||
try:
|
||||
import ipaserver
|
||||
except ImportError:
|
||||
HAS_IPASERVER = False
|
||||
else:
|
||||
HAS_IPASERVER = True
|
||||
|
||||
SERVER_SYSRESTORE_STATE = "/var/lib/ipa/sysrestore/sysrestore.state"
|
||||
NAMED_CONF = "/etc/named.conf"
|
||||
VAR_LIB_PKI_TOMCAT = "/var/lib/pki/pki-tomcat"
|
||||
|
||||
|
||||
def is_ntpd_configured():
|
||||
# ntpd is configured when sysrestore.state contains the line
|
||||
# [ntpd]
|
||||
ntpd_conf_section = re.compile('^\s*\[ntpd\]\s*$')
|
||||
|
||||
try:
|
||||
with open(SERVER_SYSRESTORE_STATE) as f:
|
||||
for line in f.readlines():
|
||||
if ntpd_conf_section.match(line):
|
||||
return True
|
||||
return False
|
||||
except IOError:
|
||||
return False
|
||||
|
||||
def is_dns_configured():
|
||||
# dns is configured when /etc/named.conf contains the line
|
||||
# dyndb "ipa" "/usr/lib64/bind/ldap.so" {
|
||||
bind_conf_section = re.compile('^\s*dyndb\s+"ipa"\s+"[^"]+"\s+{$')
|
||||
|
||||
try:
|
||||
with open(NAMED_CONF) as f:
|
||||
for line in f.readlines():
|
||||
if bind_conf_section.match(line):
|
||||
return True
|
||||
return False
|
||||
except IOError:
|
||||
return False
|
||||
|
||||
def is_dogtag_configured(subsystem):
|
||||
# ca / kra is configured when the directory /var/lib/pki/pki-tomcat/[ca|kra]
|
||||
# exists
|
||||
available_subsystems = { 'ca', 'kra' }
|
||||
assert subsystem in available_subsystems
|
||||
|
||||
return os.path.isdir(os.path.join(VAR_LIB_PKI_TOMCAT, subsystem))
|
||||
|
||||
def is_ca_configured():
|
||||
return is_dogtag_configured('ca')
|
||||
|
||||
def is_kra_configured():
|
||||
return is_dogtag_configured('kra')
|
||||
|
||||
def is_client_configured():
|
||||
# IPA Client is configured when /etc/ipa/default.conf exists
|
||||
# and /var/lib/ipa-client/sysrestore/sysrestore.state exists
|
||||
|
||||
fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
|
||||
return (os.path.isfile(paths.IPA_DEFAULT_CONF) and fstore.has_files())
|
||||
|
||||
def is_server_configured():
|
||||
# IPA server is configured when /etc/ipa/default.conf exists
|
||||
# and /var/lib/ipa/sysrestore/sysrestore.state exists
|
||||
return (os.path.isfile(paths.IPA_DEFAULT_CONF) and
|
||||
os.path.isfile(SERVER_SYSRESTORE_STATE))
|
||||
|
||||
def get_ipa_conf():
|
||||
# Extract basedn, realm and domain from /etc/ipa/default.conf
|
||||
parser = RawConfigParser()
|
||||
parser.read(paths.IPA_DEFAULT_CONF)
|
||||
basedn = parser.get('global', 'basedn')
|
||||
realm = parser.get('global', 'realm')
|
||||
domain = parser.get('global', 'domain')
|
||||
return dict(
|
||||
basedn=basedn,
|
||||
realm=realm,
|
||||
domain=domain
|
||||
)
|
||||
|
||||
def get_ipa_version():
|
||||
try:
|
||||
from ipapython import version
|
||||
except ImportError:
|
||||
return None
|
||||
else:
|
||||
version_info = []
|
||||
for part in version.VERSION.split('.'):
|
||||
# DEV versions look like:
|
||||
# 4.4.90.201610191151GITd852c00
|
||||
# 4.4.90.dev201701071308+git2e43db1
|
||||
if part.startswith('dev') or 'GIT' in part:
|
||||
version_info.append(part)
|
||||
else:
|
||||
version_info.append(int(part))
|
||||
|
||||
return dict(
|
||||
api_version=version.API_VERSION,
|
||||
num_version=version.NUM_VERSION,
|
||||
vendor_version=version.VENDOR_VERSION,
|
||||
version=version.VERSION,
|
||||
version_info=version_info
|
||||
)
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
# The module does not change anything, meaning that
|
||||
# check mode is supported
|
||||
|
||||
ipa_facts = dict(
|
||||
packages= dict(
|
||||
ipalib=HAS_IPALIB,
|
||||
ipaserver=HAS_IPASERVER,
|
||||
),
|
||||
configured=dict(
|
||||
client=False,
|
||||
server=False,
|
||||
dns=False,
|
||||
ca=False,
|
||||
kra=False,
|
||||
ntpd=False
|
||||
)
|
||||
)
|
||||
|
||||
if HAS_IPALIB:
|
||||
if is_client_configured():
|
||||
ipa_facts['configured']['client'] = True
|
||||
|
||||
ipa_facts['version'] = get_ipa_version()
|
||||
for key,value in six.iteritems(get_ipa_conf()):
|
||||
ipa_facts[key] = value
|
||||
|
||||
if HAS_IPASERVER:
|
||||
if is_server_configured():
|
||||
ipa_facts['configured']['server'] = True
|
||||
ipa_facts['configured']['dns'] = is_dns_configured()
|
||||
ipa_facts['configured']['ca'] = is_ca_configured()
|
||||
ipa_facts['configured']['kra'] = is_kra_configured()
|
||||
ipa_facts['configured']['ntpd'] = is_ntpd_configured()
|
||||
|
||||
module.exit_json(
|
||||
changed=False,
|
||||
ansible_facts=dict(ipa=ipa_facts)
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -151,7 +151,10 @@ def get_ipa_conf():
|
||||
parser.read(paths.IPA_DEFAULT_CONF)
|
||||
result = dict()
|
||||
for item in ['basedn', 'realm', 'domain', 'server', 'host', 'xmlrpc_uri']:
|
||||
value = parser.get('global', item)
|
||||
if parser.has_option('global', item):
|
||||
value = parser.get('global', item)
|
||||
else:
|
||||
value = None
|
||||
if value:
|
||||
result[item] = value
|
||||
|
||||
@@ -251,6 +254,7 @@ def ensure_ipa_client(module):
|
||||
if keytab:
|
||||
cmd.append("--keytab")
|
||||
cmd.append(keytab)
|
||||
cmd.append("-d")
|
||||
if otp:
|
||||
cmd.append("--password")
|
||||
cmd.append(otp)
|
||||
|
||||
@@ -36,7 +36,7 @@ description:
|
||||
options:
|
||||
principal:
|
||||
description: Kerberos principal used to manage the host
|
||||
required: false
|
||||
required: true
|
||||
default: admin
|
||||
password:
|
||||
description: Password for the kerberos principal
|
||||
@@ -44,6 +44,10 @@ options:
|
||||
keytab:
|
||||
description: Keytab file containing the Kerberos principal and encrypted key
|
||||
required: false
|
||||
lifetime:
|
||||
description: Sets the default lifetime for initial ticket requests
|
||||
required: false
|
||||
default: 1h
|
||||
fqdn:
|
||||
description: the fully-qualified hostname of the host to add/modify/remove
|
||||
required: true
|
||||
@@ -251,9 +255,10 @@ def main():
|
||||
"""
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
keytab = dict(required=False, type='path'),
|
||||
#keytab = dict(required=False, type='path'),
|
||||
principal = dict(default='admin'),
|
||||
password = dict(required=False, no_log=True),
|
||||
#password = dict(required=False, no_log=True),
|
||||
ccache = dict(required=False, type='path'),
|
||||
fqdn = dict(required=True),
|
||||
certificates = dict(required=False, type='list'),
|
||||
sshpubkey= dict(required=False),
|
||||
@@ -261,27 +266,21 @@ def main():
|
||||
random = dict(default=False, type='bool'),
|
||||
state = dict(default='present', choices=[ 'present', 'absent' ]),
|
||||
),
|
||||
required_one_of=[ [ 'password', 'keytab'], ],
|
||||
mutually_exclusive=[ [ 'password', 'keytab' ], ],
|
||||
#mutually_exclusive=[['password','keytab']],
|
||||
#required_one_of=[['[password','keytab']],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
principal = module.params.get('principal', 'admin')
|
||||
password = module.params.get('password')
|
||||
keytab = module.params.get('keytab')
|
||||
ccache = module.params.get('ccache')
|
||||
fqdn = unicode(module.params.get('fqdn'))
|
||||
state = module.params.get('state')
|
||||
|
||||
try:
|
||||
ccache_dir = tempfile.mkdtemp(prefix='krbcc')
|
||||
ccache_name = os.path.join(ccache_dir, 'ccache')
|
||||
os.environ['KRB5CCNAME']=ccache
|
||||
|
||||
if keytab:
|
||||
kinit_keytab(principal, keytab, ccache_name)
|
||||
elif password:
|
||||
kinit_password(principal, password, ccache_name)
|
||||
|
||||
os.environ['KRB5CCNAME'] = ccache_name
|
||||
cfg = dict(
|
||||
context='ansible_module',
|
||||
confdir=paths.ETC_IPA,
|
||||
|
||||
@@ -1,6 +1,32 @@
|
||||
---
|
||||
# tasks file for ipaclient
|
||||
|
||||
# The following block is executed when using OTP to enroll IPA client
|
||||
# ie when neither ipaclient_password not ipaclient_keytab is set
|
||||
# It connects to ipaserver and add the host with --random option in order
|
||||
# to create a OneTime Password
|
||||
- block:
|
||||
- name: Install - Get a One-Time Password for client enrollment
|
||||
ipahost:
|
||||
state: present
|
||||
principal: "{{ ipaserver_principal | default('admin') }}"
|
||||
password: "{{ ipaserver_password | default(omit) }}"
|
||||
keytab: "{{ ipaserver_keytab | default(omit) }}"
|
||||
fqdn: "{{ ansible_fqdn }}"
|
||||
lifetime: "{{ ipaserver_lifetime | default(omit) }}"
|
||||
random: True
|
||||
register: ipahost_output
|
||||
# If the host is already enrolled, this command will exit on error
|
||||
# The error can be ignored
|
||||
failed_when: ipahost_output|failed and "Password cannot be set on enrolled host" not in ipahost_output.msg
|
||||
delegate_to: "{{ groups.ipaservers[0] }}"
|
||||
|
||||
- name: Install - Store the previously obtained OTP
|
||||
set_fact:
|
||||
ipaclient_otp: "{{ipahost_output.host.randompassword if ipahost_output.host is defined else 'dummyotp' }}"
|
||||
|
||||
when: ipaclient_password is not defined and ipaclient_keytab is not defined
|
||||
|
||||
- name: Install - Install IPA client package
|
||||
package:
|
||||
name: "{{ ipaclient_package }}"
|
||||
@@ -9,11 +35,11 @@
|
||||
- name: Install - Configure IPA client
|
||||
ipaclient:
|
||||
state: present
|
||||
domain: "{{ ipaclient_domain }}"
|
||||
realm: "{{ ipaclient_realm }}"
|
||||
server: "{{ ipaclient_server }}"
|
||||
principal: "{{ ipaclient_principal }}"
|
||||
password: "{{ ipaclient_password }}"
|
||||
keytab: "{{ ipaclient_keytab }}"
|
||||
otp: "{{ ipaclient_otp }}"
|
||||
extra_args: "{{ ipaclient_extraargs }}"
|
||||
domain: "{{ ipaclient_domain | default(omit) }}"
|
||||
realm: "{{ ipaclient_realm | default(omit) }}"
|
||||
server: "{{ ipaclient_server | default(omit) }}"
|
||||
principal: "{{ ipaclient_principal | default(omit) }}"
|
||||
password: "{{ ipaclient_password | default(omit) }}"
|
||||
keytab: "{{ ipaclient_keytab | default(omit) }}"
|
||||
otp: "{{ ipaclient_otp | default(omit) }}"
|
||||
extra_args: "{{ ipaclient_extraargs | default(omit) }}"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# defaults file for ipaclient
|
||||
# defaults/fedora.yml
|
||||
# vars/default.yml
|
||||
ipaclient_package: freeipa-client
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# defaults file for ipaclient
|
||||
# defaults/rhel.yml
|
||||
# vars/rhel.yml
|
||||
ipaclient_package: ipa-client
|
||||
|
||||
|
||||
11
site.yml
11
site.yml
@@ -3,17 +3,6 @@
|
||||
hosts: ipaclients
|
||||
become: true
|
||||
|
||||
pre_tasks:
|
||||
|
||||
- name: For OTP client registration, add client and get OTP
|
||||
ipahost:
|
||||
keytab: files/admin.keytab
|
||||
fqdn: "{{ ansible_fqdn }}"
|
||||
random: True
|
||||
register: ipahost
|
||||
delegate_to: "{{ groups.ipaservers[0] }}"
|
||||
|
||||
roles:
|
||||
- role: ipaclient
|
||||
state: present
|
||||
ipaclient_otp: "{{ ipahost.host.randompassword }}"
|
||||
|
||||
Reference in New Issue
Block a user