Tiny static tool: resolves _FILE secrets to env vars, then execs your app in distroless images.
929
A tiny, dependency-free, statically linked binary that resolves Docker/Kubernetes-style
*_FILE secret references into plain environment variables and then execs your
actual application — designed to run in scratch or distroless images that have
no shell.
DB_PASSWORD_FILE=/run/secrets/db_password
│
▼
fileenv reads the file
│
▼
DB_PASSWORD=<file contents> → exec("myapp", ...)
Docker Swarm and Kubernetes both mount secrets as files (typically under
/run/secrets), but many applications only know how to read configuration from
environment variables. The common workaround is a shell-based docker-entrypoint.sh
with a file_env() function (used by the official postgres, mysql, wordpress
images, among others). That approach requires a shell — which distroless/scratch
images intentionally don't have.
fileenv implements the same idea as a single static binary with no runtime
dependencies, so it also works in minimal, shell-less images.
CGO_ENABLED=0)_FILE, resolves the referenced file,
and sets the same variable name without the suffixexec (not fork) — the target
process keeps PID 1, so signals like SIGTERM from docker stop /
docker service update reach it directly, with no zombie-process risk and no
need for a separate init system (e.g. tini)echo-generated secrets)fileenv iterates over its own environment.FOO_FILE=/path/to/file, it reads /path/to/file and sets
FOO=<contents of the file> (trailing \n/\r\n stripped).PATH if not an absolute path).exec(), replacing itself with that command — the target process
inherits the now-fully-populated environment.If a file cannot be read, fileenv exits with a non-zero status and an error
message on stderr; it never silently continues with a missing secret.
Copy the binary out of the published image into your own multi-stage build —
this is the pattern used by tools like secrets-init or tini-static:
FROM ghcr.io/skriptfabrik/fileenv:1 AS fileenv
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=fileenv /usr/local/bin/fileenv /usr/local/bin/fileenv
COPY myapp /usr/local/bin/myapp
ENTRYPOINT ["/usr/local/bin/fileenv"]
CMD ["--", "/usr/local/bin/myapp"]
Images are published to both:
ghcr.io/skriptfabrik/fileenvskriptfabrik/fileenvAvailable tags: <major>, <major>.<minor>, <major>.<minor>.<patch>, and
latest (tracks the most recent non-prerelease release). Pin to at least the
major tag (:1) in production.
Every release includes
prebuilt binaries for the most common platforms, plus a checksums.txt:
| OS | Architecture | Archive |
|---|---|---|
| Linux | amd64 | fileenv_<version>_linux_amd64.tar.gz |
| Linux | arm64 | fileenv_<version>_linux_arm64.tar.gz |
| Linux | armv7 | fileenv_<version>_linux_armv7.tar.gz |
| macOS | amd64 | fileenv_<version>_darwin_amd64.tar.gz |
| macOS | arm64 (Apple Sil.) | fileenv_<version>_darwin_arm64.tar.gz |
| Windows | amd64 | fileenv_<version>_windows_amd64.zip |
curl -LO https://github.com/skriptfabrik/fileenv/releases/latest/download/fileenv_<version>_linux_amd64.tar.gz
curl -LO https://github.com/skriptfabrik/fileenv/releases/latest/download/checksums.txt
sha256sum --ignore-missing -c checksums.txt
tar -xzf fileenv_<version>_linux_amd64.tar.gz
go installgo install github.com/skriptfabrik/fileenv@latest
fileenv [--] <command> [args...]
The -- is optional and only improves readability in Dockerfiles / Compose
files; fileenv myapp --serve and fileenv -- myapp --serve behave identically.
fileenv --version # prints the build version and exits
services:
app:
image: myapp
entrypoint: ["fileenv", "--"]
command: ["node", "server.js"]
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
volumes:
- ./secrets/db_password:/run/secrets/db_password:ro
services:
app:
image: myapp
entrypoint: ["fileenv", "--"]
command: ["node", "index.js"]
secrets:
- db_password
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
db_password:
external: true
Swarm mounts secrets at /run/secrets/<secret_name>; point the _FILE variable
at that path explicitly (the secret name and the desired environment variable
name don't have to match).
env:
- name: DB_PASSWORD_FILE
value: /etc/secrets/db-password
volumeMounts:
- name: db-password
mountPath: /etc/secrets
readOnly: true
_FILE suffix is recognized; there is no configurable prefix/suffix
(kept intentionally simple — fork the project if you need that).FOO and FOO_FILE are set, FOO_FILE wins and overwrites FOO._FILE) are ignored.\r\n/\n — no
further parsing, quoting, or templating is applied.fileenv never logs variable names or values.:nonroot
distroless variant (as shown above) unless you have a specific reason not to.Requirements: Go 1.22+, Docker with Buildx (for multi-arch image builds).
git clone https://github.com/skriptfabrik/fileenv.git
cd fileenv
go build -o fileenv .
go vet ./...
./fileenv --version
Local multi-arch image build (no push):
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t fileenv:dev .
.
├── main.go # the entire implementation
├── go.mod
├── Dockerfile # multi-arch, distroless runtime
└── .github/workflows/
├── ci.yml # build & vet on push/PR
└── release.yml # binaries + Docker images on GitHub Release
Releases are fully automated via GitHub Actions and triggered by publishing a
GitHub Release with a semantic-versioning tag (vX.Y.Z, e.g. v1.2.0):
v1.2.0 on GitHub (this can be a new
tag or an existing one)..github/workflows/release.yml then, in parallel:
.tar.gz/.zip, generates
checksums.txt, and uploads everything to the release, andlinux/amd64, linux/arm64, linux/arm/v7)
Docker image and pushes it to both ghcr.io/skriptfabrik/fileenv and
skriptfabrik/fileenv on Docker Hub, tagged 1.2.0, 1.2, 1, and
latest.Required repository secrets for the Docker Hub push (GHCR authenticates with
the built-in GITHUB_TOKEN, no extra secret needed):
| Secret | Description |
|---|---|
DOCKERHUB_USERNAME | Docker Hub username or org |
DOCKERHUB_TOKEN | Docker Hub access token (Account Settings → Security → New Access Token) |
Issues and pull requests are welcome. Given the intentionally small scope of this tool, please open an issue to discuss larger changes before submitting a PR.
Content type
Image
Digest
sha256:12d343513…
Size
1.4 MB
Last updated
about 2 months ago
docker pull skriptfabrik/fileenv