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

@ -7,7 +7,7 @@
#
# Usage (via SSH):
# ssh disinto-register@edge "register <project> <pubkey>"
# ssh disinto-register@edge "deregister <project>"
# ssh disinto-register@edge "deregister <project> <pubkey>"
# ssh disinto-register@edge "list"
#
# Output: JSON on stdout
@ -30,11 +30,12 @@ usage() {
cat <<EOF
Usage:
register <project> <pubkey> Register a new tunnel
deregister <project> Remove a tunnel
deregister <project> <pubkey> Remove a tunnel (requires owner pubkey)
list List all registered tunnels
Example:
ssh disinto-register@edge "register myproject ssh-ed25519 AAAAC3..."
ssh disinto-register@edge "deregister myproject ssh-ed25519 AAAAC3..."
EOF
exit 1
}
@ -104,10 +105,11 @@ do_register() {
echo "$response"
}
# Deregister a tunnel
# Usage: do_deregister <project>
# Deregister a tunnel — requires ownership proof
# Usage: do_deregister <project> <pubkey>
do_deregister() {
local project="$1"
local caller_pubkey="$2"
# Get current port before removing
local port
@ -118,6 +120,15 @@ do_deregister() {
exit 1
fi
# Verify caller owns this project (pubkey must match)
local stored_pubkey
stored_pubkey=$(get_pubkey "$project")
if [ "$caller_pubkey" != "$stored_pubkey" ]; then
echo '{"error":"pubkey mismatch"}'
exit 1
fi
# Remove from registry
free_port "$project" >/dev/null
@ -196,13 +207,17 @@ main() {
do_register "$project" "$pubkey"
;;
deregister)
# deregister <project>
local project="$args"
if [ -z "$project" ]; then
echo '{"error":"deregister requires <project>"}'
# deregister <project> <pubkey>
local project="${args%% *}"
local pubkey="${args#* }"
if [ "$pubkey" = "$args" ]; then
pubkey=""
fi
if [ -z "$project" ] || [ -z "$pubkey" ]; then
echo '{"error":"deregister requires <project> <pubkey>"}'
exit 1
fi
do_deregister "$project"
do_deregister "$project" "$pubkey"
;;
list)
do_list