VS Code’s Docker extension generates insecure and broken images
Visual Studio Code is a popular editor, and its Docker extension now supports generating
Dockerfiles for Flask and Django.
This sounds quite convenient: you don’t have to write your own, your editor will do it for you.
But while the extension claims it “makes it easy to build, manage, and deploy containerized applications,” you don’t actually want to deploy the images it generates.
That’s because the
Dockerfiles it creates are insecure and operationally broken.
Update: The VS Code team has started fixing this; the latest release (1.1) fixes one of the issues (running as root). They don’t seem to think installing security updates is worthwhile, though.
The nature of the problem: a management failure
Before I show you how these Docker images are insecure, it’s worth explaining who is at fault, and why this is such a problem.
Dockerfiles are perfectly fine for local development, and so I don’t feel the developers who implemented this feature are particularly to blame.
Yes, there are some mistakes in the implementation, but we all make mistakes—I’ve made plenty.
The issues are the marketing—on the extension page, for example—that says you can “deploy” these images, and the corresponding management failure to ensure this promise is followed up on:
- If you’re a product manager talking about “deployment”, you need to make sure security, and to a lesser extent operational correctness, are part of the requirements.
- If you’re an engineering manager and someone is going to deploy code based on your product, you should do at least a little research about security best practices.
Now, I could have just quietly filed a GitHub issue, as I’ve done in the past for other projects, and not turned this into a blog post.
But Visual Studio Code is a major product with a huge number of users; Microsoft is pouring money into this editor and then giving it away for free. As of March 2020:
- The Visual Studio Code Python extension has an install count of 17.5 million.
- The Docker extension has an install count of 4 million.
- And as an example of marketing reach, the Visual Studio Code Twitter account has 265 thousand followers.
With that scale of impact, it’s critical that Visual Studio Code management ensure that tools that promise to make deployable applications actually implement minimal security. And that is not happening.
Let’s see what’s wrong with
Dockerfile that the Docker extension generates:
# For more information, please refer to https://aka.ms/vscode-docker-python FROM python:3.8 EXPOSE 5000 # Keeps Python from generating .pyc files in the container ENV PYTHONDONTWRITEBYTECODE 1 # Turns off buffering for easier container logging ENV PYTHONUNBUFFERED 1 # Install pip requirements ADD requirements.txt . RUN python -m pip install -r requirements.txt WORKDIR /app ADD . /app # During debugging, this entry point will be overridden. For more information, refer to https://aka.ms/vscode-docker-python-debug CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
How is this insecure?
Problem #1: The container runs as root
Running as root opens you up to a whole slew of potential attack vectors. Docker containers should therefore run as a non-root user.
Problem #2: The base packages aren’t getting security updates
As of March 2020, the
python:3.8 image is based off of Debian’s Buster release.
Much of the time the system packages provided by the Docker images are up-to-date with the latest security fixes, but not always—there’s sometimes a window of a few days where Debian has released a new package but the Docker image hasn’t been updated.
curl had a security fix released to the Debian package repositories on Feb 22, 2020 (changelog), but the Debian and Python Docker images were only updated and rebuilt on Feb 25 (commit history).
That means you need to update the system packages when you rebuild the image.
In this case, you would do so by adding this to the top of the
RUN apt-get update && apt-get -y upgrade
A bad Gunicorn configuration
While less of a concern than security, the minimal configuration provided by the
Dockerfile isn’t ideal in other ways.
For Django and Flask, the Docker images generated by the Visual Studio Code Docker extension use Gunicorn. Unfortunately, Gunicorn’s default configuration can make the server freeze for seconds at a time when it’s run in Docker.
If you’re going to use Gunicorn with Docker, you need to configure it appropriately.
Now, to be fair, the Gunicorn issue is somewhat unexpected; it is surprising that Gunicorn doesn’t just do the right thing by default.
But security should be a minimal checklist item if you’re telling people they can deploy their application with your software. Visual Studio Code should do better.
The concise and pragmatic guide to Docker packaging for production
Docker packaging for production is complicated, with as many as 70+ best practices to get right. And you want small images, fast builds, and your Python application running securely.
Take the fast path to learning best practices, by using the Python on Docker Production Handbook.
Learn practical Python software engineering skills you can use at your job
Too much to learn? Don't know where to start?
Sign up for my newsletter, and join over 4900 Python developers and data scientists learning practical tools and techniques, from Docker packaging to testing to Python best practices, with a free new article in your inbox every week.