#8735 ccache-sweeper removes valid ccaches
Closed: fixed by frenaud. Opened by slev.

Current implementation of ccache-sweeper was borrowed from mod_auth_gssapi https://github.com/gssapi/mod_auth_gssapi/blob/master/contrib/sweeper.py, but that example is outdated. There are several issues:

  • credentials lifetime
    today's gssproxy doesn't set correct lifetime for credentials:
(gdb) bt
#0  gpm_acquire_cred (minor_status=minor_status@entry=0x7ffc958cc4e8, in_cred_handle=in_cred_handle@entry=0x766a10, desired_name=<optimized out>, time_req=time_req@entry=4294967295, desired_mechs=desired_mechs@entry=0x7ffc958cc600, cred_usage=cred_usage@entry=1, impersonate=false, output_cred_handle=0x763340, actual_mechs=0x0, time_rec=0x7ffc958cc5d0) at src/client/gpm_acquire_cred.c:128
#1  0x00007f20343f5e3d in gssi_acquire_cred_from (minor_status=0x7ffc958cc6e4, desired_name=0x0, time_req=4294967295, desired_mechs=0x7ffc958cc600, cred_usage=1, cred_store=0x73f2a0, output_cred_handle=0x7ffc958cc5e8, actual_mechs=0x0, time_rec=0x7ffc958cc5d0) at src/mechglue/gpp_acquire_cred.c:165
#2  0x00007f20348496c4 in gss_add_cred_from (minor_status=minor_status@entry=0x7ffc958cc6e4, input_cred_handle=<optimized out>, desired_name=desired_name@entry=0x0, desired_mech=<optimized out>, cred_usage=cred_usage@entry=1, initiator_time_req=initiator_time_req@entry=4294967295, acceptor_time_req=<optimized out>, cred_store=0x73f2a0, output_cred_handle=0x0, actual_mechs=0x0, initiator_time_rec=0x7ffc958cc6e8, acceptor_time_rec=0x7ffc958cc6ec) at g_acquire_cred.c:544
#3  0x00007f2034849c87 in gss_acquire_cred_from (minor_status=0x7ffc958cc7c0, desired_name=0x0, time_req=4294967295, desired_mechs=0x0, cred_usage=1, cred_store=0x73f2a0, output_cred_handle=0x7ffc958cc7d0, actual_mechs=0x7ffc958cc7d8, time_rec=0x7ffc958cc7bc) at g_acquire_cred.c:190
#4  0x00007f203457e952 in ?? () from /usr/lib64/python3/site-packages/gssapi/raw/ext_cred_store.cpython-38.so
(gdb) p res->output_cred_handle.elements.elements_val.initiator_time_rec 
$11 = 59
(gdb) p res->output_cred_handle.elements.elements_val.acceptor_time_rec 
$12 = 0
(gdb) p res->output_cred_handle.elements.elements_val.cred_usage 
$13 = GSSX_C_INITIATE
(gdb) l 137
132             if (res->output_cred_handle->elements.elements_len) {
133                 e = &res->output_cred_handle->elements.elements_val[0];
134                 if (e->initiator_time_rec < e->acceptor_time_rec) {
135                     t = e->initiator_time_rec;
136                 } else {
137                     t = e->acceptor_time_rec;
138                 }
139             }
140
141             *time_rec = t;

This means that condition return creds.lifetime == 0 in ipa-ccache-sweeper always succeeds and all (either valid or expired) ccaches older than 30min are removed.
Though this can be overcomed with explicit creds inquiring the usage of service/ipa-api gssproxy service is not suitable for this task because of

  • cred_store service config options tell gssproxy to make use of corresponding credential store to acquire credentials from and if remote credentials change then gssproxy stores them back to input credentials. It seems to be intentional:
    https://github.com/gssapi/gssproxy/commit/a145ea3d4317f52b25ca44c14c4333d9a9e01bd9

For example, if credentials for 'admin@' user principal are expired.

input creds:

(gdb) p *creds.elements.elements_val 
$26 = {
  MN = {
    display_name = {
      octet_string_len = 14,
      octet_string_val = 0x2157780 "admin@IPA.TEST"
    },
    name_type = {
      octet_string_len = 10,
      octet_string_val = 0x21577c0 "*\206H\206\367\022\001\002\002\001"
    },
    exported_name = {
      octet_string_len = 33,
      octet_string_val = 0x2097fb0 "\004\001"
    },
    exported_composite_name = {
      octet_string_len = 37,
      octet_string_val = 0x21513f0 "\004\002"
    },
    name_attributes = {
      name_attributes_len = 0,
      name_attributes_val = 0x0
    },
    extensions = {
      extensions_len = 0,
      extensions_val = 0x0
    }
  },
  mech = {
    octet_string_len = 9,
    octet_string_val = 0x2156c90 "*\206H\206\367\022\001\002\002\372\033\325\344\177"
  },
  cred_usage = GSSX_C_INITIATE,
  initiator_time_rec = 59,
  acceptor_time_rec = 0,
  options = {
    options_len = 0,
    options_val = 0x0
  }
}

