netx/netx_api/security_bootstrap.py
oliver 6eeaa457b8 Default UME TLS verify off for lab self-signed certs.
Restore ume_verify_tls=false so onsite UME login works without a .env override; production should set NETX_UME_VERIFY_TLS=true or pin a CA.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-06 15:15:48 +08:00

50 lines
1.8 KiB
Python

"""Startup security checks for bind address vs insecure lab defaults."""
from __future__ import annotations
import logging
import sys
from .auth_tokens import ensure_auth_secret, is_legacy_insecure_secret
from .config import settings
_log = logging.getLogger("netx.security")
def _is_loopback_host(host: str) -> bool:
h = str(host or "").strip().lower()
return h in {"127.0.0.1", "::1", "localhost"}
def assert_secure_defaults_or_exit() -> None:
"""Refuse non-loopback bind when lab secrets / default admin password remain."""
# Always materialize per-install JWT secret before bind checks.
ensure_auth_secret()
if bool(getattr(settings, "allow_insecure_defaults", False)):
_log.warning("NETX_ALLOW_INSECURE_DEFAULTS=1 — skipping insecure-default bind check")
return
host = str(settings.host or "127.0.0.1")
if _is_loopback_host(host):
return
problems: list[str] = []
explicit = str(settings.auth_secret or "").strip()
if is_legacy_insecure_secret(explicit):
problems.append(
"NETX_AUTH_SECRET is still the legacy shared development value "
"(unset it to use data/auth/jwt_secret, or set a unique secret)"
)
pwd = str(settings.bootstrap_admin_password or "").strip()
if pwd in {"", "admin123"}:
problems.append("NETX_BOOTSTRAP_ADMIN_PASSWORD is still the lab default (admin123)")
if not bool(getattr(settings, "ume_verify_tls", False)):
problems.append("NETX_UME_VERIFY_TLS=false while binding on a non-loopback interface")
if problems:
for p in problems:
_log.error("insecure default: %s", p)
_log.error(
"Refusing to start on host=%s. Set unique secrets, or bind 127.0.0.1, "
"or set NETX_ALLOW_INSECURE_DEFAULTS=1 for lab only.",
host,
)
sys.exit(2)