# ============================================================ # lokistack - Secure Multi-Stage Dockerfile # ============================================================ # P0 Fixes: # - Non-root user (lokistack:1000) # - No hardcoded JWT_SECRET (validated at runtime) # - HEALTHCHECK instruction added # - Binary installation verification # P1 Fixes: # - Supply chain risk reduction (--ignore-scripts where applicable) # - File ownership with --chown # - Security environment variables # ============================================================ # --------------------------------------------------------------- # Stage 1: Frontend Builder (Node.js) # --------------------------------------------------------------- FROM node:20-alpine AS frontend-builder WORKDIR /app/frontend # Install dependencies separately to leverage layer caching COPY frontend/package*.json ./ # Use --ignore-scripts to reduce supply chain attack surface RUN npm ci --ignore-scripts && \ npm cache clean --force # Copy source and build COPY frontend/ ./ RUN npm run build # --------------------------------------------------------------- # Stage 2: Backend Builder (Go) # --------------------------------------------------------------- FROM golang:1.24-alpine AS backend-builder RUN apk add --no-cache git ca-certificates tzdata ENV GOTOOLCHAIN=local WORKDIR /app/backend # Download dependencies (cached layer) COPY backend/go.* ./ RUN go mod download # Copy source and build static binary # -trimpath:抹掉源码绝对路径(否则二进制里能 strings 出 /app/backend/controllers/*.go 共 66 处) COPY backend/ ./ RUN CGO_ENABLED=0 GOOS=linux go build \ -trimpath \ -a -installsuffix cgo \ -ldflags="-s -w -X main.version=${APP_VERSION:-docker} -extldflags '-static'" \ -o bin/lokistack . # --------------------------------------------------------------- # Stage 3: Final Runtime Image # --------------------------------------------------------------- FROM alpine:3.20 # Install runtime dependencies: # ca-certificates: HTTPS TLS verification # openssh-client: SSH key auth for host deployment # bash: Entrypoint script support # wget: HEALTHCHECK (lighter than curl) RUN apk --no-cache add \ ca-certificates \ openssh-client \ bash \ wget # --------------------------------------------------------------- # P0: Create non-root user and group # --------------------------------------------------------------- RUN addgroup -g 1000 lokistack && \ adduser -u 1000 -G lokistack -s /bin/sh -D lokistack # --------------------------------------------------------------- # Working directory with proper ownership # --------------------------------------------------------------- WORKDIR /app RUN chown lokistack:lokistack /app # ---- Copy application files with correct ownership (P1) ---- COPY --from=frontend-builder --chown=lokistack:lokistack /app/frontend/dist ./dist COPY --from=backend-builder --chown=lokistack:lokistack /app/backend/bin/lokistack ./lokistack # Create data directory with non-root ownership RUN mkdir -p /app/data && chown -R lokistack:lokistack /app/data # Create .kube directory for non-root user (P0: not /root/.kube) RUN mkdir -p /home/lokistack/.kube && \ chown -R lokistack:lokistack /home/lokistack && \ chmod 700 /home/lokistack/.kube # ---- Security hardening: remove unnecessary tools ---- RUN rm -rf /tmp/* /var/cache/apk/* # --------------------------------------------------------------- # Security environment variables # --------------------------------------------------------------- ENV DATA_DIR=/app/data ENV SERVER_PORT=8080 ENV KUBECONFIG=/home/lokistack/.kube/config ENV HOME=/home/lokistack # NOTE: JWT_SECRET and ENCRYPTION_KEY are NOT set here. # They MUST be provided at runtime via docker-compose env or secrets. # The entrypoint script will enforce this requirement. # ---- Copy and configure entrypoint script ---- COPY --chown=lokistack:lokistack docker-entrypoint.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/docker-entrypoint.sh EXPOSE 8080 # --------------------------------------------------------------- # P0: HEALTHCHECK - verifies static file serving (no auth needed) # --------------------------------------------------------------- HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \ CMD wget --no-verbose --tries=1 --spider \ http://localhost:${SERVER_PORT}/index.html || exit 1 # --------------------------------------------------------------- # P0: Switch to non-root user # --------------------------------------------------------------- USER lokistack ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] CMD ["./lokistack"]