RHEL Engineering is moving the tracking of its product development work on RHEL 6 through RHEL 9 to Red Hat Jira (issues.redhat.com). If you're a Red Hat customer, please continue to file support cases via the Red Hat customer portal. If you're not, please head to the "RHEL project" in Red Hat Jira and file new tickets here. Individual Bugzilla bugs in the statuses "NEW", "ASSIGNED", and "POST" are being migrated throughout September 2023. Bugs of Red Hat partners with an assigned Engineering Partner Manager (EPM) are migrated in late September as per pre-agreed dates. Bugs against components "kernel", "kernel-rt", and "kpatch" are only migrated if still in "NEW" or "ASSIGNED". If you cannot log in to RH Jira, please consult article #7032570. That failing, please send an e-mail to the RH Jira admins at rh-issues@redhat.com to troubleshoot your issue as a user management inquiry. The email creates a ServiceNow ticket with Red Hat. Individual Bugzilla bugs that are migrated will be moved to status "CLOSED", resolution "MIGRATED", and set with "MigratedToJIRA" in "Keywords". The link to the successor Jira issue will be found under "Links", have a little "two-footprint" icon next to it, and direct you to the "RHEL project" in Red Hat Jira (issue links are of type "https://issues.redhat.com/browse/RHEL-XXXX", where "X" is a digit). This same link will be available in a blue banner at the top of the page informing you that that bug has been migrated.
Bug 1780308 - KCM: always preferring existing cached credentials breaks remote logins
Summary: KCM: always preferring existing cached credentials breaks remote logins
Keywords:
Status: CLOSED CURRENTRELEASE
Alias: None
Product: Red Hat Enterprise Linux 8
Classification: Red Hat
Component: sssd
Version: 8.1
Hardware: Unspecified
OS: Unspecified
high
unspecified
Target Milestone: rc
: 8.0
Assignee: jstephen
QA Contact: sssd-qe
URL:
Whiteboard: sync-to-jira
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2019-12-05 16:40 UTC by kludhwan
Modified: 2024-03-25 15:33 UTC (History)
16 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2020-10-27 15:42:43 UTC
Type: Bug
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Fedora Pagure SSSD/sssd issue 4017 0 None None None 2019-12-05 16:40:45 UTC
Github SSSD sssd issues 4988 0 None closed KCM: always preferring existing cached credentials breaks remote logins 2021-01-12 03:40:37 UTC

Description kludhwan 2019-12-05 16:40:04 UTC
The vast majority of our hosts are Kerberized NFS clients with /home auto-mounted on-demand from an NFS server which requires sec=krb5p.

For this reason, it is critical for us that GSSAPI credential delegation works properly for remote logins via ssh. If it does not, the user will be denied access to their /home directory upon logging in to a host remotely.

For our RHEL7 and RHEL8 hosts, credential delegation works properly if using the kernel persistent keyring for the Kerberos credential cache. For our RHEL8 hosts, we are testing whether we can replace the kernel persistent keyring cache with KCM.

On RHEL8, we're using the latest openssh-server and sssd-kcm packages:

$ rpm -q openssh-server sssd-kcm
openssh-server-7.8p1-4.el8.x86_64
sssd-kcm-2.0.0-43.el8_0.3.x86_64

We have encountered an issue with OpenSSH sshd credential delegation when using KCM as the Kerberos credential cache. Specifically: if credentials already exist in KCM for the user in question, KCM always discards the incoming credentials from sshd in preference to the credentials that already exist in the cache. This is true even if the existing credentials in KCM are expired.

Here's a demonstration of the issue.

On my desktop host, I have current credentials cached:

$ klist

Ticket cache: KEYRING:persistent:123456789:krb_ccache_fgQUgAM
Default principal: username

Valid starting       Expires              Service principal
2019-05-24 11:26:29  2019-05-25 11:26:25  krbtgt/EXAMPLE.ORG
        renew until 2019-05-28 13:38:47

