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
- Build the application:
- Install the binary:
- Install using the built-in installer (recommended):
Or with a specific user:
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
= "local_keys"
= "cat"
= ["/home/%u/.ssh/authorized_keys"]
= true
= 30
= "nobody"
= false
Example: /etc/ssh/auth_cmd.d/02-ldap-keys.toml
= "ldap_keys"
= "/usr/local/bin/ldap-ssh-keys"
= ["--user", "%u", "--hostname", "%h", "--connection", "%C"]
= true
= 60
= "ldap-user"
= false
Example: /etc/ssh/auth_cmd.d/03-audit-only.toml
= "audit_logger"
= "/usr/local/bin/ssh-audit-log"
= ["--user", "%u", "--key-type", "%t", "--fingerprint", "%f"]
= true
= 10
= "audit"
= true # Don't include output in authorized keys
Configuration Options
Required Fields
name: A descriptive name for the commandcommand: The command/script to execute
Optional Fields
args: Array of arguments to pass to the commandenabled: 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
= "comprehensive_auth"
= "/usr/local/bin/auth-checker"
= [
"--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
useris specified in a command config, that command runs as the specified user - If
useris not specified, the command runs as the same user asssh-auth-cmd - If
ssh-auth-cmdis not running as root, theuserfield 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)
This is the mode OpenSSH calls. It processes all enabled configurations and outputs authorized keys.
Configuration 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)
# Install with specific user
# Install with custom sshd_config location
The install command:
- Migrates existing
AuthorizedKeysCommandto a config file in/etc/ssh/auth_cmd.d/ - Comments out the old configuration
- Adds the new ssh-auth-cmd configuration
- Preserves existing
AuthorizedKeysCommandUsersettings 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
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
readonlyflag 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-authuser - Database queries might run as a
db-authuser - Local file access might run as
nobody - Audit logging might run as an
audituser
Example Configurations
Basic Local + LDAP Setup
/etc/ssh/auth_cmd.d/01-local.toml:
= "local_keys"
= "cat"
= ["/home/%u/.ssh/authorized_keys"]
= true
= 30
= "nobody"
/etc/ssh/auth_cmd.d/02-ldap.toml:
= "ldap_lookup"
= "/usr/local/bin/ldap-ssh-keys"
= ["--user", "%u", "--hostname", "%h"]
= true
= 60
= "ldap-auth"
Enterprise Setup with Audit Trail
/etc/ssh/auth_cmd.d/01-audit.toml:
= "connection_audit"
= "/usr/local/bin/log-ssh-attempt"
= [
"--user", "%u",
"--original-user", "%U",
"--connection", "%C",
"--hostname", "%h",
"--key-fingerprint", "%f",
"--key-type", "%t"
]
= true
= 10
= "audit"
= true # Just for logging, don't provide keys
/etc/ssh/auth_cmd.d/02-corporate-keys.toml:
= "corporate_ldap"
= "/usr/local/bin/corporate-auth"
= ["--user", "%u", "--domain", "corp.example.com"]
= true
= 60
= "corp-auth"
/etc/ssh/auth_cmd.d/03-emergency.toml:
= "emergency_access"
= "/usr/local/bin/emergency-keys"
= ["--user", "%u", "--validate-emergency"]
= true
= 30
= "emergency-auth"
Development/Testing Setup
/etc/ssh/auth_cmd.d/01-local.toml:
= "local_keys"
= "cat"
= ["/home/%u/.ssh/authorized_keys"]
= true
= 30
/etc/ssh/auth_cmd.d/02-shared-dev.toml:
= "shared_dev_keys"
= "cat"
= ["/etc/ssh/shared_dev_keys"]
= true
= 10
Migration from Single Configuration
If you're migrating from the original single-file configuration:
- Run the install command to automatically migrate:
-
The installer will:
- Move your existing
AuthorizedKeysCommandto a config file - Comment out the old configuration
- Install the new ssh-auth-cmd configuration
- Move your existing
-
Verify the migration:
Troubleshooting
Configuration Issues
# Check all configurations
# Test manually for a specific user
# Test with full OpenSSH context
Permission Problems
# Fix directory permissions
# Check command permissions
SSH Debug Mode
Enable SSH debug logging to see what's happening:
# In /etc/ssh/sshd_config
# Then check logs
Common Issues
-
"Configuration directory is writable by group or others"
- Fix:
sudo chmod 755 /etc/ssh/auth_cmd.d/
- Fix:
-
"Configuration file is writable by group or others"
- Fix:
sudo chmod 600 /etc/ssh/auth_cmd.d/*.toml
- Fix:
-
"Command is not owned by root"
- Fix:
sudo chown root:root /path/to/command
- Fix:
-
"Invalid placeholder"
- Check that you're only using supported placeholders: %C, %D, %f, %h, %k, %t, %U, %u, %%
-
"User not found"
- Ensure the user specified in the
userfield exists on the system
- Ensure the user specified in the
Performance Considerations
- Commands run sequentially in alphabetical order by filename
- Set appropriate timeouts to prevent hanging connections
- Use
readonly = truefor audit/logging commands that don't provide keys - Consider disabling unnecessary commands in production environments
Best Practices
- Naming Convention: Use numbered prefixes (01-, 02-, etc.) to control execution order
- User Separation: Run different commands as different users for security isolation
- Timeouts: Set conservative timeouts to prevent hanging SSH connections
- Auditing: Use readonly commands for comprehensive audit logging
- Testing: Always test configurations with
config-checkbefore deployment - Monitoring: Monitor command execution times and failure rates
- Backup: Keep backups of working configurations before making changes
Integration Examples
With HashiCorp Vault
= "vault_ssh_ca"
= "/usr/local/bin/vault-ssh-helper"
= ["-mode", "ca", "-username", "%u"]
= true
= 45
= "vault-ssh"
With FreeIPA/Red Hat IdM
= "ipa_keys"
= "/usr/bin/sss_ssh_authorizedkeys"
= ["%u"]
= true
= 30
= "sssd"
With Custom Database
= "db_keys"
= "/usr/local/bin/db-ssh-keys"
= [
"--user", "%u",
"--client-ip", "%C",
"--hostname", "%h"
]
= true
= 60
= "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.