-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathDockerfile.mcp
More file actions
139 lines (121 loc) · 5.56 KB
/
Dockerfile.mcp
File metadata and controls
139 lines (121 loc) · 5.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# =============================================================================
# CyberChef MCP Server - Hardened Docker Image
# =============================================================================
# Security Features:
# - Distroless Chainguard base image (zero CVEs, minimal attack surface)
# - Multi-stage build (dev for building, distroless for runtime)
# - Non-root user execution (UID 65532 'nonroot')
# - Read-only filesystem compatible
# - No shell, package manager, or unnecessary tools in runtime
# - Wolfi-based OS with daily security updates
# - SLSA Build Level 3 provenance
#
# Base Image: Chainguard Node.js (cgr.dev/chainguard/node)
# - Zero known CVEs (as of build time)
# - 70% smaller layer data vs traditional images
# - 7-day SLA for critical CVE patches
# - FIPS-validated cryptography available
#
# Alternative: Docker Hardened Images (DHI) for Node.js 22 are available via
# Docker Hub subscription for enterprise deployments requiring Docker-native
# hardening. See: https://docs.docker.com/dhi/about/what/
#
# References:
# - Chainguard Images: https://edu.chainguard.dev/chainguard/chainguard-images/
# - Node.js Migration: https://edu.chainguard.dev/chainguard/migration/migrating-node/
# =============================================================================
# -----------------------------------------------------------------------------
# Stage 1: Build Stage (using -dev variant with shell and build tools)
# -----------------------------------------------------------------------------
FROM cgr.dev/chainguard/node:latest-dev AS builder
# Run as root for build operations (Chainguard -dev includes root user)
USER root
WORKDIR /app
# Copy package files first for better layer caching
COPY package.json package-lock.json ./
# Install dependencies without running postinstall (which needs Gruntfile)
# Using --ignore-scripts to prevent arbitrary code execution during install
RUN npm ci --ignore-scripts
# Copy all source files
COPY . .
# Apply patches for Node 22 compatibility (SlowBuffer deprecation)
# These packages use the deprecated SlowBuffer which was removed/changed in newer Node versions
RUN sed -i 's/new SlowBuffer/Buffer.alloc/g' node_modules/avsc/lib/types.js && \
sed -i 's/SlowBuffer/Buffer/g' node_modules/buffer-equal-constant-time/index.js
# Run postinstall scripts (fixes imports etc. defined in package.json)
RUN npm run postinstall
# Generate CyberChef configuration and Node index
RUN npx grunt configTests
# Remove unnecessary files to reduce final image size and eliminate dev-time vulnerabilities
RUN rm -rf \
.git \
.github \
tests \
docs \
*.md \
Gruntfile.js \
babel.config.js \
eslint.config.mjs \
nightwatch.conf.cjs \
webpack.config.js \
.eslintrc.json \
.babelrc \
node_modules/@esbuild \
node_modules/esbuild \
node_modules/webpack \
node_modules/babel-loader \
node_modules/grunt* \
node_modules/nightwatch \
node_modules/selenium-webdriver \
node_modules/eslint* 2>/dev/null || true
# -----------------------------------------------------------------------------
# Stage 2: Runtime Stage (distroless, minimal attack surface)
# -----------------------------------------------------------------------------
FROM cgr.dev/chainguard/node:latest
# Security: Add metadata labels
LABEL org.opencontainers.image.title="CyberChef MCP Server" \
org.opencontainers.image.description="MCP server exposing 300+ CyberChef operations as AI tools" \
org.opencontainers.image.vendor="DoubleGate" \
org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.source="https://github.com/doublegate/CyberChef-MCP" \
org.opencontainers.image.documentation="https://github.com/doublegate/CyberChef-MCP/blob/master/docs/user_guide.md"
WORKDIR /app
# Copy built application from builder stage
# Chainguard's nonroot user (UID 65532) owns the files
COPY --from=builder --chown=65532:65532 /app /app
# Security: Set TMPDIR to use /tmp (writable via tmpfs in read-only mode)
ENV TMPDIR=/tmp
# Health check for container orchestration
# Note: MCP servers use stdio, so we check if node is responsive
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD node -e "process.exit(0)" || exit 1
# =============================================================================
# Read-Only Filesystem Usage (Security Hardening)
# =============================================================================
# This image is compatible with Docker's read-only filesystem mode for enhanced
# security. To run with a read-only root filesystem:
#
# docker run -i --rm --read-only \
# --tmpfs /tmp:rw,noexec,nosuid,size=100m \
# ghcr.io/doublegate/cyberchef-mcp_v1:latest
#
# The tmpfs mount provides writable space for:
# - Temporary files from compression operations (Gzip, Bzip2, etc.)
# - Node.js runtime temporary files
# - Operation intermediate results
#
# tmpfs flags:
# - rw: Read-write (required for temp files)
# - noexec: Prevent execution of files in /tmp (security)
# - nosuid: Ignore setuid/setgid bits (security)
# - size=100m: Limit tmpfs to 100MB (adjust based on operation needs)
#
# Benefits of read-only mode:
# - Prevents container compromise from modifying system files
# - Ensures container immutability
# - Meets compliance requirements (PCI-DSS, SOC 2, FedRAMP)
# - Reduces attack surface for container escape vulnerabilities
# =============================================================================
# Run the MCP server
# Note: Chainguard distroless has "node" as ENTRYPOINT, so CMD is just the script path
CMD ["src/node/mcp-server.mjs"]