#!/usr/bin/env bash # # JbTecWiz Support Centre -- generated fix script # # Fault : "Permission denied (publickey)" # Fix : Work out what the client is doing before you lose the session # Source: https://jbtecwiz.com/support/lnx-ssh-publickey # # Run as : Shell on the client # Expect : 10 minutes # Risk : low # Reversible : yes # # WHEN THIS IS THE RIGHT FIX # No other access. Diagnose from the client first -- and if you have a # working session open anywhere, keep it open. # # HOW TO UNDO IT # None. # # Walks the fix one step at a time and asks before each. Steps with no # command are yours to do -- it prints those and waits. DRYRUN=1 prints # without executing; UNATTENDED=1 does not ask. # # -------------------------------------------------------------------- # NO WARRANTY - USE AT YOUR OWN RISK # # This script is provided by JbTecWiz as-is and with no warranty of any # kind, express or implied. You run it entirely at your own risk. # # JbTecWiz accepts no liability for any loss or damage arising from its # use, including but not limited to data loss, downtime, or configuration # changes that turn out to be wrong for your system. # # You are responsible for reading this script before running it, for # satisfying yourself that it suits the machine in front of you, and for # having a working backup first. Some steps cannot be undone. # -------------------------------------------------------------------- set -uo pipefail DRYRUN="${DRYRUN:-0}" UNATTENDED="${UNATTENDED:-0}" failed=0 rule() { printf "\n%s\n" "$(printf '-%.0s' $(seq 1 70))"; if [ $# -gt 0 ]; then echo "$1"; fi; } prose() { echo "$1" | fold -s -w 74 | sed "s/^/ /"; } # Returns 0 when the caller should run the command, 1 when it should not. # A manual step always returns 1 -- there is nothing for the caller to run. step() { # step [command lines...] local n="$1" dotext="$2" why="$3" mode="$4"; shift 4 rule " Step $n of 5" prose "$dotext" if [ -n "$why" ]; then echo; prose "$why"; fi if [ "$mode" = "manual" ]; then echo; echo " -> Do this yourself, then press Enter to carry on." if [ "$UNATTENDED" = "0" ] && [ "$DRYRUN" = "0" ]; then read -r _; fi return 1 fi echo; printf " %s\n" "$@"; echo if [ "$DRYRUN" = "1" ]; then echo " (dry run -- not executed)"; return 1; fi if [ "$UNATTENDED" = "0" ]; then read -r -p " Run this step? [Y]es / [S]kip / [Q]uit " a case "$a" in [Qq]*) echo " Stopped at your request."; exit 0 ;; [Ss]*) echo " Skipped."; return 1 ;; esac fi return 0 } rule echo " "Permission denied (publickey)"" echo " Work out what the client is doing before you lose the session" echo echo " Risk: low Reversible 10 minutes" echo prose 'No warranty. Use at your own risk - JbTecWiz accepts no liability. Read it before you run it, and have a backup.' rule echo if [ "$UNATTENDED" = "0" ] && [ "$DRYRUN" = "0" ]; then read -r -p " Ready? [y/N] " go case "$go" in [Yy]*) ;; *) echo " Nothing was changed."; exit 0;; esac fi if step 1 'Run with verbose output and read which keys are offered and how the server answers.' 'The '\''Offering public key'\'' lines tell you exactly what the client sent. If your intended key is not listed, the problem is entirely client-side.' cmd 'ssh -vvv user@host 2>&1 | grep -Ei '\''offering|authentications that can continue|no such|denied'\'''; then ssh -vvv user@host 2>&1 | grep -Ei 'offering|authentications that can continue|no such|denied' if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 1 failed. The rest of the fix may depend on it." >&2 fi fi if step 2 'Force the specific key and stop the agent offering others.' 'An agent with many keys can exhaust MaxAuthTries before reaching the right one, which the server reports as this same error.' cmd 'ssh -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes user@host'; then ssh -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes user@host if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 2 failed. The rest of the fix may depend on it." >&2 fi fi if step 3 'Check the local key permissions -- OpenSSH refuses to use a private key others can read.' '' cmd 'chmod 700 ~/.ssh && chmod 600 ~/.ssh/id_ed25519'; then chmod 700 ~/.ssh && chmod 600 ~/.ssh/id_ed25519 if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 3 failed. The rest of the fix may depend on it." >&2 fi fi if step 4 'Confirm the public key you think is installed matches the private key you are using.' '' cmd 'ssh-keygen -y -f ~/.ssh/id_ed25519 | awk '\''{print $1, $2}'\'''; then ssh-keygen -y -f ~/.ssh/id_ed25519 | awk '{print $1, $2}' if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 4 failed. The rest of the fix may depend on it." >&2 fi fi step 5 'Check you are connecting as the right user -- cloud images use ec2-user, ubuntu, admin or similar, not root.' '' manual || true rule " Confirm it worked" prose 'The connection succeeds.' rule if [ "$failed" -gt 0 ]; then echo " Finished with $failed failed step(s)." echo " Read the full write-up at https://jbtecwiz.com/support/lnx-ssh-publickey" else echo " Finished." fi echo prose 'To undo: None.' rule