Docker Node Workflow

Workflow for secure Node development with Docker.

Ever worried about the security of the npm ecosystem? The danger is real.

A dependency you install from npm may contain malicious code that can run with your application. When you run your app locally with node, that code may have full access to your local environment variables, filesystem, etc.

This is known in software security as a supply chain attack — because it’s a vulnerability in your application’s dependencies.

Even just installing a script via npm can have dangerous side effects. Straight from the horse’s mouth (source):

it is possible for a maliciously-written npm package, when installed, to execute a script.

Things are even more dangerous with the prevalence of npx, which encourages immediate execution of unknown code on your local machine.

Solution

We can use docker to install dependencies and run our app locally. You can mount your local working directory so that’s all your app has access to when run.

This would look something like:

$ docker run -it --rm --mount src="$(pwd)",target=/app,type=bind -w /app node index.js

Here’s a set of shell functions that can ease this:

function docker-here() {
  docker run --interactive --tty --rm --mount src="$(pwd)",target=/app,type=bind --workdir /app $@
}

function docker-node() {
  docker-here node $@
}

function docker-npx() {
  docker-here node npx $@
}

Now you can run simply with:

$ docker-node index.js

Or if you need to set any environment variables, or expose a port, or other docker options, you can use:

$ docker-here -e DEBUG=* -p 8080:8080 node index.js

What if you need dependencies, but you’d like to only install within the container?

Create a Dockerfile:

FROM node
WORKDIR /app
COPY package.json .
RUN npm install
RUN mv node_modules /
COPY . .
RUN npm run build || true
CMD node .

Then build it:

$ docker build .
Successfully built ea7f8be6d66

Then run it:

$ docker run -it f0a0eabe6d66 node index.js

I’ve built a script called docked-node that encapsulates the Docker setup, so all you have to do is run your script:

$ docked-node index.js

Voila!