Skip to content

About

A simple C program designed to apply a custom umask to any child process.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

umask-wrapper

Build Release Downloads License

A tiny static binary that sets the umask from the APP_UMASK environment variable and then runs your command. It is meant for containers whose image has no shell or no built-in umask setting (scratch, distroless and many hardened images), so you can control the permissions of the files they create on shared volumes.

It can also load environment variables from files (FILE__<NAME>=<path>), so images that only read secrets from environment variables can use Docker secrets instead of having the value in the compose file or docker inspect.

Note

AI disclosure: This project is built and maintained with substantial help from AI coding assistants (GitHub Copilot). AI is used to write and modify the code, tests, documentation and CI configuration, and to manage the repository. Dependency updates are merged and released automatically, without human review, when the automated tests pass. Review the code and test it in your own environment before relying on it.

Features

  • No dependencies — one statically linked file (~10–70 KB); works in FROM scratch images
  • Transparent — replaces itself with your command (exec), so signals, PID 1, arguments, environment and exit codes are untouched
  • Fails safe — an invalid APP_UMASK stops the container instead of silently creating world-writable files
  • Multi-architecture — x86_64, arm64, armv7 and i386
  • Verifiable — every release has SHA-256 checksums and a signed build provenance attestation

Download

Pick the file for your architecture from the latest release:

Architecture uname -m File
64-bit Intel/AMD x86_64 umask-wrapper.x86_64
64-bit ARM (e.g. Raspberry Pi 4/5) aarch64 umask-wrapper.arm64
32-bit ARM armv7l umask-wrapper.armv7
32-bit Intel i386 / i686 umask-wrapper.i386
curl -fsSLo umask-wrapper https://github.com/scottfridwin/umask-wrapper/releases/latest/download/umask-wrapper.x86_64
chmod +x umask-wrapper

To verify the download, compare it with SHA256SUMS from the same release, or check its provenance with the GitHub CLI:

gh attestation verify umask-wrapper --repo scottfridwin/umask-wrapper

Usage

APP_UMASK=0002 ./umask-wrapper <command> [args...]
APP_UMASK Result
not set The command runs with the umask it inherited
1–4 octal digits, up to 0777 (e.g. 0002, 022, 0) The umask is set, then the command runs
anything else, including an empty value Error message, exit code 125; the command is not run

Exit codes follow the same convention as env:

Exit code Meaning
125 umask-wrapper error (no command given, invalid APP_UMASK, a FILE__ variable that can't be loaded)
126 The command was found but could not be run (e.g. not executable)
127 The command was not found
anything else The command's own exit code

Docker Compose

Mount the binary into the container, make it the entrypoint, and pass the image's original entrypoint and command as the command:

services:
  app:
    image: example/app:1.2.3
    entrypoint: ["/umask-wrapper"]
    command: ["/usr/local/bin/entrypoint.sh"]  # the image's original ENTRYPOINT + CMD
    environment:
      - APP_UMASK=0002  # files 664, directories 775
    volumes:
      - ./umask-wrapper:/umask-wrapper:ro

Find an image's original entrypoint and command with:

docker image inspect example/app:1.2.3 --format '{{json .Config.Entrypoint}} {{json .Config.Cmd}}'

Common values: 0022 (default on most systems; files 644), 0002 (group-writable; files 664), 0077 (private; files 600).

Variables from files

For every environment variable FILE__<NAME>=<path>, umask-wrapper sets NAME to the contents of the file and removes FILE__<NAME> before running the command:

services:
  app:
    image: example/app:1.2.3
    entrypoint: ["/umask-wrapper"]
    command: ["/usr/local/bin/entrypoint.sh"]
    environment:
      - FILE__DB_PASS=/run/secrets/db_password  # the app sees DB_PASS
    secrets:
      - db_password
    volumes:
      - ./umask-wrapper:/umask-wrapper:ro
  • Trailing newlines (\n, \r\n) are removed; everything else, including inner newlines, is kept. An empty file sets an empty value. An existing NAME is replaced.
  • NAME must be a valid variable name ([A-Za-z_][A-Za-z0-9_]*).
  • A file that can't be read, is larger than 64 KiB or contains a NUL byte stops the container with exit code 125; the error names the variable, never the file's contents.
  • APP_UMASK is optional; use either feature on its own.
  • The value is only in the command's process environment (/proc/<pid>/environ, readable by the same user), not in the container's configuration.

Further reading

License

MIT

About

A simple C program designed to apply a custom umask to any child process.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages