Start multiple dependent daemons in one systemd service
Don't. Systemd explicitly does not support more than one "monitored" process per .service unit. The k5start should be a separate service that FreeRADIUS depends on.
So, for my ideal solution the freeradius.service would create the /run/freeradius directory, then launch something like a ticket.service and then resume to start RADIUS. Looks similar to BindsTo=, but still somehow different.
Pre-create the directory via tmpfiles.d, as was common practice before the "RuntimeDirectory=" was added to systemd as a feature.
/etc/tmpfiles.d/freeradius.conf
d /run/freeradius 0750 radius radius -
Once you have that, you can link the two services using regular Requires= and After= dependencies:
[Unit]
Requires=kstart@radius.service
After=kstart@radius.service
Note that with recent MIT libkrb5, you don't need a separate task to maintain the keytab – libkrb5 can acquire tickets using a "client keytab" all on its own, if specified via environment variable:
radiusd.conf
ENV {
KRB5_CLIENT_KTNAME = 'FILE:/etc/raddb/radius.keytab'
}
...or if the keytab is placed at FILE:/var/lib/krb5/user/%{euid}/client.keytab (see default_client_keytab_name in krb5.conf(5).)
Another issue of lesser concern is that k5start in this case is run as the RADIUS user i.e., the keytab must be readable by the RADIUS user. I like it better to have it as root:root 0600.
k5start supports chown'ing the ticket cache to another user using the -o <user> option.
An alternative option is to use gssproxy, which is like ssh-agent for Kerberos tickets. With gssproxy enabled, radiusd will not need a ticket cache at all – gssproxy will be the one to renew tickets and establish GSS security contexts on behalf of radiusd.
/etc/gssproxy/50-radius.conf
[service/ldap]
mechs = krb5
cred_store = ccache:/var/lib/gssproxy/clients/krb5cc_%U
cred_store = client_keytab:/etc/radius.keytab
cred_usage = initiate
euid = radius_user
radiusd.conf
ENV {
GSS_USE_PROXY = '1'
}