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

Better support for rootless containers #636

Merged
merged 7 commits into from
May 13, 2023

Conversation

zeehio
Copy link
Contributor

@zeehio zeehio commented Apr 21, 2023

Short summary

Running containers under rootless docker/podman lets us:

  • avoid permission issues in mounted volumes without any extra run setting (root in container == user at the host)
  • avoid granting privileges to host users, enhancing system security
  • simplify container images (just run them with root, it's safe because it's actually the user without extra privileges!)

For backwards compatibility, this pull request assumes users still don't run rootless docker by default, so we require users running rootless containers to define -e RUNROOTLESS=true. Until a method is devised to detect if a container is running rootless or not from within the container.

In this pull request, I modify the userconf script so if we are running rootless -e RUNROOTLESS=true we do not create users or change sudoers or do any of those things. With this change, we can run rstudio server under an unprivileged user without issues.

mkdir $HOME/work
podman run -ti -e PASSWORD=helloworld -e RUNROOTLESS=true -v $HOME/work:/root/work -p 10000:8787 <img-name>

Visit localhost:10000 and login using root and helloworld.

Thanks for considering merging this.

Alternative

As an alternative solution we could have different images: Something like rocker/rstudio-rootless or rocker-rootless/rstudio

FROM rocker/rstudio
COPY init_userconf.sh /etc/cont-init.d/02_userconf

But I think it is easier to just merge this

Historic background

Here is some longer story of why things are the way they are, to bring some context to all this user mess that exists in docker images. It may not be fully accurate, but good enough

Stage 1: We are root

  • Docker is a client-server application.
  • The docker daemon runs as the root user.
  • docker users need to run docker commands under root or using sudo (e.g. sudo docker run...).

This situation is problematic because:

  • docker users have root access to the host
  • docker images may create/modify files as root in the host (even accidentally if some host directory is mounted!)
  • files created by docker are owned by the root user, this easily becomes a permission mess
  • There are audit limitations, since all docker users connect to the same docker daemon typically without authentication. We don't know who does what.

People wants to use docker so much that a docker user group is created, and all users in that docker group do not need to type sudo to run docker anymore, although effectively it is as if they did. The risk is still there, only hidden.

Stage 2: Images drop root privileges

Docker is a complex piece of software that relies on namespaces and control groups, features of the linux kernel that are under heavy development.

Therefore the fastest and easiest solution to address some of these issues comes from the image builders. The container starts running as root, but image builders following best-practices drop those permissions as soon as possible and read environment variables set when the container is created so users can choose the user id they would like to be used to create files, avoiding the file permission mess.

This depends on the good-will of the image builder, but "works".

This adds a lot of complexity, because images now have to consider multiple users and permissions (allow root inside the container for apt-get install, use sudoers...)

Stage 3: Run with docker run --user

Docker allows to specify the user the image will run as. The Docker daemon runs as root, but the container is started as running with a user id, and that user in the container typically does not have root privileges anymore.

Docker here avoids file permission issues, but at some cost. Since now the image starting scripts do not have root access in the container, allowing for apt-get inside the container becomes far more tricky.

To my knowledge, this option does not get a lot of adoption in rocker and jupyter notebook images.

Stage 4: User namespaces docker run --user-ns

The linux kernel starts having support for user namespaces.

Basically we can map user ids in the container to a range of user ids in the host. Depending on how this is used, this can lead to files created by the image not being owned by root anymore, but by a super high user ID.

To my knowledge, this option does not get a lot of adoption in rocker and jupyter notebooks.

Stage 5: Rootless docker

Enough namespace and cgroup solutions exist in the kernel for the docker daemon to be able to run containers without root permissions.

Running the docker daemon as root is a security risk, and it is also an auditability issue, so this becomes an actual better-designed solution to the permission problem. Now each user can run its own docker daemon. Since the docker daemon runs as the user, it does not have any special permissions, no damage to the host can be made.

Therefore we do not need images to drop privileges or follow any best practices to be responsible, since they are not allowed to do any damage by default anymore. Things can be simple again! However we must still be backwards compatible with those who have or want to use docker as root.

