If you are not familiar with Distroless, its container image built by google which is basically docker image minus operating system. Sounds interesting, right? We have been building our docker image using common base images like: ubuntu, alpine, debian which has lots of OS packages and libraries that might not be required for our application. As docker is preferred for its simplicity and with preference to running application only but the packages which remain untouched while running our application code could be security hole.
What you can’t expect from Distroless
docker exec(run) -it --name mydocker ...
If its end of world when you can’t use this command, then you are not using docker in right way. Yes, it might(or not)be needed while building base image and for rare debugging but the habit is not good. If you enter into docker container in live system or in Kubernetes, then its against the nature :)
docker run -it gcr.io/distroless/base /bin/sh
docker: Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"/bin/sh\": stat /bin/sh: no such file or directory": unknown.
It might not be Perfect for Smaller Size
I have been using alpine linux as base image which is just about 4MB. Few blog posts claimed its smallest docker image, then with more curiosity, I first pulled the base image
docker pull gcr.io/distroless/base
The size is 16.6 MB
Likewise, nodejs Distroless image
gcr.io/distroless/nodejs is 75.1MB whereas nodejs alpine image is 68MB. Yes, its smaller than standard nodejs or python images but alpine defeats.
So, if you are choosing just for image size I cannot proudly say this is best one.
Few points that could make arguments or we can adopt Distroless in trade of image size:
- Less attack surface: By avoiding unnecessary stuffs on the packaged docker images, the doors for any kind of attack from inside or outside is reduced. Distroless has no package manager like apk tools in alpine, apt in ubuntu. In case, attacker want to change a live container installing packages, there’s no chance.
- Avoid Image Vulnerabilities: Using general OS specific docker images, they need to be updated in case of any vulnerabilities or apply security patches. Also, packages and libraries vulnerability can be avoided to greater extent.
- Confirms Immutability: Immutability should be in the heart while running docker container. Even if by chance you are doing manual operation inside docker, the was needs to be left instantly.
- Secure Secret Variables: We basically use file based secrets or environment variables. If someone by some way
execinto docker container, the secret is clearly exposed but as Distroless doesn’t have shell access.
- Secure Network Connection/Service Call: We could have services running in docker which are not exposed to external world but visible to internal network for eg. by using service name in Kubernetes. In case of any unprivileged access, the service call can be easily made from one container to other in the network. Also, for security purpose, we limit database access from inside the container in network which becomes useless if someone gets shell access. Restricting shell access stops this kind of attack surfaces by Distroless.
If you are interested in trying out Distroless, its available on base image, for java and glibc runtime. Experimental images for nodejs, python2.7 & 3, dotnet are also available. Its really worth a try at least !!
A simple example for GoLang using base image:
If you have any points to or not to use Distroless, feel free to drop in comment.