Dockerfile Security Best Practices
Icarus, our honeypot, utilizes sandboxing via Docker for an extra layer of security. If an attacker compromises the machine, they only expose the limited container OS which is exactly what you want in a honeypot! Even though it’s a low interaction honeypot so hackers can't do much to it and sandboxing isn’t a primary feature, improvement is still possible.
This guide, Dockerfile Security Best Practices, was recently released and it should help me make some tweaks to the current setup to beef up the security. I use Docker with Icarus to increase my knowledge of it since I don’t have a lot of experience with it yet. Using the guide as a checklist, let’s see how I did with Icarus!
Do not store secrets in environment variables
Not only are there are no secrets in our honeypot, but I also don’t set environment variables in general. Setting environmental variables is not generally considered a problem, it’s more of an issue with readable secrets. Attackers can find those secrets so avoid this if you can.
Pass !
Only use trusted base images
I used FROM python:3.8-buster, an official image, to build Icarus. Though one could make the distinction that Official is not Trusted, for my purpose it certainly qualifies.
Python 3.9 has been released so once I have the chance to test Icarus against 3.9, it may be time to upgrade. The new changes look exciting but are not applicable to Icarus at the moment.
Pass !
Do not use ‘latest’ tag for base image
I pinned the base image to python 3.8. The article notes that running latest version will result in vulnerabilities. My biggest concern is function over security since python version changes can break programs.
Pass !
Avoid curl bashing
I don’t run anything from curl or wget and pipe it into bash since you don’t really know what could end up in that bash script. It is best to avoid this sort of behaviour in all scripts.
A Docker step, which I commented out, has git pulling the repo. It is unnecessary because you already have the repo. Though not as risky as piping to bash, it is not without risk for the same reasons. An attacker could compromise the git pull in much the same was as they compromise the curl.
Pass !
Do not upgrade your system packages
I used to break this rule all the time. It also balloons the size of docker images and adds to container startup time. The things at the top of your dockerfile should change least frequently. I adopted this approach a while back when I realized that the chain of images needing updates when upgrading packages sometimes breaks and makes it very difficult to find bugs.
Pass!
Do not use ADD if possible
This is like the curl/wget rule above.
Pass !
Do not sudo
I don’t need to run sudo because I violate the next rule. Applicable XKCD COMIC
Pass !
Do not root
I violate this rule. The well known reserved network ports (aka 1-1024) require root to operate so I never considered this an issue. Fortunately there are options to address this weakness including Docker port rebinding which is already happening so adjusting it is easy.
Fail !
Time for a fix
I have to move all ports between 1-1024 in the Docker instance above 1025 to fix my root problem. So port 22 becomes 2022 for example.
I then simply switch the port mapping
-p 21:2021/tcp
-p 22:2022/tcp
etc…
and add the following lines to the dockerfile to disable root:
RUN groupadd -r NOTROOT && useradd --no-log-init -r -g NOTROOT NOTROOT
RUN chown NOTROOT -R /icarus/
USER NOTROOT
The honeypot now runs as a limited user inside the guest OS.
Pass !