ssh-auth-cmd 0.1.0

SSH AuthorizedKeysCommand multiplexer - chain multiple SSH authentication sources
ssh-auth-cmd-0.1.0 is not a library.

ssh-auth-cmd Configuration and Setup

Overview

ssh-auth-cmd is a Rust application designed to chain multiple SSH AuthorizedKeysCommand configurations, since OpenSSH only supports configuring a single one. The new version supports individual configuration files, user switching, comprehensive OpenSSH placeholder support, and automatic installation.

Installation

  1. Build the application:
cargo build --release
  1. Install the binary:
sudo cp target/release/ssh-auth-cmd /usr/local/bin/
sudo chmod +x /usr/local/bin/ssh-auth-cmd
  1. Install using the built-in installer (recommended):
sudo /usr/local/bin/ssh-auth-cmd install

Or with a specific user:

sudo /usr/local/bin/ssh-auth-cmd install --user nobody

Configuration Directory Structure

Commands are now configured in individual TOML files in /etc/ssh/auth_cmd.d/:

/etc/ssh/auth_cmd.d/
├── 01-local-keys.toml
├── 02-ldap-keys.toml
├── 03-database-keys.toml
└── 99-emergency-keys.toml

Files are processed in alphabetical order, so you can use prefixes to control execution order.

Configuration File Format

Each configuration file contains a single command definition:

Example: /etc/ssh/auth_cmd.d/01-local-keys.toml

name = "local_keys"
command = "cat"
args = ["/home/%u/.ssh/authorized_keys"]
enabled = true
timeout = 30
user = "nobody"
readonly = false

Example: /etc/ssh/auth_cmd.d/02-ldap-keys.toml

name = "ldap_keys"
command = "/usr/local/bin/ldap-ssh-keys"
args = ["--user", "%u", "--hostname", "%h", "--connection", "%C"]
enabled = true
timeout = 60
user = "ldap-user"
readonly = false

Example: /etc/ssh/auth_cmd.d/03-audit-only.toml

name = "audit_logger"
command = "/usr/local/bin/ssh-audit-log"
args = ["--user", "%u", "--key-type", "%t", "--fingerprint", "%f"]
enabled = true
timeout = 10
user = "audit"
readonly = true  # Don't include output in authorized keys

Configuration Options

Required Fields

  • name: A descriptive name for the command
  • command: The command/script to execute

Optional Fields

  • args: Array of arguments to pass to the command
  • enabled: Whether this command is enabled (default: true)
  • timeout: Timeout in seconds for command execution (default: 30)
  • user: UNIX user to run the command as (only when ssh-auth-cmd runs as root)
  • readonly: If true, discard stdout output (useful for logging/auditing)

OpenSSH Placeholder Support