Hi podman! Podman was designed to run rootless by default, and maybe even was able to do so before docker (I don't really know). podman does not even need a daemon, although podman supports a daemon to increase compatibility with docker.

How does this work? Using user namespaces in a more transparent way:

  • alice, with user id 1000, has a rootless docker daemon running, so she can run docker daemons without any root privilege.
  • alice creates a container (podman run..., docker run...), mounting some directories she has access to (--volume) without caring for permissions or user ids
  • docker/podman creates the container and runs the entrypoint. The entrypoint seems to run as root from within the container, but from the host it appears to run as alice. If the entrypoint scripts do not do anything weird with the users, the entrypoint and commands that run afterwards run as well as root/alice. Files created on the mounted volume appear to be owned by alice. If alice tries to mount a volume she can't write on (e.g. --volume /sbin:/somewhere) the root/alice user in the container won't be able to write on it, because alice does not have permissions to do that.

That's all we want and need!

But... backwards compatiblity!

Until someone finds a convention to determine if a container is running under rootless docker, we, image builders, can't tell if we should drop privileges or simply use them.

So, I would like to ask alice to set an environment variable to tell me if she is running rootless, so I can just use the root/alice user without a care for setting up users and permissions and sudoers. I'll have to ask alice to use an environment variable for now...

@cboettig
Copy link
Member

Support for rootless RStudio for podman has been discussed before, e.g. rocker-org/rocker#202, #108, #346, and I think some users may have gotten it working? (@agila5 , or @hute37 may have pointers?)

Rootless RStudio sessions are also possible through singularity, which is actually even documented https://rocker-project.org/use/singularity.html (yay!, though I think it needs updating?)

@zeehio do you have a working rootless image using the approach you outline here? This looks like only a change to the init_userconf.sh script, which by itself I don't think will work (the default command on the rstudio-based Dockerfiles is not changed in this PR, which is /init, which runs the S6-init system (which requires root), which runs the init_userchonf.sh and as root but also potentially other scripts that require root, including launching RStudio server, which requires root. As noted above, it's possible to work around most or all of these, though some solutions have security concerns).

anyway, rootless support is certainly an important theme and we welcome discussion, at very least we could probably add a docs page on the topic as well!

@benz0li
Copy link
Contributor

benz0li commented Apr 21, 2023

@zeehio Out of curiosity: What environment is the use case here: A multi-tenant Linux server with rootless docker/podman and possibly X11 installed?

@zeehio
Copy link
Contributor Author

zeehio commented Apr 21, 2023

@zeehio Out of curiosity: What environment is the use case here: A multi-tenant Linux server with rootless Docker/Podman and possibly X11 installed?

Well in my case no X11 but yes. Ubuntu server with rootless podman

@benz0li
Copy link
Contributor

benz0li commented Apr 21, 2023

@zeehio Out of curiosity: What environment is the use case here: A multi-tenant Linux server with rootless Docker/Podman and possibly X11 installed?

Well in my case no X11 but yes. Ubuntu server with rootless podman

IMHO only one user should be allowed to deploy applications on a server – but that is a matter of opinion. The deployed application should be multi-tenant and as much isolated as possible.

Yes: user namespaces; No: mounting of volumes (= Not even rootless docker/podman for other users).

@hute37
Copy link

hute37 commented Apr 21, 2023

In our statistical labs, we need to provide all students with a user customizable R environment without admin (root) access, based on Azure Ubuntu workstations.

Using containers was a natural choice, so we decided to base our standard project on Rocker Images.

But Docker wasn't an option 'cause of (too) many security issues in our context. Singularity could be a good alternative, used in HPC environments.

The alternative we chose was Red-Hat "podman", that provides a service-less "root-less", "sandboxed" in user home, without admin access, able to share mounted directories.

Using standard RStudio in rocker images poses a problem:

"by default, the RStudio login requires a process user change to an unprivileged user in container"

This is seen as a security requirement in a host based server installation, but in a podman "root-less" environment, not only not imply a security gain, but cause siduid/sudgid mapping issues in volume sharing between host and container.

Our approach was to "patch" rstudio config, in order to allow "root" as a valid RStudio user, running provileged (uid:0, gid:0) in container. For details:

Also consider --ulimit=host podman option to disable process limits in containers

The login in rstudio still poses some issues anyway:

  • podman does not propagate alternative group permission inside container as a security measure.

