On 03/05/2013 02:10 PM, Petr Viktorin wrote:
Thanks! The mechanism works, but see below.
This is a RFE so it needs a design document.
http://freeipa.org/page/V3/Client_install_using_keytab
For context, I'll include your comment from trac:
> From my investigation I would conclude that we cannot support client
> install using backed-up keytab when the host has been unenrolled
> (e.g. after running ipa-client-install --uninstall). When
> unenrolling, we disable the host entry in LDAP and therefore
> effectively disable the Kerberos key, SSL certificate and all
> services of a host.
>
> We should only support reenrollment for clients that have not been
> unenrolled, and therefore still have valid Kerberos key.
I think it also makes sense from a security point of view: if the
machine is compromised, I'd expect that after unenrolling it can't
come back on its own.
Yes, that's also an issue here.
A new option --keytab has been added to ipa-client-install. This
can be used to specify path to the keytab and can be used instead
of -p or -w options.
With the patch this only works with --unatended; in interactive mode
it still asks for the admin username and password.
Fixed.
A host that has been previously unenrolled and does not have its
host entry disabled or removed, can be re-enrolled using
a previously backed up keytab file.
I'd not say "unenrolled" here, unenrolling from IPA disables the host.
Reworded.
[...]
diff --git a/ipa-client/ipa-install/ipa-client-install
b/ipa-client/ipa-install/ipa-client-install
index
308c3f8d0ec39e1e7f048d37a34738bf6a4853e2..e78b36a3c386184dc0cb1c83d8169890e3fa75da
100755
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -104,6 +104,8 @@ def parse_options():
help="principal to use to join the IPA realm"),
basic_group.add_option("-w", "--password", dest="password",
sensitive=True,
help="password to join the IPA realm (assumes
bulk password unless principal is also set)"),
+ basic_group.add_option("-k", "--keytab", dest="keytab",
sensitive=True,
+ help="path to backed up keytab from previous
enrollment"),
The keytab filename is not sensitive.
Fixed. I misunderstood what the option stands for.
[...]
- if options.unattended and (options.password is None and
options.principal is None and options.prompt_password is False) and
not options.on_master:
+ if options.unattended and (options.password is None and
+ options.principal is None and
+ options.keytab is None and
+ options.prompt_password is False)\
+ and not options.on_master:
Style issue: Wrap everything in the parentheses instead of using the
backslash.
Fixed.
[...]
+ if returncode != 0:
+ root_logger.error("Kerberos authentication
failed "
+ "using keytab: %s" %
options.keytab)
Fixed.
Use a comma instead of the %
[...]
I'm not a C expert but the ipa-join changes look fine.
Thanks for the review, updated patches are attached.
Tomas
>From 56288351b8ab9dc8b3076a7f4b895601a047eecb Mon Sep 17 00:00:00 2001
From: Tomas Babej <tba...@redhat.com>
Date: Tue, 26 Feb 2013 13:20:13 +0100
Subject: [PATCH] Add support for re-enrolling hosts using keytab
A host that has been recreated and does not have its
host entry disabled or removed, can be re-enrolled using
a previously backed up keytab file.
A new option --keytab has been added to ipa-client-install. This
can be used to specify path to the keytab and can be used instead
of -p or -w options.
A new option -f has been added to ipa-join. It forces client to
join even if the host entry already exits. A new certificate,
ssh keys are generated, ipaUniqueID stays the same.
https://fedorahosted.org/freeipa/ticket/3374
---
ipa-client/ipa-install/ipa-client-install | 40 +++++++++++++++++++++++++++----
ipa-client/ipa-join.c | 14 +++++++----
2 files changed, 44 insertions(+), 10 deletions(-)
diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install
index 308c3f8d0ec39e1e7f048d37a34738bf6a4853e2..a16a6b2d7cddbf7085b27c3835a4676919a8a15b 100755
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -104,6 +104,8 @@ def parse_options():
help="principal to use to join the IPA realm"),
basic_group.add_option("-w", "--password", dest="password", sensitive=True,
help="password to join the IPA realm (assumes bulk password unless principal is also set)"),
+ basic_group.add_option("-k", "--keytab", dest="keytab",
+ help="path to backed up keytab from previous enrollment"),
basic_group.add_option("-W", dest="prompt_password", action="store_true",
default=False,
help="Prompt for a password to join the IPA realm"),
@@ -1691,8 +1693,12 @@ def install(options, env, fstore, statestore):
except ipaclient.ntpconf.NTPConfigurationError:
pass
- if options.unattended and (options.password is None and options.principal is None and options.prompt_password is False) and not options.on_master:
- root_logger.error("One of password and principal are required.")
+ if options.unattended and ((options.password is None and
+ options.principal is None and
+ options.keytab is None and
+ options.prompt_password is False)\
+ and not options.on_master):
+ root_logger.error("One of password / principal / keytab is required.")
return CLIENT_INSTALL_ERROR
if options.hostname:
@@ -1910,8 +1916,10 @@ def install(options, env, fstore, statestore):
ipaservices.backup_and_replace_hostname(fstore, statestore, options.hostname)
if not options.unattended:
- if options.principal is None and options.password is None and options.prompt_password is False:
- options.principal = user_input("User authorized to enroll computers", allow_empty=False)
+ if (options.principal is None and options.password is None and
+ options.prompt_password is False and options.keytab is None):
+ options.principal = user_input("User authorized to enroll "
+ "computers", allow_empty=False)
root_logger.debug(
"will use principal provided as option: %s", options.principal)
@@ -1985,12 +1993,34 @@ def install(options, env, fstore, statestore):
else:
stdin = sys.stdin.readline()
- (stderr, stdout, returncode) = run(["kinit", principal], raiseonerr=False, stdin=stdin, env=env)
+ (stderr, stdout, returncode) = run(["kinit", principal],
+ raiseonerr=False,
+ stdin=stdin,
+ env=env)
if returncode != 0:
root_logger.error("Kerberos authentication failed")
root_logger.info("%s", stdout)
print_port_conf_info()
return CLIENT_INSTALL_ERROR
+ elif options.keytab:
+ join_args.append("-f")
+ if os.path.exists(options.keytab):
+ (stderr, stdout, returncode) = run(
+ ['/usr/bin/kinit','-k', '-t', options.keytab,
+ 'host/%s@%s' % (hostname, cli_realm)],
+ env=env,
+ raiseonerr=False)
+
+ if returncode != 0:
+ root_logger.error("Kerberos authentication failed "
+ "using keytab: %s", options.keytab)
+ root_logger.info("%s", stdout)
+ print_port_conf_info()
+ return CLIENT_INSTALL_ERROR
+ else:
+ root_logger.error("Keytab file could not be found: %s"
+ % options.keytab)
+ return CLIENT_INSTALL_ERROR
elif options.password:
nolog = (options.password,)
join_args.append("-w")
diff --git a/ipa-client/ipa-join.c b/ipa-client/ipa-join.c
index 8369e360f90dfc4ade1db792745b660da50677ca..df33d3b08cf69a37ae9de76266a071825a95871f 100644
--- a/ipa-client/ipa-join.c
+++ b/ipa-client/ipa-join.c
@@ -558,7 +558,7 @@ done:
}
static int
-join_krb5(const char *ipaserver, char *hostname, char **hostdn, const char **princ, const char **subject, int quiet) {
+join_krb5(const char *ipaserver, char *hostname, char **hostdn, const char **princ, const char **subject, int force, int quiet) {
xmlrpc_env env;
xmlrpc_value * argArrayP = NULL;
xmlrpc_value * paramArrayP = NULL;
@@ -663,7 +663,7 @@ join_krb5(const char *ipaserver, char *hostname, char **hostdn, const char **pri
goto cleanup;
}
xmlrpc_struct_find_value(&env, structP, "krblastpwdchange", &krblastpwdchangeP);
- if (krblastpwdchangeP) {
+ if (krblastpwdchangeP && !force) {
xmlrpc_value * singleprincP = NULL;
/* FIXME: all values are returned as lists currently. Once this is
@@ -929,7 +929,7 @@ cleanup:
static int
-join(const char *server, const char *hostname, const char *bindpw, const char *basedn, const char *keytab, int quiet)
+join(const char *server, const char *hostname, const char *bindpw, const char *basedn, const char *keytab, int force, int quiet)
{
int rval = 0;
pid_t childpid = 0;
@@ -1003,7 +1003,8 @@ join(const char *server, const char *hostname, const char *bindpw, const char *b
rval = 6;
goto cleanup;
}
- rval = join_krb5(ipaserver, host, &hostdn, &princ, &subject, quiet);
+ rval = join_krb5(ipaserver, host, &hostdn, &princ, &subject, force,
+ quiet);
}
if (rval) goto cleanup;
@@ -1100,6 +1101,7 @@ main(int argc, const char **argv) {
static const char *basedn = NULL;
int quiet = 0;
int unenroll = 0;
+ int force = 0;
struct poptOption options[] = {
{ "debug", 'd', POPT_ARG_NONE, &debug, 0,
_("Print the raw XML-RPC output in GSSAPI mode"), NULL },
@@ -1113,6 +1115,8 @@ main(int argc, const char **argv) {
_("IPA Server to use"), _("hostname") },
{ "keytab", 'k', POPT_ARG_STRING, &keytab, 0,
_("Specifies where to store keytab information."), _("filename") },
+ { "force", 'f', POPT_ARG_NONE, &force, 0,
+ _("Force the host join. Rejoin even if already joined."), NULL },
{ "bindpw", 'w', POPT_ARG_STRING, &bindpw, 0,
_("LDAP password (if not using Kerberos)"), _("password") },
{ "basedn", 'b', POPT_ARG_STRING, &basedn, 0,
@@ -1149,7 +1153,7 @@ main(int argc, const char **argv) {
} else {
ret = check_perms(keytab);
if (ret == 0)
- ret = join(server, hostname, bindpw, basedn, keytab, quiet);
+ ret = join(server, hostname, bindpw, basedn, keytab, force, quiet);
}
exit(ret);
--
1.7.11.7
_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel