fully passwordless nfs through kerberos

The short answer is that the current NFS Kerberos authentication mechanism (RPCSEC_GSS) does not support this. The principal that's making the call is the one who gets access. So if you don't want users to manually get tickets, then you'll need to have the host automatically get tickets for them.

In the future, the newer RPCSEC_GSSv3 protocol might have options for allowing hosts to impersonate arbitrary users, but it hasn't yet been finished nor implemented.


If you want to allow hosts to impersonate any UID, then you don't need Kerberos at all – switch back to the sec=sys security mode that was used "in the old days". In this mode, the host literally gets to specify a symbolic identifier of the user. (Permission checks still happen, of course.)

In the end, there is no functional difference between allowing a host to impersonate any user via Kerberos (authenticated using the host's /etc/krb5.keytab), versus allowing a host to impersonate any user via basic UID claim (authenticated using the host's IPsec or WireGuard private key or) – and the latter will give you much higher performance than GSSAPI can achieve.


Within Kerberos, when using existing tools only (without outright implementing some kind of host-level authentication for RPC), the closest thing you have is constrained delegation with protocol transition (S4U2Self + S4U2Proxy), where a service is allowed to get tickets to specific other services in the name of a user. It is commonly used in Active Directory environments but is also supported by MIT Kerberos KDCs (and probably Heimdal KDCs – the code is there, thanks to Samba, but I do not know how to enable it on Heimdal).

To enable this in a MIT Kerberos KDC you will need to use the LDAP backend; the file-based HDB backend doesn't support storing the additional fields.

  1. Set the ok_to_auth_as_delegate principal flag on the client's host principal (can be done through kadmin, or by ORing 0x200000 into the krbTicketFlags LDAP attribute).

    kadmin.local modprinc +ok_to_auth_as_delegate host/foo.example.com
    
  2. Set the client principal's krbAllowedToDelegateTo LDAP attribute to a list of NFS service principals that it may create the fake tickets for. (One service per value.)

    ldapmodify <<EOF
    dn: krbPrincipalName=host/[email protected],cn=EXAMPLE.COM,ou=Kerberos,o=Example
    add: krbAllowedToDelegateTo
    krbAllowedToDelegateTo: nfs/fs1.example.com
    -
    EOF
    
  3. Test whether S4U features work, as root:

    # Acquire host credentials using system keytab
    host_cc=FILE:/tmp/krb5cc_host
    kinit -c $host_cc -k
    klist -c $host_cc
    
    # Acquire NFS tickets on behalf of the user using S4U2Proxy
    kvno -c $host_cc -I $user_name -P nfs/fs1.example.com
    klist -c $host_cc
    
    # Do the same, but put the tickets in that user's cache
    # so that rpc.gssd would be able to find them
    user_cc=FILE:/tmp/krb5cc_$(id -u $user)
    kvno -c $host_cc -I $user -P nfs/fs1.example.com --out-cache $user_cc
    chown $user: $user_cc
    
  4. Install gss-proxy on the client, and edit its included nfs-client.conf to use S4U2Proxy instead of individual client keytabs:

    [service/nfs-client]
      mechs = krb5
      cred_store = keytab:/etc/krb5.keytab
      cred_store = ccache:FILE:/var/lib/gssproxy/clients/krb5cc_%U
      impersonate = yes
      allow_any_uid = yes
      trusted = yes
      euid = 0
    

    This example is based on https://github.com/gssapi/gssproxy/blob/main/docs/NFS.md#user-impersonation-via-constrained-delegation.

  5. Configure the client's rpc.gssd daemon to use gss-proxy by adding GSS_USE_PROXY=1 to the environment:

    # systemctl edit rpc-gssd
    
    [Service]
    Environment=GSS_USE_PROXY=1
    
    # systemctl restart rpc-gssd
    

If Kerberos is used exclusively for NFS, and if each host only needs a limited set of users, then the host can store client keytabs (which hold the password-derived keys) for those users. This is roughly equivalent to storing the users' passwords, as the keytab allows