This guide sets up secure password-based SSH using your OS keyring.
No plaintext passwords, no hardcoding, works for multiple servers and any tool that calls SSH.
- Any SSH call prompts for a password
- SSH_ASKPASS calls
askpass.shwith the prompt - The script retrieves the password from the keyring and prints it
- SSH receives the password and logs in
- No plaintext storage; minimal memory exposure
Use secret-tool (Linux) to store each server password:
secret-tool store --label="server-1" host 192.168.1.10 user demo_userhost: server IP or hostnameuser: SSH login username
Check it:
secret-tool lookup host 192.168.1.10 user demo_userIt should print the password.
Create ~/.ssh/askpass.sh:
#!/usr/bin/env bash
prompt="$1"
user=""
host=""
# Only handle password prompts
if [[ ! "$prompt" =~ [Pp]assword:\ *$ ]]; then
echo "Unhandled prompt type" >&2
echo "SSH_ASKPASS script `$0` received an unhandled prompt." >&2
echo "The script is written to fetch passwords from OS Keyring, fallback to manual password prompting when not found." >&2
echo "It does NOT handle other scenarios, since SSH_ASKPASS is a one-line pipeline; SSH Prompt IN, Password Out." >&2
echo "To resolve this issue, you unset the following env variables TEMPORARILY:" >&2
echo "SSH_ASKPASS, SSH_ASKPASS_REQUIRE, DISPLAY" >&2
echo "Rerun the SSH command lead to unhandled scenario, then fix the problem." >&2
echo "After that, SSH_ASKPASS can handle password prompting automatically." >&2
exit 1
fi
# Parse user@host from prompt like "user@host's password: "
if [[ $prompt =~ ^([^@]+)@([^\'s]+) ]]; then
user="${BASH_REMATCH[1]}"
host="${BASH_REMATCH[2]}"
fi
# Fetch from keyring
password=$(secret-tool lookup host "$host" user "$user" 2>/dev/null)
if [[ -z "$password" ]]; then
# Always read from /dev/tty, never from stdin
echo "SSH_ASKPASS: Password not found in OS Keyring" >&2
read -r -s -p "Enter SSH password for $user@$host: " password < /dev/tty > /dev/tty
echo > /dev/tty
fi
echo "$password"Make it executable:
chmod 700 ~/.ssh/askpass.shAdd to your ~/.zshrc (or .bashrc):
export SSH_ASKPASS="$HOME/.ssh/askpass.sh"
export SSH_ASKPASS_REQUIRE=force
export DISPLAY=:0
# Set GIT_ASKPASS empty to prevent SSH_ASKPASS from interfering Git prompts
export GIT_ASKPASS=SSH_ASKPASS: path to the scriptSSH_ASKPASS_REQUIRE=force: forces usage even in terminalDISPLAY: required for SSH_ASKPASS (any value works)
ssh demo_user@192.168.1.10- Should log in automatically using the password from the keyring
secret-tool store --label="server-2" host 192.168.1.11 user demo_user- The same
askpass.shscript works for multiple servers - No changes needed in the script for additional hosts
- The script works as long as SSH attempts the correct username. However, connecting to new hosts for the first time breaks this script because SSH may prompt you to type
yes/noto add the key. - A workaound is to add the hosts to
~/.ssh/configas shown below:# Local LAN ranges - auto-accept new host keys Host 192.168.* StrictHostKeyChecking accept-new # Everything else - strict (default) Host * StrictHostKeyChecking yes
✅ Security notes
- Passwords are encrypted in the OS keyring
- No plaintext files or hardcoded passwords
- Works safely for multiple servers and multiple users
- Fully compatible with terminal SSH calls or tools that invoke SSH under the hood