Search code examples
dockerkubernetesmicrok8scontainerd

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


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?


Solution

  • 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 cli crictl Description Unsupported Features
    attach attach Attach to a running container --detach-keys, --sig-proxy
    exec exec Run 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)