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
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 asssh-auth-cmd
- If
ssh-auth-cmd
is not running as root, theuser
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)
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
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
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
:
= "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
AuthorizedKeysCommand
to 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
user
field 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 = true
for 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-check
before 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.