diff --git a/README.md b/README.md index 4575e5b..132d366 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This is an automated build linked with the [debian](https://hub.docker.com/_/deb # Usage -- Required: define users as command arguments, STDIN or mounted in `/etc/sftp-users.conf` +- Required: define users as command arguments, STDIN or mounted in `/etc/sftp/users.conf` (syntax: `user:pass[:e][:uid[:gid[:dir1[,dir2]...]]]...`). - Set UID/GID manually for your users if you want them to make changes to your mounted volumes with permissions matching your host filesystem. @@ -74,7 +74,7 @@ OpenSSH client, run: `sftp -P 2222 foo@` ``` docker run \ - -v /host/users.conf:/etc/sftp-users.conf:ro \ + -v /host/users.conf:/etc/sftp/users.conf:ro \ -v mySftpVolume:/home \ -v /host/ssh_host_rsa_key:/etc/ssh/ssh_host_rsa_key \ -v /host/ssh_host_rsa_key.pub:/etc/ssh/ssh_host_rsa_key.pub \ @@ -103,10 +103,13 @@ docker run \ Tip: you can use [atmoz/makepasswd](https://hub.docker.com/r/atmoz/makepasswd/) to generate encrypted passwords: `echo -n "your-password" | docker run -i --rm atmoz/makepasswd --crypt-md5 --clearfrom=-` -## Using SSH key (and no password) +## Logging in with SSH keys -Mount all public keys in the user's `.ssh/keys/` directory. All keys are automatically -appended to `.ssh/authorized_keys`. +Mount public keys in the user's `.ssh/keys/` directory. All keys are +automatically appended to `.ssh/authorized_keys` (you can't mount this file +directly, because OpenSSH requires limited file permissions). In this example, +we do not provide any password, so the user `foo` can only login with his SSH +key. ``` docker run \ @@ -117,6 +120,28 @@ docker run \ foo::1001 ``` +## Providing your own SSH host key + +This container will generate new SSH host keys at first run. To avoid that your +users get a MITM warning when you recreate your container (and the host keys +changes), you can mount your own host keys. + +``` +docker run \ + -v /host/ssh_host_ed25519_key:/etc/ssh/ssh_host_ed25519_key \ + -v /host/ssh_host_rsa_key:/etc/ssh/ssh_host_rsa_key \ + -v /host/share:/home/foo/share \ + -p 2222:22 -d atmoz/sftp \ + foo::1001 +``` + +Tip: you can generate your keys with these commands: + +``` +ssh-keygen -t ed25519 -f /host/ssh_host_ed25519_key < /dev/null +ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key < /dev/null +``` + ## Execute custom scripts or applications Put your programs in `/etc/sftp.d/` and it will automatically run when the container starts. diff --git a/entrypoint b/entrypoint index 861a328..1216bed 100755 --- a/entrypoint +++ b/entrypoint @@ -2,8 +2,9 @@ set -e export DEBIAN_FRONTEND=noninteractive -userConfPath="/etc/sftp-users.conf" -userConfFinalPath="/var/run/sftp-users.conf" +userConfPath="/etc/sftp/users.conf" +userConfPathLegacy="/etc/sftp-users.conf" +userConfFinalPath="/var/run/sftp/users.conf" function printHelp() { echo "Add users as command arguments, STDIN or mounted in $userConfPath" @@ -96,8 +97,15 @@ if [ "$1" == "--readme" ]; then exit 0 fi +# Backward compatibility with legacy config path +if [ ! -f "$userConfPath" -a -f "$userConfPathLegacy" ]; then + mkdir -p "$(dirname $userConfPath)" + ln -s "$userConfPathLegacy" "$userConfPath" +fi + # Create users only on first run if [ ! -f "$userConfFinalPath" ]; then + mkdir -p "$(dirname $userConfFinalPath)" # Append mounted config to final config if [ -f "$userConfPath" ]; then diff --git a/tests/run b/tests/run index cc2897a..f02540f 100755 --- a/tests/run +++ b/tests/run @@ -44,9 +44,11 @@ function beforeTest() { mkdir "$tmpDir" echo "test::$(id -u):$(id -g):dir1,dir2" >> "$tmpDir/users" + echo "user.with.dot::$(id -u):$(id -g)" >> "$tmpDir/users" $sudo docker run \ - -v "$tmpDir/users:/etc/sftp-users.conf:ro" \ + -v "$tmpDir/users:/etc/sftp/users.conf:ro" \ -v "$scriptDir/id_rsa.pub":/home/test/.ssh/keys/id_rsa.pub:ro \ + -v "$scriptDir/id_rsa.pub":/home/user.with.dot/.ssh/keys/id_rsa.pub:ro \ -v "$tmpDir":/home/test/share \ --name "$sftpContainerName" \ --expose 22 \ @@ -96,19 +98,19 @@ function runSftpCommands() { function waitForServer() { containerName="$1" - echo -n "Waiting for $containerName to open port 22 " + echo -n "Waiting for $containerName to open port 22 ..." for i in {1..30}; do sleep 1 ip="$(getSftpIp $containerName)" echo -n "." - if nc -z $ip 22; then - echo " OK" + if [ -n "$ip" ] && nc -z $ip 22; then + echo " OPEN" return 0; fi done - echo " FAIL" + echo " TIMEOUT" return 1 } @@ -132,6 +134,13 @@ function testLoginUsingSshKey() { assertReturn $? 0 } +function testUserWithDotLogin() { + $skipAllTests && skip && return 0 + + runSftpCommands "$sftpContainerName" "user.with.dot" "exit" + assertReturn $? 0 +} + function testWritePermission() { $skipAllTests && skip && return 0 @@ -189,6 +198,34 @@ function testMinimalContainerStart() { fi } +function testLegacyConfigPath() { + $skipAllTests && skip && return 0 + + tmpContainerName="$sftpContainerName""_legacy" + + echo "test::$(id -u):$(id -g)" >> "$tmpDir/legacy_users" + $sudo docker run \ + -v "$tmpDir/legacy_users:/etc/sftp-users.conf:ro" \ + --name "$tmpContainerName" \ + --expose 22 \ + -d "$sftpImageName" \ + > "$redirect" + + waitForServer $tmpContainerName + + ps="$($sudo docker ps -q -f name="$tmpContainerName")" + assertNotEqual "$ps" "" + + if [ "$output" != "quiet" ]; then + $sudo docker logs "$tmpContainerName" + fi + + if [ "$cleanup" == "cleanup" ]; then + $sudo docker rm -fv "$tmpContainerName" > "$redirect" + fi +} + + # Bind-mount folder using script in /etc/sftp.d/ function testCustomContainerStart() { $skipAllTests && skip && return 0