From e1f937f42c0b119ad1b59451e99e43529b2ce396 Mon Sep 17 00:00:00 2001 From: Cobra Date: Tue, 7 Apr 2026 13:42:45 -0400 Subject: [PATCH] Generate per-device SSH keypair instead of copying operator keys Each device gets a unique ed25519 keypair generated at preconfig time. Private key goes to Infisical (bigbrother/SSH_PRIVKEY_), public key to the SD card only. No operator keys or identifying comments on device. --- scripts/deploy.sh | 8 +---- scripts/preconfig_sd.sh | 67 +++++++++++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/scripts/deploy.sh b/scripts/deploy.sh index d92b0e7..8f4d5ac 100644 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -75,13 +75,7 @@ if [[ $SETUP_EXIT -ne 0 ]]; then exit $SETUP_EXIT fi -# ── 4. Strip key comments from authorized_keys ─────────────────────────────── -step "Stripping SSH key comments (OPSEC)..." -ssh -o StrictHostKeyChecking=no "$TARGET" \ - "awk '{print \$1, \$2}' /root/.ssh/authorized_keys > /tmp/.ak_clean && mv /tmp/.ak_clean /root/.ssh/authorized_keys && chmod 600 /root/.ssh/authorized_keys" 2>/dev/null || true -info "Key comments stripped" - -# ── 5. Final status ────────────────────────────────────────────────────────── +# ── 4. Final status ────────────────────────────────────────────────────────── echo "" step "Deployment status" ssh -o StrictHostKeyChecking=no "$TARGET" \ diff --git a/scripts/preconfig_sd.sh b/scripts/preconfig_sd.sh index e33f77a..b931216 100755 --- a/scripts/preconfig_sd.sh +++ b/scripts/preconfig_sd.sh @@ -1,9 +1,14 @@ #!/usr/bin/env bash # Pre-configure an Armbian SD card before first boot. -# Handles: WiFi, root password, SSH keys (comments stripped), hostname, wizard bypass. +# Handles: WiFi, root password, per-device SSH keypair, hostname, wizard bypass. # -# Usage: sudo bash scripts/preconfig_sd.sh SSID PASSPHRASE [MOUNT_POINT] -# MOUNT_POINT defaults to /mnt/opi +# Generates a fresh ed25519 keypair unique to this device. +# Private key is stored in Infisical under /bigbrother/DEVICE_ID. +# Public key is written to the SD card — no operator keys touch the device. +# +# Usage: sudo bash scripts/preconfig_sd.sh SSID PASSPHRASE DEVICE_ID [MOUNT_POINT] +# DEVICE_ID short identifier for this unit (e.g. bb-01, drop-lab) +# MOUNT_POINT defaults to /mnt/opi set -euo pipefail RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' @@ -15,15 +20,20 @@ error() { echo -e "${RED}[-]${NC} $*"; exit 1; } SSID="${1:-}" PASSPHRASE="${2:-}" -MOUNT="${3:-/mnt/opi}" +DEVICE_ID="${3:-}" +MOUNT="${4:-/mnt/opi}" -[[ -z "$SSID" || -z "$PASSPHRASE" ]] && { - echo "Usage: sudo $0 SSID PASSPHRASE [MOUNT_POINT]" +[[ -z "$SSID" || -z "$PASSPHRASE" || -z "$DEVICE_ID" ]] && { + echo "Usage: sudo $0 SSID PASSPHRASE DEVICE_ID [MOUNT_POINT]" + echo " DEVICE_ID short label for this unit stored in Infisical (e.g. bb-01)" exit 1 } [[ -d "$MOUNT/etc" ]] || error "Mount point not valid: $MOUNT — is the SD card mounted?" +CREDS="${HOME}/.local/bin/creds" +[[ -x "$CREDS" ]] || error "creds CLI not found at $CREDS — cannot store key in Infisical" + # ── WiFi ────────────────────────────────────────────────────────────────────── NM_DIR="${MOUNT}/etc/NetworkManager/system-connections" NM_FILE="${NM_DIR}/wifi-bb.nmconnection" @@ -61,20 +71,35 @@ sed -i "s|^root:[^:]*:|root:${HASH}:|" "${MOUNT}/etc/shadow" info "Root password set" unset ROOT_PASS ROOT_PASS2 -# ── SSH authorized_keys (comments stripped) ─────────────────────────────────── -# Drop only the key material — no hostnames, usernames, or tool names in comments -if [[ -f "${HOME}/.ssh/authorized_keys" ]]; then - SSH_DIR="${MOUNT}/root/.ssh" - mkdir -p "$SSH_DIR" - # Strip comments: keep only type + base64 key, drop the comment field - awk '{print $1, $2}' "${HOME}/.ssh/authorized_keys" > "${SSH_DIR}/authorized_keys" - chmod 700 "$SSH_DIR" - chmod 600 "${SSH_DIR}/authorized_keys" - KEY_COUNT=$(wc -l < "${SSH_DIR}/authorized_keys") - info "Wrote ${KEY_COUNT} SSH key(s) (comments stripped)" +# ── Per-device SSH keypair ──────────────────────────────────────────────────── +# Generate fresh keypair — no operator keys, no identifying comments +TMP_KEY=$(mktemp) +ssh-keygen -t ed25519 -N "" -C "" -f "$TMP_KEY" -q +PRIVKEY=$(cat "$TMP_KEY") +PUBKEY=$(cat "${TMP_KEY}.pub") +rm -f "$TMP_KEY" "${TMP_KEY}.pub" + +# Store private key in Infisical under bigbrother/DEVICE_ID +# Key name: SSH_PRIVKEY_ (uppercase, hyphens to underscores) +INFISICAL_KEY="SSH_PRIVKEY_$(echo "$DEVICE_ID" | tr '[:lower:]-' '[:upper:]_')" +if "$CREDS" set "$INFISICAL_KEY" "$PRIVKEY" bigbrother 2>/dev/null; then + info "Private key stored in Infisical: bigbrother/${INFISICAL_KEY}" else - warn "No authorized_keys found at ${HOME}/.ssh/authorized_keys — SSH key auth will not work" + # Fallback: print key and warn — operator must store it manually + warn "Could not store key in Infisical. SAVE THIS PRIVATE KEY NOW:" + echo "------" + echo "$PRIVKEY" + echo "------" fi +unset PRIVKEY + +# Write only the public key to the device +SSH_DIR="${MOUNT}/root/.ssh" +mkdir -p "$SSH_DIR" +echo "$PUBKEY" > "${SSH_DIR}/authorized_keys" +chmod 700 "$SSH_DIR" +chmod 600 "${SSH_DIR}/authorized_keys" +info "Per-device public key written to SD card (no operator keys present)" # ── Hostname ────────────────────────────────────────────────────────────────── echo "orangepi" > "${MOUNT}/etc/hostname" @@ -86,4 +111,8 @@ info "First-login wizard disabled" echo "" info "SD card ready. Unmount, insert, and power on." -info "Once booted: bash scripts/deploy.sh root@10.0.0.0 --enable-service" +info "To connect after boot:" +info " ${CREDS} get ${INFISICAL_KEY} bigbrother > /tmp/bb-${DEVICE_ID}.key" +info " chmod 600 /tmp/bb-${DEVICE_ID}.key" +info " ssh -i /tmp/bb-${DEVICE_ID}.key root@10.0.0.0" +info "To deploy: bash scripts/deploy.sh root@10.0.0.0 --enable-service"