Add the Loki query UI, access policies, ingress insights, alert and registry settings, and their backend APIs. Include the related Kubernetes deployment and collector updates required by the integrated application. Validated with go test ./..., npm run build, and npm run lint.
125 lines
4.4 KiB
Docker
125 lines
4.4 KiB
Docker
# ============================================================
|
|
# opsx-loki - Secure Multi-Stage Dockerfile
|
|
# ============================================================
|
|
# P0 Fixes:
|
|
# - Non-root user (opsxloki: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
|
|
COPY backend/ ./
|
|
RUN CGO_ENABLED=0 GOOS=linux go build \
|
|
-a -installsuffix cgo \
|
|
-ldflags="-s -w -extldflags '-static'" \
|
|
-o bin/opsxloki .
|
|
|
|
# ---------------------------------------------------------------
|
|
# 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 opsxloki && \
|
|
adduser -u 1000 -G opsxloki -s /bin/sh -D opsxloki
|
|
|
|
# ---------------------------------------------------------------
|
|
# Working directory with proper ownership
|
|
# ---------------------------------------------------------------
|
|
WORKDIR /app
|
|
RUN chown opsxloki:opsxloki /app
|
|
|
|
# ---- Copy application files with correct ownership (P1) ----
|
|
COPY --from=frontend-builder --chown=opsxloki:opsxloki /app/frontend/dist ./dist
|
|
COPY --from=backend-builder --chown=opsxloki:opsxloki /app/backend/bin/opsxloki ./opsxloki
|
|
|
|
# Create data directory with non-root ownership
|
|
RUN mkdir -p /app/data && chown -R opsxloki:opsxloki /app/data
|
|
|
|
# Create .kube directory for non-root user (P0: not /root/.kube)
|
|
RUN mkdir -p /home/opsxloki/.kube && \
|
|
chown -R opsxloki:opsxloki /home/opsxloki && \
|
|
chmod 700 /home/opsxloki/.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/opsxloki/.kube/config
|
|
ENV HOME=/home/opsxloki
|
|
|
|
# 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=opsxloki:opsxloki 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 opsxloki
|
|
|
|
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
|
CMD ["./opsxloki"]
|