$ sudo -u backup_agent keyctl add user LUKS_PASSWORD "your-secure-password" @u
1013632990
$ sudo -u backup_agent keyctl list @u
1 key in keyring:
1013632990: --alswrv 110 110 user: LUKS_PASSWORD
$ sudo -u backup_agent keyctl read 1013632990
keyctl_read_alloc: Permission denied
I'm trying to create a key for a service user that it would use from a script later from a cron job. I can't understand why the last step above results in a permission denied error. Any ideas?
The key needs to be reachable from the process's "session keyring" (@s
or @us
).
If you run keyctl describe <id>
to see the full permissions on the newly added key, it'll show four sets of permissions: possessor, owner, group, other. By default they are:
$ sudo keyctl describe 398779806
398779806: alswrv-----v------------ 0 0 user: foo
So the permissions are alswrv
for possessor, -----v
for owner, ------
for group/other – which means that matching owner UID is insufficient to r
ead the key. Full permissions are only granted if the key is "possessed" i.e. reachable from your process's @s
or @us
session keyring.
The "user" keyring @u is not considered on its own – merely having UID 110 isn't enough; it actually has to be linked from the session keyring of the process doing the operation. If you run keyctl show
without parameters (listing the session keyring), you'll usually see that it contains a link to your user keyring – shown as _uid.XXX
– and that is what grants you "possession" of the keys in @u.
$ keyctl show
Session Keyring
1046546095 --alswrv 2001 100 keyring: _ses
348545926 --alswrv 2001 65534 \_ keyring: _uid.2001
But the session keyring is inherited through fork and even through setuid, so sudo keyctl show
will still show your original session containing a link to the original user's @u keyring; e.g. it is not _uid.0
but _uid.2001
in this example.
$ sudo keyctl show
Session Keyring
1046546095 --alswrv 2001 100 keyring: _ses
348545926 ---lswrv 2001 65534 \_ keyring: _uid.2001
So in order to gain possession of the new key, you have to end up with a @s (either the same session or a brand new session) which has a link to the backup_agent's @u.
This probably won't be a problem for cron jobs, as they already start from a fresh environment – going through PAM anew, and having pam_keyinit
set up a fresh @s with the correct link to @u. Likewise, something like run0
(systemd's sudo alternative which asks init to spawn the shell indirectly) will get a new session keyring through PAM.
$ run0 keyctl show
Session Keyring
363016313 --alswrv 0 0 keyring: _ses
774763472 --alswrv 0 65534 \_ keyring: _uid.0
398779806 --alswrv 0 0 \_ user: foo
To make sudo work, however, you'd need either to:
Link _uid.0
into the same (caller's) session keyring, which is probably a bad idea since it gives the invoker access to all keys in the target's @u keyring:
$ sudo keyctl link @u @s
$ keyctl show
Session Keyring
1046546095 --alswrv 2001 100 keyring: _ses
348545926 --alswrv 2001 65534 \_ keyring: _uid.2001
774763472 ---lswrv 0 65534 \_ keyring: _uid.0
398779806 --alswrv 0 0 \_ user: foo
(You cannot link just the key alone, since you don't have the l
permission either.)
Or, create a new process with a new session keyring:
$ sudo -s
# keyctl show
1046546095 --alswrv 2001 100 keyring: _ses
348545926 ---lswrv 2001 65534 \_ keyring: _uid.2001
# keyctl session [spawns a subshell]
# keyctl link @u @s
# keyctl show
304967203 --alswrv 0 0 keyring: _ses
774763472 --alswrv 0 65534 \_ keyring: _uid.0
398779806 --alswrv 0 0 \_ user: foo