How to Configure Chroot SFTP with Restricted Rsync Over SSH for Backup Servers


3 views

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:

  1. 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
  1. 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
  1. 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:

  1. Verify all required libraries are in chroot's lib directories
  2. Ensure proper permissions on chroot directory (root:root, 755)
  3. Check SELinux/apparmor contexts if enabled
  4. 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)