We need to enable alternative group membership in order to access data in shared volumes.
Details are here:

This is not a complete solution. It works only in R/Rscript but not alter RStudio login, after which alternative group membership is lost anyway.

Now we are busy trying to enable NVIDIA CUDA support in container.
We are following this guide:

Rootless container support in Kubernetes in another thing. It was discssed here:


For podman don't miss Dan Walsh's Blog:

__

As a security note, be careful about storing your ~/.ssh private keys if github/gitlab enabled ...

@benz0li
Copy link
Contributor

benz0li commented Apr 21, 2023

Now we are busy trying to enable NVIDIA CUDA support in container.

@hute37 You might be interested in my CUDA-enabled JupyterLab R docker stack.

@zeehio
Copy link
Contributor Author

zeehio commented Apr 21, 2023

Support for rootless RStudio for podman has been discussed before, e.g. rocker-org/rocker#202, #108, #346, and I think some users may have gotten it working? (@agila5 , or @hute37 may have pointers?)

Rootless RStudio sessions are also possible through singularity, which is actually even documented https://rocker-project.org/use/singularity.html (yay!, though I think it needs updating?)

@zeehio do you have a working rootless image using the approach you outline here? This looks like only a change to the init_userconf.sh script, which by itself I don't think will work (the default command on the rstudio-based Dockerfiles is not changed in this PR, which is /init, which runs the S6-init system (which requires root), which runs the init_userchonf.sh and as root but also potentially other scripts that require root, including launching RStudio server, which requires root. As noted above, it's possible to work around most or all of these, though some solutions have security concerns).

anyway, rootless support is certainly an important theme and we welcome discussion, at very least we could probably add a docs page on the topic as well!

The Dockerfile I used:

FROM rocker/rstudio
COPY init_userconf.sh /etc/cont-init.d/02_userconf

where init_userconf.sh is the modified file in this PR.

I created the container with:

mkdir test1
podman run \
  -ti \
  -e PASSWORD=test123 \
  -e RUNROOTLESS=true \
  -v $PWD/test1:/workdir \
  -p 20000:8787 \
  localhost/sergio-test-rstudio1:latest

And it worked.

Here is my podman info if you want:

$ podman info

host:
  arch: amd64
  buildahVersion: 1.23.1
  cgroupControllers:
  - memory
  - pids
  cgroupManager: systemd
  cgroupVersion: v2
  conmon:
    package: 'conmon: /usr/libexec/podman/conmon'
    path: /usr/libexec/podman/conmon
    version: 'conmon version 2.0.30, commit: '
  cpus: 32
  distribution:
    codename: focal
    distribution: ubuntu
    version: "20.04"
  eventLogger: journald
  hostname: nose3
  idMappings:
    gidmap:
    - container_id: 0
      host_id: 1002
      size: 1
    - container_id: 1
      host_id: 886432
      size: 65536
    uidmap:
    - container_id: 0
      host_id: 1002
      size: 1
    - container_id: 1
      host_id: 886432
      size: 65536
  kernel: 5.4.0-132-generic
  linkmode: dynamic
  logDriver: journald
  memFree: 65841872896
  memTotal: 101317976064
  ociRuntime:
    name: crun
    package: 'crun: /usr/bin/crun'
    path: /usr/bin/crun
    version: |-
      crun version UNKNOWN
      commit: ea1fe3938eefa14eb707f1d22adff4db670645d6
      spec: 1.0.0
      +SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +CRIU +YAJL
  os: linux
  remoteSocket:
    path: /run/user/1002/podman/podman.sock
  security:
    apparmorEnabled: false
    capabilities: CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT
    rootless: true
    seccompEnabled: true
    seccompProfilePath: /usr/share/containers/seccomp.json
    selinuxEnabled: false
  serviceIsRemote: false
  slirp4netns:
    executable: /usr/bin/slirp4netns
    package: 'slirp4netns: /usr/bin/slirp4netns'
    version: |-
      slirp4netns version 1.1.8
      commit: unknown
      libslirp: 4.3.1-git
      SLIRP_CONFIG_VERSION_MAX: 3
      libseccomp: 2.4.3
  swapFree: 85862641664
  swapTotal: 85862641664
  uptime: 3513h 24m 20.65s (Approximately 146.38 days)
