When using SSH key authentication, the command="..."
option in ~/.ssh/authorized_keys
provides a powerful way to restrict what a specific key can execute. However, this approach has a significant limitation: it only allows a single command to be specified per key entry.
The restrictive nature of the command
option becomes apparent when you need to:
- Allow access to multiple related commands
- Create a whitelist of permitted operations
- Maintain security while providing flexible access
1. Wrapper Script Approach
The most reliable method is to create a wrapper script that validates and dispatches commands:
#!/bin/bash
# /usr/local/bin/ssh_wrapper.sh
valid_commands=("backup" "status" "restart")
if [[ " ${valid_commands[*]} " =~ " $1 " ]]; then
"$@"
else
echo "Error: Invalid command. Allowed commands: ${valid_commands[*]}" >&2
exit 1
fi
Then in authorized_keys:
command="/usr/local/bin/ssh_wrapper.sh $SSH_ORIGINAL_COMMAND" ssh-rsa AAAAB3NzaC1yc2E...
2. ForceCommand with Case Statement
An alternative is to use ForceCommand
in sshd_config with pattern matching:
Match User restricted_user
ForceCommand case "$SSH_ORIGINAL_COMMAND" in
"backup"|"status"|"logs") eval "$SSH_ORIGINAL_COMMAND";;
*) echo "Command not allowed"; exit 1;;
esac
3. Environment Variable Validation
For more complex scenarios, combine environment variables with command restrictions:
command="if [[ \"$SSH_ALLOWED_CMD\" =~ ^(backup|status)$ ]]; then $SSH_ORIGINAL_COMMAND; else echo 'Denied'; fi" ssh-rsa AAAAB3NzaC1yc2E...
When implementing multiple command restrictions:
- Always validate command arguments
- Use absolute paths for both commands and scripts
- Consider using SSH certificates for more granular control
- Regularly audit allowed commands
Here's a more sophisticated Python-based solution:
#!/usr/bin/env python3
# /usr/local/bin/ssh_command_router.py
import sys
import subprocess
ALLOWED_COMMANDS = {
'backup': {'args': 1, 'path': '/usr/bin/backup_script'},
'status': {'args': 0, 'path': '/usr/bin/system_status'}
}
def main():
if len(sys.argv) < 2:
print("No command specified", file=sys.stderr)
return 1
cmd = sys.argv[1]
if cmd not in ALLOWED_COMMANDS:
print(f"Command {cmd} not allowed", file=sys.stderr)
return 1
if len(sys.argv[2:]) > ALLOWED_COMMANDS[cmd]['args']:
print("Too many arguments", file=sys.stderr)
return 1
try:
subprocess.run([ALLOWED_COMMANDS[cmd]['path']] + sys.argv[2:])
except Exception as e:
print(f"Error: {str(e)}", file=sys.stderr)
return 1
if __name__ == "__main__":
sys.exit(main())
Configure in authorized_keys:
command="/usr/local/bin/ssh_command_router.py $SSH_ORIGINAL_COMMAND" ssh-rsa AAAAB3NzaC1yc2E...
The command="..."
option in SSH's authorized_keys
file is commonly used to force specific commands when a particular key is used for authentication. However, many developers don't realize this option is strictly limited to single command execution.
# Example of single command restriction
ssh-rsa AAAAB3Nza... command="/usr/bin/backup.sh" user@host
In real-world scenarios, system administrators often need to:
- Allow different maintenance scripts through the same key
- Implement granular access control for CI/CD pipelines
- Create restricted interfaces for automated tools
While there's no direct regex support in authorized_keys
, we can implement multi-command restrictions through these methods:
1. Wrapper Script Approach
Create a dispatcher script that checks SSH_ORIGINAL_COMMAND
:
#!/bin/bash
# /usr/local/bin/ssh_wrapper.sh
case "$SSH_ORIGINAL_COMMAND" in
"script1")
/path/to/script1.sh
;;
"script2")
/path/to/script2.sh
;;
*)
echo "Invalid command"
exit 1
;;
esac
Then reference it in authorized_keys
:
ssh-rsa AAAAB3Nza... command="/usr/local/bin/ssh_wrapper.sh" user@host
2. ForceCommand with Match Block
Combine sshd_config
settings with key restrictions:
# In /etc/ssh/sshd_config
Match User restricteduser
ForceCommand /usr/local/bin/multi_command.sh
3. Environment Variable Validation
For more complex scenarios, validate through environment variables:
#!/bin/bash
# /usr/local/bin/env_validator.sh
if [[ "$ALLOWED_COMMANDS" == *"$SSH_ORIGINAL_COMMAND"* ]]; then
eval "$SSH_ORIGINAL_COMMAND"
else
echo "Command not permitted"
fi
When implementing multiple command restrictions:
- Always validate and sanitize command inputs
- Use absolute paths for all executables
- Implement proper logging of command execution
- Consider using SSH certificates instead of keys for more granular control
For enterprise environments, SSH certificates offer more flexibility:
# Creating a certificate with multiple force-command options
ssh-keygen -s ca_key -I "restricted_access" \
-n "script1,script2" \
-V +1d user_key.pub