From 2ac3fd82218a5bcddbaab0590579bab17b8b43f2 Mon Sep 17 00:00:00 2001 From: Blake Blackshear Date: Sun, 2 Jun 2024 07:19:24 -0500 Subject: [PATCH] improve tls implementation --- docker/main/Dockerfile | 8 +++++- .../etc/s6-overlay/s6-rc.d/certsync/run | 9 ++++-- .../rootfs/etc/s6-overlay/s6-rc.d/nginx/run | 7 ++++- .../rootfs/usr/local/nginx/conf/nginx.conf | 12 +------- .../usr/local/nginx/get_tls_settings.py | 28 +++++++++++++++++++ .../tls.conf => templates/listen.gotmpl} | 10 +++++-- frigate/config.py | 5 ++++ 7 files changed, 62 insertions(+), 17 deletions(-) create mode 100644 docker/main/rootfs/usr/local/nginx/get_tls_settings.py rename docker/main/rootfs/usr/local/nginx/{conf/tls.conf => templates/listen.gotmpl} (79%) diff --git a/docker/main/Dockerfile b/docker/main/Dockerfile index ad3857dca..51293b78b 100644 --- a/docker/main/Dockerfile +++ b/docker/main/Dockerfile @@ -35,6 +35,11 @@ ARG TARGETARCH WORKDIR /rootfs/usr/local/go2rtc/bin ADD --link --chmod=755 "https://github.com/AlexxIT/go2rtc/releases/download/v1.9.2/go2rtc_linux_${TARGETARCH}" go2rtc +FROM scratch AS tempio +ARG TARGETARCH +WORKDIR /rootfs/usr/local/tempio/bin +ADD --link --chmod=755 "https://github.com/home-assistant/tempio/releases/download/2021.09.0/tempio_${TARGETARCH}" tempio + #### # @@ -131,6 +136,7 @@ RUN pip3 wheel --wheel-dir=/wheels -r /requirements-wheels.txt FROM scratch AS deps-rootfs COPY --from=nginx /usr/local/nginx/ /usr/local/nginx/ COPY --from=go2rtc /rootfs/ / +COPY --from=tempio /rootfs/ / COPY --from=s6-overlay /rootfs/ / COPY --from=models /rootfs/ / COPY docker/main/rootfs/ / @@ -148,7 +154,7 @@ ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn ENV NVIDIA_VISIBLE_DEVICES=all ENV NVIDIA_DRIVER_CAPABILITIES="compute,video,utility" -ENV PATH="/usr/lib/btbn-ffmpeg/bin:/usr/local/go2rtc/bin:/usr/local/nginx/sbin:${PATH}" +ENV PATH="/usr/lib/btbn-ffmpeg/bin:/usr/local/go2rtc/bin:/usr/local/tempio/bin:/usr/local/nginx/sbin:${PATH}" # Install dependencies RUN --mount=type=bind,source=docker/main/install_deps.sh,target=/deps/install_deps.sh \ diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/run b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/run index f6342624e..521a07463 100755 --- a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/run +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/run @@ -10,16 +10,21 @@ echo "[INFO] Starting certsync..." lefile="/etc/letsencrypt/live/frigate/fullchain.pem" +tls_enabled=`python3 /usr/local/nginx/get_tls_settings.py | jq -r .enabled` while true do + if [[ "$tls_enabled" == 'false' ]]; then + sleep 9999 + continue + fi if [ ! -e $lefile ] then echo "[ERROR] TLS certificate does not exist: $lefile" fi - leprint=`openssl x509 -in $lefile -fingerprint -noout || echo 'failed'` + leprint=`openssl x509 -in $lefile -fingerprint -noout 2>&1 || echo 'failed'` case "$leprint" in *Fingerprint*) @@ -29,7 +34,7 @@ do ;; esac - liveprint=`echo | openssl s_client -showcerts -connect 127.0.0.1:443 2>&1 | openssl x509 -fingerprint | grep -i fingerprint || echo 'failed'` + liveprint=`echo | openssl s_client -showcerts -connect 127.0.0.1:8080 2>&1 | openssl x509 -fingerprint 2>&1 | grep -i fingerprint || echo 'failed'` case "$liveprint" in *Fingerprint*) diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run index 95527c4ab..10d15aecc 100755 --- a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run @@ -33,9 +33,14 @@ if [ ! \( -f "$letsencrypt_path/privkey.pem" -a -f "$letsencrypt_path/fullchain. echo "[INFO] No TLS certificate found. Generating a self signed certificate..." openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \ -subj "/O=FRIGATE DEFAULT CERT/CN=*" \ - -keyout "$letsencrypt_path/privkey.pem" -out "$letsencrypt_path/fullchain.pem" + -keyout "$letsencrypt_path/privkey.pem" -out "$letsencrypt_path/fullchain.pem" 2>/dev/null fi +# build templates for optional TLS support +python3 /usr/local/nginx/get_tls_settings.py | \ + tempio -template /usr/local/nginx/templates/listen.gotmpl \ + -out /usr/local/nginx/conf/listen.conf + # Replace the bash process with the NGINX process, redirecting stderr to stdout exec 2>&1 exec \ diff --git a/docker/main/rootfs/usr/local/nginx/conf/nginx.conf b/docker/main/rootfs/usr/local/nginx/conf/nginx.conf index 6bec3e187..bcd135e51 100644 --- a/docker/main/rootfs/usr/local/nginx/conf/nginx.conf +++ b/docker/main/rootfs/usr/local/nginx/conf/nginx.conf @@ -59,20 +59,10 @@ http { include go2rtc_upstream.conf; server { - listen [::]:80 ipv6only=off default_server; - - location / { - return 301 https://$host$request_uri; - } - } - - server { - # intended for external traffic, protected by auth - listen [::]:8080 ipv6only=off; # intended for internal traffic, not protected by auth listen [::]:5000 ipv6only=off; - include tls.conf; + include listen.conf; # vod settings vod_base_url ''; diff --git a/docker/main/rootfs/usr/local/nginx/get_tls_settings.py b/docker/main/rootfs/usr/local/nginx/get_tls_settings.py new file mode 100644 index 000000000..45a40ff5d --- /dev/null +++ b/docker/main/rootfs/usr/local/nginx/get_tls_settings.py @@ -0,0 +1,28 @@ +"""Prints the tls config as json to stdout.""" + +import json +import os + +import yaml + +config_file = os.environ.get("CONFIG_FILE", "/config/config.yml") + +# Check if we can use .yaml instead of .yml +config_file_yaml = config_file.replace(".yml", ".yaml") +if os.path.isfile(config_file_yaml): + config_file = config_file_yaml + +try: + with open(config_file) as f: + raw_config = f.read() + + if config_file.endswith((".yaml", ".yml")): + config: dict[str, any] = yaml.safe_load(raw_config) + elif config_file.endswith(".json"): + config: dict[str, any] = json.loads(raw_config) +except FileNotFoundError: + config: dict[str, any] = {} + +tls_config: dict[str, any] = config.get("tls", {}) + +print(json.dumps(tls_config)) diff --git a/docker/main/rootfs/usr/local/nginx/conf/tls.conf b/docker/main/rootfs/usr/local/nginx/templates/listen.gotmpl similarity index 79% rename from docker/main/rootfs/usr/local/nginx/conf/tls.conf rename to docker/main/rootfs/usr/local/nginx/templates/listen.gotmpl index fe2673f53..e301a884e 100644 --- a/docker/main/rootfs/usr/local/nginx/conf/tls.conf +++ b/docker/main/rootfs/usr/local/nginx/templates/listen.gotmpl @@ -1,5 +1,9 @@ -keepalive_timeout 70; -listen [::]:443 ipv6only=off default_server ssl; +{{ if not .enabled }} +# intended for external traffic, protected by auth +listen [::]:8080 ipv6only=off; +{{ else }} +# intended for external traffic, protected by auth +listen [::]:8080 ipv6only=off ssl; ssl_certificate /etc/letsencrypt/live/frigate/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/frigate/privkey.pem; @@ -22,3 +26,5 @@ location /.well-known/acme-challenge/ { default_type "text/plain"; root /etc/letsencrypt/www; } +{{ end }} + diff --git a/frigate/config.py b/frigate/config.py index 1bd188f55..2f9f73a14 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -115,6 +115,10 @@ class UIConfig(FrigateBaseModel): ) +class TlsConfig(FrigateBaseModel): + enabled: bool = Field(default=True, title="Enable TLS for port 8080") + + class AuthModeEnum(str, Enum): native = "native" proxy = "proxy" @@ -1303,6 +1307,7 @@ class FrigateConfig(FrigateBaseModel): database: DatabaseConfig = Field( default_factory=DatabaseConfig, title="Database configuration." ) + tls: TlsConfig = Field(default_factory=TlsConfig, title="TLS configuration.") auth: AuthConfig = Field(default_factory=AuthConfig, title="Auth configuration.") environment_vars: Dict[str, str] = Field( default_factory=dict, title="Frigate environment variables."