release: runtime-key.json has no pipeline integration #10

Open
opened 2026-04-15 11:48:28 +02:00 by jann · 0 comments
Member

The m2pack-secure client loader refuses to load .m2p archives unless the launcher delivers a runtime master key out-of-band (shared mem / env var / CLI flag — see m2pack-secure/docs/launcher-contract.md).

Today we wired the launcher to read runtime-key.json from the install dir and forward master_key_hex / sign_public_key_hex / key_id via the M2PACK_MASTER_KEY_HEX env var family, but the file itself is currently manually produced on the VPS:

m2pack export-runtime-key \
  --key /home/mt2.jakubkadlec.dev/.secrets/m2pack-secure/<date>/master.key \
  --public-key /home/mt2.jakubkadlec.dev/.secrets/m2pack-secure/<date>/signing.pub \
  --key-id 1 \
  --format json \
  --output runtime-key.json

then copied into the release tree next to Metin2.exe before make-manifest.py runs.

What needs to happen

  1. make-release.sh should take --runtime-key (master.key + signing.pub + key-id) and call m2pack export-runtime-key to generate runtime-key.json into the staging tree.
  2. Manifest generation must include runtime-key.json (today it does, since it lives in the tree when make-manifest walks — but this should be documented, not accidental).
  3. Key rotation story: bumping key_id should be a single flag; the launcher already re-fetches runtime-key.json on every update via content-addressed blob.
  4. Refuse to publish a manifest whose format is m2pack but the tree has no runtime-key.json (fail fast).

Security note

The current design parks the master key in a public webroot — not a secret in the strict sense, more like DRM. The launcher contract lists three delivery mechanisms (shared memory, env, CLI); on Linux/Wine shared mem is painful across the Wine boundary, env is what the patched launcher uses. Worth documenting the threat model in docs/release-workflow.md.

Related: jann/metin-launcher PR #1 (runtime key delivery in GameProcess).

The m2pack-secure client loader refuses to load `.m2p` archives unless the launcher delivers a runtime master key out-of-band (shared mem / env var / CLI flag — see `m2pack-secure/docs/launcher-contract.md`). Today we wired the launcher to read `runtime-key.json` from the install dir and forward `master_key_hex` / `sign_public_key_hex` / `key_id` via the `M2PACK_MASTER_KEY_HEX` env var family, but the file itself is currently **manually produced** on the VPS: ```bash m2pack export-runtime-key \ --key /home/mt2.jakubkadlec.dev/.secrets/m2pack-secure/<date>/master.key \ --public-key /home/mt2.jakubkadlec.dev/.secrets/m2pack-secure/<date>/signing.pub \ --key-id 1 \ --format json \ --output runtime-key.json ``` then copied into the release tree next to `Metin2.exe` before `make-manifest.py` runs. ## What needs to happen 1. `make-release.sh` should take `--runtime-key` (master.key + signing.pub + key-id) and call `m2pack export-runtime-key` to generate `runtime-key.json` into the staging tree. 2. Manifest generation must include `runtime-key.json` (today it does, since it lives in the tree when make-manifest walks — but this should be documented, not accidental). 3. Key rotation story: bumping `key_id` should be a single flag; the launcher already re-fetches `runtime-key.json` on every update via content-addressed blob. 4. Refuse to publish a manifest whose `format` is `m2pack` but the tree has no `runtime-key.json` (fail fast). ## Security note The current design parks the master key in a public webroot — not a secret in the strict sense, more like DRM. The launcher contract lists three delivery mechanisms (shared memory, env, CLI); on Linux/Wine shared mem is painful across the Wine boundary, env is what the patched launcher uses. Worth documenting the threat model in `docs/release-workflow.md`. Related: jann/metin-launcher PR #1 (runtime key delivery in GameProcess).
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: metin-server/m2dev-client#10