The following OpenSSH placeholders are supported in the args array:

  • %C: Connection specification (user, client IP, client port, server IP, server port)
  • %D: Routing domain
  • %f: Key fingerprint
  • %h: Hostname
  • %k`: Key being offered for authentication
  • %t: Key type
  • %U: Original username (before any transformations)
  • %u: Username being authenticated
  • %%: Literal % character

Example with Multiple Placeholders

name = "comprehensive_auth"
command = "/usr/local/bin/auth-checker"
args = [
    "--user", "%u",
    "--original-user", "%U", 
    "--hostname", "%h",
    "--connection", "%C",
    "--key-type", "%t",
    "--fingerprint", "%f",
    "--key", "%k",
    "--domain", "%D",
    "--literal-percent", "%%"
]

OpenSSH Configuration

When using the install command, ssh-auth-cmd configures OpenSSH as:

AuthorizedKeysCommand /usr/local/bin/ssh-auth-cmd key-cmd -c %C -D %D -f %f -h %h -k %k -t %t -U %U -u %u
AuthorizedKeysCommandUser root

This exhaustively uses all OpenSSH substitution variables currently defined.

User Switching

When ssh-auth-cmd runs as root (recommended), you can specify different users for each command:

  • If user is specified in a command config, that command runs as the specified user
  • If user is not specified, the command runs as the same user as ssh-auth-cmd
  • If ssh-auth-cmd is not running as root, the user field is ignored

This allows for principle of least privilege - each command can run with only the permissions it needs.

Commands and Usage

Key Command Mode (used by OpenSSH)

ssh-auth-cmd key-cmd -c %C -D %D -f %f -h %h -k %k -t %t -U %U -u %u

This is the mode OpenSSH calls. It processes all enabled configurations and outputs authorized keys.

Configuration Check

sudo ssh-auth-cmd config-check

Validates:

  • Configuration directory and file permissions
  • Configuration file syntax
  • Placeholder substitution validity
  • Command binary permissions
  • That all command binaries are only writable by root

Installation

# Install with default settings (AuthorizedKeysCommandUser root)
sudo ssh-auth-cmd install

# Install with specific user
sudo ssh-auth-cmd install --user nobody

# Install with custom sshd_config location
sudo ssh-auth-cmd install --config /etc/ssh/sshd_config.custom

The install command:

  • Migrates existing AuthorizedKeysCommand to a config file in /etc/ssh/auth_cmd.d/
  • Comments out the old configuration
  • Adds the new ssh-auth-cmd configuration
  • Preserves existing AuthorizedKeysCommandUser settings when migrating
  • Will not overwrite existing files in /etc/ssh/auth_cmd.d/

Security Considerations

File Permissions

All configuration files and the configuration directory must have secure permissions:

# Set proper permissions
sudo chown -R root:root /etc/ssh/auth_cmd.d/
sudo chmod 755 /etc/ssh/auth_cmd.d/
sudo chmod 600 /etc/ssh/auth_cmd.d/*.toml

The config-check command verifies these permissions automatically.

Command Security

  • All configured command binaries must be owned by root and not writable by others
  • Commands run with the privileges of the specified user (or the user running ssh-auth-cmd)
  • Use the readonly flag for commands that should only log/audit without providing keys

User Isolation

Different commands can run as different users for security isolation:

  • LDAP queries might run as a dedicated ldap-auth user
  • Database queries might run as a db-auth user
  • Local file access might run as nobody
  • Audit logging might run as an audit user

Example Configurations

Basic Local + LDAP Setup

/etc/ssh/auth_cmd.d/01-local.toml:

name = "local_keys"
command = "cat"
args = ["/home/%u/.ssh/authorized_keys"]
enabled = true
timeout = 30
user = "nobody"

/etc/ssh/auth_cmd.d/02-ldap.toml:

name = "ldap_lookup"
command = "/usr/local/bin/ldap-ssh-keys"
args = ["--user", "%u", "--hostname", "%h"]
enabled = true
timeout = 60
user = "ldap-auth"

Enterprise Setup with Audit Trail

/etc/ssh/auth_cmd.d/01-audit.toml:

name = "connection_audit"
command = "/usr/local/bin/log-ssh-attempt"
args = [
    "--user", "%u",
    "--original-user", "%U",
    "--connection", "%C",
    "--hostname", "%h",
    "--key-fingerprint", "%f",
    "--key-type", "%t"
]
enabled = true
timeout = 10
user = "audit"
readonly = true  # Just for logging, don't provide keys

/etc/ssh/auth_cmd.d/02-corporate-keys.toml:

name = "corporate_ldap"
command = "/usr/local/bin/corporate-auth"
args = ["--user", "%u", "--domain", "corp.example.com"]
enabled = true
timeout = 60
user = "corp-auth"

/etc/ssh/auth_cmd.d/03-emergency.toml:

name = "emergency_access"
command = "/usr/local/bin/emergency-keys"
args = ["--user", "%u", "--validate-emergency"]
enabled = true
timeout = 30
user = "emergency-auth"

Development/Testing Setup

/etc/ssh/auth_cmd.d/01-local.toml:

name = "local_keys"
command = "cat"
args = ["/home/%u/.ssh/authorized_keys"]
enabled = true
timeout = 30

/etc/ssh/auth_cmd.d/02-shared-dev.toml:

name = "shared_dev_keys"
command = "cat"
args = ["/etc/ssh/shared_dev_keys"]
enabled = true
timeout = 10

Migration from Single Configuration

If you're migrating from the original single-file configuration:

  1. Run the install command to automatically migrate:
sudo ssh-auth-cmd install
  1. The installer will:

    • Move your existing AuthorizedKeysCommand to a config file
    • Comment out the old configuration
    • Install the new ssh-auth-cmd configuration
  2. Verify the migration:

sudo ssh-auth-cmd config-check

Troubleshooting

Configuration Issues

# Check all configurations
sudo ssh-auth-cmd config-check

# Test manually for a specific user
sudo ssh-auth-cmd key-cmd -u testuser

# Test with full OpenSSH context
sudo ssh-auth-cmd key-cmd -c "testuser,192.168.1.100,22,10.0.0.1,22" -u testuser -h hostname.example.com

Permission Problems

# Fix directory permissions
sudo chown -R root:root /etc/ssh/auth_cmd.d/
sudo chmod 755 /etc/ssh/auth_cmd.d/
sudo chmod 600 /etc/ssh/auth_cmd.d/*.toml

# Check command permissions
ls -la /usr/local/bin/your-auth-command

SSH Debug Mode

Enable SSH debug logging to see what's happening:

# In /etc/ssh/sshd_config
LogLevel DEBUG

# Then check logs
sudo tail -f /var/log/auth.log

Common Issues

  1. "Configuration directory is writable by group or others"

    • Fix: sudo chmod 755 /etc/ssh/auth_cmd.d/
  2. "Configuration file is writable by group or others"

    • Fix: sudo chmod 600 /etc/ssh/auth_cmd.d/*.toml
  3. "Command is not owned by root"

    • Fix: sudo chown root:root /path/to/command
  4. "Invalid placeholder"

    • Check that you're only using supported placeholders: %C, %D, %f, %h, %k, %t, %U, %u, %%
  5. "User not found"

    • Ensure the user specified in the user field exists on the system

Performance Considerations

  • Commands run sequentially in alphabetical order by filename
  • Set appropriate timeouts to prevent hanging connections
  • Use readonly = true for audit/logging commands that don't provide keys
  • Consider disabling unnecessary commands in production environments

Best Practices

  1. Naming Convention: Use numbered prefixes (01-, 02-, etc.) to control execution order
  2. User Separation: Run different commands as different users for security isolation
  3. Timeouts: Set conservative timeouts to prevent hanging SSH connections
  4. Auditing: Use readonly commands for comprehensive audit logging
  5. Testing: Always test configurations with config-check before deployment
  6. Monitoring: Monitor command execution times and failure rates
  7. Backup: Keep backups of working configurations before making changes

Integration Examples

With HashiCorp Vault

name = "vault_ssh_ca"
command = "/usr/local/bin/vault-ssh-helper"
args = ["-mode", "ca", "-username", "%u"]
enabled = true
timeout = 45
user = "vault-ssh"

With FreeIPA/Red Hat IdM

name = "ipa_keys"
command = "/usr/bin/sss_ssh_authorizedkeys"
args = ["%u"]
enabled = true
timeout = 30
user = "sssd"

With Custom Database

name = "db_keys"
command = "/usr/local/bin/db-ssh-keys"
args = [
    "--user", "%u",
    "--client-ip", "%C",
    "--hostname", "%h"
]
enabled = true
timeout = 60
user = "db-auth"

This comprehensive setup provides a secure, flexible, and maintainable way to chain multiple SSH authentication sources while maintaining full OpenSSH compatibility and security best practices.