Files
bigbrother/scripts/preconfig_sd.sh
T
Cobra e1f937f42c 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_<ID>), public key
to the SD card only. No operator keys or identifying comments on device.
2026-04-07 13:42:45 -04:00

119 lines
4.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# Pre-configure an Armbian SD card before first boot.
# Handles: WiFi, root password, per-device SSH keypair, hostname, wizard bypass.
#
# 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'
info() { echo -e "${GREEN}[+]${NC} $*"; }
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
error() { echo -e "${RED}[-]${NC} $*"; exit 1; }
[[ $EUID -eq 0 ]] || error "Must run as root (sudo)"
SSID="${1:-}"
PASSPHRASE="${2:-}"
DEVICE_ID="${3:-}"
MOUNT="${4:-/mnt/opi}"
[[ -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"
mkdir -p "$NM_DIR"
cat > "$NM_FILE" << EOF
[connection]
id=wifi-bb
type=wifi
autoconnect=true
[wifi]
mode=infrastructure
ssid=${SSID}
[wifi-security]
auth-alg=open
key-mgmt=wpa-psk
psk=${PASSPHRASE}
[ipv4]
method=auto
[ipv6]
method=disabled
EOF
chmod 600 "$NM_FILE"
info "WiFi profile written (${SSID})"
# ── Root password ─────────────────────────────────────────────────────────────
read -s -r -p "New root password: " ROOT_PASS; echo
read -s -r -p "Confirm: " ROOT_PASS2; echo
[[ "$ROOT_PASS" == "$ROOT_PASS2" ]] || error "Passwords do not match"
HASH=$(openssl passwd -6 "$ROOT_PASS")
sed -i "s|^root:[^:]*:|root:${HASH}:|" "${MOUNT}/etc/shadow"
info "Root password set"
unset ROOT_PASS ROOT_PASS2
# ── 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_<DEVICE_ID> (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
# 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"
info "Hostname set to: orangepi"
# ── Bypass first-login wizard ─────────────────────────────────────────────────
rm -f "${MOUNT}/root/.not_logged_in_yet"
info "First-login wizard disabled"
echo ""
info "SD card ready. Unmount, insert, and power on."
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"