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,12 +129,32 @@ 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");
 | 
			
		||||
	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)
 | 
			
		||||
@@ -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