plugins:
  log:
  - k8s-file
  - none
  - journald
  network:
  - bridge
  - macvlan
  volume:
  - local
registries:
  search:
  - docker.io
  - quay.io
store:
  configFile: /home/soller/.config/containers/storage.conf
  containerStore:
    number: 3
    paused: 0
    running: 0
    stopped: 3
  graphDriverName: overlay
  graphOptions:
    overlay.mount_program:
      Executable: /usr/bin/fuse-overlayfs
      Package: 'fuse-overlayfs: /usr/bin/fuse-overlayfs'
      Version: |-
        fusermount3 version: 3.9.0
        fuse-overlayfs: version 1.5
        FUSE library version 3.9.0
        using FUSE kernel interface version 7.31
  graphRoot: /home/soller/.local/share/containers/storage
  graphStatus:
    Backing Filesystem: extfs
    Native Overlay Diff: "false"
    Supports d_type: "true"
    Using metacopy: "false"
  imageStore:
    number: 4
  runRoot: /run/user/1002/containers
  volumePath: /home/soller/.local/share/containers/storage/volumes
version:
  APIVersion: 3.4.2
  Built: 0
  BuiltTime: Thu Jan  1 01:00:00 1970
  GitCommit: ""
  GoVersion: go1.16.6
  OsArch: linux/amd64
  Version: 3.4.2

It works!

@cboettig
Copy link
Member

Thanks @zeehio , this is very nice. Would you be interested in drafting an .md PR documenting this use case as well for https://rocker-project.org? (It's just a simple quarto website, "use" docs are in https://github.com/rocker-org/website/tree/master/use) ?

Like you say, this is a nice approach as it mostly an opt-in extension and so doesn't look likely to create any breaking changes.

@eitsupi @noamross @eddelbuettel any thoughts or concerns here?

@cboettig
Copy link
Member

(not directly related, but I think the other context we often get inqueries about rootless deploy are for kubernetes setups, though not strictly necessary. I guess there is some open question about documenting rootless concepts generally vs podman-specific)

@eitsupi
Copy link
Member

eitsupi commented Apr 22, 2023

Thank you for working on this!

To be honest, I am not sure if this works properly as I do not normally use rootless Docker, Podman, etc.
Thus I can't review this right away, so it would be very helpful if someone else could confirm that this works.......

@hute37
Copy link

hute37 commented Apr 22, 2023

Some notes ...

The solution of patching /etc/rstudio/rserver.conf:

    sed -i '/auth-minimum-user-id/d'      /etc/rstudio/rserver.conf
    echo    'auth-minimum-user-id = 0' >> /etc/rstudio/rserver.conf

    sed -i '/auth-minimum-user-id/d'      /etc/rstudio/disable_auth_rserver.conf
    echo    'auth-minimum-user-id = 0' >> /etc/rstudio/disable_auth_rserver.conf

enables root login in RStudio

To avoid warnings, it is possible to add also:

touch /root/.sudo_as_admin_successful
touch /root/.Xauthority
chmod 600 /root/.Xauthority

In documentation, these podman options could be reported:

  • --ulimit=host to avoid shell limits
  • --group-add keep-groups to propagate alternative group permission (It works only in R/Rscript, not in RStudio)
  • :Z option in volume mounts (on selinux enabled systems)

For CUDA support, I follow these docs:

Podman invocation options example:

ifdef PODMAN_MODE
DOCKER := podman
DOCKER_BUILD_OPTIONS := 
DOCKER_BUILD_PULL := --pull


DOCKER_NVIDIA_TOOLKIT_OCI := /usr/share/containers/oci/hooks.d/oci-nvidia-hook.json

ifneq ("$(wildcard $(DOCKER_NVIDIA_TOOLKIT_OCI))","")
    DOCKER_NVIDIA_OPTIONS = \
           --security-opt=label=disable \
           --hooks-dir=/usr/share/containers/oci/hooks.d/ \

#          --security-opt=no-new-privileges --cap-drop=ALL \  #permissions not dropped because of rstudio compatibility

else
    DOCKER_NVIDIA_OPTIONS = ""
endif

