From 38d7223376efe03ffd46317bf37b03b7266fe1b1 Mon Sep 17 00:00:00 2001 From: Florence Blanc-Renaud <flo@redhat.com> Date: Thu, 10 Aug 2017 16:54:44 +0200 Subject: [PATCH] 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. --- action_plugins/ipahost.py | 215 ++++++++++++++++++++++++++---- action_plugins/ipahost.pyc | Bin 2096 -> 0 bytes inventory/hosts | 12 +- library/ipa_facts.py | 175 ++++++++++++++++++++++++ library/ipaclient.py | 6 +- library/ipahost.py | 25 ++-- roles/ipaclient/tasks/install.yml | 42 ++++-- roles/ipaclient/vars/default.yml | 2 +- roles/ipaclient/vars/rhel.yml | 2 +- site.yml | 11 -- 10 files changed, 427 insertions(+), 63 deletions(-) delete mode 100644 action_plugins/ipahost.pyc create mode 100644 library/ipa_facts.py diff --git a/action_plugins/ipahost.py b/action_plugins/ipahost.py index 3854dcec..d4bd4b02 100644 --- a/action_plugins/ipahost.py +++ b/action_plugins/ipahost.py @@ -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)) + if not principal: + result['failed'] = True + result['msg'] = "principal is required" return result - # Password not supplied, need to transfer the keytab file - # Check if the source keytab exists + data = self._execute_module(module_name='ipa_facts', module_args=dict(), + task_vars=None) try: - keytab = self._find_needle('files', keytab) - except AnsibleError as e: + domain = data['ansible_facts']['ipa']['domain'] + realm = data['ansible_facts']['ipa']['realm'] + except KeyError: result['failed'] = True - result['msg'] = to_native(e) + result['msg'] = "The host is not an IPA server" 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)) + items = principal.split('@') + if len(items) < 2: + principal = str('%s@%s' % (principal, realm)) - new_module_args = self._task.args.copy() - new_module_args.update(dict(keytab=tmp_keytab)) + # 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') - # Execute module - result.update(self._execute_module(module_args=new_module_args, task_vars=task_vars)) - self._remove_tmp_path(tmp) - return result + # 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]) diff --git a/action_plugins/ipahost.pyc b/action_plugins/ipahost.pyc deleted file mode 100644 index 5ef86f653d89033f779da0dc8329b5e900761cf5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2096 zcmZSn%**wXFDx>d0ScHI7#JKF7#NDf7#J8*7#LC*8FCmHq9AN0h8#wQTqcGnCI&{3 z95X`>Gea&5Llg^y&%%(y%8<*(5XHv8n8M1C%Epk!$dJOu(89pb%)k&C#SStqSc9E` zfg$t%|NsB}G#D8e7)p2;7#JM$iZhdPQeBIR@{1s%oFJ+E_`JlD%(7I75En>ca!F=> zo>O9RDnuWc>zkianv;s+2`7*z#2FYEQW+Sc7(o`NFoHbP!o(28%n%f;!NkD8kPPxJ z$Raid1_o!4jungy3^hy)DVz-191KMg3?+;pr`Iwu<S{UmFfo)cGt@9JG&3<|u`tvy zf>bs$G1P(uvsf9j*ch_FeoWy6si|cFDMpBcjRmP^WvF3+SuvTRh84js;b5p?W=LUX zut{M7vsf8yYM2><YgieIwt)n)IKgIefr7P$iJ_T+v6+#95u~J23@pRVkirf!9%K&- zLwKGZ14{`HLpB#f(H{oJS~dnogcT*c3^i;F&5R&(Q=k?_)G#n)@qzu!2sV$OAxnTE zOAzGS5+Q~xVTLRbu<?vwAF_khh=N3F*g+zUApK$>)ivx4X-pu~!9tM05eFO0!BE4& zki`iK+Z09ykUqFC5Z(hTN?`*BF#{9WlMD=55+IYo9A<`K4N!V0PGe+X;8K8sjKsW@ zoYW$PwEQB4w9K4Tg_5GgyyCRfB8B{d)S^UC(kbSGtIjM))KW;!&&^HDODR@JPRvtC z%`C}CEm9~b$}h`INmWQxC`c?WF3&GYQOGY+NL0v9tt?4Q0-KC5Bu^o~C?&N>p(I}+ zv9u&3HLoNyIk6;FAwN%{BqLQJH!&|UJvBukFFz$!p**uBL%}<>C@HllzgQ1$MtDYQ z9>Vy{VweL`bQCg66!KD2Q;I>xC#5PR=NDwArYNKp<>!J;PtMOPDay}*n*_F{Bp)n? zY%{{Hkc`Y?1xIkUQGnzdg@V+gwEUvnVz92{{DMk_a*%^S_NJyFbe4c}2_y(gI2afh zU||CmPfN_qNlhu1V_;x_C;^2SOoc*bu|iR5VQFSjYDx(x&*c`UmvDkIcw%vOd|6^q zaS1B}0|O|=ic7c|7#MQF89F|(D81NELlUHrg@J*=FF!A}1jI<mOfCWIC@w8XEeZme z2sXB;G!HBsUy@jy4OR&<0W6iCS^^dbDJo3`JGitUC9x#6gr9+dAwIPtHMz7TH6CIu zxL}D-%gjrO2L(Y+Y7nS!3<8%`d?4kyiP@>~CAkIh1&JjYVE4u+=jY|6f&&$7czkh2 zYEBN=i&^=Zc@Tx55+}bH><X|(P#7j97N_PV=BAc_4Th!Gcu+``@Ph10%d99Zh%ZPj z$}KhmYX!wmi2z8dC^a{~4B-$BaDak>r#Lky4eaTX+=3vGEnqhlr52awlmvkk1c5@k z1mvOA5>O@r`2`Yd;PA*xEr$jLI0iI8-Uk!KpfXZFBR@A)KdmS=FR?TQM5ksJB<dFz zCF>_b3US@EqExV0A~-<e3vx=+GxLh|GYb+k@{3FK3Mzv@zLf@*w-z9?xp^3Qn4}pc z7$uk_7`Yg^7+ILv7$q55SeO~b82K5w7zG$vnRys_7$q157=@XH7{!?78F?A~G(dg< zC&l=9P$0&~gMAYZb9{UdC@q0413Mo<P|YKtq$dUP2q<#d7&Snl9Rv~pM<_Hv^io09 zS}`~om4GB+;*j(fUs{rxQ>+(Xl3Gy$No8UT3=A+e(9qL^1ZEJ(9&mz3cm~X(mXE-} XX#;VXoe0QhATRMS2`~yU3NQfxf(r2! diff --git a/inventory/hosts b/inventory/hosts index a3a3ccf4..552db14b 100644 --- a/inventory/hosts +++ b/inventory/hosts @@ -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 diff --git a/library/ipa_facts.py b/library/ipa_facts.py new file mode 100644 index 00000000..625387fd --- /dev/null +++ b/library/ipa_facts.py @@ -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() diff --git a/library/ipaclient.py b/library/ipaclient.py index 37bd9c5b..a1840669 100644 --- a/library/ipaclient.py +++ b/library/ipaclient.py @@ -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) diff --git a/library/ipahost.py b/library/ipahost.py index c4914d61..08305fc1 100644 --- a/library/ipahost.py +++ b/library/ipahost.py @@ -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') - - if keytab: - kinit_keytab(principal, keytab, ccache_name) - elif password: - kinit_password(principal, password, ccache_name) + os.environ['KRB5CCNAME']=ccache - os.environ['KRB5CCNAME'] = ccache_name cfg = dict( context='ansible_module', confdir=paths.ETC_IPA, diff --git a/roles/ipaclient/tasks/install.yml b/roles/ipaclient/tasks/install.yml index cc6ce0b0..a05aee3b 100644 --- a/roles/ipaclient/tasks/install.yml +++ b/roles/ipaclient/tasks/install.yml @@ -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) }}" diff --git a/roles/ipaclient/vars/default.yml b/roles/ipaclient/vars/default.yml index a0e63eaf..eb675d4b 100644 --- a/roles/ipaclient/vars/default.yml +++ b/roles/ipaclient/vars/default.yml @@ -1,3 +1,3 @@ # defaults file for ipaclient -# defaults/fedora.yml +# vars/default.yml ipaclient_package: freeipa-client diff --git a/roles/ipaclient/vars/rhel.yml b/roles/ipaclient/vars/rhel.yml index c36d57dd..76c7a343 100644 --- a/roles/ipaclient/vars/rhel.yml +++ b/roles/ipaclient/vars/rhel.yml @@ -1,4 +1,4 @@ # defaults file for ipaclient -# defaults/rhel.yml +# vars/rhel.yml ipaclient_package: ipa-client diff --git a/site.yml b/site.yml index 43d5bcc4..18a4255a 100644 --- a/site.yml +++ b/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 }}" -- GitLab