Skip to main content

Excessive Privileges - Docker

Need

Enforce proper privilege separation in Docker containers

Context

  • Usage of Node.js 20 for server-side JavaScript development

Description

Non compliant code

FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD [ "node", "app.js" ]

The Dockerfile above is used to create a Node.js application running on Docker. Dockerfile instructions are executed in order. Here is a breakdown of what each line does:

  1. FROM node:20: This line is pulling the base image for Node.js version 20.
  2. WORKDIR /app: This sets the working directory in the container to /app.
  3. COPY package*.json ./: This line is copying the package.json and package-lock.json (if available) to the working directory in the container.
  4. RUN npm install: This installs the dependencies defined in package.json.
  5. COPY . .: This copies the rest of the application to the working directory in the container.
  6. EXPOSE 8080: This informs Docker that the container listens on the specified network ports at runtime. Here it is set to 8080.
  7. CMD [ "node", "app.js" ]: This provides defaults for an executing container which includes an executable, or if an entry point is not specified, to run an application when the container is run.

The vulnerability in this Dockerfile is that it runs the application as root in the Docker container. This is a security risk because if an attacker gains control of the container, they could gain root access to the host machine. This is an example of the excessive privileges vulnerability.

Steps

    1. Create a custom user in the Dockerfile.
    1. Use the custom user instead of the root user to execute instructions inside the container.
    1. Restrict the privileges of the custom user to minimize potential risks.
    1. Update the Dockerfile to set the custom user as the default user.
    1. Rebuild the Docker image with the updated Dockerfile.
    1. Test the application to ensure it functions correctly with the custom user.

Compliant code

# Use an official Node runtime as a parent image with digest
FROM node@sha256:c2ed73be34c27a42bd202021c7fdf1a92999fb171f2e1d54bd4b461d9344eeb2

# Create app directory
WORKDIR /app

# Install app dependencies
COPY package*.json ./

# Create a user named "appuser"
RUN groupadd -r appuser &&\
useradd -r -g appuser -d /app -s /sbin/nologin -c "Docker image user" appuser &&\
chown -R appuser:appuser /app &&\
npm install

# Bundle app source
COPY . .

# Change to non-root user
USER appuser

# Expose port and start application
EXPOSE 8080
CMD [ "node", "app.js" ]

The Dockerfile has been updated to fix the excessive privileges vulnerability. A new user named "appuser" has been created and is used to run the application instead of the root user. This restricts the privileges of the application and minimizes potential risks.

The Docker image is also now referenced by its digest, ensuring that the same image is always used, increasing the reproducibility of the build.

The application's dependencies are installed and the application source is bundled while the root user is active, then the user is switched to "appuser" before the application is started. This ensures that the application runs with restricted privileges.

The Dockerfile now needs to be used to build a new Docker image, and the application should be tested to ensure it still functions correctly with the "appuser".

References