#DOCKER_RUNTIME_OPTIONS := --ulimit=host --group-add dsdata
#DOCKER_RUNTIME_OPTIONS := --ulimit=host --group-add keep-groups --subgidname=dsuser
DOCKER_RUNTIME_OPTIONS := --ulimit=host --group-add keep-groups $(DOCKER_NVIDIA_OPTIONS)
#DOCKER_RUNTIME_OPTIONS := --ulimit=host --annotation run.oci.keep_original_groups=1 
endif


@zeehio
Copy link
Contributor Author

zeehio commented Apr 24, 2023

@cboettig I will work on the documentation.

With respect to my first post, I said:

For backwards compatibility, this pull request assumes users still don't run rootless docker by default, so we require users running rootless containers to define -e RUNROOTLESS=true. Until a method is devised to detect if a container is running rootless or not from within the container.

I'm happy to say I have found the way. 👍

Short answer

On init_userconf.sh if our uid is 0 and 4294967295 is not found on cat /proc/self/uid_map then we can assume we are running docker/podman in a rootless way.

I will update my pull request accordingly. RUNROOTLESS still can be defined by the user, but now we have a default detection method that should "just work".

Long explanation

I found a way to detect if a process is running inside a user namespace or not. When we are not mapping any namespace there is a 1-1 uid map for all 32-bit possible user ids.

On my ubuntu system:

$ cat /proc/self/uid_map
         0          0 4294967295

Read as: "Create a mapping starting from uid 0 (container) to uid 0 (host) of 4294967295 successive uids"

With podman running as root we are not mapping ids:

$ sudo podman run --rm alpine cat /proc/self/uid_map
         0          0 4294967295

If we are under any namespace, we won't be mapping everything linearly so we won't find a 4294967295 long map.

Rootless podman:

$ podman run --rm alpine cat /proc/self/uid_map
         0       1000          1
         1     100000      65536

Read as: "Create a mapping starting from uid 0 (container) to uid 1000 (host) of 1 successive uids" + "Create a mapping starting from uid 1 (container) to uid 100000 (host) of 65536 successive uids". This effectively maps my uid at the host (1000) to root in the container (0) and shifts uid 1 and successive uids in the container to my subuids 100000 and above.

According to podman's source code both the runc and crun container runtimes use this to check if we are on a rootless container or not https://github.com/containers/podman/blob/d05a9807928c1deada0f0294cd912825a0487832/pkg/rootless/rootless_linux.go#L235.

@zeehio
Copy link
Contributor Author

zeehio commented Apr 25, 2023

Hi @hute37,

You were saying:

The login in rstudio still poses some issues anyway:

podman does not propagate alternative group permission inside container as a security measure.

We need to enable alternative group membership in order to access data in shared volumes.
Details are here:

--group-add keep-groups podman option

This is not a complete solution. It works only in R/Rscript but not alter RStudio login, after which alternative group membership is lost anyway.

I have a solution, but it comes with a bit of a longer explanation:

The way this "keep-groups" works is that it sets to process that runs when the container starts the groups of the "podman run" process (your user groups). However, since the additional group IDs are not mapped into the namespace where the container processes run, the processes inside the container do not have a mapped GID that they can use to name the groups they belong to and that's why you see "nobody" o "nogroup" if you ask for their IDs.

When we run R or an RScript directly, the process already has the groups set and it does not need to refer to the IDs in any way, so it works.

However, when we start a new process through the RStudio web interface we can't set those groups directly because inside the container they do not even have a group ID.

We are not even able to usermod -aG <GID> root to add the groups at the userconf.sh script, because we do not have a GID in this namespace.

Our only option to workaround this is to ask a sysadmin to subordinate the GID of the group we want to see to our users. This subordination happens through the /etc/subgid file in the host.

What are those /etc/sub{ug}id files? The /etc/sub{ug}id files allow users to impersonate other users and groups inside the containers. The /etc/sub{ug}id files are necessary in rootless container context because containers usually may use (e.g. contain a file) with more than one user id or group id, so what we do is we give a bunch (like 65000 or more) of unused uids and gids to each user. We do not care if our users impersonate non-existing non-overlapping user ids in the host.

We are going to tell the linux kernel that we want to allow our users alice and bob impersonate the group ID of our university_data group, that has GID 2000:

