0

I am using systemd to mount a Windows share using Kerberos. To make this work, I first run kinit in a .service file to create a Kerberos credential cache (ccache). The .service runs as root as the ccache needs to be owned by root (journalctl -xe helped me with that), as mount.cifs requires root. The .mount (and .automount) use the ccache to do the Kerberized mount. When I create the ccache interactively, this works well. However, when run inside the service unit, the ccache is quickly deleted and the (auto)mount fails. It does not matter if I save it to /tmp or /run/user/0.

  1. Why are files in /tmp or /run automatically deleted?
  2. What is the preferred location for these ccache files? Is PrivateTmp a better solution? If so, how do I refer to that private tmp dir inside the service file? I tried %T/krb5cc_root.ccache, but systemctl generates an error. Is JoinsNamespaceOf the way to use the same private tmp in the mount file?

I am using systemd 219 on linux CentOS 7. Below is my .service unit. Thanks in advance!

[Unit]
Description=Kinit keytab for /mnt/windows_staging
After=network.target
Requires=network.target

[Service]
Restart=always
RestartSec=30
PrivateTmp=yes
User=root
Group=users
ExecStartPre=-/bin/mkdir -p /mnt/windows_staging
ExecStartPre=-/bin/mkdir -p /run/user/0
Environment=KRB5_KTNAME=/home/albertjan@domain/myproject/etc/keytabs/albertjan.keytab
Environment=KRB5CCNAME=/run/user/0/krb5cc_root.ccache
ExecStart=/bin/kinit albertjan -kt ${KRB5_KTNAME} -c ${KRB5CCNAME}
ExecStartPost=/bin/sleep 2
ExecStop=-/bin/kdestroy -c ${KRB5CCNAME}

[Install]
WantedBy=multi-user.target

1 Answers1

0

Why are files in /tmp or /run automatically deleted?

Because your service starts a "daemon" that immediately exits, therefore marking the service as "stopped" within seconds of starting, therefore causing the kdestroy from ExecStop= to be run.

  • Option 2: Change the .service definition to tell systemd that this is supposed to be a task that immediately exits, using these options:

    [Service]
    Type=oneshot
    RemainAfterExit=yes
    

    The Type=oneshot mode is additionally useful because will make systemd wait for ExecStart= to fully complete before the service is marked as "active", avoiding the need to add the arbitrary sleep 2. In other words, it lets you use After=kinit.service without worrying that other things will start "too early".

  • Option 1: Replace kinit with the k5start daemon from https://www.eyrie.org/~eagle/software/kstart/. This is a real daemon – a long-running process – and will be tracked as such. It will handle periodic renewal as well.

    If you use k5start with the -b option ("Detach on startup") and change the .service to Type=forking mode accordingly, you will also get the same "delay until success" behavior.

(There's also a third option of letting gssproxy handle all tickets, but cifs.upcall in CentOS doesn't support that yet. For other uses besides mounting filesystems, KRB5_CLIENT_KTNAME would let the program itself acquire tickets from keytab as needed, but it won't work in this case.)

What is the preferred location for these ccache files?

Personally I would stick with /tmp/krb5cc_* or /run/user/<uid>/krb5cc_*. (Those are the only locations NFS rpc.gssd checks.)

For SMB, cifs.upcall will look at the system default location for the UID that's performing the mount (i.e. whatever is defined in krb5.conf), which is usually /tmp/krb5cc_0 when systemd is doing so. (Although cifs.upcall can scrape KRB5CCNAME out of the invoker's environment, that doesn't help with automounts being involved, as cifs.upcall would only see systemd or autofsd as the caller.)

Is PrivateTmp a better solution?

PrivateTmp won't help, because it's not an external task that's deleting your file, it's the service itself doing so.

user1686
  • 10,162
  • 1
  • 26
  • 42
  • Hi, thanks for helping me, I appreciate it. It sounds like `k5start` is the way to go. Too bad it's not yum-installable. I never realized that for type=simple systemd units, execStop is run. I thought this happened when `systemctl stop`, explicitly or implicitly via reboot/shutdown. So, the _proper_ way to renew the kerberos ticket (max lifetime 10h) is to turn the .service into a oneshot as per your recommendation and define a .timer which triggers the .service? And the _clunky_ way is to remove the `kdestroy` execStop, but keep the Restart* parts? – Albert-Jan Roskam Feb 24 '23 at 09:27
  • It should be installable, the package is usually named `kstart` instead of k5start. ExecStop is run for any systemd service when it transitions to "stopped" regardless of type. Yes, it happens when you run `systemctl stop`, but it *also* happens **whenever the service stops on its own** (that is, when the daemon process exits) – the main goal of my post was to point out that your unit is immediately stopping on its own and not just staying "running" afterwards. You don't need to remove ExecStop if the unit has RemainAfterExit; that is the whole point of me suggesting RemainAfterExit. – user1686 Feb 24 '23 at 10:50