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.
This commit is contained in:
+1
-7
@@ -75,13 +75,7 @@ if [[ $SETUP_EXIT -ne 0 ]]; then
|
|||||||
exit $SETUP_EXIT
|
exit $SETUP_EXIT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── 4. Strip key comments from authorized_keys ───────────────────────────────
|
# ── 4. Final status ──────────────────────────────────────────────────────────
|
||||||
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 ──────────────────────────────────────────────────────────
|
|
||||||
echo ""
|
echo ""
|
||||||
step "Deployment status"
|
step "Deployment status"
|
||||||
ssh -o StrictHostKeyChecking=no "$TARGET" \
|
ssh -o StrictHostKeyChecking=no "$TARGET" \
|
||||||
|
|||||||
+45
-16
@@ -1,8 +1,13 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Pre-configure an Armbian SD card before first boot.
|
# 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]
|
# 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
|
# MOUNT_POINT defaults to /mnt/opi
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -15,15 +20,20 @@ error() { echo -e "${RED}[-]${NC} $*"; exit 1; }
|
|||||||
|
|
||||||
SSID="${1:-}"
|
SSID="${1:-}"
|
||||||
PASSPHRASE="${2:-}"
|
PASSPHRASE="${2:-}"
|
||||||
MOUNT="${3:-/mnt/opi}"
|
DEVICE_ID="${3:-}"
|
||||||
|
MOUNT="${4:-/mnt/opi}"
|
||||||
|
|
||||||
[[ -z "$SSID" || -z "$PASSPHRASE" ]] && {
|
[[ -z "$SSID" || -z "$PASSPHRASE" || -z "$DEVICE_ID" ]] && {
|
||||||
echo "Usage: sudo $0 SSID PASSPHRASE [MOUNT_POINT]"
|
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
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
[[ -d "$MOUNT/etc" ]] || error "Mount point not valid: $MOUNT — is the SD card mounted?"
|
[[ -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 ──────────────────────────────────────────────────────────────────────
|
# ── WiFi ──────────────────────────────────────────────────────────────────────
|
||||||
NM_DIR="${MOUNT}/etc/NetworkManager/system-connections"
|
NM_DIR="${MOUNT}/etc/NetworkManager/system-connections"
|
||||||
NM_FILE="${NM_DIR}/wifi-bb.nmconnection"
|
NM_FILE="${NM_DIR}/wifi-bb.nmconnection"
|
||||||
@@ -61,20 +71,35 @@ sed -i "s|^root:[^:]*:|root:${HASH}:|" "${MOUNT}/etc/shadow"
|
|||||||
info "Root password set"
|
info "Root password set"
|
||||||
unset ROOT_PASS ROOT_PASS2
|
unset ROOT_PASS ROOT_PASS2
|
||||||
|
|
||||||
# ── SSH authorized_keys (comments stripped) ───────────────────────────────────
|
# ── Per-device SSH keypair ────────────────────────────────────────────────────
|
||||||
# Drop only the key material — no hostnames, usernames, or tool names in comments
|
# Generate fresh keypair — no operator keys, no identifying comments
|
||||||
if [[ -f "${HOME}/.ssh/authorized_keys" ]]; then
|
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"
|
SSH_DIR="${MOUNT}/root/.ssh"
|
||||||
mkdir -p "$SSH_DIR"
|
mkdir -p "$SSH_DIR"
|
||||||
# Strip comments: keep only type + base64 key, drop the comment field
|
echo "$PUBKEY" > "${SSH_DIR}/authorized_keys"
|
||||||
awk '{print $1, $2}' "${HOME}/.ssh/authorized_keys" > "${SSH_DIR}/authorized_keys"
|
|
||||||
chmod 700 "$SSH_DIR"
|
chmod 700 "$SSH_DIR"
|
||||||
chmod 600 "${SSH_DIR}/authorized_keys"
|
chmod 600 "${SSH_DIR}/authorized_keys"
|
||||||
KEY_COUNT=$(wc -l < "${SSH_DIR}/authorized_keys")
|
info "Per-device public key written to SD card (no operator keys present)"
|
||||||
info "Wrote ${KEY_COUNT} SSH key(s) (comments stripped)"
|
|
||||||
else
|
|
||||||
warn "No authorized_keys found at ${HOME}/.ssh/authorized_keys — SSH key auth will not work"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Hostname ──────────────────────────────────────────────────────────────────
|
# ── Hostname ──────────────────────────────────────────────────────────────────
|
||||||
echo "orangepi" > "${MOUNT}/etc/hostname"
|
echo "orangepi" > "${MOUNT}/etc/hostname"
|
||||||
@@ -86,4 +111,8 @@ info "First-login wizard disabled"
|
|||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
info "SD card ready. Unmount, insert, and power on."
|
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"
|
||||||
|
|||||||
Reference in New Issue
Block a user