$ cat /etc/subgid
alice:100000:65536
bob:165536:65536

alice:2000:1
bob:2000:1

With this file, alice can impersonate 65536 group ids starting from 100000 and up to 165535 (required to run containers in general) and impersonate one additional group with id 2000. For bob we see the same, except that the range of group IDs does not overlap with Alice.

Since the group id 2000 is now subordinated to them, podman will automatically map the group id to the container, and the container will be able to give an internal id to it.

With a mapped gid we can run usermod inside the container, so when the root user logs in through the web interface he/she will have that group set.

And everything will work.

Everything? Almost! We can't control how podman assigns that internal id, so it usually is GID 1 and it usually has an ugly name like daemon, adm or bin.

But if we don't mind about this ugly name, everything works.

TLDR

With the userconf script in this pull request, you can keep groups inside rstudio as well, as long as you delegate the group id you want at the host, editing /etc/subgid.

If your university_data group has a group ID of 2000, and you want to delegate it to alice and bob, you should append to /etc/subgid:

alice:2000:1
bob:2000:1

You need to append one line per user. And you may need to podman system migrate after editing the file to refresh the changes.

This allows them to impersonate that group in the containers. I believe it is a smaller security risk than giving them sudo podman rights.

I'm trying to improve the group naming and numbering inside the container at:

where we may get more feedback

@hute37
Copy link

hute37 commented Apr 26, 2023

About "group mapping" ...

I agree with /etc/sub{ug}id discussion above.
This topic is rather complex because is related to different arguments:

  1. podman volume management
  2. RStudio "pseudo-login" process
  3. Security ...

In our context, I found a pair of use-cases when group sharing was a requirement. Unable to address this requirement in RStudio configuration, we applied external workarounds:

  • the first case was about network (cifs) volume sharing among student teams in a "hackathon" context. In the case, shared (restricted) read only access to input data was provided by enabling public read-only access to a restricted group of target machines.

  • in the second case, a pair of users needed to process in parallel a shared group of datasets, with shared write access. In order to support group write access, the users were assigned to the same primary group (gid), with 002 umask.

Volumes

In general, native podman volume management probably is the best option here. I'm not an expert, but i think this is the standard approach in Kubernetes environments. Maybe podman-compose could help

