6

I've created the following luks@.service service for systemd:

[Unit]
Description=Cryptography Setup for '%I'
After=cryptsetup-pre.target
After=dev-mapper-%i.device
Before=cryptsetup.target
Before=umount.target
BindsTo=dev-mapper-%i.device
BindsTo=dev-mapper-%i.luks.device
Conflicts=umount.target
DefaultDependencies=no
IgnoreOnIsolate=true
RequiresMountsFor=/home

[Service]
ExecStart=/usr/lib/systemd/systemd-cryptsetup attach '%I.luks' '/dev/mapper/%I' '%h/%I/secret.key' 'luks,header=%h/%I/header'
ExecStop=/usr/lib/systemd/systemd-cryptsetup detach '%I.luks'
KillMode=none
RemainAfterExit=yes
TimeoutSec=0
Type=oneshot

[Install]
WantedBy=default.target

The idea is to decrypt certain LUKS-encrypted xxx device as xxx.luks only for a given user, who enables the service with, for example:

systemctl --user enable luks@xxx

Unfortunately, even testing it with

systemctl --user start luks@xxx

fails as it always returns with exit code 1 without stating the actual reason. To me it was clear that the problem is likely in permissions. That is I know for sure that in order to manually trigger cryptsetup luksOpen ..., one has to elevate the shell, e.g. with sudo. Indeed, if I issue

sudo systemctl start luks@xxx

it works like a charm and similarly

sudo systemctl enable luks@xxx

would work for boot phase.

NOTE:
For such system-wide installation, it is of course needed to modify the service by replacing %h with the actual home directory of a giver user, which is ugly and does not serve the final purpose anyway.

Now, I'm aware of pam_mount which is capable of doing similar mounting (which I cannot use because it does not support detached LUKS headers and because it actually mounts devices, something what I don't want) on per user basis and, in fact, pam_systemd launches systemctl --user, so there definitely should be a way to obtain privileges during boot on per user basis to perform the device decryption.

By the way, failure symptoms of

systemctl --user enable luks@xxx

are even worse than those of testing it with

systemctl --user start luks@xxx

(which only returns exit code 1). That is I cannot even log in with the given user as it complains about

Failed to create bus connection: No such file or directory

because XDG_RUNTIME_DIR and DBUS_SESSION_BUS_ADDRESS are not set anymore, while they should have been by the systemd-logind.service service. Clearly, luks@xxx somehow breaks the whole initialization process but due to insufficient information in journal, I cannot identify exactly why. Thus, my current suspicion about lack of permissions still remains.

Looking forward to educated proposals. Thank you.

3
+100

An alternative solution would be to edit the sudoers file to add permissions for the user in question to run /usr/lib/systemd/systemd-cryptsetup with root permissions with NOPASSWD option enabled.

You would then edit your (user-specific) service file above to read:

ExecStart=/usr/bin/sudo /usr/lib/systemd/systemd-cryptsetup attach '%I.luks' '/dev/mapper/%I' '%h/%I/secret.key' 'luks,header=%h/%I/header'
ExecStop=/usr/bin/sudo /usr/lib/systemd/systemd-cryptsetup detach '%I.luks'

I'm not sure whether you would also have to enable !requiretty for this to work

Update:

To increase security around this, especially for a multiple-user system, I'd highly recommend creating a couple of scripts to perform the 'attach' and 'detach' steps on behalf of the user rather than giving sudo access to /usr/lib/systemd/systemd-cryptsetup directly, as otherwise any user that is given access to run this command can potentially interfere with other encrypted volumes.

  • I've chosen this solution as the configuration can be user-independent (e.g. by using the %wheel group instead) and is also the least impacting one. By the way, I didn't need !requiretty for it to work. Though, I'm still perplexed about why lack of permissions ruined the whole initialization process (my understanding was that systemd units are isolated from each other and cannot potentially cause such damage). In any case, thanks for you rich inputs. – Alexander Shukaev May 14 '17 at 21:47
  • I'm not sure what is confusing you, but I'll attempt to help: User systemd managers are run at the permission level of the user and have access to resources that the user does. Only the user (and root) has access to services managed as such. The system systemd manager is run as root and has access to all resources. Only root, and users given specific permissions (through something like sudo or polkit) have access to the system manager's services. There is no default 'isolation' between services, though there are options that can help (PrivateTmp=, User= or ProtectControlGroups= to name a few) – Benjamin May 15 '17 at 10:47
  • I meant, why should Failed to create bus connection: No such file or directory be the result of not having permissions to decrypt a device. Clearly, those two points have nothing to do with each other in the first place. – Alexander Shukaev May 15 '17 at 16:12
2

I would suggest creating and enabling a Type=oneshot RemainAfterExit=yes service for the user that creates a file with it's ExecStart directive, and removes it with it's ExecStop directive e.g.

ExecStart="/usr/bin/touch %h/.decrypt"
ExecStop="/usr/bin/rm %h/.decrypt"

You can then create and enable a luks@xxx.path unit file for the system user with an absolute path:

PathExists="/home/user/.decrypt"

This would check for the path created by the user service above, activating the luks@xxx.service unit when it is created, and deactivating it when it is removed, thus establishing an indirect dependency of the system service on the user service.

Note that for this to operate securely, the directory in which the file is created should be writable by the user only, of course.

  • This would still require enabling luks@xxx system-wide as root. Thanks but this is more of a workaround, not a final solution. – Alexander Shukaev May 12 '17 at 10:56
  • You don't need to enable luks@xxx.service, just the relevant path unit, but I do concede that it is more 'workaround' than 'elegant'. What about using PolicyKit as in the first answer here - serverfault.com/a/841150/193286 – Benjamin May 12 '17 at 11:03
  • Looks interesting. I'll give it a try. Though, does that mean that the service will be still enabled system-wide? – Alexander Shukaev May 12 '17 at 11:20
  • I believe so - I'm not sure how you'd not execute it 'system wide'. For a user instance of a systemd manager to execute something requiring elevated permissions would require itself to be running with elevated permissions (which would be insecure) or perhaps something involving control groups giving the user systemd instance the permissions to manage decryption of the filesystem (which would still be insecure, just more secure than full root permissions). – Benjamin May 12 '17 at 11:26
  • Is there a way to rather say "I want this user to be able to decrypt this device without explicitly specifying privileges."? – Alexander Shukaev May 12 '17 at 11:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.