remote:

(gdb) p *out_cred_handle->remote.elements.elements_val
$31 = {
  MN = {
    display_name = {
      octet_string_len = 30,
      octet_string_val = 0x16c9d80 "HTTP/master1.ipa.test@IPA.TEST"
    },
    name_type = {
      octet_string_len = 10,
      octet_string_val = 0x16c8940 "*\206H\206\367\022\001\002\002\001"
    },
    exported_name = {
      octet_string_len = 49,
      octet_string_val = 0x16c9db0 "\004\001"
    },
    exported_composite_name = {
      octet_string_len = 53,
      octet_string_val = 0x16c9cb0 "\004\002"
    },
    name_attributes = {
      name_attributes_len = 0,
      name_attributes_val = 0x0
    },
    extensions = {
      extensions_len = 0,
      extensions_val = 0x0
    }
  },
  mech = {
    octet_string_len = 9,
    octet_string_val = 0x16c8830 "*\206H\206\367\022\001\002\002"
  },
  cred_usage = GSSX_C_INITIATE,
  initiator_time_rec = 60,
  acceptor_time_rec = 0,
  options = {
    options_len = 0,
    options_val = 0x0
  }
}

This results in the new initial credentials for HTTP/: service principal are obtained and stored into gssproxy client ccache. Additionally, such credentials are not expirable.

[root@master1 /]# KRB5_KTNAME=/var/lib/ipa/gssproxy/http.keytab /usr/sbin/gssproxy -d --extract-ccache /run/ipa/ccaches/admin\@IPA.TEST-dfqZbs --into-ccache /tmp/ipa_krbccache_ && klist -A /tmp/ipa_krbccache_
Ticket cache: FILE:/tmp/ipa_krbccache_
Default principal: HTTP/master1.ipa.test@IPA.TEST
Valid starting       Expires              Service principal
03/02/2021 14:21:42  03/02/2021 14:22:42  krbtgt/IPA.TEST@IPA.TEST
        renew until 03/03/2021 14:21:42

For comparison the original ccache looks as:

[root@master1 /]# klist -A /tmp/ipa_krbccache
Ticket cache: FILE:/tmp/ipa_krbccache
Default principal: admin@IPA.TEST
Valid starting       Expires              Service principal
03/02/2021 14:20:35  03/02/2021 14:21:34  HTTP/master1.ipa.test@IPA.TEST
        renew until 03/03/2021 14:20:32
03/02/2021 14:20:35  03/02/2021 14:21:35  krbtgt/IPA.TEST@IPA.TEST
        for client HTTP/master1.ipa.test@IPA.TEST, renew until 03/03/2021 14:20:35
03/02/2021 14:20:35  03/02/2021 14:21:35  ldap/master1.ipa.test@
        renew until 03/03/2021 14:20:35
        Ticket server: ldap/master1.ipa.test@IPA.TEST
  • ipa-ccache-sweeper during test_ccache_sweep is run under root, while the expected user is ipaapi. So, the wrong gssproxy service is in use(service/nfs-client instead of service/ipa-api).

The problem is that a user's session in a browser will end up with:

Your session has expired. Please log in again.

Possible fixes:
- use the existing service/ipa-api gssproxy service and explicitly set the desired_name for gss_acquire_cred_from
- using the gssproxy 0.8.4+ to decrypt the encrypted ccache
- additional gssproxy service which will have only cred_store = keytab:xxx for decryption ccache. Obtaining will not happen if the requester set 'usage=initial'.

I have the working example for the latter.

PR: https://github.com/freeipa/freeipa/pull/5600

master:

  • 271fd162a76d999c9b03c5b2103ededdf3eb2fd9 ccache_sweeper: Add gssproxy service
  • 7972d28240d57f5dfbc4bb58aeb08f456524c24f cleanup: Drop never used path for httpd's ccache

ipa-4-9:

  • cf80bb33baa79ba93987ee7e63109ece4b37bbd0 ccache_sweeper: Add gssproxy service
  • 99a65e3e720d0de94abfcbfa1c2619a709d3c8db cleanup: Drop never used path for httpd's ccache

Metadata Update from @frenaud:
- Issue close_status updated to: fixed
- Issue status updated to: Closed (was: Open)

Metadata