Categories DevOps

Mastering SSH: Keys, Tunnels, and SSH-Agent

Introduction

Secure Shell (SSH) has become the backbone of secure remote system administration and data communication. Whether you’re a developer, system administrator, or DevOps engineer, understanding SSH is crucial for secure and efficient remote operations. This comprehensive guide will walk you through the essential components of SSH: keys, tunnels, and the SSH agent.

In this blog post, you’ll learn how to:

  • Create and manage SSH keys for secure authentication
  • Set up and use SSH tunnels for secure network connections
  • Leverage ssh-agent to manage your SSH keys efficiently

Getting Started with SSH Keys

Understanding SSH Key Pairs

SSH keys provide a more secure alternative to password-based authentication. Each SSH key pair consists of two parts:

  • A private key (kept secret on your local machine)
  • A public key (shared with remote servers)

Modern SSH implementations support several key types, with ED25519 being the current recommended standard due to its strong security and performance characteristics. RSA keys are also widely used, particularly when compatibility with older systems is required.

SSH keys are typically stored in the ~/.ssh directory on Unix-based systems, with standard naming conventions for different key types.

Creating Your First SSH Key Pair

To create a new SSH key pair, use the ssh-keygen command. Here’s how to generate an ED25519 key:

ssh-keygen -t ed25519 -C "your_email@example.com"

The command will produce output similar to:

Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/username/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/username/.ssh/id_ed25519
Your public key has been saved in /home/username/.ssh/id_ed25519.pub

Setting Up Keys for Remote Access

Once you’ve generated your key pair, you’ll need to copy the public key to any remote servers you want to access. The simplest way is using the ssh-copy-id command:

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@remote-host

Mastering SSH-Agent

What is ssh-agent?

SSH-agent is a key manager that holds your private keys in memory, making it convenient to use SSH keys with passphrases without having to re-enter the passphrase every time. It’s particularly useful when you:

  • Use multiple SSH keys
  • Have keys protected with passphrases
  • Need to maintain multiple secure connections

Starting and Using ssh-agent

To start ssh-agent and add your keys:

eval $(ssh-agent -s)
ssh-add ~/.ssh/id_ed25519

To list all keys currently managed by the agent:

ssh-add -l

SSH-Agent Configuration

Configure ssh-agent behavior in your ~/.ssh/config file:

Host *
    AddKeysToAgent yes
    UseKeychain yes
    IdentityFile ~/.ssh/id_ed25519

Understanding SSH Tunnels

Types of SSH Tunnels

Local Port Forwarding

Local port forwarding allows you to forward a port from your local machine to a remote server:

ssh -L 8080:localhost:80 user@remote-host

This command:

  1. Creates an SSH connection to remote-host as user
  2. Forwards connections to your local port 8080
  3. Through the SSH tunnel to remote-host
  4. And finally to port 80 on localhost relative to remote-host

This is useful for:

  • Accessing remote web interfaces securely
  • Connecting to database servers through SSH
  • Bypassing network restrictions

Remote Port Forwarding

Remote port forwarding works in the opposite direction:

ssh -R 8080:localhost:80 user@remote-host

This command:

  1. Creates an SSH connection to remote-host as user
  2. Opens port 8080 on remote-host
  3. Forwards incoming connections to that port
  4. Through the SSH tunnel back to your machine
  5. And finally to localhost:80 on your local machine

Common applications include:

  • Sharing local development servers
  • Providing temporary access to internal services
  • Remote support scenarios
  • Working around NAT or firewall restrictions

Dynamic Port Forwarding

Create a SOCKS proxy for flexible traffic routing:

ssh -D 9090 user@remote-host

This creates a SOCKS proxy server on your local machine that routes traffic through your SSH connection. Configure applications (like browsers) to use this proxy:

  1. Browser → Local port 9090 → SSH tunnel → remote-host → Internet

This provides benefits like:

  • Browsing the web via the remote server’s network location
  • Accessing internal networks securely through a jump host
  • Encrypting all your application traffic over untrusted networks
  • Bypassing geographic restrictions or network filtering

SSH Configuration Best Practices

Client-side Configuration

A well-organized ~/.ssh/config can significantly improve your SSH workflow:

Host github
    HostName github.com
    User git
    IdentityFile ~/.ssh/github_ed25519
Host production
    HostName prod.example.com
    User admin
    IdentityFile ~/.ssh/prod_ed25519

Security Considerations

When managing SSH keys and configurations, follow these essential security practices:

  • Use strong passphrases for private keys
  • Never share or expose private keys
  • Regularly rotate keys, especially for critical systems
  • Monitor and audit SSH access logs
  • Disable password authentication when possible

Troubleshooting Common Issues

Permission Problems

Common SSH permission errors and their solutions:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

This error occurs when your private key file has permissions that are too permissive. SSH requires strict permissions to ensure only you can access your private keys. Fix with:

chmod 600 ~/.ssh/id_ed25519  # Makes the file readable/writable only by you
chmod 700 ~/.ssh             # Makes the directory accessible only by you

Other common permission issues:

  • Bad owner or permissions on ~/.ssh/config: Fix with chmod 600 ~/.ssh/config
  • Authentication refused: bad ownership or modes for directory: Ensure parent directories aren’t group-writable
  • Operation not permitted: On some systems, you may need to fix ownership with chown user:user ~/.ssh/id_ed25519

