iprop: Enable secondary KDC bootstrapping w/ PKINIT
With this change it's possible to bootstrap a KDC using a client certificate with a PKINIT SAN for iprop/fqdn. Given such a certificate one could run ipropd-slave via kinit to pull down the initial copy of the HDB, then start the KDC services using the HDBGET: keytab. That should make bootstrapping new secondary KDCs very easy. One could bootstrap the KDC with such a certificate using, e.g., Safeboot (https://github.com/osresearch/safeboot), enrolling the host as a KDC.
This commit is contained in:
@@ -68,6 +68,8 @@
|
||||
.Oo Fl r Ar string \*(Ba Xo Fl Fl realm= Ns Ar string Xc Oc
|
||||
.Oo Fl d Ar file \*(Ba Xo Fl Fl database= Ns Ar file Xc Oc
|
||||
.Oo Fl k Ar kspec \*(Ba Xo Fl Fl keytab= Ns Ar kspec Xc Oc
|
||||
.Oo Xo Fl Fl no-keytab Xc Oc
|
||||
.Oo Xo Fl Fl cache= Ns Ar cspec Xc Oc
|
||||
.Op Fl Fl statusfile= Ns Ar file
|
||||
.Op Fl Fl hostname= Ns Ar hostname
|
||||
.Op Fl Fl port= Ns Ar port
|
||||
@@ -125,10 +127,40 @@ This should normally be defined as
|
||||
in
|
||||
.Pa /etc/services
|
||||
or another source of the services database.
|
||||
The master and slaves
|
||||
must each have access to a keytab with keys for the
|
||||
.Nm iprop
|
||||
service principal on the local host.
|
||||
.Pp
|
||||
The
|
||||
.Nm ipropd-master
|
||||
and
|
||||
.Nm ipropd-slave
|
||||
programs require acceptor and initiator credentials,
|
||||
respectively, for host-based principals for the
|
||||
.Ar iprop
|
||||
service and the fully-qualified hostnames of the hosts on which
|
||||
they run.
|
||||
.Pp
|
||||
The
|
||||
.Nm ipropd-master
|
||||
program uses, by default, the HDB-backed keytab
|
||||
.Ar HDBGET: ,
|
||||
though a file-based keytab can also be specified.
|
||||
.Pp
|
||||
The
|
||||
.Nm ipropd-slave
|
||||
program uses the default keytab, which is specified by the
|
||||
.Ev KRB5_KTNAME
|
||||
environment variable, or the value of the
|
||||
.Ar default_keytab_name
|
||||
configuration parameter in the
|
||||
.Ar [libdefaults]
|
||||
section.
|
||||
However, if the
|
||||
.Fl Fl no-keytab
|
||||
option is given, then
|
||||
.Nm ipropd-slave
|
||||
will use the given or default credentials cache, and it will
|
||||
expect that cache to be kept fresh externally (such as by the
|
||||
.Nm kinit
|
||||
program).
|
||||
.Pp
|
||||
There is a keep-alive feature logged in the master's
|
||||
.Pa slave-stats
|
||||
@@ -150,6 +182,11 @@ Supported options for
|
||||
Keytab for authenticating
|
||||
.Nm ipropd-slave
|
||||
clients.
|
||||
.It Fl Fl cache= Ns Ar cspec
|
||||
If the keytab given is the empty string then credentials will be
|
||||
used from the default credentials cache, or from the
|
||||
.Ar cspec
|
||||
if given.
|
||||
.It Fl d Ar file , Fl Fl database= Ns Ar file
|
||||
Database (default per KDC)
|
||||
.It Fl Fl slave-stats-file= Ns Ar file
|
||||
@@ -201,6 +238,7 @@ in the database directory, or in the directory named by the
|
||||
.Ev HEIM_PIDFILE_DIR
|
||||
environment variable.
|
||||
.Sh SEE ALSO
|
||||
.Xr kinit 1 ,
|
||||
.Xr krb5.conf 5 ,
|
||||
.Xr hprop 8 ,
|
||||
.Xr hpropd 8 ,
|
||||
|
@@ -39,6 +39,9 @@ static const char *config_name = "ipropd-slave";
|
||||
|
||||
static int verbose;
|
||||
static int async_hdb = 0;
|
||||
static int no_keytab_flag;
|
||||
static char *ccache_str;
|
||||
static char *keytab_str;
|
||||
|
||||
static krb5_log_facility *log_facility;
|
||||
static char five_min[] = "5 min";
|
||||
@@ -115,8 +118,7 @@ connect_to_master (krb5_context context, const char *master,
|
||||
}
|
||||
|
||||
static void
|
||||
get_creds(krb5_context context, const char *keytab_str,
|
||||
krb5_ccache *cache, const char *serverhost)
|
||||
get_creds(krb5_context context, krb5_ccache *cache, const char *serverhost)
|
||||
{
|
||||
krb5_keytab keytab;
|
||||
krb5_principal client;
|
||||
@@ -127,13 +129,33 @@ get_creds(krb5_context context, const char *keytab_str,
|
||||
char keytab_buf[256];
|
||||
int aret;
|
||||
|
||||
if (no_keytab_flag) {
|
||||
/* We're using an externally refreshed ccache */
|
||||
if (*cache == NULL) {
|
||||
if (ccache_str == NULL)
|
||||
ret = krb5_cc_default(context, cache);
|
||||
else
|
||||
ret = krb5_cc_resolve(context, ccache_str, cache);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "Could not resolve the default cache");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (keytab_str == NULL) {
|
||||
ret = krb5_kt_default_name (context, keytab_buf, sizeof(keytab_buf));
|
||||
if (ret)
|
||||
krb5_err (context, 1, ret, "krb5_kt_default_name");
|
||||
keytab_str = keytab_buf;
|
||||
if (ret == 0) {
|
||||
keytab_str = keytab_buf;
|
||||
} else {
|
||||
krb5_warn(context, ret, "Using HDBGET: as the default keytab");
|
||||
keytab_str = "HDBGET:";
|
||||
}
|
||||
}
|
||||
|
||||
if (*cache)
|
||||
krb5_cc_destroy(context, *cache);
|
||||
*cache = NULL;
|
||||
|
||||
ret = krb5_kt_resolve(context, keytab_str, &keytab);
|
||||
if(ret)
|
||||
krb5_err(context, 1, ret, "%s", keytab_str);
|
||||
@@ -690,7 +712,6 @@ static char *status_file;
|
||||
static char *config_file;
|
||||
static int version_flag;
|
||||
static int help_flag;
|
||||
static char *keytab_str;
|
||||
static char *port_str;
|
||||
static int detach_from_console;
|
||||
static int daemon_child = -1;
|
||||
@@ -699,8 +720,12 @@ static struct getargs args[] = {
|
||||
{ "config-file", 'c', arg_string, &config_file, NULL, NULL },
|
||||
{ "realm", 'r', arg_string, &realm, NULL, NULL },
|
||||
{ "database", 'd', arg_string, &database, "database", "file"},
|
||||
{ "no-keytab", 0, arg_flag, &no_keytab_flag,
|
||||
"use externally refreshed cache", NULL },
|
||||
{ "ccache", 0, arg_string, &ccache_str,
|
||||
"client credentials", "CCACHE" },
|
||||
{ "keytab", 'k', arg_string, &keytab_str,
|
||||
"keytab to get authentication from", "kspec" },
|
||||
"client credentials keytab", "KEYTAB" },
|
||||
{ "time-lost", 0, arg_string, &server_time_lost,
|
||||
"time before server is considered lost", "time" },
|
||||
{ "status-file", 0, arg_string, &status_file,
|
||||
@@ -740,7 +765,7 @@ main(int argc, char **argv)
|
||||
kadm5_server_context *server_context;
|
||||
kadm5_config_params conf;
|
||||
int master_fd;
|
||||
krb5_ccache ccache;
|
||||
krb5_ccache ccache = NULL;
|
||||
krb5_principal server;
|
||||
char **files;
|
||||
int optidx = 0;
|
||||
@@ -858,7 +883,7 @@ main(int argc, char **argv)
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "db->close");
|
||||
|
||||
get_creds(context, keytab_str, &ccache, master);
|
||||
get_creds(context, &ccache, master);
|
||||
|
||||
ret = krb5_sname_to_principal (context, master, IPROP_NAME,
|
||||
KRB5_NT_SRV_HST, &server);
|
||||
@@ -923,8 +948,7 @@ main(int argc, char **argv)
|
||||
if (auth_context) {
|
||||
krb5_auth_con_free(context, auth_context);
|
||||
auth_context = NULL;
|
||||
krb5_cc_destroy(context, ccache);
|
||||
get_creds(context, keytab_str, &ccache, master);
|
||||
get_creds(context, &ccache, master);
|
||||
}
|
||||
if (verbose)
|
||||
krb5_warnx(context, "authenticating to master");
|
||||
|
Reference in New Issue
Block a user