When deploying console applications through SSH, we often face a security paradox: users need shell access to launch the application, but we must prevent unauthorized file system access via SFTP. This becomes critical when your application manages its own data access controls.
SSH provides multiple channel types:
1. shell (for interactive sessions)
2. exec (for single commands)
3. subsystem (for SFTP/SCP)
4. direct-tcpip (for port forwarding)
The solution lies in selectively disabling the SFTP subsystem while maintaining shell access.
Method 1: SSH Server Configuration
Edit your /etc/ssh/sshd_config
:
# Enable shell access
AllowTcpForwarding no
X11Forwarding no
PermitTTY yes
# Disable SFTP explicitly
Subsystem sftp /bin/false
# Or alternatively:
#Subsystem sftp internal-sftp -u 0007
Method 2: Force Command Execution
In sshd_config
or user's authorized_keys
:
Match User appuser
ForceCommand /path/to/your/console_app
PermitTTY yes
X11Forwarding no
AllowTcpForwarding no
For more granular control, consider a custom shell wrapper:
#!/bin/bash
if [[ $SSH_ORIGINAL_COMMAND ]]; then
# Handle direct command execution
exec /path/to/console_app --cmd "$SSH_ORIGINAL_COMMAND"
else
# Handle interactive session
/path/to/console_app --interactive
exit # Important: terminate session after app exits
fi
After configuration, test with:
# Test shell access
ssh user@host
# Test SFTP access (should fail)
sftp user@host
- Set proper umask (e.g., 0027) for your application
- Consider using chroot for additional isolation
- Implement proper logging of all access attempts
For complex scenarios, consider rssh
or custom restricted shells:
# Install rssh on Debian/Ubuntu
sudo apt install rssh
# Configure in /etc/rssh.conf
allowscp
allowsftp
allowcvs
When building console applications with restricted access requirements, we often encounter a specific security paradox: Users need SSH shell access to launch the application (which immediately executes and terminates the session), but must be prevented from establishing SFTP connections that could expose restricted directories. This creates a legitimate need for SSH-SFTP separation that goes against typical security recommendations.
OpenSSH handles SFTP through its internal-sftp subsystem. The key realization is that shell access and SFTP are separate capabilities controlled by different configuration mechanisms:
# Standard SSH server components sshd → shell (/bin/bash) → sftp (/usr/lib/openssh/sftp-server)
In your /etc/ssh/sshd_config
, implement these changes:
# 1. Disable SFTP subsystem completely Subsystem sftp /bin/false # 2. Force command execution for specific users Match User restricted_user ForceCommand /path/to/your_app PermitTTY no X11Forwarding no AllowTcpForwarding no PermitTunnel no GatewayPorts no
For finer control, implement chrooted environments:
# In sshd_config Match Group appusers ChrootDirectory /var/restricted/%u ForceCommand /opt/app/launcher AllowAgentForwarding no PermitTunnel no
Then set up the directory structure:
sudo mkdir -p /var/restricted/username/dev/null sudo mknod /var/restricted/username/dev/null c 1 3 sudo chown root:root /var/restricted/username sudo chmod 755 /var/restricted/username
Create a restricted shell that immediately launches your application:
#!/bin/sh # /bin/restricted_shell /path/to/your_app exit 0
Then assign this shell in /etc/passwd
:
appuser:x:1001:1001::/home/appuser:/bin/restricted_shell
Test with these commands:
# Verify shell access works ssh appuser@server # Verify SFTP is blocked sftp appuser@server # Should return "Connection closed" or similar
Additional hardening measures:
- Set
PasswordAuthentication no
and use SSH keys exclusively - Implement fail2ban for brute force protection
- Regularly audit user sessions with
last
andjournalctl -u sshd
If users report connection problems:
- Check
/var/log/auth.log
for SSH errors - Verify permissions on chroot directories (must be owned by root)
- Confirm SELinux/AppArmor isn't blocking operations