1 unstable release
| 0.1.0 | Jun 9, 2025 |
|---|
#1511 in Authentication
Used in 2 crates
18KB
94 lines
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:
cargo build --release
- Install the binary:
sudo cp target/release/ssh-auth-cmd /usr/local/bin/
sudo chmod +x /usr/local/bin/ssh-auth-cmd
- 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 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
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
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)
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
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
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
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:
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:
- Run the install command to automatically migrate:
sudo ssh-auth-cmd install
-
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:
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
-
"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
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.
Dependencies
~4MB
~82K SLoC