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.

The generated 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.

Insecure images

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. For example, 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 Dockerfile:

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.

Preventable problems

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.