A tool that I think is rather under recognised is s2i. The basic idea is that you don’t put a Dockerfile into your source repo specifying the runtime to use you keep your app code bare (just code). The decision as to which security patched s2i image to compile and run the code with is a separate matter that is independent and can be centrally managed.
The way this is used in the OKD world is that a “BuildConfig” pulls your code from git to make an application image and is trigger by either a git webook or a docker registry push that updated the s2i image with a security patch.
In our case we have many node and php apps. To security patch either runtime we push the latest s2i image into our OKD docker registry and that causes all our application images to be recreated and redeployed.
Why I think that is of interest is that it basically says that what the code is, and how the code is run from a container security perspective, should not be conflated. They are two concerns that are not on the same cadence. A high impact vulnerability should be patched in the main test environment immediately and not be dependent on talking to several scrum teams about pushing a change to the Dockerfile in each team’s git repo.
When you have many apps or many small dev teams that separation to do “policy based security patching” of containers can be very useful. You can run s2i on your desktop or with container based SaaS ci tool such as circleci. It would be straightforward to run it in, say, Jenkins. That means you can have, say, dozens of micro service Jenkins deploy jobs triggered by git webook that run s2i and push the final image. You can then control the version of the s2i image you use in all the Jenkins jobs in one place. You can then script a security update that updates the s2i docker url to the latest security fix and triggers all Jenkins release jobs to run to apply the patched s2i to all microservices. No code or config needs to change in any git repo.
While I mention OKD by default it doesn’t let you run a container image as uid 0 (root). It uses a random uid and gid 0. This is for security in case the process gets out of its jail and tries to modify the host. Most public docker images just expect you run as root and file permission don’t let you run the app in the image as an arbitrary uid as docker —user ${rand_uid}:0
. You have to bake an image that gives gid 0 the file permissions to run the app. The s2i images all work under these circumstances.
If you need apps in docker to lookup the use details in /etc/passwd
when running as a random uid the you can fake that. Here is a script that runs git in docker as random uid where git wants to lookup the current in /etc/passwd
so the script fakes it.
The lesson here IMHO is that while in theory docker gives perfect isolation in practice all code is subject to security flaws. In theory many small dev teams will update all Dockerfiles immediately or very frequently but in practice dev teams are focused on features not long term security patching. (I work with one microservies platform that currently has >200 git repos and dev teams on three continents so coordinating anything is a challenge.) So security should be “defence in depth” and take concrete steps to do centralised patching of container images, not run containers as root, and use a random uid that isn’t in the host /etc/passwd
so cannot read or write outside of its jail.