Skip to content

feat(minimal): support *_FILE variables for Docker/Kubernetes secrets - #179

Merged
jsokol merged 6 commits into
testingfrom
feat/file-env-secrets
Oct 27, 2026
Merged

jsokol merged 6 commits into
testingfrom
feat/file-env-secrets

Conversation

@jsokol

@jsokol jsokol commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

Summary

Targets testing (the RC branch; promotion to master is a separate step). Merged up to date with testing after #178 (APACHE_MAX_REQUEST_WORKERS); the only conflict was the workflow's test-step list, where all steps are kept.

Addresses #83. Adds file_env to the simplerisk-minimal entrypoint: for each supported variable, VAR_FILE=/run/secrets/<name> loads the value from that file (trailing newline stripped), following the convention used by the official MySQL/MariaDB/WordPress images.

  • Supported: DB_SETUP_USER/PASS, SIMPLERISK_DB_HOSTNAME/PORT/USERNAME/PASSWORD/DATABASE, SIMPLERISK_CSRF_SECRET, MAIL_USERNAME/PASSWORD, ADMIN_USERNAME/PASSWORD
  • Setting both VAR and VAR_FILE, or an unreadable _FILE path, exits with a clear error
  • Runs before the "Docker-managed config" detection, so a _FILE-only setup still triggers config provisioning
  • _FILE vars are unset after loading; README gets a "Secrets" section with a compose example

Hardening included (credential values with metacharacters)

Secrets from a secret manager commonly contain ", ', \, $, backticks, &, | and newlines. Several existing sinks mishandled those, so they are fixed here:

  1. mysql setup/delete interpolated values into a bash -c string -> now an argv array (mysql_setup), password via MYSQL_PWD, SQL on stdin with escaped string literals/identifiers.
  2. csrf-secret.php wrote the secret into a double-quoted PHP string -> now an escaped single-quoted string. (A secret that relied on $/escape interpolation previously broke; it is now taken literally.)
  3. sed_escape broke on newlines, and config.php defines did not escape '/\ -> config_define PHP-escapes then sed-escapes; sed_escape uses parameter expansion.
  4. apply_mail_setting passed the DB password on the command line (visible in ps) -> MYSQL_PWD, and values are escaped with sql_str_escape.
  5. Mail settings were silently skipped on MySQL 8: apply_mail_setting forced --ssl-mode=DISABLED, so caching_sha2_password refused the app user's first login ("Authentication requires secure connection"). Reproduced on the published 20261020-001 image with plain passwords. It now uses the client default (PREFERRED, TLS when the server offers it).

Verification

Built the image from this branch and ran it against mysql:8.0 with secrets mounted as files, using hostile values (e.g. app password a"b$(touch /tmp/PWNED)c'd\e&f|g;h, DB user sr"user):

  • DB_SETUP=automatic: schema loaded, app user created, 155 tables, admin user created from ADMIN_PASSWORD_FILE, HTTPS returns 200
  • config.php and csrf-secret.php evaluate in PHP back to the exact secret values; the app user logs in to MySQL with the hostile password
  • No injected command executed (/tmp/PWNED* absent in app and MySQL containers)
  • DB_SETUP=delete removes the database and user; a hostile DB name (db"x'y) and user (u'"x) are created exactly
  • PID 1 (supervisord/Apache) has no secret or _FILE variables in its environment
  • VAR + VAR_FILE together, and a missing file, exit 1 with a clear message
  • Mail settings on a fresh MySQL 8 (cold auth cache): plain-password scenario that failed on 20261020-001 now stores all four settings; with hostile secret files the stored phpmailer_password/phpmailer_username match the files byte for byte (hex compared)
  • test_file_env.sh, test_escaping.sh and Add APACHE_MAX_REQUEST_WORKERS to simplerisk-minimal #178's test_set_apache_workers.sh pass in an image built from the merged tree (bash 5.2 / GNU sed); all run in container-validation; end-to-end scenarios re-run on the merged image

Known limitations / out of scope

  • The DB password still lands in plaintext in config.php (and the CSRF secret in csrf-secret.php); this keeps secrets out of the container environment and compose files, not off the container's disk.
  • The full-stack simplerisk image is unchanged (it generates its own DB passwords).
  • The official mysql image's own entrypoint cannot take a root password containing ' or \; unrelated to this change.

🤖 Generated with Claude Code

jsokol and others added 5 commits October 21, 2026 13:44
Adds file_env to the minimal entrypoint so credentials (DB setup/app
passwords, CSRF secret, mail and admin credentials) can be read from a
file such as /run/secrets/<name> instead of the environment. Setting
both VAR and VAR_FILE, or pointing at an unreadable file, is fatal.

Refs #83

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…, SQL, PHP and sed

Credential values were interpolated into a bash -c string (mysql setup/delete),
a double-quoted PHP string (csrf-secret.php) and unescaped PHP single-quoted
strings (config.php); sed_escape also broke on newlines. _FILE secrets from a
secret manager commonly contain these characters.

- run mysql via an argv array with the password in MYSQL_PWD, SQL on stdin,
  string values single-quoted and identifiers quoted with proper escaping
- write csrf-secret.php and config.php defines as escaped PHP single-quoted strings
- rewrite sed_escape with parameter expansion so newlines survive
- pass the app DB password to apply_mail_setting via MYSQL_PWD, not argv
- add test_escaping.sh and run it in container-validation

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… connection

apply_mail_setting passed --ssl-mode=DISABLED, so MySQL 8's caching_sha2_password
refused the app user's first login ("Authentication requires secure connection")
and every mail setting was skipped with only a warning. Use the client default
(PREFERRED), and escape values with sql_str_escape. Add a regression check.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jsokol
jsokol changed the base branch from master to testing October 27, 2026 18:21
# Conflicts:
#	.github/workflows/container-validation.yml
@jsokol
jsokol marked this pull request as ready for review October 27, 2026 18:34
@jsokol
jsokol merged commit bd04291 into testing Oct 27, 2026
8 checks passed
@jsokol
jsokol deleted the feat/file-env-secrets branch October 27, 2026 18:34
@jsokol jsokol mentioned this pull request Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant