diff --git a/bin/omarchy-remove-security-sshd b/bin/omarchy-remove-security-sshd new file mode 100755 index 00000000..3106c89e --- /dev/null +++ b/bin/omarchy-remove-security-sshd @@ -0,0 +1,32 @@ +#!/bin/bash + +# omarchy:summary=Disable the OpenSSH server, close the firewall port, and optionally remove authorized keys +# omarchy:requires-sudo=true + +set -e + +AUTHORIZED_KEYS="$HOME/.ssh/authorized_keys" + +echo -e "\e[32mRemoving SSH server access.\n\e[0m" + +echo "Stopping and disabling the OpenSSH server..." +sudo systemctl disable --now sshd.service 2>/dev/null || true + +if omarchy-cmd-present ufw; then + echo "Closing the SSH port in the firewall..." + sudo ufw --force delete limit 22/tcp >/dev/null 2>&1 || true + sudo ufw reload >/dev/null +fi + +if [[ -s $AUTHORIZED_KEYS ]]; then + echo + if gum confirm "Also remove all authorized SSH keys ($AUTHORIZED_KEYS)?"; then + rm -f "$AUTHORIZED_KEYS" + echo "Authorized keys removed." + else + echo "Keeping authorized keys." + fi +fi + +echo -e "\e[32m\nThe SSH server has been disabled and its firewall port closed.\e[0m" +echo "The openssh package remains installed since it also provides the ssh client." diff --git a/bin/omarchy-setup-security-sshd b/bin/omarchy-setup-security-sshd new file mode 100755 index 00000000..907bc021 --- /dev/null +++ b/bin/omarchy-setup-security-sshd @@ -0,0 +1,127 @@ +#!/bin/bash + +# omarchy:summary=Set up the OpenSSH server, open the firewall, and authorize an SSH key +# omarchy:args=[--key=] +# omarchy:examples=omarchy-setup-security-sshd | omarchy-setup-security-sshd --key="ssh-ed25519 AAAA... user@host" +# omarchy:requires-sudo=true + +set -e + +AUTHORIZED_KEYS="$HOME/.ssh/authorized_keys" +KEY="" + +for arg in "$@"; do + case "$arg" in + --key=*) KEY="${arg#--key=}" ;; + -h | --help) + echo "Usage: omarchy-setup-security-sshd [--key=]" + 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)." + exit 0 + ;; + *) + echo "omarchy-setup-security-sshd: unknown option '$arg'. Try --help." >&2 + exit 2 + ;; + esac +done + +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 keys added=0 + + 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 + + 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 -eq 0 ]]; then + echo -e "\e[31mNo valid SSH keys found for GitHub user '$username'.\e[0m" >&2 + exit 1 + fi +} + +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 +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") authorize_keys_from_github ;; + "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)" diff --git a/default/omarchy/omarchy-menu.jsonc b/default/omarchy/omarchy-menu.jsonc index a3bb097f..7461dcdd 100644 --- a/default/omarchy/omarchy-menu.jsonc +++ b/default/omarchy/omarchy-menu.jsonc @@ -142,10 +142,11 @@ "setup.default.editor.helix": {"icon":"","label":"Helix","when":"omarchy-cmd-present helix","checked":"[[ \"$(omarchy-default-editor)\" == \"helix\" ]]","action":"omarchy-default-editor helix"}, "setup.default.editor.vim": {"icon":"","label":"Vim","when":"omarchy-cmd-present vim","checked":"[[ \"$(omarchy-default-editor)\" == \"vim\" ]]","action":"omarchy-default-editor vim"}, "setup.default.editor.emacs": {"icon":"","label":"Emacs","when":"omarchy-cmd-present emacs","checked":"[[ \"$(omarchy-default-editor)\" == \"emacs\" ]]","action":"omarchy-default-editor emacs"}, - "setup.security": {"icon":"","label":"Security","keywords":"fingerprint fido2"}, + "setup.security": {"icon":"","label":"Security","keywords":"fingerprint fido2 ssh sshd"}, "setup.config": {"icon":"","label":"Config","keywords":"files hyprland bar quickshell"}, "setup.security.fingerprint": {"icon":"󰈷","label":"Fingerprint","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-security-fingerprint"}, "setup.security.fido2": {"icon":"","label":"Fido2","keywords":"key","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-security-fido2"}, + "setup.security.sshd": {"icon":"󰣀","label":"SSHD","keywords":"ssh server remote key","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-security-sshd"}, "setup.config.hyprland": {"icon":"","label":"Hyprland","action":"omarchy-launch-config-editor \"$HOME/.config/hypr/hyprland.lua\""}, "setup.config.hyprsunset": {"icon":"","label":"Hyprsunset","keywords":"night light","action":"omarchy-launch-config-editor ~/.config/hypr/hyprsunset.conf && omarchy-restart-hyprsunset"}, "setup.config.xcompose": {"icon":"󰞅","label":"XCompose","keywords":"compose key","action":"omarchy-launch-config-editor ~/.XCompose && omarchy-restart-xcompose"}, @@ -239,9 +240,10 @@ "remove.service": {"icon":"","label":"Services","keywords":"uninstall dropbox tailscale vpn","when":"omarchy-pkg-present dropbox || omarchy-pkg-present tailscale"}, "remove.windows": {"icon":"󰍲","label":"Windows","keywords":"uninstall vm","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-windows-vm remove'"}, "remove.preinstalls": {"icon":"󰏓","label":"Preinstalls","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-preinstalls"}, - "remove.security": {"icon":"","label":"Security","keywords":"fingerprint fido2"}, + "remove.security": {"icon":"","label":"Security","keywords":"fingerprint fido2 ssh sshd"}, "remove.security.fingerprint": {"icon":"󰈷","label":"Fingerprint","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-security-fingerprint"}, "remove.security.fido2": {"icon":"","label":"Fido2","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-security-fido2"}, + "remove.security.sshd": {"icon":"󰣀","label":"SSHD","keywords":"ssh server remote","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-security-sshd"}, "remove.browser.chrome": {"icon":"","label":"Chrome","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-remove-browser chrome'"}, "remove.browser.edge": {"icon":"","label":"Edge","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-remove-browser edge'"}, "remove.browser.brave": {"icon":"","label":"Brave","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-remove-browser brave'"},