How to prevent root of the host OS from accessing content inside a container? - docker

We are new to container technology and are currently evaluating whether it can be used in our new project. One of our key requirements is data security of multi-tenants. i.e. each container contains data that is owned by a particular tenant only. Even we, the server admin of the host servers, should NOT be able to access the content inside a container.
By some googling, we know that root of the host OS can execute command inside a container, for example, by the "docker execute" command. I suppose the command is executed with root privileges?
How to get into a docker container?
We wonder if such kinds of access (not just "docker execute", but also any method to access a container's content by server admin of the host servers) can be blocked/disabled by some security configurations?

For the bash command specifically,
Add the exit command in the end of the .bashrc file. So the user logs in and finally gets kicked out.
You can go through this link for the better understanding of why it is not implemented by default
https://github.com/moby/moby/issues/8664

Related

VS Code log into container as specific user

I built a Debian 10 sandbox container where I could play with my code bases. I added a user to maintain a permission wall between sudo commands typed too quickly with
USER ELDUDE
in the Dockerfile. However, when I build the container with that user as default login option VS Code fails to connect to the container with
Error: stream ended with:124 but wanted 1128865906
This is the initial error that brought me down this path.
If I do not specify the default user in the Dockerfile I can connect fine but VSCode server in the container runs as root. Now, that becomes a mess with file permissions etc if I start working on stuff.
Any idea what is going on? Can I set user names when I log into a container?
I also thought of enabling SSH on the container and connect through VS SSH but that failed thus far...

Process can write to docker volume on Windows not on Ubuntu

I have an image based on opencpu/base. It starts an apache based server, and then invokes R scripts everytime sombody calls an API endpoint.
One of those scripts tries to write a file to a location in the container. When I mount a folder into that location, it works on my Windows machine, but not on Ubuntu.
I've tried using named volumes on Ubuntu, but it does not work either. When I run bash inside the container interactively on Ubuntu, I can write and read the mounted volume just fine. But the apache process cannot.
Does anybody have some hints what could be going on here?
When you log in interactively to the container, you will have root permissions.
Apache usually runs as another user (www-data), and that user must have read permissions on the folder that you want it to read.
Make sure that the permissions of the folder matches the user that will read it.

How creating a non root user by simply setting up a random UID in a container FROM scratch works?

I'm setting up a Golang server with Docker and I want an unprivileged user to launch it inside its container for safety.
Here is the simple Dockerfile I use. I import my binary in the container and set a random UID.
FROM scratch
WORKDIR /app
COPY --chown=1001:1001 my-app-binary my-app-binary
USER 1001
CMD ["/app/my-app-binary"]
If my server listens to port 443, It doesn't work since it requires privileged rights. So my app is running by an unprivileged user as intended.
Nonetheless User 1001 was not properly created. The tutorials I saw tell me to create the user in an intermediate 'builder' container (alpine for instance) and import /etc/passwd from it. I didn't find any example doing what I do. (here one tutorial I followed)
Can someone explains to me why my solution works or what I didn't understand?
DISCLOSURE: In my answer I've used quotes from this blog post. I'm neither the author of this post nor in any way related to the author.
It's expected - containers can run under a user that is not known to the container. Quoting docker run docs:
root (id = 0) is the default user within a container. The image developer can create additional users. Those users are accessible by name. When passing a numeric ID, the user does not have to exist in the container.
-- https://docs.docker.com/engine/reference/#user
It helps you resolve issues like this:
Sometimes, when we run builds in Docker containers, the build creates files in a folder that’s mounted into the container from the host (e.g. the source code directory). This can cause us pain, because those files will be owned by the root user. When an ordinary user tries to clean those files up when preparing for the next build (for example by using git clean), they get an error and our build fails.
-- https://medium.com/redbubble/running-a-docker-container-as-a-non-root-user-7d2e00f8ee15#7d3a
And it's possible because:
Fortunately, docker run gives us a way to do this: the --user parameter. We're going to use it to specify the user ID (UID) and group ID (GID) that Docker should use. This works because Docker containers all share the same kernel, and therefore the same list of UIDs and GIDs, even if the associated usernames are not known to the containers (more on that later).
-- https://medium.com/redbubble/running-a-docker-container-as-a-non-root-user-7d2e00f8ee15#b430
The above applies to USER dockerfile command as well.
Using a UID not known to the container has some gotchas:
Your user will be $HOME-less
What we’re actually doing here is asking our Docker container to do things using the ID of a user it knows nothing about, and that creates some complications. Namely, it means that the user is missing some of the things we’ve learned to simply expect users to have — things like a home directory. This can be troublesome, because it means that all the things that live in $HOME — temporary files, application settings, package caches — now have nowhere to live. The containerised process just has no way to know where to put them.
This can impact us when we’re trying to do user-specific things. We found that it caused problems using gem install (though using Bundler is OK), or running code that relies on ENV['HOME']. So it may mean that you need to make some adjustments if you do either of those things.
Your user will be nameless, too
It also turns out that we can’t easily share usernames between a Docker host and its containers. That’s why we can’t just use docker run --user=$(whoami) — the container doesn't know about your username. It can only find out about your user by its UID.
That means that when you run whoami inside your container, you'll get a result like I have no name!. That's entertaining, but if your code relies on knowing your username, you might get some confusing results.
-- https://medium.com/redbubble/running-a-docker-container-as-a-non-root-user-7d2e00f8ee15#e295

Preventing USER root in Dockerfile (or at least being able to spot it)

We want to provide a base image (base OS + Java JRE) to developers. Since this is for a paranoid organization we want to make sure that the container will always run with the application id (a.k.a. "app"). Putting a USER app at the end of the Dockerfile for the base image is not enough since a Dockerfile for a derived image can use USER root. Is there either:
a way to prevent using the USER root in derived images, or, failing this
a watertight way to check an image for this (is searching the history for USER [root] statements enough? Or could this be concealed in some way (multistage-image...)).
If you give users access to the Docker API without additional measures, such as "authorization" ("authz") plugins, those users effectively have root permissions on the host where the Docker daemon runs; https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface.
You can configure the daemon to use user namespaces; https://docs.docker.com/engine/security/userns-remap/. When using user-namespaces, users inside the container are "remapped" to unprivileged users on the host, so root inside a container is a non-privileged user outside of the container.
There are limitations when running with user-namespaces enabled, for example, when bind mounting directories from the host, the container's process may not be able to access/write to those files (depending on configuration); this is by design, and part of the protection that user-namespaces provide, but may be an issue, depending on your situation.

Docker containers with multiple log sources

Say I have a container that has everything I need to run my web application (such as https://github.com/grigio/docker-stringer for example). How would I go about inspecting the logs for the different services (web server, application server, database server)? With all of the tutorials so far I have only been able to view the logs for the specific command run when starting the container.
One method would be to configure your logs to write to stdout and to use docker logs to retrieve them.
Another option would be to use a bindmount and link to your host file system.

Resources