Skip to content

Commit fc3d59b

Browse files
committed
✨ Add SFTP
1 parent 83568a0 commit fc3d59b

File tree

5 files changed

+165
-1
lines changed

5 files changed

+165
-1
lines changed

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99

1010
* [SSH-Proxy](ssh-proxy/README.md)
1111

12+
## Data Transfer Applications
13+
* [SFTP](sftp/README.md)
14+
1215
## 3rd-party Tools
1316

1417
* [Graylog](graylog/README.md)
15-

sftp/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
key
2+
key.pub
3+
authorized_keys

sftp/Dockerfile

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FROM alpine:3.14
2+
RUN apk add --update openssh bash shadow && \
3+
rm -rf /var/cache/apk/* && \
4+
adduser -u 1000 -g 1000 -D -s /sbin/nologin data && \
5+
usermod -p '*' data && \
6+
mkdir /app
7+
WORKDIR /app
8+
COPY docker-entrypoint.sh /
9+
10+
ENTRYPOINT ["/docker-entrypoint.sh"]

sftp/README.md

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# SFTP
2+
3+
This is an example of deploying an SFTP service on SetOps using [OpenSSH](https://www.openssh.com/). It is helpful if you want transfer files between an app and a SFTP client. This solution utilizes the SetOps volume service to share files between the SFTP app and another app.
4+
5+
## Setup
6+
7+
1. Create the app and make it public available via tcp. Only do a changeset commit after you set the protocol. Otherwise the protocol is set to `http` and cannot be changed anymore.
8+
9+
```shell
10+
setops -p <PROJECT> -s <STAGE> app:create sftp
11+
12+
setops -p <PROJECT> -s <STAGE> --app sftp network:set protocol tcp
13+
setops -p <PROJECT> -s <STAGE> --app sftp network:set public true
14+
setops -p <PROJECT> -s <STAGE> --app sftp network:set port 12345
15+
```
16+
17+
1. Mount the existing volume to the SFTP app to `/data`:
18+
19+
```shell
20+
setops -p <PROJECT> -s <STAGE> --app sftp link:create volume --path /data [--read-only]
21+
```
22+
23+
1. Set the environment variables:
24+
25+
```text
26+
# one of
27+
SSH_ECDSA_HOST_KEY: <see hint>
28+
SSH_ED25519_HOST_KEY: <see hint>
29+
SSH_RSA_HOST_KEY: <see hint>
30+
31+
(optional) SSH_PASSWORD: <see hint>
32+
(optional) SSH_AUTHORIZED_KEYS: <see hint>
33+
```
34+
35+
> Hint:
36+
>
37+
> `SSH_ECDSA_HOST_KEY`: SSH server host key (generate with `ssh-keygen -t ecdsa -b 521 -f key` without passphrase), encode to base64 with `base64 --break=0 < key`
38+
> `SSH_ED25519_HOST_KEY`: SSH server host key (generate with `ssh-keygen -t ed25519 -f key` without passphrase), encode to base64 with `base64 --break=0 < key`
39+
> `SSH_RSA_HOST_KEY`: SSH server host key (generate with `ssh-keygen -t rsa -b 4096 -f key` without passphrase), encode to base64 with `base64 --break=0 < key`
40+
>
41+
> `SSH_PASSWORD`: random (e.g. 16 character) password (generate with `pwgen 16 1`)
42+
>
43+
> `SSH_AUTHORIZED_KEYS`: SSH public keys files, encode to base64 with `base64 --break=0 < authorized_keys`
44+
45+
Use the `setops -p <PROJECT> -s <STAGE> --app sftp env:set <var>:<value>` to set the values. The port of the SFTP server is gathered by using the `$PORT` environment variables.
46+
47+
1. Commit your changes with `setops -p <PROJECT> -s <STAGE> changeset:commit`.
48+
49+
1. Build & Deploy the SFTP app using:
50+
51+
```shell
52+
docker build -t <CLIENT>.setops.net/<PROJECT>/<STAGE>/sftp .
53+
docker push <CLIENT>.setops.net/<PROJECT>/<STAGE>/sftp
54+
55+
setops -p <PROJECT> -s <STAGE> --app sftp release:create sha256:<sha>
56+
setops -p <PROJECT> -s <STAGE> --app sftp release:activate 1
57+
setops -p <PROJECT> -s <STAGE> changeset:commit
58+
```
59+
60+
## Connection
61+
62+
To connect to the SFTP server, use the following settings:
63+
64+
- Server: run `setops -p <PROJECT> -s <STAGE> --app sftp domain` to get the domain
65+
- User: `data`
66+
- Auth: either use the password you provided (via the `SSH_PASSWORD` env variable) or a client with the your SSH private key
67+
- Port: see App Network Port (`app:info sftp`, default `5000`)

sftp/docker-entrypoint.sh

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
main() {
5+
echo "Prepare server config"
6+
cat << EOF > /etc/ssh/sshd_config
7+
Protocol 2
8+
UseDNS no
9+
MaxAuthTries 5
10+
LoginGraceTime 60
11+
MaxSessions 5
12+
MaxStartups 10:30:60
13+
LogLevel INFO
14+
Subsystem sftp internal-sftp
15+
ChrootDirectory /data
16+
EOF
17+
18+
echo "Setting port"
19+
echo "Port $PORT" >> /etc/ssh/sshd_config
20+
21+
echo "Setting host keys"
22+
if [ -z "${SSH_ECDSA_HOST_KEY=}" ] && [ -z "${SSH_ED25519_HOST_KEY=}" ] && [ -z "${SSH_RSA_HOST_KEY=}" ]; then
23+
echo "> No host key was set. Expecting at least one of SSH_ECDSA_HOST_KEY, SSH_ED25519_HOST_KEY, SSH_RSA_HOST_KEY."
24+
exit 1
25+
fi
26+
if [ ! -z "${SSH_ECDSA_HOST_KEY=}" ]; then
27+
base64 -d <<< "$SSH_ECDSA_HOST_KEY" > /etc/ssh/ssh_host_ecdsa_key
28+
chmod 600 /etc/ssh/ssh_host_ecdsa_key
29+
echo "HostKey /etc/ssh/ssh_host_ecdsa_key" >> /etc/ssh/sshd_config
30+
fi
31+
if [ ! -z "${SSH_ED25519_HOST_KEY=}" ]; then
32+
base64 -d <<< "$SSH_ED25519_HOST_KEY" > /etc/ssh/ssh_host_ed25519_key
33+
chmod 600 /etc/ssh/ssh_host_ed25519_key
34+
echo "HostKey /etc/ssh/ssh_host_ed25519_key" >> /etc/ssh/sshd_config
35+
fi
36+
if [ ! -z "${SSH_RSA_HOST_KEY=}" ]; then
37+
base64 -d <<< "$SSH_RSA_HOST_KEY" > /etc/ssh/ssh_host_rsa_key
38+
chmod 600 /etc/ssh/ssh_host_rsa_key
39+
echo "HostKey /etc/ssh/ssh_host_rsa_key" >> /etc/ssh/sshd_config
40+
fi
41+
42+
echo "Setting authorized_keys for user data"
43+
touch /etc/ssh/authorized_keys
44+
if [ ! -z "${SSH_AUTHORIZED_KEYS=}" ]; then
45+
base64 -d <<< "$SSH_AUTHORIZED_KEYS" > /etc/ssh/authorized_keys
46+
else
47+
echo "> Skipping because SSH_AUTHORIZED_KEYS is unset"
48+
fi
49+
chown data:root /etc/ssh/authorized_keys
50+
chmod 600 /etc/ssh/authorized_keys
51+
52+
echo "Setting password for user data"
53+
if [ ! -z "${SSH_PASSWORD=}" ]; then
54+
echo "data:$SSH_PASSWORD" | chpasswd
55+
echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config
56+
echo "ChallengeResponseAuthentication yes" >> /etc/ssh/sshd_config
57+
else
58+
echo "PasswordAuthentication no" >> /etc/ssh/sshd_config
59+
echo "ChallengeResponseAuthentication no" >> /etc/ssh/sshd_config
60+
echo "> Password auth deactivated since no password was provided"
61+
fi
62+
63+
echo "Setting user config"
64+
cat << EOF >> /etc/ssh/sshd_config
65+
AllowUsers data
66+
Match User data
67+
ForceCommand internal-sftp -l INFO
68+
AllowTcpForwarding no
69+
PermitTunnel no
70+
X11Forwarding no
71+
AuthorizedKeysFile /etc/ssh/authorized_keys
72+
EOF
73+
74+
printf "\n------------ Generated config ------------\n"
75+
cat /etc/ssh/sshd_config
76+
printf "\n------------------------------------------\n\n"
77+
78+
echo "Starting sshd..."
79+
exec /usr/sbin/sshd -D
80+
}
81+
82+
main "$@"

0 commit comments

Comments
 (0)