fix: edge-control: deregister has no ownership check — any authorized SSH key can take over any project (#1091)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/nomad-validate Pipeline was successful

Require the caller to prove ownership on deregister by providing the
pubkey that was used during registration. The stored pubkey is loaded
from registry.json and compared byte-for-byte against the supplied key.

Changes:
- Add get_pubkey() helper to lib/ports.sh
- Update do_deregister() to verify caller pubkey before removing project
- Update SSH protocol to "deregister <project> <pubkey>"
- Update bin/disinto CLI to read tunnel keypair and pass pubkey
- Return {"error":"pubkey mismatch"} on failure (no pubkey leakage)
- Add unit tests for both success and failure paths

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
dev-qwen2 2026-04-20 19:12:31 +00:00
parent 65df00ea6a
commit 0243f546da
4 changed files with 298 additions and 13 deletions

View file

@ -71,7 +71,7 @@ Usage:
Edge subcommands:
register [project] Register a new tunnel (generates keypair if needed)
deregister <project> Remove a tunnel registration
deregister <project> Remove a tunnel registration (requires tunnel keypair)
status Show registered tunnels
Agent subcommands:
@ -2737,7 +2737,7 @@ EOF
# Manage edge tunnel registrations (reverse SSH tunnels to edge hosts)
# Usage: disinto edge <verb> [options]
# register [project] Register a new tunnel (generates keypair if needed)
# deregister <project> Remove a tunnel registration
# deregister <project> Remove a tunnel registration (requires tunnel keypair)
# status Show registered tunnels
disinto_edge() {
local subcmd="${1:-}"
@ -2885,12 +2885,25 @@ disinto_edge() {
edge_host="${EDGE_HOST:-edge.disinto.ai}"
fi
# Read tunnel pubkey (same keypair used for register)
local secrets_dir="${FACTORY_ROOT}/secrets"
local tunnel_pubkey="${secrets_dir}/tunnel_key.pub"
if [ ! -f "$tunnel_pubkey" ]; then
echo "Error: no tunnel keypair found at ${tunnel_pubkey}" >&2
echo "Register a tunnel first, or seed the keypair." >&2
exit 1
fi
local pubkey
pubkey=$(tr -d '\n' < "$tunnel_pubkey")
# SSH to edge host and deregister
echo "Deregistering tunnel for ${project} on ${edge_host}..."
local response
response=$(ssh -o StrictHostKeyChecking=accept-new -o BatchMode=yes \
"disinto-register@${edge_host}" \
"deregister ${project}" 2>&1) || {
"deregister ${project} ${pubkey}" 2>&1) || {
echo "Error: failed to deregister tunnel" >&2
echo "Response: ${response}" >&2
exit 1
@ -2956,7 +2969,7 @@ Usage: disinto edge <verb> [options]
Manage edge tunnel registrations:
register [project] Register a new tunnel (generates keypair if needed)
deregister <project> Remove a tunnel registration
deregister <project> Remove a tunnel registration (requires tunnel keypair)
status Show registered tunnels
Options: