Skip to content

fix: harden Docker auth signing secrets#425

Open
DivyamTalwar wants to merge 1 commit into
morphik-org:mainfrom
DivyamTalwar:fix/docker-installer-session-secret
Open

fix: harden Docker auth signing secrets#425
DivyamTalwar wants to merge 1 commit into
morphik-org:mainfrom
DivyamTalwar:fix/docker-installer-session-secret

Conversation

@DivyamTalwar

Copy link
Copy Markdown

Summary

This hardens authenticated self-hosted Docker setups by requiring non-placeholder signing secrets of at least 32 characters when bypass_auth_mode = false. The Docker installers now generate a SESSION_SECRET_KEY alongside the existing generated JWT secret, Docker Compose no longer falls back to a placeholder JWT secret, and startup validation rejects missing, blank, placeholder, or too-short JWT/session signing secrets.

LOCAL_URI_PASSWORD remains optional at startup because blank or unset values disable /local/generate_uri, but if it is configured, the app and hosted Docker installers now reject placeholder or too-short values before serving requests.

The Docker guide and hosted installers now require Docker Compose 2.24.0 or newer so .env can be optional while shell/CI secret injection continues to work. The Docker quick start also now creates .env before docker compose up --build so new users get both required signing secrets before startup.

Changes

  • Generate SESSION_SECRET_KEY in both hosted Docker installers.
  • Restrict hosted Docker .env files to the current user after creation and updates, including stricter Windows ACL cleanup.
  • Hide LOCAL_URI_PASSWORD terminal input in the hosted Docker installers.
  • Remove the Compose-level JWT_SECRET_KEY:-your-secret-key-here fallback and pass through auth secrets explicitly from .env or the shell.
  • Keep .env optional in Compose so CI and secret-manager workflows can still inject JWT_SECRET_KEY, SESSION_SECRET_KEY, and LOCAL_URI_PASSWORD through the process environment.
  • Require Docker Compose 2.24.0+ in Docker docs and hosted installers because optional env_file support is used.
  • Update the Docker quick start to create .env with separate generated JWT and session secrets before the first Compose run.
  • Validate JWT_SECRET_KEY and SESSION_SECRET_KEY when auth bypass is disabled.
  • Validate configured LOCAL_URI_PASSWORD values while keeping a missing/blank local URI password as the disabled state for /local/generate_uri.
  • Return an explicit disabled response from /local/generate_uri when LOCAL_URI_PASSWORD is blank or unset.
  • Update Docker docs to mention the session secret requirement, local URI password behavior, and auth-secret troubleshooting.
  • Add focused unit/static tests for config validation, installer generation, optional Compose .env wiring, shell-secret injection, installer validation failure behavior, endpoint disabled behavior, and Docker docs.

Why this matters

Self-hosted Docker deployments with authentication enabled should not silently use shared development signing secrets. Missing or placeholder session signing keys are especially risky because Starlette sessions depend on SESSION_SECRET_KEY, while the old Compose JWT fallback could hide a missing production secret from runtime validation.

Tests

Commands run:

  • .venv/bin/python -m pytest core/tests/unit/test_config_auth_secrets.py core/tests/unit/test_installer_auth_env.py -q — passed (58 passed, 1 skipped)
  • bash -n install_docker.sh && bash -n install_and_start.sh — passed
  • .venv/bin/python -m py_compile core/config.py core/api.py core/local_uri.py core/tests/unit/test_config_auth_secrets.py core/tests/unit/test_installer_auth_env.py — passed
  • uv run ty check core/tests/unit/test_installer_auth_env.py core/tests/unit/test_config_auth_secrets.py core/local_uri.py — passed
  • git diff --check — passed

Not run successfully:

  • uv run ruff check core/config.py core/api.py core/tests/unit/test_config_auth_secrets.py core/tests/unit/test_installer_auth_env.py — failed because ruff is not installed in the local project environment.
  • uv run ruff format --check core/config.py core/api.py core/tests/unit/test_config_auth_secrets.py core/tests/unit/test_installer_auth_env.py — failed because ruff is not installed in the local project environment.
  • PowerShell parser execution — skipped locally because neither pwsh nor powershell is installed. The test is present and will run where PowerShell is available.

Risk

Risk level: medium

This intentionally changes startup behavior for bypass_auth_mode = false: missing, blank, placeholder, or short JWT/session signing secrets now fail fast instead of falling back to unsafe defaults. Missing/blank LOCAL_URI_PASSWORD remains compatible as the disabled state for /local/generate_uri; only configured placeholder or too-short local URI passwords now fail validation. Rollback is straightforward by reverting this commit, but doing so would restore unsafe fallback behavior.

Issue

No existing issue. This was discovered during repository analysis and follow-up security review of the self-hosted Docker path.

Notes for maintainers

  • This PR does not change the direct installers.
  • This PR keeps environment-variable based Docker secret delivery; moving production Docker secrets to Docker secrets or an external secret manager would be a separate deployment-hardening follow-up.

Authenticated Docker deployments could start with missing or placeholder signing material, including a development session secret. This fails fast for weak auth secrets, generates session secrets in hosted installers, and keeps Docker secret delivery compatible with both optional .env files and shell-injected CI environments.

Constraint: Preserve bypass-mode local development defaults, keep blank LOCAL_URI_PASSWORD as the disabled /local/generate_uri state, and avoid making .env mandatory for CI/secret-manager deployments.

Rejected: Raw Compose env_file parsing | it raises the Compose requirement and conflicts with preserving shell-injected secret workflows.

Rejected: Compose required-variable syntax | it would break bypass-mode local development before app-level config can apply defaults.

Confidence: high

Scope-risk: moderate

Directive: Keep LOCAL_URI_PASSWORD optional at startup; validate it only when configured with a nonblank value.

Tested: .venv/bin/python -m pytest core/tests/unit/test_config_auth_secrets.py core/tests/unit/test_installer_auth_env.py -q (58 passed, 1 skipped); bash -n install_docker.sh && bash -n install_and_start.sh; .venv/bin/python -m py_compile core/config.py core/api.py core/local_uri.py core/tests/unit/test_config_auth_secrets.py core/tests/unit/test_installer_auth_env.py; uv run ty check core/tests/unit/test_installer_auth_env.py core/tests/unit/test_config_auth_secrets.py core/local_uri.py; git diff --check

Not-tested: PowerShell parser execution skipped locally because pwsh/powershell is unavailable; ruff unavailable in local project environment.
@DivyamTalwar
DivyamTalwar marked this pull request as ready for review July 3, 2026 20:57
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