Skip to content

ZlatanOmerovic/ssh-agent

Repository files navigation

SSH Agent Auto-Loader

Automatic SSH agent management and key loading for Windows (Git Bash), Linux, and macOS.

SSH Agent Auto-Loader

Features

Single SSH Agent - Only one ssh-agent runs regardless of how many terminal sessions you open ✅ Auto-Load Keys - Automatically loads all SSH private keys from ~/.ssh/Smart Agent Reuse - Detects and reuses existing agent across sessions ✅ Cross-Platform - Works on Windows (Git Bash), Linux (bash/zsh), and macOS (bash/zsh) ✅ macOS Keychain Integration - Optional integration with macOS Keychain for passphrase storage

Quick Start

Warning: The commands below append to your shell config. If you already have SSH agent management in your .bashrc/.zshrc, review for conflicts before sourcing.

Windows (Git Bash)

curl -fsSL https://raw.githubusercontent.com/ZlatanOmerovic/ssh-agent/master/.bashrc-windows-gitbash >> ~/.bashrc
source ~/.bashrc

Linux

For bash:

curl -fsSL https://raw.githubusercontent.com/ZlatanOmerovic/ssh-agent/master/.bashrc-linux >> ~/.bashrc
source ~/.bashrc

For zsh:

curl -fsSL https://raw.githubusercontent.com/ZlatanOmerovic/ssh-agent/master/.zshrc-linux >> ~/.zshrc
source ~/.zshrc

macOS

For zsh (default since macOS Catalina 10.15):

curl -fsSL https://raw.githubusercontent.com/ZlatanOmerovic/ssh-agent/master/.zshrc-macos >> ~/.zshrc
source ~/.zshrc

For bash:

curl -fsSL https://raw.githubusercontent.com/ZlatanOmerovic/ssh-agent/master/.bashrc-macos >> ~/.bashrc
source ~/.bashrc

Files Included

File Purpose
.bashrc-windows-gitbash For Windows Git Bash
.bashrc-linux For Linux systems (bash)
.zshrc-linux For Linux systems (zsh)
.bashrc-macos For macOS (bash) - includes Keychain integration
.zshrc-macos For macOS (zsh) - recommended for macOS
ssh-config-macos Optional SSH config for enhanced macOS Keychain integration

Detailed Installation