Connection Issues

When troubleshooting connection problems, use verbose mode with increasing levels of detail:

ssh -v user@hostname     # Single -v for basic verbosity
ssh -vv user@hostname    # Double -v for more detailed output
ssh -vvv user@hostname   # Triple -v for maximum debugging information

This provides detailed output about:

  • Authentication attempts (which keys are being tried)
  • Key usage and negotiation
  • Protocol negotiation steps
  • Connection establishment details
  • Host key verification

Common connection errors and solutions:

ErrorPossible Solution
Connection refusedCheck if SSH server is running and port is correct
Host key verification failedRemove old key with ssh-keygen -R hostname
Permission denied (publickey)Verify your public key is in remote’s authorized_keys
Connection timed outCheck network connectivity and firewall rules

To determine if the problem is with SSH or the network, try testing basic connectivity:

ping remote-host
telnet remote-host 22
nc -zv remote-host 22

Common agent issues can be diagnosed with:

ssh-add -l              # Lists keys currently in ssh-agent
echo $SSH_AUTH_SOCK     # Verifies the SSH agent socket path is set correctly
ps aux | grep ssh-agent # Confirms ssh-agent is running

Typical solutions include:

  • Restarting ssh-agent: eval $(ssh-agent -s)
  • Checking environment variables: env | grep SSH
  • Verifying key permissions: ls -la ~/.ssh/
  • Manually adding keys: ssh-add ~/.ssh/id_ed25519
  • For MacOS: ssh-add --apple-use-keychain ~/.ssh/id_ed25519

If keys aren’t being remembered between sessions, ensure your shell configuration (e.g., ~/.bashrc or ~/.zshrc) is properly starting ssh-agent and adding keys:

# Add to your .bashrc or .zshrc
if [ -z "$SSH_AUTH_SOCK" ]; then
    eval $(ssh-agent -s)
    ssh-add ~/.ssh/id_ed25519 2>/dev/null
fi

When ssh-agent refuses to add a key, check:

  • Key file permissions
  • Passphrase correctness
  • Key format compatibility
  • System ssh-agent limitations

Advanced Tips and Tricks

Time-saving Configurations

Create helpful aliases in your shell configuration:

alias ssh-list='ssh-add -l'
alias ssh-reload='eval $(ssh-agent -s) && ssh-add'

Advanced SSH config options:

Host *
    ServerAliveInterval 60
    ControlMaster auto
    ControlPath ~/.ssh/control/%r@%h:%p
    ControlPersist 10m

Multiple Key Management

Organize keys by purpose or service:

~/.ssh/
    ├── personal/
    │   ├── github_ed25519
    │   └── gitlab_ed25519
    └── work/
        ├── prod_ed25519
        └── staging_ed25519

Automation Possibilities

  • Use SSH config with automation tools
  • Integrate with CI/CD pipelines
  • Create wrapper scripts for common operations

Conclusion

Mastering SSH keys, tunnels, and ssh-agent is essential for modern system administration and development. By following the practices outlined in this guide, you can:

  • Maintain secure and efficient remote access
  • Streamline your workflow with proper key management
  • Create secure tunnels for various use cases
  • Troubleshoot common SSH issues effectively

For further learning, consider exploring:

  • Certificate-based SSH authentication
  • Hardware security keys
  • Advanced tunnel configurations
  • Custom SSH protocols and extensions

Appendix

Common Commands Reference

# Key Management
ssh-keygen -t ed25519 -C "comment"
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host
ssh-add -l
# Tunnel Creation
ssh -L local_port:remote_host:remote_port user@host
ssh -R remote_port:local_host:local_port user@host
ssh -D proxy_port user@host
# Debugging
ssh -v user@host
ssh-add -l
ssh -T git@github.com

Configuration Templates

Basic ~/.ssh/config template:

Host *
    AddKeysToAgent yes
    UseKeychain yes
    ServerAliveInterval 60
Host github.com
    User git
    IdentityFile ~/.ssh/github_ed25519
Host bastion
    HostName bastion.example.com
    User admin
    IdentityFile ~/.ssh/bastion_ed25519
    ForwardAgent yes

Troubleshooting Checklist

  1. Key Permissions
    • Private key: 600
    • Public key: 644
    • ~/.ssh directory: 700
  2. Connection Issues
    • Check SSH service status
    • Verify hostname and port
    • Confirm network connectivity
    • Review server logs
  3. Agent Problems
    • Verify agent is running
    • Check environment variables
    • Confirm key addition
    • Test with ssh-add -l
    • Test key permissions
    • Validate SSH config syntax
    • Check for conflicting agent processes
  4. Tunnel Verification
    • Confirm port availability
    • Check firewall rules
    • Verify service accessibility
    • Monitor tunnel stability
  5. Authentication Flow
    • Review authentication methods
    • Check authorized_keys format
    • Verify user permissions
    • Examine PAM configuration

Remember to maintain a systematic approach when troubleshooting SSH issues. Start with the basics and work your way through more complex possibilities. Document any changes made to configurations to help track the resolution process. When all standard troubleshooting steps fail, consider:

  • Reviewing system logs (/var/log/auth.log)
  • Testing with alternative SSH clients
  • Creating a minimal test configuration
  • Consulting your organization’s security policies

You May Also Like