#!/bin/bash # omarchy:summary=Set up the OpenSSH server, open the firewall, and authorize an SSH key # omarchy:args=[--key=] [--gh-keys ] # omarchy:examples=omarchy-setup-security-sshd | omarchy-setup-security-sshd --gh-keys dhh | omarchy-setup-security-sshd --key="ssh-ed25519 AAAA... user@host" # omarchy:requires-sudo=true set -e AUTHORIZED_KEYS="$HOME/.ssh/authorized_keys" KEY="" GITHUB_USER="" # Checked while parsing, before anything is installed or opened: an empty or # option-shaped username otherwise falls through to the interactive menu having # already changed the machine, and `--gh-keys --help` would take --help as the # username and set the server up on its way to failing. require_github_user() { if [[ -z $1 || $1 == -* ]]; then echo "omarchy-setup-security-sshd: --gh-keys needs a GitHub username." >&2 exit 2 fi } while (( $# > 0 )); do case "$1" in --key=*) KEY="${1#--key=}" ;; --gh-keys=*) GITHUB_USER="${1#--gh-keys=}" require_github_user "$GITHUB_USER" ;; --gh-keys) shift GITHUB_USER="${1:-}" require_github_user "$GITHUB_USER" ;; -h | --help) echo "Usage: omarchy-setup-security-sshd [--key=] [--gh-keys ]" echo echo "Sets up the OpenSSH server, opens the SSH port in the UFW firewall," echo "and authorizes an SSH key (from GitHub, pasted, or passed via --key)." echo echo "Passing --key or --gh-keys skips the prompts, so the command can run" echo "unattended from a script or a fresh machine's first login." exit 0 ;; *) echo "omarchy-setup-security-sshd: unknown option '$1'. Try --help." >&2 exit 2 ;; esac shift done if [[ -n $KEY && -n $GITHUB_USER ]]; then echo "omarchy-setup-security-sshd: pass either --key or --gh-keys, not both." >&2 exit 2 fi setup_sshd() { echo "Installing and starting the OpenSSH server..." omarchy-pkg-add openssh sudo systemctl enable --now sshd.service } open_firewall() { if omarchy-cmd-missing ufw; then echo "UFW is not installed; skipping firewall rule." return fi echo "Opening the SSH port in the firewall (rate limited against brute force)..." sudo ufw limit 22/tcp comment "omarchy-sshd" >/dev/null sudo ufw reload >/dev/null } valid_key() { ssh-keygen -lf /dev/stdin <<<"$1" >/dev/null 2>&1 } authorize_key() { local key="$1" if ! valid_key "$key"; then echo -e "\e[31mNot a valid SSH public key: $key\e[0m" >&2 return 1 fi mkdir -p "$HOME/.ssh" chmod 700 "$HOME/.ssh" touch "$AUTHORIZED_KEYS" chmod 600 "$AUTHORIZED_KEYS" if grep -qxF "$key" "$AUTHORIZED_KEYS"; then echo "Key already authorized: $(ssh-keygen -lf /dev/stdin <<<"$key")" else echo "$key" >>"$AUTHORIZED_KEYS" echo "Authorized key: $(ssh-keygen -lf /dev/stdin <<<"$key")" fi } authorize_keys_from_github() { local username="$1" keys added=0 echo "Fetching keys from https://github.com/$username.keys..." if ! keys=$(curl -fsSL "https://github.com/$username.keys") || [[ -z $keys ]]; then echo -e "\e[31mCould not fetch any SSH keys for GitHub user '$username'.\e[0m" >&2 exit 1 fi while IFS= read -r key; do [[ -z $key ]] && continue authorize_key "$key" && added=$((added + 1)) done <<<"$keys" if (( added == 0 )); then echo -e "\e[31mNo valid SSH keys found for GitHub user '$username'.\e[0m" >&2 exit 1 fi } prompt_for_github_user() { local username username=$(gum input --prompt "GitHub username> " --placeholder "dhh") || exit 1 if [[ -z $username ]]; then echo -e "\e[31mNo GitHub username given.\e[0m" >&2 exit 1 fi authorize_keys_from_github "$username" } authorize_pasted_key() { local key key=$(gum input --prompt "Public key> " --placeholder "ssh-ed25519 AAAA... user@host") || exit 1 if [[ -z $key ]]; then echo -e "\e[31mNo SSH key given.\e[0m" >&2 exit 1 fi authorize_key "$key" || exit 1 } echo -e "\e[32mSetting up SSH server access with key-based authentication.\n\e[0m" setup_sshd open_firewall echo if [[ -n $KEY ]]; then authorize_key "$KEY" || exit 1 elif [[ -n $GITHUB_USER ]]; then authorize_keys_from_github "$GITHUB_USER" else case $(gum choose "Grab key from GitHub" "Paste key manually" --header "How would you like to add your SSH key?") in "Grab key from GitHub") prompt_for_github_user ;; "Paste key manually") authorize_pasted_key ;; *) exit 1 ;; esac fi echo -e "\e[32m\nPerfect! The SSH server is running and your key is authorized.\e[0m" echo "You can now connect with: ssh $USER@$(hostname)"