build-secrets
Secrets during Dockerfile builds
The updated Dockerfile builder keeps supplied secrets out of the build context. Only public configuration is materialized in the configured env file and supplied as build arguments. Runtime env delivery is unchanged. This change is prepared in source; check the deployed agent version before relying on it.
An application that needs credentials while building must declare a BuildKit secret mount. A Dockerfile without mounts receives public settings only; a build that needs more will fail until its Dockerfile is updated. HostSSH does not silently copy credentials into image layers to make that build pass.
For a single variable, name the mount after the variable:
# syntax=docker/dockerfile:1
FROM node:22-alpine AS builder
WORKDIR /app
# Install dependencies and copy source here.
RUN --mount=type=secret,id=DATABASE_URL,required=true \
DATABASE_URL="$(cat /run/secrets/DATABASE_URL)" npm run build
For frameworks that read dotenv files, the reserved hostssh_build_env mount holds
the supplied public and secret build settings together:
RUN --mount=type=secret,id=hostssh_build_env,target=/app/.env,required=true \
--mount=type=secret,id=hostssh_build_env,target=/app/.env.production,required=true \
npm run build \
&& find /app/.next/standalone -type f -name '.env*' -delete
Next.js copies loaded dotenv files into its standalone output. The cleanup above
must run in the same RUN as the build, before Docker saves the layer. A separate
cleanup layer leaves the original credentials recoverable from earlier layers.
For other frameworks, verify whether their output copies build-time configuration.
Choose the paths your framework actually reads, including the app directory in a
monorepo. Add the mount to every step that needs it. Do not declare an environment
variable named hostssh_build_env; that identifier belongs to the aggregate mount.
Individual mounts preserve their exact bytes. Aggregate dotenv delivery rejects
multiline values; framework dotenv expansion rules still apply to special characters.
Secret files are created outside the source directory with mode 0600 inside a 0700 directory and removed when the build returns, including normal build failures. A configured temp directory inside the source is rejected. A process kill or machine crash can require later cleanup of private temporary directories.
Secret-bearing builds use --no-cache, because Docker does not include mount contents
in its cache keys. This costs build time but ensures changed settings are actually
used. Public-only builds retain normal caching.
Build commands must not print credentials or copy mounted files into build outputs.
HostSSH cannot prevent application code from doing so. Keep repository-owned env
files out of Docker contexts yourself: this change prevents HostSSH from injecting
secrets, and does not sanitize a repository's existing files. Never classify a secret
as public through a framework prefix or HOSTSSH_PUBLIC_BUILD_VARS.
The external HostPack builder and node-local legacy deployment scripts have separate contracts. Updating the Dockerfile builder alone does not secure those paths or remove secrets already present in old images, logs or build caches.