From 6382392f7350a7e1ea0f2345fa78e025bdf2772e Mon Sep 17 00:00:00 2001 From: Michael Guarino Date: Tue, 22 Sep 2026 18:44:36 +0000 Subject: [PATCH] chore(security): harden service Dockerfiles --- dockerfiles/Dockerfile.softserve | 27 +++++++------------ dockerfiles/Dockerfile.test | 2 +- go/cloud-query/Dockerfile | 7 +++-- go/demo/flaky-service/Dockerfile | 13 ++++++--- go/demo/flaky-service/Dockerfile.sidecar | 14 +++++++--- go/deployment-operator/Dockerfile | 3 +++ go/kubernetes-agent/api/Dockerfile | 4 +++ go/kubernetes-agent/hack/docker/Dockerfile | 5 ++++ .../hack/docker/Dockerfile.agentk | 5 ++++ js/console/Dockerfile | 7 +++++ js/documentation/Dockerfile | 8 ++++++ 11 files changed, 68 insertions(+), 27 deletions(-) diff --git a/dockerfiles/Dockerfile.softserve b/dockerfiles/Dockerfile.softserve index 84fe323c59..c151177ca7 100644 --- a/dockerfiles/Dockerfile.softserve +++ b/dockerfiles/Dockerfile.softserve @@ -11,20 +11,13 @@ EXPOSE 23232 EXPOSE 23233 EXPOSE 9418 -# basics, in case need to access shell to debug/troubleshoot -RUN apk update --no-cache # Upgrade OpenSSL packages to fix CVE-2025-1670 (NULL pointer dereference in CMS EnvelopedData processing) # and QUIC PATH_CHALLENGE DoS vulnerability -RUN apk add --no-cache "libssl3>=3.5.7-r0" "libcrypto3>=3.5.7-r0" -# Upgrade libexpat to fix authorization bypass vulnerability allowing arbitrary SQL execution -RUN apk upgrade --no-cache libexpat -# Upgrade zlib to fix buffer overflow vulnerability in untgz utility (CVE in zlib <= 1.3.1) -RUN apk upgrade --no-cache zlib -# Keep curl at or above the latest version available in Alpine 3.24. -RUN apk add --no-cache sudo git vim "curl>=8.21.0-r0" - -# create keys -RUN apk add --no-cache openssh-client +# Upgrade libexpat and zlib for their security fixes, then install build utilities. +RUN apk update --no-cache && \ + apk upgrade --no-cache libexpat zlib && \ + apk add --no-cache "libssl3>=3.5.7-r0" "libcrypto3>=3.5.7-r0" \ + sudo git vim "curl>=8.21.0-r0" openssh-client # soft-serve install # Reason that we manually install soft-serve instead of using the soft-serve docker image is that @@ -50,14 +43,12 @@ EXPOSE 23232 EXPOSE 23233 EXPOSE 9418 -# needs git for repos to be accessible -RUN apk update --no-cache # Upgrade OpenSSL packages to fix CVE-2025-1670 (NULL pointer dereference in CMS EnvelopedData processing) # and QUIC PATH_CHALLENGE DoS vulnerability -RUN apk add --no-cache "libssl3>=3.5.7-r0" "libcrypto3>=3.5.7-r0" -# Upgrade libexpat to fix authorization bypass vulnerability allowing arbitrary SQL execution -RUN apk upgrade --no-cache libexpat musl musl-utils zlib -RUN apk add --no-cache git +# Upgrade libexpat, musl, and zlib before installing git for repository access. +RUN apk update --no-cache && \ + apk upgrade --no-cache libexpat musl musl-utils zlib && \ + apk add --no-cache "libssl3>=3.5.7-r0" "libcrypto3>=3.5.7-r0" git COPY --from=builder /usr/bin/soft /usr/bin/ COPY --from=builder /go/data /data diff --git a/dockerfiles/Dockerfile.test b/dockerfiles/Dockerfile.test index 9aadf2cbf3..a189b162a7 100644 --- a/dockerfiles/Dockerfile.test +++ b/dockerfiles/Dockerfile.test @@ -17,7 +17,7 @@ RUN if [ "$OS_VARIANT" = "alpine" ]; then \ apk update && apk upgrade --no-cache && \ apk add --no-cache git build-base curl ca-certificates; \ else \ - apt-get update && apt-get install -y git build-essential curl ca-certificates; \ + apt-get update && apt-get install -y --no-install-recommends git build-essential curl ca-certificates; \ rm -rf "${RUSTUP_HOME}" "${CARGO_HOME}"; \ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain ${RUST_TOOLCHAIN}; \ fi && \ diff --git a/go/cloud-query/Dockerfile b/go/cloud-query/Dockerfile index 7098a2d319..b1e8aa42e8 100644 --- a/go/cloud-query/Dockerfile +++ b/go/cloud-query/Dockerfile @@ -16,7 +16,7 @@ COPY internal/ internal/ # Build the cloud-query binary RUN CGO_ENABLED=0 go build -o bin/cloud-query cmd/*.go -FROM cgr.dev/chainguard/wolfi-base AS final +FROM cgr.dev/chainguard/wolfi-base@sha256:1d95114038f76513a9ace6fca107d5582b08c65981f81f61cb56bf7fd2ef216d AS final ARG BUILD_TIME=1970-01-01T00:00:00Z ARG GIT_COMMIT=unknown @@ -42,4 +42,7 @@ COPY --from=builder /workspace/bin/cloud-query /usr/local/bin/cloud-query USER nonroot -CMD ["/usr/local/bin/cloud-query"] \ No newline at end of file +# The minimal Wolfi base has no HTTP probe client; Kubernetes probes /healthz. +HEALTHCHECK NONE + +CMD ["/usr/local/bin/cloud-query"] diff --git a/go/demo/flaky-service/Dockerfile b/go/demo/flaky-service/Dockerfile index 5aa10bb16f..77126c8b02 100644 --- a/go/demo/flaky-service/Dockerfile +++ b/go/demo/flaky-service/Dockerfile @@ -17,20 +17,27 @@ COPY . . RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o flaky-service . # Step 2: Create a smaller image to run the application -FROM alpine:latest +FROM alpine:3.22@sha256:5291449c3df73caf6ed85e649dec1b9e818b39a5d8c871e97afc13e9cd5e8fa8 # Install necessary dependencies to run Go binaries RUN apk --no-cache add ca-certificates +RUN addgroup -S app && adduser -S -G app app + # Set the Current Working Directory inside the container -WORKDIR /root/ +WORKDIR /app # Copy the Go binary from the build stage -COPY --from=build /app/flaky-service . +COPY --from=build --chown=app:app /app/flaky-service ./flaky-service # Expose the port your app will run on (adjust if needed) EXPOSE 8080 EXPOSE 8081 +USER app + +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --quiet --spider http://127.0.0.1:8081/metrics || exit 1 + # Command to run the application CMD ["./flaky-service", "--response-behavior-modifier=timestamp", "--behavior-modifier-timestamp-modulus=3"] diff --git a/go/demo/flaky-service/Dockerfile.sidecar b/go/demo/flaky-service/Dockerfile.sidecar index 53dcb68eb8..10bfe66c92 100644 --- a/go/demo/flaky-service/Dockerfile.sidecar +++ b/go/demo/flaky-service/Dockerfile.sidecar @@ -2,14 +2,22 @@ FROM alpine:3.18 # Install any dependencies your shell script might need (e.g., bash, curl, etc.) -RUN apk update && apk add --no-cache bash curl +RUN apk add --no-cache bash curl + +RUN addgroup -S app && adduser -S -G app app + +WORKDIR /app # Copy the shell script from the host to the container -COPY api_caller.sh ./api_caller.sh +COPY --chown=app:app api_caller.sh ./api_caller.sh # Make sure the script is executable RUN chmod +x ./api_caller.sh +USER app + +# This sidecar has no listener; it only calls endpoints in its companion container. +HEALTHCHECK NONE + # Set the default command to run the shell script with the provided arguments CMD ["./api_caller.sh", "-e", "localhost:8080/api", "-m", "localhost:8081/metrics", "-t", "1.34"] - diff --git a/go/deployment-operator/Dockerfile b/go/deployment-operator/Dockerfile index 985d19d9c6..21fdf0eb95 100644 --- a/go/deployment-operator/Dockerfile +++ b/go/deployment-operator/Dockerfile @@ -55,4 +55,7 @@ USER 65532:65532 ENV GOMONTY_FFI_CACHE_DIR=/tmp/gomonty +HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ + CMD wget --quiet --spider http://127.0.0.1:9001/readyz || exit 1 + ENTRYPOINT ["/workspace/deployment-agent"] diff --git a/go/kubernetes-agent/api/Dockerfile b/go/kubernetes-agent/api/Dockerfile index 7047f837d0..859e1398d9 100644 --- a/go/kubernetes-agent/api/Dockerfile +++ b/go/kubernetes-agent/api/Dockerfile @@ -69,4 +69,8 @@ USER nonroot:nonroot # The port that the application listens on. EXPOSE 8000 8001 + +# The scratch image contains only the application binary, with no probe client. +HEALTHCHECK NONE + ENTRYPOINT ["/dashboard-api", "--insecure-bind-address=0.0.0.0", "--bind-address=0.0.0.0"] diff --git a/go/kubernetes-agent/hack/docker/Dockerfile b/go/kubernetes-agent/hack/docker/Dockerfile index bc9bb0527f..47e188806c 100644 --- a/go/kubernetes-agent/hack/docker/Dockerfile +++ b/go/kubernetes-agent/hack/docker/Dockerfile @@ -99,6 +99,8 @@ COPY --from=builder /binaries/api /api COPY --from=builder /binaries/kas /kas COPY --from=builder /binaries/agentk /agentk +USER nonroot:nonroot + # Create a simple entrypoint script (shell script won't work in distroless) # Instead, we'll use kas as the default entrypoint # Users can override with: docker run image /api or /agentk @@ -117,3 +119,6 @@ ENTRYPOINT ["/kas"] # 8154 - Kubernetes API # 8155 - Internal API EXPOSE 8000 8001 8150 8151 8153 8154 8155 + +# The distroless runtime has no shell or HTTP client for an in-image probe. +HEALTHCHECK NONE diff --git a/go/kubernetes-agent/hack/docker/Dockerfile.agentk b/go/kubernetes-agent/hack/docker/Dockerfile.agentk index 179493fc9f..894462078f 100644 --- a/go/kubernetes-agent/hack/docker/Dockerfile.agentk +++ b/go/kubernetes-agent/hack/docker/Dockerfile.agentk @@ -75,6 +75,8 @@ LABEL source="https://github.com/pluralsh/console/go/kubernetes-agent" \ # Copy all binaries from builder COPY --from=builder /binaries/agentk /agentk +USER nonroot:nonroot + # Create a simple entrypoint script (shell script won't work in distroless) # Instead, we'll use kas as the default entrypoint # Users can override with: docker run image /api or /agentk @@ -93,3 +95,6 @@ ENTRYPOINT ["/agentk"] # 8154 - Kubernetes API # 8155 - Internal API # EXPOSE 8000 8001 8150 8151 8153 8154 8155 + +# Agentk is a reverse-tunnel client and the distroless runtime has no probe client. +HEALTHCHECK NONE diff --git a/js/console/Dockerfile b/js/console/Dockerfile index 25c70c4fb6..4c7ce24f06 100644 --- a/js/console/Dockerfile +++ b/js/console/Dockerfile @@ -16,5 +16,12 @@ RUN corepack enable \ COPY js/console/ ./console/ COPY js/design-system/ ./design-system/ +RUN chown -R node:node /app + WORKDIR /app/console +USER node + +# This image only runs a finite asset build and exposes no service to probe. +HEALTHCHECK NONE + CMD ["yarn", "build"] diff --git a/js/documentation/Dockerfile b/js/documentation/Dockerfile index 36f4ba4ff6..c76e57ab1a 100644 --- a/js/documentation/Dockerfile +++ b/js/documentation/Dockerfile @@ -32,7 +32,15 @@ WORKDIR /app COPY --from=base /app/node_modules/ ./node_modules/ COPY --from=base /app/documentation/ ./documentation/ +# Next writes its runtime cache beneath the application directory. +RUN chown -R node:node /app + EXPOSE 3000 WORKDIR /app/documentation +USER node + +HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ + CMD wget --quiet --spider http://127.0.0.1:3000/ || exit 1 + CMD ["node", "/app/node_modules/next/dist/bin/next", "start", "-p", "3000"]