Harden Docker Image And Move SQLite DB To External Volume
===========================================================
Description
The current Dockerfile
of our application writes an embedded SQLite database into the image filesystem and attempts to make that file writable at runtime by an unprivileged user. This violates container immutability principles and creates permission inconsistencies. To follow container best practices more strictly, we want to ensure the application image is fully immutable, allow SQLite to write to a mounted volume, isolate the writable /data
path for runtime use only, and drop root privileges before the application starts.
Proposed Solution
To achieve this, we will refactor the container architecture to:
- Ensure the built image is immutable and owned by root.
- Run the application as a non-root user (
express
). - Have the SQLite database reside in a writable volume (
sqlite3-data
). - Have the application read from an environment variable (
SQLITE_DATA_PATH
) to determine the path to the database.
Suggested Implementation
Refactor Dockerfile (Stage 2)
# Copy README and assets, often displayed in container registries such as Docker Hub or GHCR
COPY --chown=root:root --chmod=644 README.md ./
COPY --chown=root:root --chmod=755 assets/ ./assets/
# Install SQLite runtime libraries and create a system-like user for running the app
RUN apk add --no-cache sqlite-libs && \
adduser -D -g "" express
# Copy transpiled JavaScript, pruned node_modules, SQLite database and Swagger JSON, owned by express
COPY --from=builder --chown=root:root --chmod=755 /app/dist ./dist
COPY --from=builder --chown=root:root --chmod=755 /app/node_modules ./dist/node_modules
COPY --from=builder --chown=root:root --chmod=644 /app/dist/swagger.json ./dist/swagger.json
# Drop privileges: run as non-root user
USER express
Add Docker Volume
version: "3.8"
services:
express-app:
build:
context: .
dockerfile: Dockerfile
ports:
- "9000:9000"
environment:
- SQLITE_DATA_PATH=/data/players-sqlite3.db
volumes:
- sqlite3-data:/data
volumes:
sqlite3-data:
Acceptance Criteria
To ensure the proposed solution meets the requirements, we will verify the following:
- The Dockerfile is updated to make app code read-only and writable only at
/data
. - The SQLite DB is stored in a Docker-managed named volume (
sqlite3-data
). - The application reads the database path from
SQLITE_DATA_PATH
. - The application runs as a non-root user without permission issues.
- Local development and production both support volume mounting cleanly.
Benefits of the Proposed Solution
The proposed solution provides several benefits, including:
- Improved security: By storing the SQLite database in a writable volume, we ensure that the database is not stored in the image filesystem, which can be accessed by unauthorized users.
- Better container immutability: By making the image and owned by root, we ensure that the image is not modified during runtime, which can lead to permission inconsistencies.
- Simplified application development: By running the application as a non-root user, we simplify the development process and reduce the risk of permission issues.
- Improved scalability: By using a Docker-managed named volume, we can easily scale the application and ensure that the database is always available.
Conclusion
In conclusion, the proposed solution provides a more secure, scalable, and maintainable way to deploy the application. By refactoring the Dockerfile and using a Docker-managed named volume, we can ensure that the application meets the requirements of container best practices and provides a better user experience.
===========================================================
Q: What is the main issue with the current Dockerfile?
A: The current Dockerfile writes an embedded SQLite database into the image filesystem and attempts to make that file writable at runtime by an unprivileged user. This violates container immutability principles and creates permission inconsistencies.
Q: Why is it important to follow container best practices?
A: Following container best practices ensures that the application is secure, scalable, and maintainable. It also helps to prevent permission inconsistencies and ensures that the application can be easily scaled.
Q: What are the benefits of storing the SQLite database in a writable volume?
A: Storing the SQLite database in a writable volume provides several benefits, including improved security, better container immutability, simplified application development, and improved scalability.
Q: How does the proposed solution improve security?
A: The proposed solution improves security by storing the SQLite database in a writable volume, which ensures that the database is not stored in the image filesystem and can be accessed by unauthorized users.
Q: What is the role of the SQLITE_DATA_PATH
environment variable?
A: The SQLITE_DATA_PATH
environment variable is used to determine the path to the database. This allows the application to read the database path from the environment variable, rather than hardcoding it in the application code.
Q: How does the proposed solution simplify application development?
A: The proposed solution simplifies application development by running the application as a non-root user. This reduces the risk of permission issues and makes it easier to develop and test the application.
Q: What is the role of the Docker-managed named volume?
A: The Docker-managed named volume is used to store the SQLite database. This allows the database to be easily scaled and ensures that it is always available.
Q: How does the proposed solution improve scalability?
A: The proposed solution improves scalability by using a Docker-managed named volume to store the SQLite database. This allows the database to be easily scaled and ensures that it is always available.
Q: What are the acceptance criteria for the proposed solution?
A: The acceptance criteria for the proposed solution include:
- The Dockerfile is updated to make app code read-only and writable only at
/data
. - The SQLite DB is stored in a Docker-managed named volume (
sqlite3-data
). - The application reads the database path from
SQLITE_DATA_PATH
. - The application runs as a non-root user without permission issues.
- Local development and production both support volume mounting cleanly.
Q: What are the benefits of using a Docker-managed named volume?
A: The benefits of using a Docker-managed named volume include improved security, better container immutability, simplified application development, and improved scalability.
Q: How does the proposed solution improve container immutability?
A: The proposed solution improves container immutability by making the image and owned by root. This ensures that the image is not modified during runtime and reduces the risk permission inconsistencies.
Q: What is the role of the USER
instruction in the Dockerfile?
A: The USER
instruction in the Dockerfile is used to drop privileges and run the application as a non-root user. This reduces the risk of permission issues and makes it easier to develop and test the application.
Q: How does the proposed solution improve application development?
A: The proposed solution improves application development by running the application as a non-root user. This reduces the risk of permission issues and makes it easier to develop and test the application.
Q: What are the next steps after implementing the proposed solution?
A: After implementing the proposed solution, the next steps include testing the application to ensure that it meets the acceptance criteria and verifying that the application is secure, scalable, and maintainable.