-
Notifications
You must be signed in to change notification settings - Fork 440
docs: improve Dockerfile for hardened images #2270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -223,58 +223,42 @@ RUN install-php-extensions pdo_mysql pdo_pgsql #... | |||||||||
|
|
||||||||||
| # Copy shared libs of frankenphp and all installed extensions to temporary location | ||||||||||
| # You can also do this step manually by analyzing ldd output of frankenphp binary and each extension .so file | ||||||||||
| RUN apt-get update && apt-get install -y libtree && \ | ||||||||||
| EXT_DIR="$(php -r 'echo ini_get("extension_dir");')" && \ | ||||||||||
| FRANKENPHP_BIN="$(which frankenphp)"; \ | ||||||||||
| LIBS_TMP_DIR="/tmp/libs"; \ | ||||||||||
| mkdir -p "$LIBS_TMP_DIR"; \ | ||||||||||
| for target in "$FRANKENPHP_BIN" $(find "$EXT_DIR" -maxdepth 2 -type f -name "*.so"); do \ | ||||||||||
| libtree -pv "$target" | sed 's/.*── \(.*\) \[.*/\1/' | grep -v "^$target" | while IFS= read -r lib; do \ | ||||||||||
| [ -z "$lib" ] && continue; \ | ||||||||||
| base=$(basename "$lib"); \ | ||||||||||
| destfile="$LIBS_TMP_DIR/$base"; \ | ||||||||||
| if [ ! -f "$destfile" ]; then \ | ||||||||||
| cp "$lib" "$destfile"; \ | ||||||||||
| fi; \ | ||||||||||
| done; \ | ||||||||||
| done | ||||||||||
|
|
||||||||||
|
|
||||||||||
| # Distroless debian base image, make sure this is the same debian version as the base image | ||||||||||
| RUN apt-get update; \ | ||||||||||
| apt-get install -y --no-install-recommends libtree; \ | ||||||||||
| mkdir -p /tmp/libs; \ | ||||||||||
| for target in $(which frankenphp) \ | ||||||||||
| $(find "$(php -r 'echo ini_get("extension_dir");')" -maxdepth 2 -name "*.so"); do \ | ||||||||||
| libtree -pv "$target" 2>/dev/null | grep -oP '(?:── )\K/\S+(?= \[)' | while IFS= read -r lib; do \ | ||||||||||
| [ -f "$lib" ] && cp -n "$lib" /tmp/libs/; \ | ||||||||||
| done; \ | ||||||||||
| done; | ||||||||||
|
|
||||||||||
|
|
||||||||||
| # Distroless Debian base image, make sure this matches the Debian version of the builder | ||||||||||
| FROM gcr.io/distroless/base-debian13 | ||||||||||
| # Docker hardened image alternative | ||||||||||
| # Docker hardened image alternative: | ||||||||||
| # FROM dhi.io/debian:13 | ||||||||||
|
|
||||||||||
|
Comment on lines
+237
to
241
|
||||||||||
| # Location of your app and Caddyfile to be copied into the container | ||||||||||
| ARG PATH_TO_APP="." | ||||||||||
| ARG PATH_TO_CADDYFILE="./Caddyfile" | ||||||||||
|
|
||||||||||
| # Copy your app into /app | ||||||||||
| # For further hardening make sure only writable paths are owned by the nonroot user | ||||||||||
| COPY --chown=nonroot:nonroot "$PATH_TO_APP" /app | ||||||||||
| COPY "$PATH_TO_CADDYFILE" /etc/caddy/Caddyfile | ||||||||||
|
|
||||||||||
| # Copy frankenphp and necessary libs | ||||||||||
| COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp | ||||||||||
| COPY --from=builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions | ||||||||||
| COPY --from=builder /tmp/libs /usr/lib | ||||||||||
|
|
||||||||||
| # Copy php.ini configuration files | ||||||||||
| COPY --from=builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d | ||||||||||
| COPY --from=builder /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini | ||||||||||
|
|
||||||||||
| # Caddy data dirs — must be writable for nonroot, even on a read-only root filesystem | ||||||||||
| ENV XDG_CONFIG_HOME=/config \ | ||||||||||
| XDG_DATA_HOME=/data | ||||||||||
| COPY --from=builder --chown=nonroot:nonroot /data/caddy /data/caddy | ||||||||||
| COPY --from=builder --chown=nonroot:nonroot /config/caddy /config/caddy | ||||||||||
| # Config and data dirs must be writable for nonroot, even on a read-only root filesystem | ||||||||||
| ENV XDG_CONFIG_HOME=/config XDG_DATA_HOME=/data | ||||||||||
| COPY --from=builder --chown=nonroot:nonroot /data /data | ||||||||||
| COPY --from=builder --chown=nonroot:nonroot /config /config | ||||||||||
|
|
||||||||||
| USER nonroot | ||||||||||
| # Copy your app and Caddyfile | ||||||||||
| COPY --chown=nonroot:nonroot . /app | ||||||||||
|
Comment on lines
+254
to
+255
|
||||||||||
| # Copy your app and Caddyfile | |
| COPY --chown=nonroot:nonroot . /app | |
| # Copy your app (kept root-owned) and Caddyfile | |
| COPY . /app |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
RUNline chains commands with;rather than&&, so a failedapt-get update(orapt-get install) won’t reliably stop the build at the point of failure. For Dockerfile examples, it’s better to use&&(or enableset -e) so failures abort immediately and don’t produce confusing downstream errors.