When setting up remote automation, many developers need to allow SSH access for executing specific commands without granting full shell access. The standard approach using authorized_keys
restrictions like no-pty
prevents interactive login but still leaves all commands accessible.
There are several robust methods to enforce single command execution:
# Method 1: authorized_keys command="" (most secure)
command="/home/rpcall/bin/command.sh" ssh-rsa AAAAB3NzaC1yc2E...
# Method 2: ForceCommand in sshd_config
Match User rpcall
ForceCommand /home/rpcall/bin/command.sh
To safely pass parameters while maintaining security:
# In command.sh:
#!/bin/bash
# Read arguments from SSH_ORIGINAL_COMMAND
args=($SSH_ORIGINAL_COMMAND)
param1=${args[0]}
param2=${args[1]}
# Process parameters safely
echo "Received params: $param1, $param2"
Here's an end-to-end solution:
# 1. Create restricted user
sudo adduser --shell /bin/rbash --disabled-password rpcall
# 2. Set up authorized_keys
mkdir -p ~rpcall/.ssh
echo 'command="/home/rpcall/bin/command.sh",no-port-forwarding,no-X11-forwarding,no-pty ssh-rsa [KEY]' > ~rpcall/.ssh/authorized_keys
# 3. Create the command script
cat > /home/rpcall/bin/command.sh << 'EOF'
#!/bin/bash
# Validate allowed commands
case "$SSH_ORIGINAL_COMMAND" in
"metrics")
/usr/bin/metrics-collector
;;
"backup")
/usr/local/bin/backup-script
;;
*)
echo "Invalid command"
exit 1
;;
esac
EOF
# 4. Set permissions
chmod 755 /home/rpcall/bin/command.sh
chown -R rpcall:rpcall /home/rpcall
For more complex scenarios consider:
- Using SSH certificates with custom principals
- Implementing a restricted shell (rbash) with PATH limitations
- Combining ForceCommand with a configuration management system
Always remember to:
- Audit all environment variables
- Sanitize all command parameters
- Implement proper logging
- Use separate SSH keys for different automation purposes
When implementing remote command execution via SSH, we often need to restrict users to specific commands while preventing full shell access. The standard approach using authorized_keys
restrictions like no-pty
prevents interactive login but still allows arbitrary command execution.
The most elegant solution is using SSH's command=""
option in authorized_keys
:
from="trusted_ip",no-agent-forwarding,no-X11-forwarding,no-port-forwarding,no-pty,command="/home/rpcall/bin/command.sh" ssh-rsa AAAAB3NzaC1yc2E...
This forces execution of command.sh
regardless of what command the client attempts to run.
To handle parameters while maintaining security:
#!/bin/bash
# /home/rpcall/bin/command.sh
# Verify SSH_ORIGINAL_COMMAND is empty
if [[ -n "$SSH_ORIGINAL_COMMAND" ]]; then
echo "Command execution not allowed" >&2
exit 1
fi
# Process passed arguments
param1="$1"
param2="$2"
# Your processing logic here
For more complex scenarios, consider using environment variables instead of command-line arguments:
from="trusted_ip",no-pty,command="/home/rpcall/bin/command.sh",environment="REMOTE_PARAM1=value1",environment="REMOTE_PARAM2=value2" ssh-rsa AAAAB3NzaC1yc2E...
Create a custom restricted shell that only executes your script:
#!/bin/bash
# /bin/rpcall_shell
if [[ "$1" != "/home/rpcall/bin/command.sh" ]]; then
exit 1
fi
shift
exec "$@"
Then set this as the user's shell in /etc/passwd
:
rpcall:x:1001:1001::/home/rpcall:/bin/rpcall_shell
- Always validate input parameters
- Use absolute paths for all commands
- Implement proper error logging
- Consider using SSH certificates instead of keys
- Regularly audit your implementation
Here's a full implementation example:
# 1. Create the restricted user
sudo useradd -m -s /bin/false rpcall
# 2. Create the command script
sudo mkdir -p /home/rpcall/bin
sudo tee /home/rpcall/bin/command.sh >/dev/null <<'EOF'
#!/bin/bash
# Only allow execution when no command is specified
if [[ -n "$SSH_ORIGINAL_COMMAND" ]]; then
echo "Error: Direct command execution not allowed" >&2
exit 1
fi
# Process arguments
echo "Executing with parameters: $1 $2"
# Your actual processing here
EOF
# 3. Set permissions
sudo chmod 755 /home/rpcall/bin/command.sh
sudo chown rpcall:rpcall /home/rpcall/bin/command.sh
# 4. Configure authorized_keys
sudo -u rpcall mkdir -p /home/rpcall/.ssh
sudo -u rpcall tee -a /home/rpcall/.ssh/authorized_keys >/dev/null <