Prerequisites

  1. SSH directory must exist and have correct permissions:

    mkdir -p ~/.ssh
    chmod 700 ~/.ssh
  2. Private keys should have secure permissions:

    chmod 600 ~/.ssh/id_*
    chmod 600 ~/.ssh/*_rsa
    # Repeat for all your private keys

Installation Steps

1. Download and append the appropriate file for your OS/shell

Important: These commands append to your existing config — they will not overwrite your current .bashrc or .zshrc. If you prefer a clean install, back up your config first and use -o instead of >>.

# For Windows Git Bash
curl -fsSL https://raw.githubusercontent.com/ZlatanOmerovic/ssh-agent/master/.bashrc-windows-gitbash >> ~/.bashrc

# For Linux (bash)
curl -fsSL https://raw.githubusercontent.com/ZlatanOmerovic/ssh-agent/master/.bashrc-linux >> ~/.bashrc

# For Linux (zsh)
curl -fsSL https://raw.githubusercontent.com/ZlatanOmerovic/ssh-agent/master/.zshrc-linux >> ~/.zshrc

# For macOS with zsh (recommended)
curl -fsSL https://raw.githubusercontent.com/ZlatanOmerovic/ssh-agent/master/.zshrc-macos >> ~/.zshrc

# For macOS with bash
curl -fsSL https://raw.githubusercontent.com/ZlatanOmerovic/ssh-agent/master/.bashrc-macos >> ~/.bashrc

2. Load the configuration

# For bash
source ~/.bashrc

# For zsh
source ~/.zshrc

Or simply restart your terminal.

3. (Optional) macOS Keychain Integration

For automatic passphrase storage in macOS Keychain:

# Back up existing SSH config (if any)
[ -f ~/.ssh/config ] && cp ~/.ssh/config ~/.ssh/config.bak

# Download the SSH config
curl -fsSL -o ~/.ssh/config https://raw.githubusercontent.com/ZlatanOmerovic/ssh-agent/master/ssh-config-macos

# Set correct permissions
chmod 600 ~/.ssh/config

This enables:

  • Automatic passphrase storage in Keychain
  • Keys persist across reboots
  • No need to re-enter passphrases

How It Works

Key Loading Logic

The script automatically loads SSH keys from ~/.ssh/, excluding:

  • Directories (including the agent/ directory)
  • Files ending in .pub (public keys)
  • Files ending in .ppk (PuTTY format keys)
  • known_hosts and related files
  • config files
  • authorized_keys files
  • Log, backup, and text files (.log, .bak, .old, .txt)

Any remaining file is attempted with ssh-add. If it is not a valid key, it is silently skipped.

Agent Management

  1. First terminal session: Starts a new ssh-agent and loads all keys
  2. Subsequent sessions: Detects existing agent and reuses it
  3. After reboot: Starts fresh agent and reloads keys
  4. No duplicates: Only one ssh-agent process runs at a time
  5. Crash recovery: Detects dead/unresponsive agents and restarts automatically
  6. Corruption resistant: Handles corrupted or empty environment files gracefully

macOS Keychain Integration

The macOS versions include automatic detection and use of the --apple-use-keychain flag:

  • macOS 12.0+: Uses --apple-use-keychain flag
  • Older macOS: Falls back to standard ssh-add
  • Stores passphrases securely in macOS Keychain
  • Works with both bash and zsh versions

Verification

After installation, open a new terminal. You should see:

Starting new SSH agent...
  Added: id_ed25519
  Added: id_rsa

Open another terminal window - it should connect silently (agent already running).

To manually check loaded keys:

ssh-add -l

Customization

Show Loaded Keys on Startup

Uncomment these lines at the bottom of your .bashrc or .zshrc:

echo "Loaded SSH keys:"
ssh-add -l

Exclude Specific Key Files

Add patterns to the skip conditions in the load_ssh_keys function:

# Add to the existing case statement
case "$(basename "$key")" in
    known_hosts*|environment*|config*|authorized_keys*|*.log|*.bak|*.old|*.txt|my_special_key) continue ;;
esac

Load Keys from Additional Directories

Duplicate the for loop and change the path:

for key in ~/my-other-keys/*; do
    # ... same logic
done

Troubleshooting

Keys Not Loading

Check file permissions:

ls -la ~/.ssh/

Private keys should be -rw------- (600).

Verify keys are valid:

ssh-keygen -y -f ~/.ssh/your_key

Check for passphrase issues: If your keys have passphrases, you'll be prompted to enter them. On macOS, enable Keychain integration to store passphrases.

Multiple Agents Running

Kill all ssh-agent processes:

# Linux/macOS
pkill ssh-agent

# Windows Git Bash
taskkill /F /IM ssh-agent.exe

Remove environment file:

rm ~/.ssh/agent/environment

Restart terminal.

macOS Keychain Not Working

Ensure SSH config has correct permissions:

chmod 600 ~/.ssh/config

Manually add keys to Keychain:

ssh-add --apple-use-keychain ~/.ssh/id_ed25519

Verify Keychain integration:

ssh-add -l

Wrong Shell on macOS

Check your default shell:

echo $SHELL
  • If /bin/zsh: Use .zshrc-macos
  • If /bin/bash: Use .bashrc-macos

Change default shell to zsh (recommended):

chsh -s /bin/zsh

Compatibility

Operating Systems

  • ✅ Windows 10/11 with Git Bash
  • ✅ Linux (all distributions with bash/zsh)
  • ✅ macOS 10.15 Catalina and later

Shells

  • ✅ bash (all platforms)
  • ✅ zsh (macOS, Linux)
  • ⚠️ Other shells: May work but not tested

SSH Versions

  • ✅ OpenSSH 7.0+
  • ✅ OpenSSH 8.0+ (recommended for macOS Keychain support)

Testing

The project includes a full test suite that runs safely inside Docker — it will never touch your host machine's SSH config, keys, or agent.

Requirements

  • Docker installed and running

Run All Tests

./test/run-tests.sh

Run Tests for a Specific Shell

# Bash configs only (.bashrc-linux, .bashrc-macos, .bashrc-windows-gitbash)
./test/run-tests.sh bash

# Zsh configs only (.zshrc-linux, .zshrc-macos)
./test/run-tests.sh zsh

What's Tested

The test suite runs 11 tests per config across all 5 shell config variants (85 tests total):

Test Description
1 Start agent with no keys in ~/.ssh/
2 Start agent and load multiple keys (ed25519 + RSA)
3 Reuse existing agent across sessions (same PID, keys preserved)
4 Recover from agent crash (killed process, stale env file)
5 Handle corrupted environment file (no shell errors leaked)
6 Handle empty environment file
7 Detect stale PID after reboot (PID reused by another process)
8 Handle non-numeric PID in environment file
9 Reload keys after ssh-add -D (agent running but empty)
10 Skip non-key files (known_hosts, authorized_keys, .txt, .log, .bak)
11 No duplicate ssh-agent processes after repeated sourcing

Expected Output

╔══════════════════════════════════════════════════════════════╗
║  FINAL SUMMARY
╠══════════════════════════════════════════════════════════════╣
║  Suites passed: 5
║  Suites failed: 0
╚══════════════════════════════════════════════════════════════╝

Security Notes

  • Agent environment file is stored with 600 permissions (owner read/write only)
  • Private keys should always be 600 permissions
  • Public keys can be 644 permissions
  • On macOS, Keychain provides encrypted storage for passphrases
  • Never commit private keys to version control

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Reporting Issues

When reporting issues, please include:

  • Operating system and version
  • Shell type and version (bash --version or zsh --version)
  • SSH version (ssh -V)
  • Contents of ~/.ssh/ (filenames only, no keys!)
  • Error messages

License

MIT License - Feel free to use and modify as needed.

Acknowledgments

Inspired by the need for consistent SSH agent management across multiple platforms and terminal sessions.


Star this repo if you find it useful!