The following cheatsheet is meant to show how to use Docker to sandbox untrusted code. The goal is to minimize the damage that could be made by malicius code downloaded from untrusted source.
Running a code this way allows to:
- prevent code from accessing the rest of the filesystem
- easily revert all changes
- run a code with near native performance
- control network access
- run processes as superuser without giving them controll of entire device
The main downside of using Docker is that it shares the same kernel as the host, which means that vulnerabilities of host’s kernel could be used to escape from container. There are other ways to sandbox code like virtualization, AppArmor, firejail.
Run a command in a disposible container Link to heading
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
Example for python:
docker run -it --rm --name my-running-script -v "$PWD":/usr/src/myapp -w /usr/src/myapp python:3 python script.py
It crates python3 container, runs a
python script.py command and removes it as soon as script finishes execution.
-itruns a command with interactive shell. Allows you to provide input
--rmremoves container as soon as it finishes executing
-v "$PWD":/usr/src/myapppoints your current directory (on host machine) to path
/usr/src/myappinside a container
-wsets working directory to
python:3is a base docker image, on which we are running our command
python script.pyis a command we want to run inside a container
Effect (only seen when container is still running):
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3dc148f99f74 python:3 "python script.py" 5 seconds ago Up 4 seconds my-running-script
For multiple commands (runs
sh command which then executes chain of commands)
docker run -it --rm --name my-running-script -v "$PWD":/usr/src/myapp -w /usr/src/myapp python:3 sh -c "python script.py && echo test"
Accessing running container’s filesystem Link to heading
If container is still running (
docker ps -a returns status “Up”):
$ docker exec -it b325ffe9fe18 /bin/bash
b325ffe9fe18 is a container id.
Accessing closed container’s filesystem Link to heading
If status of container is “Exited” we cannot enter shell in it. But if we still want to inspect files, processes and make use of stuff in it, we can make snapshot of it and run it independently.
Assuming we create non-disposable container like this:
docker run -it --name my-running-script -v "$PWD":/usr/src/myapp -w /usr/src/myapp python:3 python script.py
docker ps -a command returns:
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 69b5fe1b8934 python:3 "python script.py" 5 seconds ago Exited (0) 4 seconds ago my-running-script
Commit the stopped container:
docker commit 69b5fe1b8934 image_name_of_snapshot
image_name_of_snapshot is a name for newly created image.
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE image_name_of_snapshot latest 692b940a0f2a 45 seconds ago 920MB
Then to enter shell:
docker run -it --rm --entrypoint /bin/bash image_name_of_snapshot
More complex scenarios Link to heading
FROM python:3 WORKDIR /usr/src/app COPY script.py . CMD [ "python", "./script.py" ]
docker build -t test_base_image . --load
Then run and log in to shell:
docker run -it --entrypoint /bin/bash test_base_image