With bind volumes the are also some mount options that support uid/gid mapping (I didn't tried)

For default podman group membership mapping:

RStudio "pseudo-login"

RStudio comes in two flavors: "Community" and "Pro", where most differences are in full user environment setup alter RStudio login. In community version, the rsession process does not support a true (pam compliant) login process, but implements a "basic" change in process credentials. Cfr. discussion here:

This "pseudo-login" process probably does not support --group-add keep-groups run option.

Security

While disabling RStudio login could help in this context, I think that is not a valid solution.
Let a password-less "sudo terminal-enabled" web server to be exposed as a service is a huge security risk, also in a "rootless" podman container.
BTW, packages you install are "trusted" with the same security level ("root in container")

One important point in security is that "root" escalation is not the only sensible target.

Your work is a "target":

  • sensible datasets that can be "stolen" or "encrypted"
  • your code may be exposed
  • your ssh private keys can be sent somewhere

While this is true also in "rootless" podman environment, to enable unauthorized "sudo" on privileged ("docker" group membership) docker environments can compromise host machine security.

Copy link
Member

@eitsupi eitsupi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you format like this? (Please check the CI log)

--- /github/workspace/scripts/init_userconf.sh.orig
+++ /github/workspace/scripts/init_userconf.sh
@@ -13,7 +13,7 @@
 RUNROOTLESS=${RUNROOTLESS:=auto}
 
 if [ "${RUNROOTLESS}" = "auto" ]; then
-    RUNROOTLESS=$(grep 4294967295 /proc/self/uid_map > /dev/null && echo "false" || echo "true")
+    RUNROOTLESS=$(grep 4294967295 /proc/self/uid_map >/dev/null && echo "false" || echo "true")
 fi
 
 USERHOME="/home/${USER}"

Once this is fixed, may I merge this?

@zeehio
Copy link
Contributor Author

zeehio commented May 11, 2023

I fixed that linting you mentioned and I replaced my (hardcoded) overflow GID with the actual overflow GID reported by the kernel, as it should be.

Meanwhile I'm trying to provide a pull request to podman providing the features discussed in their thread, which will make the configuration of additional groups straightforward in rootless settings with rstudio. The pull request for the webpage is accurate, but I hope to eventually be able to simplify it a lot

@eitsupi
Copy link
Member

eitsupi commented May 11, 2023

Thanks for updates!

I would like to merge this for now.
@cboettig Any thoughts?

Copy link
Member

@eitsupi eitsupi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge this for now.
Please let me know if you encounter any problems, thanks.

@eitsupi eitsupi merged commit 8ab4e7d into rocker-org:master May 13, 2023
eitsupi added a commit to rocker-org/website that referenced this pull request May 13, 2023
Tagging @cboettig since he suggested me to write something here

I have a solution for running the container rootless:

- rocker-org/rocker-versioned2#636

There are many advantages on rootless containers, the main one being
security.

The main caveat with rootless containers is when we want to map
additional groups to the container (for instance when we have an
additional group that owns a "shared_data" directory we want to access).
In that case, we still need to learn quite a bit about id mapping. I've
done my best to explain how things work and to provide a step by step
guide in this pull request.

Hopefully this will eventually be simplified. It may be that I have
overlooked something

- containers/podman#18333

I guess we can wait some days to see how the issue evolves. It may be
that I've missed something and my solution is overly complicated or that
some feature needs to land in podman to simplify additional group
management.

English is not my primary language. I would appreciate feedback or
change in wordings.

Besides I've been writing this for too long. I may need to take some
time to get some perspective and re-read it again, but I believe it is
worth a first read.

---------

Co-authored-by: eitsupi <[email protected]>
@benz0li
Copy link
Contributor

benz0li commented Jun 27, 2023

@zeehio @hute37 You may be interested in my multi-arch (linux/amd64, linux/arm64/v8) [CUDA-enabled] Data Science Dev Containers for R, Python and Julia.

@benz0li
Copy link
Contributor

benz0li commented Aug 28, 2023

@zeehio My CUDA-enabled JupyterLab docker stacks now support Docker/Podman rootless mode. E.g.


Create an empty home directory:

mkdir "${PWD}/jupyterlab-root"

Use the following command to run the container as root:

podman run -it --rm \
  -p 8888:8888 \
  -u root \
  -v "${PWD}/jupyterlab-root":/home/root \
  -e NB_USER=root \
  -e NB_UID=0 \
  -e NB_GID=0 \
  glcr.b-data.ch/jupyterlab/r/verse start-notebook.sh --allow-root

❗ The home directory of root is /home/root – and not /root. This was a necessary adjustment.

@zeehio I would appreciate feedback from you.

@zeehio
Copy link
Contributor Author

zeehio commented Sep 3, 2023

@zeehio My CUDA-enabled JupyterLab docker stacks now support Docker/Podman rootless mode. E.g.

Create an empty home directory:

mkdir "${PWD}/jupyterlab-root"

Use the following command to run the container as root:

podman run -it --rm \
  -p 8888:8888 \
  -u root \
  -v "${PWD}/jupyterlab-root":/home/root \
  -e NB_USER=root \
  -e NB_UID=0 \
  -e NB_GID=0 \
  glcr.b-data.ch/jupyterlab/r/verse start-notebook.sh --allow-root

❗ The home directory of root is /home/root – and not /root. This was a necessary adjustment.

@zeehio I would appreciate feedback from you.

It looks good to me. I would however remove the -u root since I believe that's not needed on rootless podman.

Unfortunately my testing machine for rootless podman happens on a VM with a rather small disk on an older laptop, and when I tried to pull your image the disk got full. I hope you can test it on your end.

@benz0li
Copy link
Contributor

benz0li commented Sep 3, 2023

@zeehio Thank you for the feedback.

It looks good to me. I would however remove the -u root since I believe that's not needed on rootless podman.

USER is set to jovyan in the default JupyterLab docker images. So -u root is required to run the container as root.

For convenience reasons, there is e.g. glcr.b-data.ch/jupyterlab/r/verse:latest-root. There, USER is set to root.

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

Successfully merging this pull request may close these issues.

5 participants