When setting up secure backup servers, administrators often face this dilemma: How to provide rsync functionality through SSH while maintaining strict filesystem isolation via chroot. The standard SFTP-chroot approach breaks rsync's operation because:
rsync -avz /local/path user@remote:/path
# Requires full SSH shell access to spawn remote rsync process
Here's how to implement secure rsync in chroot without granting full shell access:
- Create the chroot environment (Debian/Ubuntu example):
sudo mkdir -p /srv/chroot/user/{bin,lib,lib64,dev,etc}
sudo cp /bin/bash /srv/chroot/user/bin/
sudo cp /usr/bin/rsync /srv/chroot/user/bin/
# Copy required libraries using ldd
- Configure SSH forced command in
/etc/ssh/sshd_config
:
Match User backupuser
ChrootDirectory /srv/chroot/user
ForceCommand /usr/local/bin/rsync-wrapper.sh
AllowTCPForwarding no
X11Forwarding no
PermitTTY no
- Create the rsync wrapper script (
/usr/local/bin/rsync-wrapper.sh
):
#!/bin/bash
case "$SSH_ORIGINAL_COMMAND" in
rsync\ --server*)
/bin/rsync --server ${SSH_ORIGINAL_COMMAND#*rsync --server }
;;
*)
echo "Rejected: $SSH_ORIGINAL_COMMAND"
exit 1
;;
esac
Test the configuration with:
ssh -T backupuser@server rsync --version
rsync -avz -e "ssh -T" /local/path backupuser@server:/backup
For production environments, consider these enhancements:
# Limit rsync to specific subdirectory
ForceCommand /usr/local/bin/rsync-wrapper.sh /allowed/path
# Log all rsync attempts
logger -p auth.info "Rsync attempt by $USER: $SSH_ORIGINAL_COMMAND"
# Rate limiting in sshd_config:
MaxStartups 3:30:5
If rsync fails, check these points:
- Verify all required libraries are in chroot's lib directories
- Ensure proper permissions on chroot directory (root:root, 755)
- Check SELinux/apparmor contexts if enabled
- Test with
strace -f ssh user@host rsync --version
When setting up secure backup servers, we often face this dilemma: we want to provide rsync functionality while maintaining strict chroot isolation and preventing full SSH shell access. The fundamental issue stems from rsync's dependency on SSH for remote operations, while we only want to allow SFTP access for security reasons.
Rsync typically requires these components to work:
1. SSH binary access (for remote shell execution)
2. Write permissions in target directory
3. Proper PATH environment variables
But in our chroot/SFTP-only setup, all these are restricted by design.
Here's how to implement this securely:
Step 1: Configure the chroot environment
First, set up the basic chroot as per the Arch Linux guide, then add these modifications:
# /etc/ssh/sshd_config
Match Group backupusers
ChrootDirectory /var/chroot/%u
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
PermitTTY no
Step 2: Create a minimal rsync wrapper
Create this executable in the chroot:
#!/bin/bash
# /var/chroot/template/bin/rsync-wrapper
case "$SSH_ORIGINAL_COMMAND" in
rsync\ --server*)
/usr/bin/rsync --daemon --no-detach --config=/etc/rsyncd.conf
;;
*)
echo "Rejected: $SSH_ORIGINAL_COMMAND"
exit 1
;;
esac
Step 3: Set up the rsync daemon config
Configure rsync in daemon mode with chroot restrictions:
# /etc/rsyncd.conf
[backup]
path = /home/%U
use chroot = yes
read only = no
uid = %U
gid = %U
auth users = %U
secrets file = /etc/rsyncd.secrets
For simpler setups, consider using rsync's included rrsync script:
# /etc/ssh/sshd_config
Match Group backupusers
ForceCommand /usr/bin/rrsync -ro /home/%u/
- Always test permissions with a non-privileged user first
- Regularly audit your chroot environments
- Consider using filesystem quotas to prevent abuse
- Implement proper logging for all rsync transfers
When things go wrong, check:
1. /var/log/auth.log for SSH permission errors
2. rsync --verbose output with -e "ssh -vvv"
3. SELinux/apparmor context if enabled
4. The chroot directory permissions (must be owned by root)