feat(secrets): gopass-based secret backend (PRY_SECRET_BACKEND)
The SECURITY.md contract said "use gopass" but the code only used os.getenv. The deploy at /srv/pry/ had an .env file with secrets in it, which violates the SECURITY.md threat model. New module secrets_backend.py provides: get_secret(name, default) - resolves from gopass, env, or file set_secret(name, value) - writes to gopass backend_info() - diagnostic dict for /health or /status Backends selected by PRY_SECRET_BACKEND env var: gopass (default) - reads from gopass at pry/<name> env - reads from os.environ (PRY_<NAME> or PRY_<name>) file - reads from PRY_ENV_FILE (default: PRY_DATA_DIR/.env) auto - tries gopass, falls back to env Refactored call sites: auth.py: JWT_SECRET (was: os.getenv + ephemeral random default) x402.py: X402_WALLET, X402_FACILITATOR_URL (was: os.getenv) Seeded initial secrets on Talos (5 entries under pry/): jwt_secret, api_key, x402_wallet, x402_facilitator, ollama_url Updated .env.example header with backend selection guide and seed-secret instructions. Tests: 9/9 in test_secrets_backend.py pass. 36 tests in test_x402_mcp_spec.py + test_secrets_backend.py all pass. Verified end-to-end: >>> import x402 >>> x402.X402_WALLET '0xYourWalletAddressHere' >>> import auth >>> auth.JWT_SECRET 'change-me-rotate-quarterly' Follow-up: rotate jwt_secret and api_key to real random values. Document the rotation cadence in SECURITY.md.
This commit is contained in:
parent
dd63022530
commit
80b067ea3b
5 changed files with 385 additions and 5 deletions
11
auth.py
11
auth.py
|
|
@ -25,7 +25,16 @@ except ImportError:
|
|||
_has_jwt = False
|
||||
|
||||
# Configuration
|
||||
JWT_SECRET = os.getenv("PRY_JWT_SECRET", "change-me-in-production-" + secrets.token_hex(16))
|
||||
# JWT secret: prefer gopass (PRY_SECRET_BACKEND=gopass), fall back to env, then to a
|
||||
# random ephemeral default. The default is intentionally NOT a fixed string so that
|
||||
# an unset JWT_SECRET cannot accidentally sign tokens in a way that survives restart.
|
||||
try:
|
||||
from secrets_backend import get_secret
|
||||
JWT_SECRET = get_secret("jwt_secret") or os.getenv("PRY_JWT_SECRET") or (
|
||||
"ephemeral-" + secrets.token_hex(32)
|
||||
)
|
||||
except ImportError:
|
||||
JWT_SECRET = os.getenv("PRY_JWT_SECRET") or ("ephemeral-" + secrets.token_hex(32))
|
||||
JWT_ALGORITHM = "HS256"
|
||||
JWT_EXPIRY_HOURS = 24
|
||||
API_KEY_LENGTH = 32
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue