Skip to content

styliteag/ssh-central-agent

Repository files navigation

SSH Central Agent (SCA)

SCA stands for SSH Central Agent - a sophisticated SSH gateway system that provides secure, multi-level SSH access to remote hosts through a centralized jump host infrastructure.

What is SCA?

The SSH Central Agent (SCA) is a gateway system that:

  • Centralizes SSH agent management - Combines local and remote SSH keys into a single, unified agent
  • Provides multi-level access control - Routes connections through security-level-based jump hosts (levels 0-3)
  • Enables seamless authentication - Allows you to use keys from different sources (local YubiKey, remote server agents, etc.) simultaneously
  • Manages secure connections - Handles SSH agent forwarding and multiplexing automatically

The sca command creates a subshell environment where your SSH client can access both local and remote SSH keys through a single agent socket, making it easy to connect to hosts across different security zones without manually managing multiple SSH agents.

Use Case: Centralized YubiKey Access via SSH Gateway

A common enterprise deployment pattern involves:

  1. SSH Gateway Hosts: Multi-level jump hosts (sca-jmp-level1, sca-jmp-level2, sca-jmp-level3, etc.) that route connections to protected infrastructure based on security levels
  2. Central Servers with YubiKeys: Each jump host (level 1 and above) can have one or more YubiKeys physically attached and managed by the SSH agent. Level 0 typically does not use YubiKeys.
  3. Local Agent Access: Users connect to the appropriate gateway based on their security level, which forwards the remote SSH agent socket (containing YubiKey keys) to their local machine

How It Works

When you run sca, it:

  • Connects to the SSH gateway host corresponding to your security level (level 1-x) using your local credentials
  • Establishes an SSH agent forwarding connection to the jump host's agent (which has access to one or more YubiKeys)
  • Creates a local socket (~/.ssh/scadev-agent.sock) that proxies authentication requests to the remote YubiKey(s)
  • Multiplexes this remote agent with your local agent, giving you access to both sets of keys seamlessly

Multi-YubiKey Support: Each jump host can have multiple YubiKeys attached, and all keys from all YubiKeys on that host become available through the forwarded agent socket. This allows for redundancy, different key types, or multiple security roles within the same level.

Benefits

  • Centralized Security: YubiKeys remain physically secured at the jump host servers, never leaving the controlled environment
  • Multi-Level Architecture: Different security levels (1-x) can have their own YubiKey(s), allowing for granular access control and separation of concerns
  • Scalable Key Management: Each level can have one or more YubiKeys, supporting redundancy, different key types, or multiple security roles
  • No Physical Access Required: Users don't need direct physical access to the YubiKeys - authentication happens remotely through the gateway
  • Seamless Experience: Once connected via sca, you can use YubiKey-protected keys just like local keys - no manual intervention needed
  • Multi-User Access: Multiple authorized users at the same security level can access the same secure keys simultaneously through their own gateway connections
  • Audit Trail: All authentication attempts go through the centralized gateway, providing better security monitoring and logging
  • Key Protection: Private keys never leave the secure server - only signing operations are forwarded, keeping the actual key material safe

This architecture is ideal for organizations that need to provide secure SSH access to sensitive infrastructure while maintaining strict control over hardware security keys across multiple security levels.

Server Setup Documentation

Detailed documentation for setting up the sca-jmp (jump host) and sca-key (YubiKey server) infrastructure will be published in a future release. This will include:

  • Jump host configuration and deployment
  • YubiKey server setup and agent configuration
  • Multi-level security architecture implementation
  • Best practices for production deployments

Interested in Enterprise Deployment?

If your company is interested in implementing this SSH gateway architecture with centralized YubiKey management, we can help with setup and deployment. Please contact us for assistance with:

  • Architecture design and planning
  • Jump host and YubiKey server configuration
  • Security level implementation
  • Custom deployment requirements

Quick Start

Prerequisites

  1. Generate an SSH key (if you don't have one):
# Standard key
ssh-keygen -t ed25519 -C your_email@example.com -f ~/.ssh/id_ed25519 -N yourpassword

# Or with YubiKey
ssh-keygen -t ecdsa-sk -O no-touch-required -C "your_email@example.com (notouch+passphrase)" -f ~/.ssh/id_your_sk

# Recommended: Create a dedicated key for SCA connections
ssh-keygen -t ed25519 -C "sca-connection" -f ~/.ssh/id_ed25519_sca -N yourpassword
  1. Ensure your SSH agent is running (optional):
# Check if agent is running
ssh-add -l

# If not, start it
eval $(ssh-agent)

# Add your key
ssh-add ~/.ssh/id_ed25519

Note: If you don't have a local SSH agent running, sca will automatically detect and use identity files (like ~/.ssh/id_ed25519) by creating a temporary agent. This ensures you only need to enter your passphrase once.

Installation

Recommended location: Check out the repository in ~/.ssh/sca. The playbook will adapt to any location, but ~/.ssh/sca is the recommended path.

First-time setup:

  1. Clone the repository:

    git clone https://github.com/styliteag/ssh-central-agent ~/.ssh/sca
    # or git clone https://github.com/styliteag/ssh-central-agent ~/.ssh/sca
  2. Create the hosts directory: After checkout, create a hosts directory. This can be:

    • A symlink to another private repository (recommended for team setups)
    • An empty directory (if you don't have access to the private hosts repo yet)
    • A separate private git repository
    # Option 1: Create empty directory
    mkdir hosts
    
    # Option 2: Clone private repo as hosts directory
    git clone <private-hosts-repo-url> hosts
  3. Configure your settings (optional):

    # Copy the example file
    cp localvars-example.yml localvars.yml
    
    # Edit localvars.yml and set:
    # - sca_key_server: IP or hostname of your SCA key server
    # - sca_key_server_port: Port number
    # - remote_username: Your username on remote servers
    # - my_ssh_key: (optional) Custom key for SCA connections, e.g., ~/.ssh/id_ed25519_sca
  4. Run the Ansible playbook:

    ansible-playbook playbook.yml

This will:

  • Generate the Python entrypoint sca and the legacy bash entrypoint sca.sh
  • Create SSH configuration files (config_single for Host blocks, config_match for Match blocks)
  • Add Include lines to ~/.ssh/config (load order: config_singlehosts/*config_match)
  • Set up shell integration (.bashrc/.zshrc)

Note: The playbook automatically adapts to wherever you've checked out the repository. See SETUP.md for detailed setup instructions.

What’s New (Python Port)

The project now ships two parallel entrypoints:

  • sca → Python implementation (generated from templates/sca.py.j2)
  • sca.sh → Legacy bash implementation (generated from templates/sca.sh.j2)

Use sca by default. Keep sca.sh only for legacy workflows or comparison.

Usage

Start a shell with access to remote keys using the SSH Central Agent:

sca

Or use eval \sca -e`to set the SSH agent in your current shell (similar tossh-agent -s`):

eval `sca -e --key=local`
# Now SSH_AUTH_SOCK is set in your current shell
ssh-add -l  # List available keys

Show version information:

sca -v          # Show version and socket paths
sca --version   # Same as above
sca --help      # Show help message

Direct SSH Connection:

Positional arguments are automatically treated as SSH arguments - sca is an SSH tool by default:

sca user@hostname                    # Connect using remote agent (default)
sca --key=local user@hostname        # Connect using local agent
sca --key=mux user@hostname          # Connect using multiplexed agent

When using SSH options that start with - (like -p, -o), use -- to separate SCA options from SSH arguments:

sca --key=remote -- -p9922 root@10.20.3.254 hostname
sca --key=local -- -o StrictHostKeyChecking=no user@host
sca --key=mux -- -p9922 -v user@hostname

All arguments after -- are passed directly to ssh, so you can use any SSH options:

sca --key=local -- -p9922 -v user@hostname
sca --key=mux -- user@hostname "command to run"

Subshell Mode:

Use -s or --shell to open a subshell with the MUX agent environment set, instead of connecting to a host:

sca -s                               # Open subshell with MUX agent environment
sca --shell                          # Same as above
sca --shell --key=local              # Subshell with local agent

Command Options

Basic Usage:

sca --key=local         # Start subshell with local key only
sca --key=remote        # Start subshell with remote key only (default)
sca --key=mux           # Start subshell with multiplexed agent (local + remote)

Host Management:

sca --list              # List all configured hosts
sca --find hostname     # Find and display information about a specific host
sca --add hostname      # Add a new host to the configuration

Direct SSH Connection (default):

sca user@host                          # Connect using remote agent (default)
sca --key=local user@host              # Connect using local agent
sca --key=mux user@host               # Connect using multiplexed agent
sca --key=remote -- -p9922 root@10.20.3.254 hostname  # Use -- for SSH options starting with -
sca --key=mux -- -p9922 user@host     # Connect using multiplexed agent with options

Subshell Mode:

sca -s                                 # Open subshell with MUX agent environment
sca --shell                            # Same as above
sca --shell --key=local                # Subshell with local agent only

Advanced Options:

sca -s                  # Open a subshell with the MUX agent environment set
sca -e --key=local      # Output env vars for eval (use with eval \`sca -e --key=local\`)
sca --wait              # Run in background and monitor connection, restart if needed
sca --kill              # Kill all agents and connections, remove socket files
sca -d                  # Enable debug mode (verbose output)
sca -r                  # Reverse the order of agents when multiplexing
sca -l 2                # Set security level (0-3, default: auto-detect)
sca -v, --version       # Show version information and exit
sca -h, --help          # Show help message and exit

Combined Options:

sca -dr --key=local     # Debug mode + reverse agent order
sca --wait --key=local  # Background monitoring mode

SSH Agent Multiplexing

The system uses the built-in Python multiplexer (sshagentmux.py) to combine local and remote SSH agents into a single socket. No external multiplexer is supported.

Shell Integration

Add to your ~/.zshrc or ~/.bashrc:

# SCA-KEY subshell integration (SSH Central Agent)
if [ -n "$SCA_SUBSHELL" ] ; then
  echo "SCA_SUBSHELL: $SCA_SUBSHELL"
  PS1="$PS1($SCA_SUBSHELL) "
  if [ -n "$MUX_SSH_AUTH_SOCK" ] ; then
    export SSH_AUTH_SOCK=$MUX_SSH_AUTH_SOCK
  elif [ -n "$SCA_SSH_AUTH_SOCK" ] ; then
    export SSH_AUTH_SOCK=$SCA_SSH_AUTH_SOCK
  fi
else
  export LOCAL_SSH_AUTH_SOCK=$SSH_AUTH_SOCK
fi

Troubleshooting

Check agent status:

ssh-add -l

View socket files:

ls -la ~/.ssh/scadev-*

Kill and restart:

sca --kill
sca

Documentation

See AGENTS.md for detailed documentation including:

  • Architecture overview
  • Configuration management
  • Debugging guide
  • Multiplexer details (Python only)

macOS Notes

For macOS, you may need to use /usr/local/bin/ssh-agent instead of the built-in one:

which ssh
# Should show: /usr/local/bin/ssh

ssh -V
# Should show: OpenSSH_8.8p1 or later

If needed:

pkill ssh-agent
eval $(/usr/local/bin/ssh-agent)
ssh-add ~/.ssh/id_xx_sk