As a developer of a service or script that accesses IPA API , I want a convenient option to automatically acquire a TGT with a Kerberos keytab so that I don't have to roll my own Kerberos authentication code.
The ipa CLI took and IPA's Python API require a valid Kerberos ticket to authenticate against an IPA server. In my experience, lots of users are struggling with Kerberos authentication, especially for automation scripts and in services that use ipalib.api. Users often fall back to horrible hacks like echo password | kinit or k5start. I had to role my own code for several integration projects like Custodia, Fedora Account System, and now HMSIDM ipa-hcc.
ipa
ipalib.api
echo password | kinit
One recommended approach is a dedicated service account (ipa service-add myservice/$(hostname)) and a keytab (ipa-getkeytab -p myservice/$(hostname) -k /path/to/myservice.keytab). A TGT can then be acquired with the keytab. Automation has some quirks, e.g. kinit -kt assumes the principal is a host principal.
ipa service-add myservice/$(hostname)
ipa-getkeytab -p myservice/$(hostname) -k /path/to/myservice.keytab
kinit -kt
$ kinit -kt /path/to/myservice.keytab kinit: Keytab contains no suitable keys for host/host.ipa.example@IPA.EXAMPLE while getting initial credentials
The KRB5_CLIENT_KTNAME env var does the trick. I'm not sure whether it also performs TGT refresh and auto-renewal correctly. It's not documented on https://freeipa.readthedocs.io, ipa --help, or man ipa(1).
KRB5_CLIENT_KTNAME
ipa --help
man ipa(1)
$ kdestroy -A $ KRB5_CLIENT_KTNAME=/path/to/mservice.keytab ipa ping -------------------------------------------- IPA server version 4.10.1. API version 2.251 -------------------------------------------- [root@server cloud-user]# klist Ticket cache: KCM:0:19169 Default principal: myservice/host.ipa.example@IPA.EXAMPLE Valid starting Expires Service principal 09/01/23 04:08:13 09/02/23 03:21:05 krbtgt/IPA.EXAMPLE@IPA.EXAMPLE 09/01/23 04:08:13 09/02/23 03:21:05 HTTP/server.ipa.example@IPA.EXAMPLE
GSS_USE_PROXY=1 doesn't auto-acquire a TGT for me. I have to manually initiate the credentials. Perhaps the application is unable to detect the principal name automatically from the keytab? In my app, the keytab is only readable to gss-proxy, not the app.
GSS_USE_PROXY=1
# sudo -u myservice python Python 3.9.16 (main, May 29 2023, 00:00:00) [GCC 11.3.1 20221121 (Red Hat 11.3.1-4)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import os, subprocess, gssapi >>> name = gssapi.Name("myservice/host.ipa.example@IPA.EXAMPLE", gssapi.NameType.kerberos_principal) >>> cred = gssapi.Credentials(name=name, usage="initiate") >>> print(subprocess.check_output(["klist"], text="utf-8")) Ticket cache: KCM:388:94967 Default principal: myservice/host.ipa.example@IPA.EXAMPLE Valid starting Expires Service principal 12/31/69 19:00:00 12/31/69 19:00:00 Encrypted/Credentials/v1@X-GSSPROXY:
--keytab
api.bootstrap()
GSS_USE_PROXY
Metadata Update from @cheimes: - Custom field rhbz adjusted to https://bugzilla.redhat.com/show_bug.cgi?id=1513934
Not sure what specifically is your issue with GSSProxy. The output you have shown is the correct and expected one because klist does not use GSSAPI and therefore only sees raw entries in the credentials cache. That raw entry is how GSSProxy puts an encrypted credential inside the credentials cache: raw krb5 calls will not be able to operate on it directly but still be able to fetch an encrypted blob.
klist
IPA Python code that deals with GSSAPI already uses everything you need if corresponding environmental variables are set. This is feature of MIT Kerberos' GSSAPI implementation and is used transparently. We don't need to add anything here.
Adding options to pass-in keytab location may enable setting up KRB5_CLIENT_KTNAME variable in the CLI code. However, I'd like to avoid setting GSS_USE_PROXY by the framework. Use of the GSSProxy is a concious decision of the service administrator as it requires use of a special configuration on top of that.
My plans are to extend IPA CLI's handling of credentials going down the road because we need to handle non-password methods too. GSSAPI has no way to acquire TGTs for anything but password-based or keytab-based authentication. There is no way to pass creds for PKINIT or external IdP or 2FA preauthentication methods, so we need to extend things first in order to come close.
Documenting it should probably go to https://freeipa.readthedocs.io/en/latest/api/jsonrpc_usage.html
If KRB5_CLIENT_KTNAME is sufficient to both acquire a TGT and automatically renew a TGT with IPA framework, then all we need is some documentation to make the feature discoverable by users. The GSSAPI feature is not well known by users. I suggest to include a reference in man ipa(1), ipa --help and in the upstream docs.
Oh, I forgot to post the error case of GSS_USE_PROXY. I assume it fails because gssproxy doesn't know the principal name (input_cred_handle: <Null>). A successful gss-proxy request has a non-NULL input cred handle which contains the principal name string and gssapi.NameType.kerberos_principal OID. I'll try to find more time next week to investigate further.
input_cred_handle: <Null>
gssapi.NameType.kerberos_principal
sudo -u myservice /bin/bash bash-5.1$ kdestroy -A bash-5.1$ GSS_USE_PROXY=1 ipa ping ipa: ERROR: Could not create log_dir '/.ipa/log' ipa: ERROR: Major (458752): No credentials were supplied, or the credentials were unavailable or inaccessible, Minor (2598845069): No Kerberos credentials available (default cache: KCM:)
gssproxy debug logs:
[CID 12][2023/09/01 09:19:55]: [status] Handling query input: 0x556d30fdff90 (100) [CID 12][2023/09/01 09:19:55]: Connection matched service myservice [CID 12][2023/09/01 09:19:55]: [status] Processing request [0x556d30fdff90 (100)] [CID 12][2023/09/01 09:19:55]: [status] Executing request 6 (GSSX_ACQUIRE_CRED) from [0x556d30fdff90 (100)] [CID 12][2023/09/01 09:19:55]: gp_rpc_execute: executing 6 (GSSX_ACQUIRE_CRED) for service "myservuce", euid: 388,socket: (null) GSSX_ARG_ACQUIRE_CRED( call_ctx: { "" [ ] } input_cred_handle: <Null> add_cred: 0 desired_name: <Null> time_req: 0 desired_mechs: { } cred_usage: INITIATE > GSSX_RES_ACQUIRE_CRED( status: { 458752 { 1 2 840 113554 1 2 2 } 2529639107 "No credentials were supplied, or the credentials were unavailable or inaccessib> [CID 12][2023/09/01 09:19:55]: [status] Returned buffer 6 (GSSX_ACQUIRE_CRED) from [0x556d30fdff90 (100)]: [0x7fe548045b00 (192)] [CID 12][2023/09/01 09:19:55]: [status] Handling query output: 0x7fe548045b00 (192) [2023/09/01 09:19:55]: [status] Handling query reply: 0x7fe548045b00 (192) [2023/09/01 09:19:55]: [status] Sending data: 0x7fe548045b00 (192) [2023/09/01 09:19:55]: [status] Sending data [0x7fe548045b00 (192)]: successful write of 192
Next time, I should read the documentation! It works as expected when I include krb5_principal in my gss-proxy service file...
krb5_principal
# cat /etc/gssproxy/85-myservice.conf [service/myservice] mechs = krb5 cred_store = keytab:/var/lib/ipa/gssproxy/myservice.keytab allow_client_ccache_sync = true cred_usage = initiate euid = myservice krb5_principal = myservice/host.ipa.example
Yep.
GSSProxy needs configuration to map incoming request. If you do have that configuration, it will work properly. Using GSS_USE_PROXY=1 is not enough without configuration.
I have created a feature request for gssapi to introduce variable substitution for FQDN. It has variables for username and UID already. https://github.com/gssapi/gssproxy/issues/81
I had configuration and it worked with an explicit principal name in the application. My file was missing krb5_principal = myservice/host.ipa.example to get it working with just GSS_USE_PROXY=1 ipa ping.
krb5_principal = myservice/host.ipa.example
GSS_USE_PROXY=1 ipa ping
For the record, Simo pointed out that cred_store = keytab:/path/to/keytab is wrong for clients. The qualifier keytab: is equivalent to KRB5_KTNAME for servers. cred_store = client_keytab:/path/to/keytab behaves like KRB5_CLIENT_KTNAME and does not need akrb5_principal setting.
cred_store = keytab:/path/to/keytab
keytab:
KRB5_KTNAME
cred_store = client_keytab:/path/to/keytab
Log in to comment on this ticket.