feature(entrypoint): generate self-signed certificate
- generate via specific invocation - auto-generate if SSL and no mounted certificate found - allow specifying hostname for certificate
This commit is contained in:
parent
e8d238f3c3
commit
c48e985d23
@ -5,11 +5,14 @@ ARG NODE_VERSION=16
|
|||||||
ARG ALPINE_VERSION=3.14
|
ARG ALPINE_VERSION=3.14
|
||||||
FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION}
|
FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION}
|
||||||
|
|
||||||
# create new node user with set id from build-arg
|
# create new node user with set id from build-arg and create volume directories
|
||||||
ARG NODE_UID=9999
|
ARG NODE_UID=9999
|
||||||
RUN deluser --remove-home node \
|
RUN deluser --remove-home node \
|
||||||
&& addgroup -g ${NODE_UID} -S node \
|
&& addgroup -g ${NODE_UID} -S node \
|
||||||
&& adduser -G node -S -u ${NODE_UID} node
|
&& adduser -G node -S -u ${NODE_UID} node \
|
||||||
|
&& mkdir /watch /certs \
|
||||||
|
&& chown root:node /certs \
|
||||||
|
&& chmod 770 /certs
|
||||||
|
|
||||||
# create default volumes in-case user forgets, expose default port
|
# create default volumes in-case user forgets, expose default port
|
||||||
VOLUME [ "/watch", "/certs" ]
|
VOLUME [ "/watch", "/certs" ]
|
||||||
@ -40,6 +43,7 @@ ENV LR_EXCLUDE=".git/,.svn/,.vscode/,.idea/"
|
|||||||
ENV LR_DELAY=500
|
ENV LR_DELAY=500
|
||||||
ENV LR_DEBUG=true
|
ENV LR_DEBUG=true
|
||||||
ENV LR_HTTPS=true
|
ENV LR_HTTPS=true
|
||||||
|
ENV CERT_HOSTNAME=""
|
||||||
|
|
||||||
# install livereload npm as node user then switch back to root user
|
# install livereload npm as node user then switch back to root user
|
||||||
USER node
|
USER node
|
||||||
@ -51,11 +55,13 @@ RUN mkdir -p .npm-global/bin .npm-global/lib \
|
|||||||
|
|
||||||
# copy scripts and fix-up all permissions
|
# copy scripts and fix-up all permissions
|
||||||
USER root
|
USER root
|
||||||
|
COPY [ "selfsigned.cnf", "/etc/selfsigned.cnf" ]
|
||||||
COPY [ "livereload.js", "/home/node/livereload.js" ]
|
COPY [ "livereload.js", "/home/node/livereload.js" ]
|
||||||
COPY [ "entrypoint.sh", "/usr/local/bin/entrypoint.sh" ]
|
COPY [ "entrypoint.sh", "/usr/local/bin/entrypoint.sh" ]
|
||||||
RUN chown node:node /home/node/livereload.js \
|
RUN chown node:node /home/node/livereload.js \
|
||||||
&& chmod 644 /home/node/livereload.js \
|
&& chmod 644 /home/node/livereload.js \
|
||||||
&& chmod 755 /usr/local/bin/entrypoint.sh
|
&& chmod 755 /usr/local/bin/entrypoint.sh \
|
||||||
|
&& chmod 644 /etc/selfsigned.cnf
|
||||||
|
|
||||||
# switch to node user, run entrypoint script by default
|
# switch to node user, run entrypoint script by default
|
||||||
USER node
|
USER node
|
||||||
|
@ -6,10 +6,26 @@
|
|||||||
|
|
||||||
# functions
|
# functions
|
||||||
certificateGenerateNew() {
|
certificateGenerateNew() {
|
||||||
certificateCheckEnabled
|
# generate self-signed certificate
|
||||||
printf "\nGenerating new self-signed certificate:\n"
|
printf "\nGenerating new self-signed certificate:\n"
|
||||||
printf "Exporting new certificate:\n"
|
# shellcheck disable=SC3028
|
||||||
exit 0
|
if [ -z "$CERT_HOSTNAME" ]; then export CERT_HOSTNAME="$HOSTNAME"; fi
|
||||||
|
if ! openssl req -new -x509 -days 365 -nodes -out /certs/fullchain.pem -keyout /certs/privkey.pem -config /etc/selfsigned.cnf; then
|
||||||
|
printf "\nUnable to generate certificate. Is your 'certs' directory writable by this container?\n\n"
|
||||||
|
exit 55
|
||||||
|
fi
|
||||||
|
printf "Exporting pfx certificate..."
|
||||||
|
if ! openssl pkcs12 -export -in /certs/fullchain.pem -inkey /certs/privkey.pem -out "/certs/${CERT_HOSTNAME}.pfx" -name "LiveReload" -passout pass:cert1234; then
|
||||||
|
printf "\nUnable to export generated certificate as PFX.\n\n"
|
||||||
|
exit 56
|
||||||
|
fi
|
||||||
|
|
||||||
|
# print message to user
|
||||||
|
printf "\n\nA self-signed certificate has been generated and saved in the location mounted to '/certs' in this container.\n"
|
||||||
|
printf "The certificate and private key are PEM formatted with names 'fullchain.pem' and 'privkey.pem', respectively.\n"
|
||||||
|
printf "If you need to import them to a Windows machine, please use the '%s.pfx' file with password 'cert1234'.\n\n" "$CERT_HOSTNAME"
|
||||||
|
|
||||||
|
if [ "$1" != "noexit" ]; then exit 0; fi
|
||||||
}
|
}
|
||||||
|
|
||||||
certificateShow() {
|
certificateShow() {
|
||||||
@ -25,7 +41,6 @@ certificateExport() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
certificateCheckEnabled() {
|
certificateCheckEnabled() {
|
||||||
httpsEnabled="$(convertCaseUpper "$LR_HTTPS")"
|
|
||||||
if [ "$httpsEnabled" != "TRUE" ]; then
|
if [ "$httpsEnabled" != "TRUE" ]; then
|
||||||
printf "\nSSL/TLS not enabled. Please set LR_HTTPS=TRUE if you want to enable SSL/TLS.\n"
|
printf "\nSSL/TLS not enabled. Please set LR_HTTPS=TRUE if you want to enable SSL/TLS.\n"
|
||||||
exit 1
|
exit 1
|
||||||
@ -42,6 +57,7 @@ doCertNew=0
|
|||||||
doCertShow=0
|
doCertShow=0
|
||||||
doServer=0
|
doServer=0
|
||||||
doShell=0
|
doShell=0
|
||||||
|
httpsEnabled="$(convertCaseUpper "$LR_HTTPS")"
|
||||||
|
|
||||||
# process action parameter
|
# process action parameter
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@ -70,6 +86,29 @@ esac
|
|||||||
|
|
||||||
# action: run server
|
# action: run server
|
||||||
if [ "$doServer" -eq 1 ]; then
|
if [ "$doServer" -eq 1 ]; then
|
||||||
|
printf "Starting LiveReload server:\n"
|
||||||
|
|
||||||
|
# https pre-flight check
|
||||||
|
if [ "$httpsEnabled" = "TRUE" ]; then
|
||||||
|
printf "[SSL/TLS mode enabled]\n"
|
||||||
|
if [ -n "$(find /certs/ -type d -empty -print)" ]; then
|
||||||
|
printf "[Generating certificate]\n"
|
||||||
|
# certs directory is empty --> auto-generate certificates
|
||||||
|
certificateGenerateNew 'noexit'
|
||||||
|
else
|
||||||
|
# certs directory contains certificates --> check if they can read
|
||||||
|
printf "[Checking mounted certificate]\n"
|
||||||
|
if ! [ -r "/certs/fullchain.pem" ]; then
|
||||||
|
printf "\nERROR: SSL/TLS mode selected but unable to read certificate!\n\n"
|
||||||
|
exit 51
|
||||||
|
fi
|
||||||
|
if ! [ -r "/certs/privkey.pem" ]; then
|
||||||
|
printf "\nERROR: SSL/TLS mode selected but unable to read private key!\n\n"
|
||||||
|
exit 52
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
printf "[Certificate OK]\n"
|
||||||
|
fi
|
||||||
exec node livereload.js
|
exec node livereload.js
|
||||||
exit "$?"
|
exit "$?"
|
||||||
fi
|
fi
|
||||||
@ -102,6 +141,7 @@ exit 99
|
|||||||
# exit codes:
|
# exit codes:
|
||||||
# 0: normal exit, no errors
|
# 0: normal exit, no errors
|
||||||
# 1: invalid or invalid parameter passed to script
|
# 1: invalid or invalid parameter passed to script
|
||||||
|
# 2: interactive shell required
|
||||||
# 50: certificate errors
|
# 50: certificate errors
|
||||||
# 51: unable to read certificate/chain
|
# 51: unable to read certificate/chain
|
||||||
# 52: unable to read private key
|
# 52: unable to read private key
|
||||||
|
16
build/selfsigned.cnf
Normal file
16
build/selfsigned.cnf
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
default_bits = 4096
|
||||||
|
default_md = sha256
|
||||||
|
distinguished_name = dn
|
||||||
|
req_extensions = san
|
||||||
|
x509_extensions = san
|
||||||
|
prompt = no
|
||||||
|
|
||||||
|
[dn]
|
||||||
|
organizationName = LiveReload WebServer
|
||||||
|
CN = ${ENV::CERT_HOSTNAME}
|
||||||
|
|
||||||
|
[san]
|
||||||
|
subjectAltName = @alt_names
|
||||||
|
|
||||||
|
[alt_names]
|
||||||
|
DNS.1 = ${ENV::CERT_HOSTNAME}
|
@ -93,4 +93,12 @@
|
|||||||
# VALID OPTIONS: true, false
|
# VALID OPTIONS: true, false
|
||||||
#LR_HTTPS=true
|
#LR_HTTPS=true
|
||||||
|
|
||||||
|
# CERT_HOSTNAME:
|
||||||
|
# Hostname to use if container is auto-generating a self-signed certificate.
|
||||||
|
# REQUIRED: NO
|
||||||
|
# DEFAULT: $HOSTNAME
|
||||||
|
# VALID OPTIONS: Any valid hostname
|
||||||
|
#CERT_HOSTNAME=$HOSTNAME
|
||||||
|
|
||||||
|
|
||||||
#EOF
|
#EOF
|
||||||
|
Loading…
Reference in New Issue
Block a user