embedded cert.sh
continuous-integration/drone/push Build was killed Details
continuous-integration/drone/tag Build was killed Details

This commit is contained in:
Paolo Asperti 2024-01-23 17:15:08 +01:00
parent 488acf16c1
commit 962624e294
Signed by: paspo
GPG Key ID: 06D46905D19D5182
13 changed files with 235 additions and 76 deletions

View File

@ -42,11 +42,11 @@ steps:
dockerfile: Dockerfile dockerfile: Dockerfile
force_tag: true force_tag: true
password: password:
from_secret: docker_gitea_password from_secret: gitea_docker_password
registry: git.asperti.com registry: git.asperti.com
repo: git.asperti.com/paspo/docker-ftps repo: git.asperti.com/paspo/docker-ftps
username: username:
from_secret: docker_gitea_username from_secret: gitea_docker_username
tags: tags:
- ${DRONE_TAG}-linux-amd64 - ${DRONE_TAG}-linux-amd64
- ${DRONE_SEMVER_MAJOR}.${DRONE_SEMVER_MINOR}-linux-amd64 - ${DRONE_SEMVER_MAJOR}.${DRONE_SEMVER_MINOR}-linux-amd64
@ -100,11 +100,11 @@ steps:
dockerfile: Dockerfile dockerfile: Dockerfile
force_tag: true force_tag: true
password: password:
from_secret: docker_gitea_password from_secret: gitea_docker_password
registry: git.asperti.com registry: git.asperti.com
repo: git.asperti.com/paspo/docker-ftps repo: git.asperti.com/paspo/docker-ftps
username: username:
from_secret: docker_gitea_username from_secret: gitea_docker_username
tags: tags:
- ${DRONE_TAG}-linux-arm64 - ${DRONE_TAG}-linux-arm64
- ${DRONE_SEMVER_MAJOR}.${DRONE_SEMVER_MINOR}-linux-arm64 - ${DRONE_SEMVER_MAJOR}.${DRONE_SEMVER_MINOR}-linux-arm64
@ -158,11 +158,11 @@ steps:
dockerfile: Dockerfile dockerfile: Dockerfile
force_tag: true force_tag: true
password: password:
from_secret: docker_gitea_password from_secret: gitea_docker_password
registry: git.asperti.com registry: git.asperti.com
repo: git.asperti.com/paspo/docker-ftps repo: git.asperti.com/paspo/docker-ftps
username: username:
from_secret: docker_gitea_username from_secret: gitea_docker_username
tags: tags:
- ${DRONE_TAG}-linux-arm - ${DRONE_TAG}-linux-arm
- ${DRONE_SEMVER_MAJOR}.${DRONE_SEMVER_MINOR}-linux-arm - ${DRONE_SEMVER_MAJOR}.${DRONE_SEMVER_MINOR}-linux-arm
@ -203,9 +203,9 @@ steps:
ignore_missing: true ignore_missing: true
spec: manifest2.tmpl spec: manifest2.tmpl
username: username:
from_secret: docker_gitea_username from_secret: gitea_docker_username
password: password:
from_secret: docker_gitea_password from_secret: gitea_docker_password
tags: tags:
- latest - latest
- ${DRONE_TAG} - ${DRONE_TAG}

View File

@ -1,17 +1,9 @@
FROM alpine:edge FROM alpine:latest
RUN \ RUN \
echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \ apk -U add proftpd proftpd-mod_tls proftpd-mod_ifsession proftpd-utils openssl perl acme.sh && \
apk -U add proftpd proftpd-mod_tls proftpd-mod_ifsession proftpd-utils openssl perl && \
mkdir -p /var/run/proftpd /etc/proftpd/custom.conf.d/ mkdir -p /var/run/proftpd /etc/proftpd/custom.conf.d/
COPY custom.conf /etc/proftpd/conf.d/custom.conf COPY rootfs /
COPY run.sh /run.sh
COPY cron.sh /cron.sh
RUN \ ENTRYPOINT ["/app/entrypoint.sh"]
chmod +x /run.sh && \
chmod +x /cron.sh && \
ln -s /cron.sh /etc/periodic/15min/reconfigure_certs.sh
ENTRYPOINT ["/run.sh"]

