diff --git a/Docker_Registry_Install_Guide.md b/Docker_Registry_Install_Guide.md index 733bcbf..6b5d060 100644 --- a/Docker_Registry_Install_Guide.md +++ b/Docker_Registry_Install_Guide.md @@ -194,6 +194,12 @@ ProtectHostname=yes LockPersonality=yes MemoryDenyWriteExecute=yes RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +RestrictSUIDSGID=yes +RemoveIPC=yes +ProtectProc=invisible +ProcSubset=pid +IPAddressDeny=any +IPAddressAllow=127.0.0.1 LimitNOFILE=65536 ExecStartPre=/usr/sbin/nginx -t -c /etc/registry/nginx.conf ExecStart=/usr/sbin/nginx -g 'daemon off;' -c /etc/registry/nginx.conf @@ -218,11 +224,15 @@ error_log /var/log/registry-proxy/error.log; http { server_tokens off; + + # Rate/connection limits (tune for CI bursts as needed) limit_req_zone $binary_remote_addr zone=reg_read:10m rate=10r/s; limit_req_zone $binary_remote_addr zone=reg_write:10m rate=5r/s; limit_conn_zone $binary_remote_addr zone=perip:10m; - # Note: Tune these limits based on your expected load. Adjust if CI bursts cause 429s. + client_max_body_size 2g; + + # TLS hardening ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\ ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\ ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256'; @@ -232,8 +242,11 @@ ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256'; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ssl_session_tickets off; - ssl_stapling on; - ssl_stapling_verify on; + + # OCSP stapling is intentionally DISABLED for private CA deployments. + # (Clients trust via installed CA cert; no public OCSP endpoint exists.) + + # Proxy settings proxy_http_version 1.1; proxy_set_header Connection ""; proxy_request_buffering off; @@ -243,6 +256,7 @@ ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256'; fastcgi_temp_path /run/registry-proxy/fastcgi_temp; uwsgi_temp_path /run/registry-proxy/uwsgi_temp; scgi_temp_path /run/registry-proxy/scgi_temp; + upstream reg { server 127.0.0.1:5000; } # 443: unauthenticated pulls only @@ -252,8 +266,11 @@ ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256'; ssl_certificate_key /etc/registry/certs/private/registry.key; ssl_protocols TLSv1.2 TLSv1.3; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + + # Hide catalog & tag listings location = /v2/_catalog { return 403; } location ~ ^/v2/.+/tags/list { return 403; } + location /v2/ { limit_req zone=reg_read burst=20 nodelay; limit_conn perip 20; @@ -273,8 +290,14 @@ ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256'; ssl_certificate_key /etc/registry/certs/private/registry.key; ssl_protocols TLSv1.2 TLSv1.3; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + + # mTLS client auth via private Client CA ssl_client_certificate /etc/registry/certs/clients/ca.crt; ssl_verify_client on; + + # Optional: enable client-cert revocation (publish a CRL and uncomment) + # ssl_crl /etc/registry/certs/clients/ca.crl; + location /v2/ { limit_req zone=reg_write burst=10; limit_conn perip 20; @@ -291,6 +314,8 @@ EOF # Set proper permissions for nginx config (root-owned) sudo chown root:root /etc/registry/nginx.conf sudo chmod 644 /etc/registry/nginx.conf + +**Note (Private CA):** OCSP stapling is disabled because our CA is private (no public OCSP responder). Clients trust the registry via the installed CA certificate. If you later migrate to a public CA, re-enable stapling and add a DNS resolver and `ssl_trusted_certificate`. ``` ### 2.6 Install Container Policy @@ -536,6 +561,15 @@ curl -k -X PUT https://YOUR_ACTUAL_IP_ADDRESS/v2/ -I | grep 403 || echo "WARNING # 4443 requires client cert curl -kI https://YOUR_ACTUAL_IP_ADDRESS:4443/v2/ | egrep '400|401|403' || echo "WARNING: 4443 may not require auth" +# 443 should return 200 with registry API header; catalog is forbidden +curl -vk https://REGISTRY_HOST/v2/ | grep -i Docker-Distribution-Api-Version +curl -vk https://REGISTRY_HOST/v2/_catalog # expect 403 + +# 4443 requires mTLS, should return 200 with client certs +curl -vk --cert client.crt --key client.key https://REGISTRY_HOST:4443/v2/ | grep -i Docker-Distribution-Api-Version + +# OCSP stapling is intentionally disabled; you should not expect stapling-related headers in responses. + # Verify Podman is using non-home paths sudo su - CI_SERVICE_USER -c "env PODMAN_ROOT=/var/tmp/podman-\$(id -u)/root PODMAN_RUNROOT=/run/user/\$(id -u)/podman-run PODMAN_TMPDIR=/var/tmp/podman-\$(id -u)/tmp XDG_DATA_HOME=/var/tmp/podman-\$(id -u)/xdg-data XDG_CONFIG_HOME=/var/tmp/podman-\$(id -u)/xdg-config podman info --format '{{.Store.GraphRoot}} {{.Store.RunRoot}}'" ```