Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Advantage of using sudo spawner over adding capabilities CAP_SETUID, CAP_SETGID to JupyterHub #62

Open
gatoniel opened this issue Mar 26, 2020 · 6 comments

Comments

@gatoniel
Copy link

Hi,

I am running JupyterHub as separate non-root user with systemd without sudospawner. Instead I leverage the systemd AmbientCapabilities option. My jupyterhub.service file looks like this:

[Unit]
Description=JupyterHub
After=syslog.target network.target podman-chp.service

[Service]
User=jupyterhub
AmbientCapabilities=CAP_SETUID CAP_SETGID
Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/jupyterhub/bin"
Environment="CONFIGPROXY_AUTH_TOKEN=<secret>"
ExecStart=/opt/jupyterhub/bin/jupyterhub -f /opt/jupyterhub/etc/jupyterhub/jupyterhub_config.py

[Install]
WantedBy=multi-user.target

With this I can use the PAMAuthenticator for logging in and use the standard spawner for creating the single user notebooks. My question now is: Am I missing some feature of the sudospawner configuration? Or do I get the same effects with my configuration?

NOTE: I am running on CentOS 8. Maybe this makes a difference?

@mangecoeur
Copy link

This is a very good question - I had been looking for systemd functionality like this since in my tutorial I just run the server as root. But I am not familiar enough with systemd to understand what the implications of the CAP_* settings are. If they are what we need I would like to update my tutorial to use your systemd config.

@gatoniel
Copy link
Author

gatoniel commented Jun 8, 2020

A process running with CAP_SETUID is able to set / change its own user ID. Similarly a process with CAP_SETGID can change its group ID. When a process spawns a new subprocess this subprocess inherits the UID and GID of the process. So when the JupyterHub starts a new singleuser it needs to change the singleusers UID and GID. Normally JupyterHub runs as root, then the singleuser runs as root. Since root can change UID and GID, the singleuser changes UID and GID to the correct ones.

To run JupyterHub as non-root we need to add the possibility to change UID and GID. In sudospawner this is accomplished by adding the non-root user to the sudoers.

The line AmbientCapabilities=CAP_SETUID CAP_SETGID adds the mentioned capabilities to the JupyterHub Process. So the process does not need to be root, but is still allowed to change UID and GID. Once they are changed by supprocesses these subprocesses loose the capability and are stuck with UID and GID until their end. I do not now if this opens security issues or different problems. My JupyterHub runs stable with this config. Since it is in systemd I think it is a very straight forward way. So in my oppinion they are what you need :D but I am no expert...

@manics
Copy link
Member

manics commented Jun 8, 2020

@gatoniel this looks pretty neat! I don't know whether it's more/less/as safe as sudospawner. You could try asking on https://discourse.jupyter.org/ since more people are likely to see it?

@mangecoeur
Copy link

@gatoniel Thanks, that makes sense - I've never actually looked at how jupyterhub sets the user for the spawned processes but good to know it works. Do you know if CAP_SETUID/SETGID allow to set the values to the root user?

I guess a downside relative to sudospawner could be that AFAIU the latter only allows to run the hard-coded jupyter process. I don't know if there are systemd options for doing that.

I wonder if there is a way to use systemdspawner together with the CAP_* settings - at the moment systemdspawner still requires the hub to run as root 🤔

@gatoniel
Copy link
Author

Hi, I tested the config with the standard spawner. Now I am using podmanspawner in combination with PAMAuthenticator, that I have modified to fully work with systemd, PAM and D-Bus (mainly to set loginuid correct). Therefore I need to switch from the non-root user to root and then back to the new logged in user. This is due to some permissions I need for logging in a user at the system. So in short: YES, with CAP_* you can switch back to root.

I can´t comment on the other two raised questions due to lack of knowledge...

@bcbnz
Copy link

bcbnz commented Jan 2, 2021

I think doing this opens up some security issues, at least without further configuration. As the single-user server is now running with CAP_SETUID, any code run in a notebook or terminal can set the UID to 0 and run any further code as root:

 [In 1]: import os
         os.setuid(0)

 [In 2]: os.getuid()
[Out 2]: 0

 [In 3]: import subprocess
         subprocess.run("whoami", capture_output=True).stdout
[Out 3]: b'root\n'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants