zabbix / zabbix-docker

Official Zabbix Dockerfiles
https://www.zabbix.com
GNU Affero General Public License v3.0
2.35k stars 1.37k forks source link

nginx_ssl.conf not sym-linked v7.0.4 #1518

Closed sjackson0109 closed 5 days ago

sjackson0109 commented 6 days ago
SUMMARY

I am unable to open a socket connection to TCP port 443. Root-cause: The /etc/nginx/http.d/nginx_ssl.conf symlink does not exist.

ENVIRONMENT
root@docker-host:~/zabbix-docker# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 24.04.1 LTS
Release:        24.04
Codename:       noble

root@docker-host:~/zabbix-docker# docker -v
Docker version 27.3.1, build ce12230

root@docker-host:~/zabbix-docker# ls -l ./compose.yaml 
lrwxrwxrwx 1 root root 42 Sep 24 08:26 ./compose.yaml -> docker-compose_v3_alpine_pgsql_latest.yaml
CONTAINERS
root@docker-host:~/zabbix-docker# docker compose up -d
[+] Running 9/9
 ✔ Network zabbix-docker_tools_frontend              Created  0.1s 
 ✔ Network zabbix-docker_database                    Created  0.0s 
 ✔ Network zabbix-docker_backend                     Created  0.0s 
 ✔ Network zabbix-docker_frontend                    Created  0.1s 
 ✔ Network zabbix-docker_default                     Created  0.1s 
 ✔ Container zabbix-docker-postgres-server-1         Started  0.2s 
 ✔ Container zabbix-docker-db-data-pgsql-1           Started  0.3s 
 ✔ Container zabbix-docker-zabbix-web-nginx-pgsql-1  Started  0.6s 
 ✔ Container zabbix-docker-zabbix-server-1           Started  0.6s 

root@docker-host:~/zabbix-docker# docker ps
CONTAINER ID   IMAGE                                             COMMAND                  CREATED         STATUS                   PORTS                                                                                NAMES
f561bb85df7c   zabbix/zabbix-server-pgsql:alpine-7.0-latest      "/usr/bin/docker-ent…"   4 minutes ago   Up 4 minutes             0.0.0.0:10051->10051/tcp, :::10051->10051/tcp                                        zabbix-docker-zabbix-server-1
1d13678a86a8   zabbix/zabbix-web-nginx-pgsql:alpine-7.0-latest   "docker-entrypoint.sh"   4 minutes ago   Up 4 minutes (healthy)   0.0.0.0:80->8080/tcp, [::]:80->8080/tcp, 0.0.0.0:443->8443/tcp, [::]:443->8443/tcp   zabbix-docker-zabbix-web-nginx-pgsql-1
2a3e351d2c51   postgres:16-alpine                                "docker-entrypoint.s…"   4 minutes ago   Up 4 minutes                                                                                                  zabbix-docker-postgres-server-1

Note: I see 3x running containers, yet docker-compose started 4x.. guess the other has nothing to do.

STEPS TO REPRODUCE
root@docker-host:~/zabbix-docker# curl localhost:443
curl: (56) Recv failure: Connection reset by peer
root@chzab02:~/zabbix-docker# 
EVIDENCE OF MISSING SYMLINK
root@docker-host:~/zabbix-docker# docker exec -it zabbix-docker-zabbix-web-nginx-pgsql-1 bash
c6ff8d494094:/usr/share/zabbix$ cat /etc/nginx/nginx.conf | grep "include"
    include       /etc/nginx/mime.types;
    include /etc/nginx/http.d/*.conf;
c6ff8d494094:/usr/share/zabbix$ ls -la /etc/nginx/http.d/*.conf
lrwxrwxrwx    1 zabbix   zabbix          22 Sep 26 09:15 /etc/nginx/http.d/nginx.conf -> /etc/zabbix/nginx.conf

I would expect 2x sym-links in the /etc/nginx/http.d/ folder.

MANUALLY CREATING THE SYMLINK
c6ff8d494094:/usr/share/zabbix$ ls -l /etc/zabbix/*.conf
-rw-rw-r--    1 zabbix   zabbix        2355 Sep 26 09:15 /etc/zabbix/nginx.conf
-rw-rw-r--    1 zabbix   zabbix        3348 Sep 26 09:15 /etc/zabbix/nginx_ssl.conf
c6ff8d494094:/usr/share/zabbix$ ln -s /etc/zabbix/nginx_ssl.conf /etc/nginx/http.d/nginx_ssl.conf
c6ff8d494094:/usr/share/zabbix$ ls -la /etc/nginx/http.d/*.conf
lrwxrwxrwx    1 zabbix   zabbix          22 Sep 26 09:15 /etc/nginx/http.d/nginx.conf -> /etc/zabbix/nginx.conf
lrwxrwxrwx    1 zabbix   zabbix          26 Sep 26 09:22 /etc/nginx/http.d/nginx_ssl.conf -> /etc/zabbix/nginx_ssl.conf
PROVING THE SYMLINK WORKS IS NOW READ BY NGINX ON RELOAD
c6ff8d494094:/usr/share/zabbix$ /usr/sbin/nginx -s reload
2024/09/26 09:23:25 [warn] 341#341: the "listen ... http2" directive is deprecated, use the "http2" directive instead in /etc/nginx/http.d/nginx_ssl.conf:2
nginx: [warn] the "listen ... http2" directive is deprecated, use the "http2" directive instead in /etc/nginx/http.d/nginx_ssl.conf:2
2024/09/26 09:23:25 [warn] 341#341: the "listen ... http2" directive is deprecated, use the "http2" directive instead in /etc/nginx/http.d/nginx_ssl.conf:3
nginx: [warn] the "listen ... http2" directive is deprecated, use the "http2" directive instead in /etc/nginx/http.d/nginx_ssl.conf:3

Clearly the /etc/nginx/http.d/nginx_ssl.conf symlink is now used, as there is a directive no-longer required in there too.

dotneft commented 6 days ago

Did you attach volume with certificates as stated in the documentation?

sjackson0109 commented 6 days ago

looks like the entrypoint.sh file checks the existance of source files in the /etc/ssl/nginx/ folder. My filenames were renamed, and the YAML file updated to mount these files from the host. The entrypoint.sh file checks for specific filenames.

Here is the file:

prepare_web_server() {                                                                                                               
    NGINX_CONFD_DIR="/etc/nginx/http.d"                                                                                              
    NGINX_SSL_CONFIG="/etc/ssl/nginx"                                                                                                

    if [ ! -f "/proc/net/if_inet6" ]; then                                                                                           
        sed -i '/listen \[::\]/d' "$ZABBIX_ETC_DIR/nginx.conf"                                                                       
        sed -i '/listen \[::\]/d' "$ZABBIX_ETC_DIR/nginx_ssl.conf"                                                                   
    fi                                                                                                                               

    echo "** Adding Zabbix virtual host (HTTP)"                                                                                      
    if [ -f "$ZABBIX_ETC_DIR/nginx.conf" ]; then                                                                                     
        ln -sfT "$ZABBIX_ETC_DIR/nginx.conf" "$NGINX_CONFD_DIR/nginx.conf"                                                           
    else                                                                                                                             
        echo "**** Impossible to enable HTTP virtual host"                                                                           
    fi                                                                                                                               

    if [ -f "$NGINX_SSL_CONFIG/ssl.crt" ] && [ -f "$NGINX_SSL_CONFIG/ssl.key" ] && [ -f "$NGINX_SSL_CONFIG/dhparam.pem" ]; then      
        echo "** Enable SSL support for Nginx"                                                                                       
        if [ -f "$ZABBIX_ETC_DIR/nginx_ssl.conf" ]; then                                                                             
            ln -sfT "$ZABBIX_ETC_DIR/nginx_ssl.conf" "$NGINX_CONFD_DIR/nginx_ssl.conf"                                               
        else                                                                                                                         
            echo "**** Impossible to enable HTTPS virtual host"                                                                      
        fi                                                                                                                           
    else                                                                                                                             
        echo "**** Impossible to enable SSL support for Nginx. Certificates are missed."                                             
    fi                                                                                                                               
}  

The script is doing one specific check: if [ -f "$NGINX_SSL_CONFIG/ssl.crt" ] && [ -f "$NGINX_SSL_CONFIG/ssl.key" ] && [ -f "$NGINX_SSL_CONFIG/dhparam.pem" ];

My certificates are not using custom DHPARAMS - so i don't have all 3x files volume-mounted to the container's disk. You don't officially need the dhparams file if you are using an RSA certificate type. So i don't agree with the logic.

dotneft commented 6 days ago

In this case feel free to use custom Nginx SSL configuration file without dhparam.pem file.

sjackson0109 commented 6 days ago

the entrypoint shell script is the problem, not the custom nginx_ssl.conf file.

for reference my nginx_ssl.conf file looks like this:


    ssl_certificate     /etc/ssl/nginx/ssl.crt;
    ssl_certificate_key /etc/ssl/nginx/ssl.key;
    #ssl_dhparam /etc/ssl/nginx/dhparam.pem;
sjackson0109 commented 6 days ago

How about an update to the docker-entrypoint.sh file?


prepare_web_server() {
    NGINX_CONFD_DIR="/etc/nginx/http.d"
    NGINX_SSL_CONFIG="/etc/ssl/nginx"

    if [ ! -f "/proc/net/if_inet6" ]; then
        sed -i '/listen \[::\]/d' "$ZABBIX_ETC_DIR/nginx.conf"
        sed -i '/listen \[::\]/d' "$ZABBIX_ETC_DIR/nginx_ssl.conf"
    fi

    echo "** Adding Zabbix virtual host (HTTP)"
    if [ -f "$ZABBIX_ETC_DIR/nginx.conf" ]; then
        ln -sfT "$ZABBIX_ETC_DIR/nginx.conf" "$NGINX_CONFD_DIR/nginx.conf"
    else
        echo "**** Impossible to enable HTTP virtual host"
    fi

    if [ -f "$NGINX_SSL_CONFIG/ssl.crt" ] && [ -f "$NGINX_SSL_CONFIG/ssl.key" ] && [ -f "$NGINX_SSL_CONFIG/dhparam.pem" ]; then
        echo "** Enable ECDSA SSL support for Nginx"
        if [ -f "$ZABBIX_ETC_DIR/nginx_ssl.conf" ]; then
            ln -sfT "$ZABBIX_ETC_DIR/nginx_ssl.conf" "$NGINX_CONFD_DIR/nginx_ssl.conf"
        else
            echo "**** Impossible to enable HTTPS virtual host"
        fi
    else
        if [ -f "$NGINX_SSL_CONFIG/ssl.crt" ] && [ -f "$NGINX_SSL_CONFIG/ssl.key" ]; then
            echo "** Enable RSA SSL support for Nginx"
            if [ -f "$ZABBIX_ETC_DIR/nginx_ssl.conf" ]; then
                ln -sfT "$ZABBIX_ETC_DIR/nginx_ssl.conf" "$NGINX_CONFD_DIR/nginx_ssl.conf"
            else
                echo "**** Impossible to enable HTTPS virtual host"
            fi
        else
        echo "**** Impossible to enable SSL support for Nginx. Certificates files are missed."
        echo "**** TIP: Try placing your ssl.crt, ssl.key and dhparams.pem (optional) in the /etc/ssl/nginx/ container directory."
    fi
}
dotneft commented 6 days ago

You can place your nginx_ssl.conf directly to $NGINX_CONFD_DIR/nginx_ssl.conf.

sjackson0109 commented 6 days ago

The sym link should be created by the docker-endpoint.sh script. Nuff said really.

Happy to perform workarounds, on my local copy, by placing config files in desired place. That doesn't negate the fact this script is supposed to handle the symlinks for us. I still believe this is a bug, and a developer should expand on the docker-endpoint.sh script. I'll happily commit it, if someone else agrees this is a bug.

dotneft commented 6 days ago

We are trying to provide as much as possible secure SSL configuration. Most of heavy / big installations do not use SSL directly in a container, such users prefer to have load balancers or HTTP proxies. Of course it is possible to check file, and modify SSL configuration in the script, but then it is possible that users will ask for custom ciphers and other Nginx / PHP parameters... consider all of possible params?

sjackson0109 commented 6 days ago

Just update the script that i provided ~3 hrs ago. It's clearly expecting 3x files, when an RSA cert doesn't need the dhparam.pem file for nginx to bind successfully to that cert. It's only really needed for ECDSA types.

I'm using LetsEncrypt to obtain my certs... with the following modification inside compose_zabbix_components.yaml:

 web-nginx:
  volumes:
   - ${DATA_DIRECTORY}/ssl/mydomainame/fullchain.pem:/etc/ssl/nginx/ssl.crt:ro
   - ${DATA_DIRECTORY}/ssl/mydomainame/privkey.pem:/etc/ssl/nginx/ssl.key:ro

If you want to go ahead and NOT modify the script; then update your isntallation guide, and explain that the DHPARAMS file needs to be created and volume mounted. how to create (host):

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

followed by

 web-nginx:
   volumes:
   - ${DATA_DIRECTORY}/ssl/mydomainame/fullchain.pem:/etc/ssl/nginx/ssl.crt:ro
   - ${DATA_DIRECTORY}/ssl/mydomainame/privkey.pem:/etc/ssl/nginx/ssl.key:ro
   - /etc/ssl/certs/dhparam.pem:/etc/ssl/nginx/dhparam.pem:ro

Then rebuild your containers:

docker compose up -d --force-recreate
dotneft commented 6 days ago

It is documented, please, check: https://github.com/zabbix/zabbix-docker/tree/7.0/Dockerfiles/web-nginx-mysql#etcsslnginx

sjackson0109 commented 6 days ago

I did follow those steps. The volume mounted files are visible in my debug LS commands above.

dotneft commented 5 days ago

If you want to go ahead and NOT modify the script; then update your isntallation guide, and explain that the DHPARAMS file needs to be created and volume mounted. Documentation clearly explains that all three files must exist in the volume: The volume must contains three files ssl.crt, ssl.key and dhparam.pem prepared for Nginx SSL connections.

sjackson0109 commented 2 days ago

NGINX doesn't require 3x files. Your proposed config file does. Only certificates of ECDSA certificate type requires the dhparams file. I'm pointing out a mistake here.