Execute command as another user in container using containerd's ctr

12/21/2020

I've installed microk8s on Ubuntu to have a simple Kubernetes cluster for test purposes.

I have a usecase where I have to execute a command in a container (in a kubernetes pod) with another user than the one which is used to run the container.

Since kubectl does not provide such a possibility, the workaround for docker environment is to use docker exec -u. But the Kubernetes cluster installed by microk8s does not use docker as container runtime, but only containerd.

I did not find a possibility to execute a command (as it is possible with docker) in a container as another user with containerd's ctr cli.

Is there a possibility?

-- buderu
containerd
docker
kubernetes
microk8s

1 Answer

1/7/2021

As noted in the comment:

@buderu I'm afraid this will not be possible with containerd's ctrl cli as per this documentation.

Citing above documentation:

Mapping from docker cli to crictl

The exact versions for below mapping table are for docker cli v1.40 and crictl v1.19.0.

docker clicrictlDescriptionUnsupported Features
attachattachAttach to a running container--detach-keys, --sig-proxy
execexecRun a command in a running container--privileged, --user, --detach-keys

A way to approach the problem would be the following: use crictl exec to run a UID-changing program which in turn runs the desired payload; for example, to run a login bash shell as user with UID 1000:

  • $ crictl exec -i -t gosu 1000 bash -l

A word about gosu. It's Go-based setuid+setgid+setgroups+exec program:

$ gosu
Usage: ./gosu user-spec command [args]
   eg: ./gosu tianon bash
       ./gosu nobody:root bash -c 'whoami && id'
       ./gosu 1000:1 id

./gosu version: 1.1 (go1.3.1 on linux/amd64; gc)

You can read more about it by following it's github page:

It's worth noting that the solution above won't work with a generic container.

User is required to install mentioned program by either:

  • Including the installation part in Dockerfile when creating container's image.
  • Downloading it into the container (provided that the container have the ability to download files with curl or wget):
    • $ crictl exec my-container wget -O /gosu https://github.com/tianon/gosu/releases/download/1.12/gosu-amd64
    • $ crictl exec -i -t my-container /gosu 1000 some-other-command

A side note!

Using second option (downloading straight into the container) required also to run:

  • $ chmod +x ./gosu

Additional notes to consider:

  • su and sudo are meant for a full-fledged UNIX system, and likely won't work unless PAM is installed and the user to switch to is listed in /etc/passwd

  • gosu and setpriv are much simpler and will basically only run Linux setuid() syscall and then execute the specified payload

  • gosu, being a Go program, can be easily compiled statically which simplifies deployment (just copy the binary in the container)

-- Dawid Kruk
Source: StackOverflow