But if I ssh to a particular remote RHEL8 host and run klist, this is what I see:

$ ssh remoteserver.example.org klist
Could not chdir to home directory /home/username: Permission denied
/usr/bin/xauth:  timeout in locking authority file /home/username/.Xauthority
bash: /home/username/.bashrc: Permission denied
Ticket cache: KCM:987654321:90786
Default principal: username

Valid starting       Expires              Service principal
2019-05-22 01:09:06  2019-05-22 23:39:49  nfs/nfsserver.example.org
        renew until 2019-05-27 11:44:41
2019-05-21 23:44:41  2019-05-22 23:39:49  krbtgt/EXAMPLE.ORG
        renew until 2019-05-27 11:44:41
2019-05-22 17:38:45  2019-05-22 23:39:49  cifs/dfsserver.example.org
        renew until 2019-05-27 11:44:41

The credentials KCM is caching are from a login session 2 days ago. They are expired, which is why I am denied access to my auto-mounted NFS home directory. But KCM discarded the new, unexpired, incoming credentials from sshd, preferring instead to cling to the expired credentials that were already cached.

If I open a separate login session on remoteserver.example.org and run kdestroy -A, then (and only then) will KCM accept the new forwarded credentials from sshd:

On remoteserver.example.org:

$ kdestroy -A
$ klist -A

Now, repeating the ssh klist command:

$ ssh remoteserver.example.org klist
Ticket cache: KCM:987654321:39355
Default principal: username

Valid starting       Expires              Service principal
2019-05-24 12:27:22  2019-05-25 11:26:25  krbtgt/EXAMPLE.ORG
        renew until 2019-05-28 13:38:47
2019-05-24 12:27:23  2019-05-25 11:26:25  nfs/nfsserver.example.org
        renew until 2019-05-28 13:38:47

Voilà: KCM accepts the new forwarded credentials, and thus I have access to my auto-mounted NFS home directory, so there are no permission denied errors.

So, in summary, KCM's behavior of never accepting new delegated credentials if there are existing credentials already in the cache breaks remote logins, and is a dealbreaker for using KCM. It means that if you remotely login to host that is using KCM as the Kerberos credentials cache via sshd, credential delegation only works properly the very first time. After that, credential delegation will always fail. And when the existing delegated credentials expire, any subsequent attempt to use those credentials within that login session will fail, producing authentication errors.

It is important to note that this is a subtlety different problem than the issue of KCM not automatically renewing credentials that it did not acquire itself (e.g., through pam_sss.so). Even if KCM did automatically renew all credentials, that would not solve this problem, because eventually KCM's existing credentials would expire, and then this problem would reoccur.

