clawdie-iso/firstboot/shell-ssh.sh
Sam & Claude ae11ae03ff firstboot: Add shell-ssh.sh module and restore shell-system.sh
- Create new shell-ssh.sh module for SSH key installation and password setup
  * Install SSH public keys to authorized_keys (root + clawdie)
  * Configure sshd: disable password auth if key provided, enable if not
  * Set system user passwords (auto-generate or use provided)
  * Save emergency root password to root/.firstboot-emergency-password
- Restore shell-system.sh (was accidentally overwritten during rename)

Enables secure SSH-key-first access with password fallback.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-24 07:45:50 +00:00

260 lines
7.9 KiB
Bash

#!/bin/sh
# Clawdie Shell — SSH & System User Password Module
# Purpose: Configure SSH keys and system user passwords
# Author: Clawdie Project
# POSIX-compliant (no bash-isms)
set -eu
# Configuration (can be overridden for testing)
LOG_FILE="${LOG_FILE:-/var/log/clawdie-firstboot.log}"
PROGRESS_FILE="${PROGRESS_FILE:-/var/log/clawdie-firstboot.progress}"
EMERGENCY_PASSWORD_FILE="${EMERGENCY_PASSWORD_FILE:-/root/.firstboot-emergency-password}"
# Derived from wizard/build inputs (caller sets these)
# SSH_PUBLIC_KEY - Optional SSH public key (ssh-ed25519 or ssh-rsa)
# ROOT_PASSWORD - Optional root password (if empty, auto-generate)
# CLAWDIE_USER_PASSWORD - Optional clawdie user password (if empty, auto-generate)
# ============================================================================
# MAIN ENTRY POINT
# ============================================================================
clawdie_shell_ssh_setup() {
# Main orchestrator
# 1. Configure SSH keys (if provided)
# 2. Set system passwords (if provided or auto-generate)
# 3. Configure SSH auth methods (key-only or key+password)
log_msg "[ssh] Starting SSH and password setup"
# Generate emergency root password if not provided
if [ -z "${ROOT_PASSWORD:-}" ]; then
ROOT_PASSWORD=$(gen_secret)
fi
# Generate clawdie user password if not provided
if [ -z "${CLAWDIE_USER_PASSWORD:-}" ]; then
CLAWDIE_USER_PASSWORD=$(gen_secret)
fi
# Setup SSH keys if provided
if [ -n "${SSH_PUBLIC_KEY:-}" ]; then
clawdie_shell_ssh_install_pubkey
clawdie_shell_ssh_disable_password_auth
log_msg "[ssh] SSH public key installed, password auth disabled"
else
clawdie_shell_ssh_enable_password_auth
log_msg "[ssh] No SSH key provided, password auth enabled (less secure)"
fi
# Set system user passwords
clawdie_shell_ssh_set_passwords "$ROOT_PASSWORD" "$CLAWDIE_USER_PASSWORD"
log_msg "[ssh] System user passwords set"
# Save emergency root password to file
clawdie_shell_ssh_save_emergency_password "$ROOT_PASSWORD"
log_msg "[ssh] Emergency root password saved"
echo "[SSH] COMPLETE" >> "$PROGRESS_FILE"
log_msg "[ssh] SSH setup complete"
}
# ============================================================================
# SSH PUBLIC KEY INSTALLATION
# ============================================================================
clawdie_shell_ssh_install_pubkey() {
# Install SSH_PUBLIC_KEY to authorized_keys for both root and clawdie user
local root_ssh_dir="/root/.ssh"
local clawdie_ssh_dir="/home/clawdie/.ssh"
# Setup root authorized_keys
if [ ! -d "$root_ssh_dir" ]; then
mkdir -p "$root_ssh_dir"
chmod 700 "$root_ssh_dir"
fi
echo "$SSH_PUBLIC_KEY" >> "$root_ssh_dir/authorized_keys" 2>/dev/null || {
log_msg "[ssh] ERROR: Failed to install SSH key for root"
return 1
}
chmod 600 "$root_ssh_dir/authorized_keys"
log_msg "[ssh] Installed SSH key for root user"
# Setup clawdie authorized_keys
if [ ! -d "$clawdie_ssh_dir" ]; then
mkdir -p "$clawdie_ssh_dir"
chmod 700 "$clawdie_ssh_dir"
fi
echo "$SSH_PUBLIC_KEY" >> "$clawdie_ssh_dir/authorized_keys" 2>/dev/null || {
log_msg "[ssh] ERROR: Failed to install SSH key for clawdie"
return 1
}
chmod 600 "$clawdie_ssh_dir/authorized_keys"
chown -R clawdie:clawdie "$clawdie_ssh_dir"
log_msg "[ssh] Installed SSH key for clawdie user"
return 0
}
# ============================================================================
# SSH AUTH METHOD CONFIGURATION
# ============================================================================
clawdie_shell_ssh_disable_password_auth() {
# Disable password authentication in sshd_config
# Keep PubkeyAuthentication enabled
local sshd_config="/etc/ssh/sshd_config"
if [ ! -f "$sshd_config" ]; then
log_msg "[ssh] WARNING: sshd_config not found"
return 1
fi
# Ensure PubkeyAuthentication is enabled
if grep -q "^#*PubkeyAuthentication" "$sshd_config"; then
sed -i '' 's/^#*PubkeyAuthentication.*/PubkeyAuthentication yes/' "$sshd_config"
else
echo "PubkeyAuthentication yes" >> "$sshd_config"
fi
# Disable PasswordAuthentication
if grep -q "^#*PasswordAuthentication" "$sshd_config"; then
sed -i '' 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' "$sshd_config"
else
echo "PasswordAuthentication no" >> "$sshd_config"
fi
# Disable PermitRootLogin with password (allow pubkey only)
if grep -q "^#*PermitRootLogin" "$sshd_config"; then
sed -i '' 's/^#*PermitRootLogin.*/PermitRootLogin prohibit-password/' "$sshd_config"
else
echo "PermitRootLogin prohibit-password" >> "$sshd_config"
fi
log_msg "[ssh] Disabled password auth in sshd_config"
return 0
}
clawdie_shell_ssh_enable_password_auth() {
# Enable password authentication in sshd_config (fallback)
# Less secure but prevents lockout if user loses SSH key
local sshd_config="/etc/ssh/sshd_config"
if [ ! -f "$sshd_config" ]; then
log_msg "[ssh] WARNING: sshd_config not found"
return 1
fi
# Enable PasswordAuthentication
if grep -q "^#*PasswordAuthentication" "$sshd_config"; then
sed -i '' 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' "$sshd_config"
else
echo "PasswordAuthentication yes" >> "$sshd_config"
fi
# Allow root login with password
if grep -q "^#*PermitRootLogin" "$sshd_config"; then
sed -i '' 's/^#*PermitRootLogin.*/PermitRootLogin yes/' "$sshd_config"
else
echo "PermitRootLogin yes" >> "$sshd_config"
fi
log_msg "[ssh] WARNING: Password auth enabled (less secure)"
return 0
}
# ============================================================================
# PASSWORD MANAGEMENT
# ============================================================================
clawdie_shell_ssh_set_passwords() {
local root_pwd="$1"
local clawdie_pwd="$2"
# Set root password using echo | pw usermod
echo "$root_pwd" | pw usermod root -h 0 2>/dev/null || {
log_msg "[ssh] ERROR: Failed to set root password"
return 1
}
log_msg "[ssh] Root password set"
# Set clawdie user password
# Create user if it doesn't exist
if ! id clawdie >/dev/null 2>&1; then
pw useradd -n clawdie -u 1000 -g wheel -m -s /bin/sh 2>/dev/null || {
log_msg "[ssh] ERROR: Failed to create clawdie user"
return 1
}
log_msg "[ssh] Created clawdie user"
fi
echo "$clawdie_pwd" | pw usermod clawdie -h 0 2>/dev/null || {
log_msg "[ssh] ERROR: Failed to set clawdie password"
return 1
}
log_msg "[ssh] Clawdie user password set"
return 0
}
clawdie_shell_ssh_save_emergency_password() {
local root_pwd="$1"
# Save emergency password to file (root-only, readable only by root)
{
echo "EMERGENCY ROOT PASSWORD"
echo "=============================="
echo ""
echo "Generated at: $(date)"
echo "Password: $root_pwd"
echo ""
echo "Access:"
echo " ssh root@<domain>"
echo ""
echo "WARNING: Store this securely."
echo "This file should be moved to secure storage and deleted from this system."
} > "$EMERGENCY_PASSWORD_FILE" 2>/dev/null || {
log_msg "[ssh] WARNING: Could not save emergency password file"
return 1
}
chmod 600 "$EMERGENCY_PASSWORD_FILE"
log_msg "[ssh] Emergency password saved to $EMERGENCY_PASSWORD_FILE"
return 0
}
# ============================================================================
# UTILITY: Logging & Secret Generation
# ============================================================================
log_msg() {
local msg="$1"
echo "$msg" >> "$LOG_FILE" 2>/dev/null || true
}
gen_secret() {
openssl rand -base64 32 | tr -d '\n/+=' | head -c 32
}
# ============================================================================
# Export for use by firstboot.sh
# ============================================================================
case "${0##*/}" in
shell-ssh.sh)
# Direct execution (for testing)
clawdie_shell_ssh_setup
;;
*)
# Sourced from another script — functions available
;;
esac