View File

@ -22,7 +22,7 @@ docker run -d --name my-ftps \
``` ```
The *MASQUERADE* parameter is the only required one. You can use an IP address (which is discouraged) or a DNS name. The *MASQUERADE* parameter is the only required one. You can use an IP address (which is discouraged) or a DNS name.
You must provide valid certificates for TLS; if you use Lets'Encrypt, you can mofify like this: You must provide valid certificates for TLS; if you use Lets'Encrypt, you can modify like this:
```bash ```bash
docker run -d --name my-ftps \ docker run -d --name my-ftps \
@ -33,7 +33,7 @@ docker run -d --name my-ftps \
docker.asperti.com/paspo/ftps docker.asperti.com/paspo/ftps
``` ```
## docker-compose ## docker-compose (external certificate)
```yaml ```yaml
version: "3" version: "3"
@ -56,12 +56,66 @@ services:
- PASSIVEPORTS_START=21210 - PASSIVEPORTS_START=21210
- PASSIVEPORTS_END=21220 - PASSIVEPORTS_END=21220
- MAXCLIENTS=500 - MAXCLIENTS=500
- MAXCLIENTSPERHOST=100 - MAXCLIENTSPERHOST=100
- TLS_CERT=/certs/live/ftp.mydomain.com/cert.pem - TLS_CERT=/certs/live/ftp.mydomain.com/cert.pem
- TLS_KEY=/certs/live/ftp.mydomain.com/privkey.pem - TLS_KEY=/certs/live/ftp.mydomain.com/privkey.pem
- TLS_CHAIN=/certs/live/ftp.mydomain.com/chain.pem - TLS_CHAIN=/certs/live/ftp.mydomain.com/chain.pem
``` ```
## docker-compose (using internal acme.sh)
```yaml
version: "3"
services:
ftps-server:
image: docker.asperti.com/paspo/ftps
restart: always
ports:
- "21:21"
- "20:20"
- "21210-21220:21210-21220"
volumes:
- "/srv/ftps/auth:/auth"
- "/srv/ftps/conf:/etc/proftpd/custom.conf.d:ro"
- "/srv/ftps/data:/home"
- "/srv/ftps/acme:/acme"
environment:
- MASQUERADE=ftp.mydomain.com
- PASSIVEPORTS_START=21210
- PASSIVEPORTS_END=21220
- MAXCLIENTS=500
- MAXCLIENTSPERHOST=100
- ENABLE_ACME=1 # "1" will enable, anything else means external cert
- ACME_SERVER=letsencrypt # optional
- ACME_EMAIL=myemail@gmail.com # used by letsencrypt
- ACME_DNS=dns_ovh # see below
- OVH_END_POINT=ovh-eu
- OVH_AK=abc123abc123abc1 # application key
- OVH_AS=abc123abc123abc1abc123abc123abc1 # application secret
- OVH_CK=abc123abc123abc1abc123abc123abc1 # consumer key
```
## The rationale behind the acme.sh alternative
You normally use an external letsencrypt client to obtain the certificate and then pass it to the docker container. In some cases, you can't use an external acme client and/or you can't do HTTP-01 auth.
The included `acme.sh` client will help you to setup DNS-01 auth and in keeping the cert updated.
Please check [here](https://github.com/acmesh-official/acme.sh/wiki/dnsapi) for supported dns providers.
Each provider will use different environment variables, you have to add these variables to the container's environment.
### OVH
A quick way to create required credentials for OVH:
- login to your [OVH accuont](https://www.ovh.com/manager/)
- paste in your browser an URL like the following one:
```txt
https://api.ovh.com/createToken/?GET=/domain/zone/mydomain.com/*&POST=/domain/zone/mydomain.com/*&PUT=/domain/zone/mydomain.com/*&GET=/domain/zone/mydomain.com&DELETE=/domain/zone/mydomain.com/record/*
```
This will create some credentials that'll allow management only for that domain (`mydomain.com`).
## passive ports ## passive ports
If you want to change the passive ports range (which by default is 50000-50050), you can do so via environment variables (PASSIVEPORTS_START and PASSIVEPORTS_END). If you want to change the passive ports range (which by default is 50000-50050), you can do so via environment variables (PASSIVEPORTS_START and PASSIVEPORTS_END).

28
rootfs/app/acme-cert-init.sh Executable file
View File

@ -0,0 +1,28 @@
#!/bin/sh
MASQUERADE=${MASQUERADE:-127.0.0.1}
ACME_SERVER=${ACME_SERVER:-letsencrypt}
ACME_DNS=${ACME_DNS:-myapi}
if [ ! -d /acme/cert ] ; then
mkdir -p /acme/cert
fi
if [ -n "${ACME_EMAIL}" ] ; then
ACME_EMAIL="--accountemail ${ACME_EMAIL}"
fi
if [ ! -f "/acme/cert/cert.pem" ] ; then
echo "Initializing certificate with acme.sh"
# shellcheck disable=SC2086
acme.sh --issue -d "${MASQUERADE}" \
--home /acme \
--dns "${ACME_DNS}" \
--server "${ACME_SERVER}" \
--cert-file /acme/cert/cert.pem \
--key-file /acme/cert/privkey.pem \
--fullchain-file /acme/cert/chain.pem \
--reloadcmd /app/acme-refresh-cert.sh ${ACME_EMAIL}
else
echo "Certificate ready"
fi

5
rootfs/app/acme-cron.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
if [ "$ENABLE_ACME" = "1" ] ; then
/usr/bin/acme.sh --cron --home /acme
fi

38
rootfs/app/acme-refresh-cert.sh Executable file
View File

@ -0,0 +1,38 @@
#!/bin/sh
############ FILES
TLS_CERT=/acme/cert/cert.pem
TLS_KEY=/acme/cert/privkey.pem
TLS_CHAIN=/acme/cert/chain.pem
[ ! -f "$TLS_CERT" ] && exit 1
[ ! -f "$TLS_KEY" ] && exit 1
[ ! -f "$TLS_CHAIN" ] && exit 1
############ CHECK CERT KEY ALGO
ALGO=$(openssl x509 -in "$TLS_CERT"-text | sed -n 's/\ *Public Key Algorithm: //p' | tr '\n')
############ UPDATE cert config if needed
if [ "$ALGO" = "id-ecPublicKey" ] ; then
cat > /etc/proftpd/conf.d/certificate.conf <<EOF
<IfModule mod_tls.c>
TLSECCertificateFile "$TLS_CERT"
TLSECCertificateKeyFile "$TLS_KEY"
TLSCertificateChainFile "$TLS_CHAIN"
</IfModule>
EOF
fi
if [ "$ALGO" = "rsaEncryption" ] ; then
cat > /etc/proftpd/conf.d/certificate.conf <<EOF
<IfModule mod_tls.c>
TLSRSACertificateFile "$TLS_CERT"
TLSRSACertificateKeyFile "$TLS_KEY"
TLSCertificateChainFile "$TLS_CHAIN"
</IfModule>
EOF
fi
############ RELOAD PROFTPD IF RUNNING
pidof proftpd >/dev/null && killall -HUP proftpd

20
cron.sh → rootfs/app/cert-init.sh Normal file → Executable file
View File

@ -1,23 +1,18 @@
#!/bin/sh #!/bin/sh
############ TLS ############ TLS
TLS_CERT=${TLS_CERT:-/certs/cert.pem} TLS_CERT=${TLS_CERT:-/certs/cert.pem}
TLS_KEY=${TLS_KEY:-/certs/privkey.pem} TLS_KEY=${TLS_KEY:-/certs/privkey.pem}
TLS_CHAIN=${TLS_CHAIN:-/certs/chain.pem} TLS_CHAIN=${TLS_CHAIN:-/certs/chain.pem}
cat $TLS_CERT > /etc/proftpd/cert.pem cat "$TLS_CERT" > /etc/proftpd/cert.pem
cat $TLS_KEY > /etc/proftpd/privkey.pem cat "$TLS_KEY" > /etc/proftpd/privkey.pem
cat $TLS_CHAIN > /etc/proftpd/chain.pem cat "$TLS_CHAIN "> /etc/proftpd/chain.pem
############ IF CERT IS THE SAME, THEN EXIT
md5sum -c /sums 1&>2 2>/dev/null && exit
############ CHECK CERT KEY ALGO ############ CHECK CERT KEY ALGO
ALGO=$(openssl x509 -in /etc/proftpd/cert.pem -text | sed -n 's/\ *Public Key Algorithm: //p' | tr '\n') ALGO=$(openssl x509 -in /etc/proftpd/cert.pem -text | sed -n 's/\ *Public Key Algorithm: //p' | tr '\n')
############ UPDATE cert config if needed
if [ "$ALGO" = "id-ecPublicKey" ] ; then if [ "$ALGO" = "id-ecPublicKey" ] ; then
cat > /etc/proftpd/conf.d/certificate.conf <<EOF cat > /etc/proftpd/conf.d/certificate.conf <<EOF
<IfModule mod_tls.c> <IfModule mod_tls.c>
@ -38,8 +33,5 @@ cat > /etc/proftpd/conf.d/certificate.conf <<EOF
EOF EOF
fi fi
md5sum "$TLS_CERT" > /sums md5sum "$TLS_CERT" > /app/sums
echo "Certificate ready"
############ RELOAD
killall -HUP proftpd

52
run.sh → rootfs/app/cron.sh Normal file → Executable file
View File

@ -1,29 +1,23 @@
#!/bin/sh #!/bin/sh
############ MASQUERADE ############ IF ACME IS ENABLED, THIS IS THE WRONG SCRIPT
if [ ! "$ENABLE_ACME" = "1" ] ; then
MASQUERADE=${MASQUERADE:-127.0.0.1} exit
echo "MasqueradeAddress ${MASQUERADE}" > /etc/proftpd/conf.d/masquerade.conf fi
############ AUTH
[ ! -f /auth/passwd ] && touch /auth/passwd
chmod 0600 /auth/passwd
chmod 0700 /auth
############ TLS ############ TLS
TLS_CERT=${TLS_CERT:-/certs/cert.pem} TLS_CERT=${TLS_CERT:-/certs/cert.pem}
TLS_KEY=${TLS_KEY:-/certs/privkey.pem} TLS_KEY=${TLS_KEY:-/certs/privkey.pem}
TLS_CHAIN=${TLS_CHAIN:-/certs/chain.pem} TLS_CHAIN=${TLS_CHAIN:-/certs/chain.pem}
cat $TLS_CERT > /etc/proftpd/cert.pem cat "$TLS_CERT" > /etc/proftpd/cert.pem
cat $TLS_KEY > /etc/proftpd/privkey.pem cat "$TLS_KEY" > /etc/proftpd/privkey.pem
cat $TLS_CHAIN > /etc/proftpd/chain.pem cat "$TLS_CHAIN" > /etc/proftpd/chain.pem
############ IF CERT IS THE SAME, THEN EXIT
md5sum -c /app/sums >/dev/null 2>/dev/null && exit
############ CHECK CERT KEY ALGO ############ CHECK CERT KEY ALGO
ALGO=$(openssl x509 -in /etc/proftpd/cert.pem -text | sed -n 's/\ *Public Key Algorithm: //p' | tr '\n') ALGO=$(openssl x509 -in /etc/proftpd/cert.pem -text | sed -n 's/\ *Public Key Algorithm: //p' | tr '\n')
if [ "$ALGO" = "id-ecPublicKey" ] ; then if [ "$ALGO" = "id-ecPublicKey" ] ; then
@ -46,27 +40,7 @@ cat > /etc/proftpd/conf.d/certificate.conf <<EOF
EOF EOF
fi fi
md5sum "$TLS_CERT" > /sums md5sum "$TLS_CERT" > /app/sums
############ PASSIVE PORTS ############ RELOAD
killall -HUP proftpd
PASSIVEPORTS_START=${PASSIVEPORTS_START:-50000}
PASSIVEPORTS_END=${PASSIVEPORTS_END:-50050}
echo "PassivePorts ${PASSIVEPORTS_START} ${PASSIVEPORTS_END}" > /etc/proftpd/conf.d/passive_ports.conf
############ MAX CLIENTS
MAXCLIENTS=${MAXCLIENTS:-30}
MAXCLIENTSPERHOST=${MAXCLIENTSPERHOST:-5}
echo "Maxclients ${MAXCLIENTS}" > /etc/proftpd/conf.d/maxclients.conf
echo "MaxClientsPerHost ${MAXCLIENTSPERHOST}" >> /etc/proftpd/conf.d/maxclients.conf
############ START CRON
crond -b
############ START
proftpd -n

36
rootfs/app/entrypoint.sh Executable file
View File

@ -0,0 +1,36 @@
#!/bin/sh
############ MASQUERADE
MASQUERADE=${MASQUERADE:-127.0.0.1}
echo "MasqueradeAddress ${MASQUERADE}" > /etc/proftpd/conf.d/masquerade.conf
############ AUTH
[ ! -f /auth/passwd ] && touch /auth/passwd
chmod 0600 /auth/passwd
chmod 0700 /auth
############ PASSIVE PORTS
PASSIVEPORTS_START=${PASSIVEPORTS_START:-50000}
PASSIVEPORTS_END=${PASSIVEPORTS_END:-50050}
echo "PassivePorts ${PASSIVEPORTS_START} ${PASSIVEPORTS_END}" > /etc/proftpd/conf.d/passive_ports.conf
############ MAX CLIENTS
MAXCLIENTS=${MAXCLIENTS:-30}
MAXCLIENTSPERHOST=${MAXCLIENTSPERHOST:-5}
echo "Maxclients ${MAXCLIENTS}" > /etc/proftpd/conf.d/maxclients.conf
echo "MaxClientsPerHost ${MAXCLIENTSPERHOST}" >> /etc/proftpd/conf.d/maxclients.conf
############ CERT INIT
ENABLE_ACME=${ENABLE_ACME:-no}
if [ "$ENABLE_ACME" = "1" ] ; then
/app/acme-cert-init.sh
else
/app/cert-init.sh
fi
############ START CRON
crond -b
############ START
proftpd -n

38
rootfs/app/refresh-cert.sh Executable file
View File

@ -0,0 +1,38 @@
#!/bin/sh
############ FILES
TLS_CERT=/acme/cert/cert.pem
TLS_KEY=/acme/cert/privkey.pem
TLS_CHAIN=/acme/cert/chain.pem
[ ! -f "$TLS_CERT" ] && exit 1
[ ! -f "$TLS_KEY" ] && exit 1
[ ! -f "$TLS_CHAIN" ] && exit 1
############ CHECK CERT KEY ALGO
ALGO=$(openssl x509 -in "$TLS_CERT"-text | sed -n 's/\ *Public Key Algorithm: //p' | tr '\n')
############ UPDATE cert config if needed
if [ "$ALGO" = "id-ecPublicKey" ] ; then
cat > /etc/proftpd/conf.d/certificate.conf <<EOF
<IfModule mod_tls.c>
TLSECCertificateFile "$TLS_CERT"
TLSECCertificateKeyFile "$TLS_KEY"
TLSCertificateChainFile "$TLS_CHAIN"
</IfModule>
EOF
fi
if [ "$ALGO" = "rsaEncryption" ] ; then
cat > /etc/proftpd/conf.d/certificate.conf <<EOF
<IfModule mod_tls.c>
TLSRSACertificateFile "$TLS_CERT"
TLSRSACertificateKeyFile "$TLS_KEY"
TLSCertificateChainFile "$TLS_CHAIN"
</IfModule>
EOF
fi
############ RELOAD PROFTPD IF RUNNING
pidof proftpd >/dev/null && killall -HUP proftpd

View File

@ -0,0 +1 @@
../../../app/acme-cron.sh

View File

@ -0,0 +1 @@
../../../app/cron.sh