#!/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_ (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"