Similarly, adding expired-credentials-reaper functionality to KCM would not address this issue, either, unless the reaper check was activated on-demand, every time credentials were accessed. On-demand reaping would incur a performance penalty, and since KCM is already about an order of magnitude slower than using the kernel persistent keyring, this is undesirable. (I'd like to see a expired credentials reaper, but it should be a background task, the same as the credential renewal task).

The real issue here is that KCM needs to be smarter about what it does with delegated credentials when there are already existing credentials in the cache. KCM's current behavior (never take the new credentials; always keep the existing credentials) is clearly wrong, and leads to massive breakage for sites that rely on credential delegation to work.

But it is not clear that the inverse behavior—always overwriting the existing credentials with the new credentials—is necessarily the correct behavior, either. For example, what if the incoming credentials expire in 5 minutes, while the existing credentials do not expire for another 20 hours? Even if a future KCM renewed all credentials, unless the site has set krb5_renew_interval to something unreasonably short (e.g., 3 minutes), this will create a window where the existing credentials have expired.

Perhaps the best solution would be a new option for KCM. E.g.:

    delegation_acceptance_criteria (string)

    Controls how KCM behaves when a new credentials delegation request is made for a user (e.g., via sshd), but there are already existing credentials for the user in the cache.

    If set to always, KCM always accepts the new credentials being delegated, overwriting the existing credentials.

    If set to newer, KCM replaces the existing credentials with the new credentials, but only if the new credentials are newer (that is, have an expiration date that is farther in the future). If the existing credentials have a longer lifetime remaining, they are retained, and the incoming credentials are discarded.

    If set to never, KCM always discards the new credentials being delegated, and keeps the existing credentials. This is true even if the existing credentials have expired but the new credentials have not. (This is probably not what you want.)

    If not specified, the default is always.

    Note that if there are no existing credentials already in the cache, KCM always accepts the new credentials. This option only affects KCM's behavior when a new delegation request is made for a user and there are already existing credentials for the user in the cache.

I'm not sure that never should even be an option. Yes, it's KCM's current behavior, but I cannot think of a use case where pre-existing credentials should always win, even if expired.

We're treating this as a low-priority issue, because the easiest work-around is to simply go back to using the kernel persistent keyring for the Kerberos credentials cache. But the advantages of KCM over the kernel persistent keyring are compelling, so we'd like to eventually move to KCM.

Comment 3 James Ralston 2020-01-13 23:02:49 UTC
Note that BZ#1712875 (Old kerberos credentials active instead of valid new ones) did not resolve this issue.

With BZ#1712875 in place, when ssh delegates credentials to a remote host that is using KCM, the newly-delegated credentials are made active, but old credentials (if present) remain in the cache. While that addresses the issue of the user not having access to resources because sssd did not switch to the newly-delegated credential, it does not address the other problems that result when the credential cache contains multiple identical principals.

For example, depending on the ordering of credentials in the cache, invoking "kswitch -p PRINCPAL" can select old, expired credentials in the cache. This is because kswitch does not expect the credential cache to contain multiple identical principals, and provides no mechanism to refine the selection of the principal that "kswitch -p PRINCIPAL" selects if multiple principals are present. This is understandable, considering that of the credential cache types that support collections, neither kernel persistent keyrings nor the DIR: credential cache support duplicate credentials.

Again, as per the description above: KCM must not create multiple principals in the cache. If an incoming connection is attempting to delegate a credential for a principal that already has a credential in the cache, KCM *must not* create a duplicate credential. It must either discard the incoming credential in favor of the one already in the cache, or overwrite the credential already in the cache with the incoming credential.

As per above, it might make sense for sssd to provide a knob (e.g., delegation_acceptance_criteria) that effects how KCM decides which action to take, instead of always overwriting the existing credential with the incoming credential.

Comment 4 James Ralston 2020-01-21 20:53:18 UTC
(Per our support case, I am adding this requested information.)

Description of problem:

See the Description.

Version-Release number of selected component (if applicable):

sssd-2.2.0-19.el8.x86_64

How reproducible:

Login multiple times to the same host via ssh via gssapi-with-mic or gssapi-keyex authentication with credential forwarding enabled.

Steps to Reproduce:

1. Ensure that sssd-kcm is installed on the target host.

2. Login to the target host via ssh via gssapi-with-mic or gssapi-keyex authentication with credential forwarding enabled and run "kinit -A".  Results will be similar to the following:

$ klist -A
Ticket cache: KCM:116201957:39355
Default principal: username

Valid starting       Expires              Service principal
2020-01-21 15:43:47  2020-01-22 11:59:51  krbtgt/EXAMPLE.ORG
        renew until 2020-01-27 23:38:52

3. Log out, login again (via ssh via gssapi-with-mic or gssapi-keyex), and run "klist -A" again:

$ klist -A
Ticket cache: KCM:116201957:62082
Default principal: username

Valid starting       Expires              Service principal
2020-01-21 15:44:16  2020-01-22 11:59:51  krbtgt/EXAMPLE.ORG
        renew until 2020-01-27 23:38:52

Ticket cache: KCM:116201957:39355
Default principal: username

Valid starting       Expires              Service principal
2020-01-21 15:43:47  2020-01-22 11:59:51  krbtgt/EXAMPLE.ORG
        renew until 2020-01-27 23:38:52

Actual results:

You will see that KCM has duplicated the credential in the cache.

Expected results:

KCM should overwrite the old credential with the incoming credential (which is how the kernel persistent keyring behaves), discard the incoming credential in favor of the one already in the cache, or provide a configuration option to help influence how KCM selects the credential to keep versus the one to discard.

Additional info:

Having multiple credentials in the cache breaks "kswitch -p". No other Kerberos credential cache type supports multiple credentials in the catch for the exact same principal. sssd shouldn't, either.

Comment 7 Orion Poplawski 2020-06-01 21:31:02 UTC
This is a problem for us as well.

Comment 8 Simone Caronni 2020-06-23 09:13:11 UTC
I strongly believe this is related to this as well: https://bugzilla.redhat.com/show_bug.cgi?id=1645624

If I clear the caches, goa-identity-service does not constantly poll sssd_kcm like crazy trying to renew the keys in the cache.

Comment 9 jstephen 2020-09-11 15:57:07 UTC
(In reply to James Ralston from comment #4)
> 
> Actual results:
> 
> You will see that KCM has duplicated the credential in the cache.
> 
> Expected results:
> 
> KCM should overwrite the old credential with the incoming credential (which
> is how the kernel persistent keyring behaves), discard the incoming
> credential in favor of the one already in the cache, or provide a
> configuration option to help influence how KCM selects the credential to
> keep versus the one to discard.
> 
> Additional info:
> 
> Having multiple credentials in the cache breaks "kswitch -p". No other
> Kerberos credential cache type supports multiple credentials in the catch
> for the exact same principal. sssd shouldn't, either.


It looks to me that the persistent Keyring ccache exhibits the same behavior, it does *not* remove the previously delegated credential. 


[vagrant.vm ~]$ ssh -K testuser1.vm kdestroy -A
[vagrant.vm ~]$ ssh -K testuser1.vm klist -A
Ticket cache: KEYRING:persistent:340600004:krb_ccache_ehsVzI9
Default principal: testuser1

Valid starting       Expires              Service principal
09/11/2020 15:30:21  09/12/2020 15:16:53  krbtgt/IPA.VM
[vagrant.vm ~]$ 
[vagrant.vm ~]$ 
[vagrant.vm ~]$ 
[vagrant.vm ~]$ 
[vagrant.vm ~]$ 
[vagrant.vm ~]$ 
[vagrant.vm ~]$ ssh -K testuser1.vm klist -A
Ticket cache: KEYRING:persistent:340600004:krb_ccache_F1XP75X
Default principal: testuser1

Valid starting       Expires              Service principal
09/11/2020 15:30:23  09/12/2020 15:16:53  krbtgt/IPA.VM

Ticket cache: KEYRING:persistent:340600004:krb_ccache_ehsVzI9
Default principal: testuser1

Valid starting       Expires              Service principal
09/11/2020 15:30:21  09/12/2020 15:16:53  krbtgt/IPA.VM
[vagrant.vm ~]$ 
[vagrant.vm ~]$ 
[vagrant.vm ~]$ 
[vagrant.vm ~]$ 
[vagrant.vm ~]$ 
[vagrant.vm ~]$ 
[vagrant.vm ~]$ ssh -K testuser1.vm klist -A
Ticket cache: KEYRING:persistent:340600004:krb_ccache_js83pc7
Default principal: testuser1

Valid starting       Expires              Service principal
09/11/2020 15:30:25  09/12/2020 15:16:53  krbtgt/IPA.VM

Ticket cache: KEYRING:persistent:340600004:krb_ccache_F1XP75X
Default principal: testuser1

Valid starting       Expires              Service principal
09/11/2020 15:30:23  09/12/2020 15:16:53  krbtgt/IPA.VM

Ticket cache: KEYRING:persistent:340600004:krb_ccache_ehsVzI9
Default principal: testuser1

Valid starting       Expires              Service principal
09/11/2020 15:30:21  09/12/2020 15:16:53  krbtgt/IPA.VM


The keyring does remove old tickets after some time, could that be the reason you are noticing a difference in behavior with KCM and the kernel keyring ccache?

Comment 10 James Ralston 2020-09-23 19:22:01 UTC
From re-testing, I believe you are correct: I also see that repeated logins within an arbitrary window of time will generate multiple credentials in the kernel persistent keyring. I suspect I did not realize that the kernel persistent keyring has this behavior because—as you mentioned—the kernel persistent keyring purges old credentials after some period of time.

However, this doesn't change the underlying issue: KCM does not purges old credentials, and when receiving a remote credential via ssh via gssapi-with-mic or gssapi-keyex authentication, KCM always prefers an existing credential in the cache, which is typically older (or outright expired).

I still stand by my original request: KCM should not create a duplicate credentials in the cache. Rather, it should either keep the existing credential in the cache (discarding the incoming credential), or overwrite the existing credential with the incoming credential. There should be an sssd option to control this behavior (e.g., delegation_acceptance_criteria).

Additionally, based on Simone's report in BZ#1645624, even if the above logic is implemented, it sounds like KCM really needs a background credential remover, similar to what the kernel persistent keyring has, to remove expired credentials.

Comment 12 jstephen 2020-10-01 21:21:27 UTC
(In reply to James Ralston from comment #10)

Hi James, thanks a lot for your inputs.

> From re-testing, I believe you are correct: I also see that repeated logins
> within an arbitrary window of time will generate multiple credentials in the
> kernel persistent keyring. I suspect I did not realize that the kernel
> persistent keyring has this behavior because—as you mentioned—the kernel
> persistent keyring purges old credentials after some period of time.
> 
> However, this doesn't change the underlying issue: KCM does not purges old
> credentials, and when receiving a remote credential via ssh via
> gssapi-with-mic or gssapi-keyex authentication, KCM always prefers an
> existing credential in the cache, which is typically older (or outright
> expired).

Could you please double-check and confirm that this issue still occurs on sssd-kcm-2.2.0-19.el8 or higher, specifically the issue where KCM does not switch to the newly delegated credentials, but expired credentials are chosen instead.

The reason I ask is because in my testing I am seeing that KCM is always switching to the updated credentials when newly received remote credentials are delegated over SSH with GSSAPI, and the behavior you described is exactly the behavior which should have been fixed. Excerpt from the upstream PR comment: "...Afterwards, klist or similar would see that the default ccache is empty and just pick the first non-empty one as a fallback, which would often be one of the previous expired ones."

(Note, I am testing in my Fedora kerberized NFS environment with sssd-2.3.1-4.fc33.x86_64, this includes the fixes from https://bugzilla.redhat.com/show_bug.cgi?id=1712875 and no other KCM changes should make a difference in these codepaths)

If the preferring expired credentials problem persists then please provide 'debug_level=9' debug logs from sssd-kcm on the targethost. I would like to look for logs similar to:

   [kcm_op_set_default_create_step_done] (0x0400): The ccache was created, switching to it
   [kcm_op_initialize_got_default] (0x0400): The default ccached was not set, switching to the initialized

> 
> I still stand by my original request: KCM should not create a duplicate
> credentials in the cache. Rather, it should either keep the existing
> credential in the cache (discarding the incoming credential), or overwrite
> the existing credential with the incoming credential. There should be an
> sssd option to control this behavior (e.g., delegation_acceptance_criteria).

For now, please ignore the duplicate credentials aspect of this problem, I would like to focus on ensuring KCM is switching to newly delegated credentials and not selecting expired ccache credentials.
> 
> Additionally, based on Simone's report in BZ#1645624, even if the above
> logic is implemented, it sounds like KCM really needs a background
> credential remover, similar to what the kernel persistent keyring has, to
> remove expired credentials.

Comment 13 James Ralston 2020-10-05 05:14:22 UTC
Hi Justin,

From preliminary testing, I believe you are correct: as of at least sssd 2.2.3-20.el8, KCM seems to unconditionally switch to the incoming credential. So, this is definitely an improvement.

For now, I'll clear the NEEDINFO flag. We've configured our beta RHEL8 hosts to use KCM instead of the kernel persistent keyring. I'll check back in a week or so and report what problems (if any) we've noticed.

As for credential cleanups…

With the kernel persistent keyring, we set "GSSAPICleanupCredentials no" in /etc/ssh/sshd_config, because we didn't want different login sessions potentially wiping out each other's credentials. But if KCM always caches and switches to the incoming credential, then perhaps a better thing to do here is to set "GSSAPICleanupCredentials yes", so that sshd removes the credential cache when the ssh session closes.

But: that won't clean credentials that are created when a user logs in via any other mechanism than ssh with gssapi-with-mic or gssapi-keyex authentication. That's an issue for us, as a fair number of our users login to various hosts via ssh with keyboard-interactive authentication.

Setting "ccache_storage = memory" in the [kcm] section of sssd.conf could provide another mechanism to clean old credentials, but only because *all* credentials are lost when the host reboots (or sssd otherwise shuts down). But there's no guarantee that a host will reboot regularly, and flushing *all* cached credentials upon reboot is often undesirable.

So I think there is still a need for KCM to periodically clean expired credentials from the cache, both for credentials it creates itself, and for credentials created by other applications.

Comment 14 jstephen 2020-10-09 13:59:59 UTC
Thank you James for the quick response and testing confirmation. Please let me know how the results go in your testing. If you are no longer seeing exising expired credentials being switched to by KCM then I would like to close out this BZ, and to avoid confusion keep any residual issues separated out into different tickets.

We have an existing upstream ticket[1] which could help to address the issue with cleaning non-GSSAPI managed credentials. In addition, the issues you mention could be mitigated by adding KCM session support[2] to enforce isolation of different login sessions per user. I could see this as an improvement to the GSSAPI ssh-managed ccache use cases with KCM. I can also create an upstream ticket for expiring tickets in KCM if you would like.

[1] https://github.com/SSSD/sssd/issues/3593

[2] https://github.com/SSSD/sssd/issues/5334

Comment 16 James Ralston 2020-10-18 01:44:00 UTC
Hi Justin,

We haven't noticed any instances of KCM failing to set the active credential cache to the incoming credentials, so I think this ticket can be closed. Thanks for your work on this!

I agree that cleaning unused and/or expired credentials from the cache should be a separate issue.

Also, to clarify comment 10 with respect to the behavior of the kernel persistent keyring:

• If multiple incoming ssh connections for the same user are opened on a RHEL7 host, all sessions share the same credential in the cache.

• If multiple incoming ssh connections for the same user are opened on a RHEL8 host, each session gets a new credential in the cache.

So, between RHEL7 and RHEL8, the behavior of the kernel persistent keyring cache changed. I don't know what ultimately caused that change, though: it might have been changes in the kernel persistent keyring itself, changes to kernel tunables (which we can potentially revert), changes to the behavior of OpenSSH, or some combination of these.

Regardless, on RHEL7, we must continue to set "GSSAPICleanupCredentials no" in /etc/ssh/sshd_config if the kernel persistent keyring is in use, because otherwise different login sessions will wipe out each other's credentials.  On RHEL8, it is more appropriate to use "GSSAPICleanupCredentials yes" (the default) in /etc/ssh/sshd_config, for both the kernel persistent keyring and for KCM, because both credential storage types create duplicate credentials in the cache for new sessions.  (So when a session terminates and sshd cleans the credentials, that won't break other sessions.)

Comment 17 jstephen 2020-10-27 15:42:43 UTC
This was confirmed as fixed in https://github.com/SSSD/sssd/pull/876 and included in sssd-2.2.0-19.el8 and later.


Note You need to log in before you can comment on or make changes to this bug.