Implementing Chrooted SCP Transfers in OpenSSH Without Interactive Shell Access


2 views

When configuring OpenSSH for secure file transfers, we often face a dilemma: how to allow SCP operations while maintaining strict security through chroot jails and preventing interactive shell access. The standard internal-sftp solution works perfectly for SFTP but leaves SCP functionality in the cold.

SCP's fundamental architecture requires shell access because:

# This is how SCP works under the hood
client -> sshd -> /usr/bin/scp -> user's shell

Unlike SFTP which can use the direct internal-sftp subsystem, SCP needs to execute the scp binary through the user's login shell.

Here's a proven configuration that maintains security while allowing SCP:

Match group sftponly
    ChrootDirectory /sftp/%u
    X11Forwarding no
    AllowTcpForwarding no
    ForceCommand /usr/bin/rbash
    PermitEmptyPasswords no
    AllowAgentForwarding no

Create a minimal environment that supports both SCP and SFTP:

# Create the chroot directory
mkdir -p /sftp/username/{bin,lib64,usr/lib}

# Copy required binaries
cp /bin/bash /sftp/username/bin/
cp /usr/bin/scp /sftp/username/bin/
cp /usr/lib/openssh/sftp-server /sftp/username/usr/lib/

# Copy required libraries
ldd /bin/bash | awk '/=>/ {print $3}' | xargs -I {} cp {} /sftp/username/lib64/
ldd /usr/bin/scp | awk '/=>/ {print $3}' | xargs -I {} cp {} /sftp/username/lib64/

Configure a restricted shell that only allows SCP:

# Create restricted shell symlink
ln -s /bin/bash /sftp/username/bin/rbash

# Create .bash_profile
echo 'scp "$@"' > /sftp/username/.bash_profile
echo 'exit 0' >> /sftp/username/.bash_profile
chmod 555 /sftp/username/.bash_profile

Verify both protocols work as expected:

# Test SFTP
sftp -P 22 username@yourserver.com

# Test SCP
scp -P 22 testfile.txt username@yourserver.com:/upload/

This approach maintains security by:

  • Keeping the chroot environment minimal
  • Preventing shell escape through rbash
  • Maintaining file ownership and permissions
  • Logging all access attempts

When configuring OpenSSH for secure file transfers, many administrators face a dilemma: how to support both SFTP and SCP protocols while maintaining security through chroot jails. The standard internal-sftp solution works perfectly for SFTP but breaks SCP functionality.

The fundamental issue lies in how OpenSSH handles different protocols:

# Current configuration that breaks SCP
Match group sftponly
    ChrootDirectory /sftp/%u
    X11Forwarding no
    AllowTcpForwarding no
    ForceCommand internal-sftp

SCP requires shell access to spawn the scp process, which conflicts with ForceCommand. Unlike SFTP which has a dedicated internal subsystem, SCP relies on the user's shell environment.

While there's no direct equivalent to internal-sftp for SCP, we can implement a secure solution using OpenSSH's built-in capabilities:

Match group sftponly
    ChrootDirectory /sftp/%u
    X11Forwarding no
    AllowTcpForwarding no
    ForceCommand /usr/lib/openssh/sftp-server
    AuthorizedKeysCommand /usr/local/bin/validate-scp
    AuthorizedKeysCommandUser nobody

Create /usr/local/bin/validate-scp:

#!/bin/bash
# Allow SCP commands only when specific patterns are detected
if [[ "$SSH_ORIGINAL_COMMAND" =~ ^scp\ [-fr]\ .*$ ]]; then
    exec /usr/lib/openssh/sftp-server
else
    echo "Command not allowed"
    exit 1
fi

Make it executable:

chmod +x /usr/local/bin/validate-scp

For systems where AuthorizedKeysCommand isn't desirable:

Match group sftponly
    ChrootDirectory /sftp/%u
    X11Forwarding no
    AllowTcpForwarding no
    ForceCommand /usr/local/bin/scp-wrapper

Then create /usr/local/bin/scp-wrapper:

#!/bin/bash
case "$SSH_ORIGINAL_COMMAND" in
    scp*)
        /usr/lib/openssh/sftp-server
        ;;
    *)
        echo "This account is restricted to SCP/SFTP only."
        exit 1
        ;;
esac

When implementing this solution:

  • Ensure all scripts are owned by root and not writable by others
  • Regularly audit your chroot environment
  • Consider SELinux/AppArmor policies for additional protection
  • Test thoroughly with various SCP clients

Test your setup with:

ssh -vT user@host
scp -v file user@host:
sftp user@host

Check logs for any unexpected behavior:

tail -f /var/log/auth.log