Improve security #16
Some checks are pending
CI/CD Pipeline (Fully Isolated DinD) / Run Tests (DinD) (push) Waiting to run
CI/CD Pipeline (Fully Isolated DinD) / Build and Push Docker Images (DinD) (push) Blocked by required conditions
CI/CD Pipeline (Fully Isolated DinD) / Deploy to Production (push) Blocked by required conditions

This commit is contained in:
continuist 2025-08-24 18:00:07 -04:00
parent a2dcc545c5
commit fbe5bd2d94

View file

@ -198,8 +198,13 @@ RestrictSUIDSGID=yes
RemoveIPC=yes RemoveIPC=yes
ProtectProc=invisible ProtectProc=invisible
ProcSubset=pid ProcSubset=pid
# Allow loopback for upstream to registry and allow the server's public IP(s) for binds:
IPAddressDeny=any IPAddressDeny=any
IPAddressAllow=127.0.0.1 IPAddressAllow=127.0.0.1
IPAddressAllow=<SERVER_IPV4>
# If using IPv6, uncomment and set:
# IPAddressAllow=<SERVER_IPV6>
LimitNOFILE=65536 LimitNOFILE=65536
ExecStartPre=/usr/sbin/nginx -t -c /etc/registry/nginx.conf ExecStartPre=/usr/sbin/nginx -t -c /etc/registry/nginx.conf
ExecStart=/usr/sbin/nginx -g 'daemon off;' -c /etc/registry/nginx.conf ExecStart=/usr/sbin/nginx -g 'daemon off;' -c /etc/registry/nginx.conf
@ -261,7 +266,9 @@ ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
# 443: unauthenticated pulls only # 443: unauthenticated pulls only
server { server {
listen 443 ssl http2; listen <SERVER_IPV4>:443 ssl http2;
# If IPv6, also:
# listen [<SERVER_IPV6>]:443 ssl http2;
ssl_certificate /etc/registry/certs/registry.crt; ssl_certificate /etc/registry/certs/registry.crt;
ssl_certificate_key /etc/registry/certs/private/registry.key; ssl_certificate_key /etc/registry/certs/private/registry.key;
ssl_protocols TLSv1.2 TLSv1.3; ssl_protocols TLSv1.2 TLSv1.3;
@ -285,7 +292,9 @@ ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
# 4443: authenticated pushes only (mTLS) # 4443: authenticated pushes only (mTLS)
server { server {
listen 4443 ssl http2; listen <SERVER_IPV4>:4443 ssl http2;
# If IPv6, also:
# listen [<SERVER_IPV6>]:4443 ssl http2;
ssl_certificate /etc/registry/certs/registry.crt; ssl_certificate /etc/registry/certs/registry.crt;
ssl_certificate_key /etc/registry/certs/private/registry.key; ssl_certificate_key /etc/registry/certs/private/registry.key;
ssl_protocols TLSv1.2 TLSv1.3; ssl_protocols TLSv1.2 TLSv1.3;
@ -315,7 +324,7 @@ EOF
sudo chown root:root /etc/registry/nginx.conf sudo chown root:root /etc/registry/nginx.conf
sudo chmod 644 /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`. **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 migrating to a public CA later, enable stapling and add `resolver` + `ssl_trusted_certificate`.
``` ```
### 2.6 Install Container Policy ### 2.6 Install Container Policy
@ -351,6 +360,13 @@ sudo openssl genrsa -out private/registry.key 4096
sudo cp /opt/APP_NAME/registry/openssl.conf /etc/registry/certs/requests/ sudo cp /opt/APP_NAME/registry/openssl.conf /etc/registry/certs/requests/
sudo chown root:root /etc/registry/certs/requests/openssl.conf sudo chown root:root /etc/registry/certs/requests/openssl.conf
# Ensure OpenSSL config includes subjectAltName for REGISTRY_HOST and SERVER_IP
# The config should contain:
# [ req_ext ]
# subjectAltName = DNS:REGISTRY_HOST,IP:<SERVER_IPV4>
# If IPv6:
# subjectAltName = DNS:REGISTRY_HOST,IP:<SERVER_IPV4>,IP:<SERVER_IPV6>
# Generate server certificate signing request in requests subdirectory # Generate server certificate signing request in requests subdirectory
sudo openssl req -new -key private/registry.key \ sudo openssl req -new -key private/registry.key \
-out requests/registry.csr \ -out requests/registry.csr \
@ -407,6 +423,8 @@ sudo chmod 755 /etc/registry/certs
# Verify certificate creation # Verify certificate creation
sudo openssl x509 -in /etc/registry/certs/registry.crt -text -noout | grep -E "(Subject:|DNS:|IP Address:)" sudo openssl x509 -in /etc/registry/certs/registry.crt -text -noout | grep -E "(Subject:|DNS:|IP Address:)"
# Reminder: clients must use exactly REGISTRY_HOST (or those IPs) in pulls/pushes
# 3. Install server CA certificate in system trust store (for curl, wget, etc.) # 3. Install server CA certificate in system trust store (for curl, wget, etc.)
sudo cp /etc/registry/certs/ca/ca.crt /usr/local/share/ca-certificates/registry-ca.crt sudo cp /etc/registry/certs/ca/ca.crt /usr/local/share/ca-certificates/registry-ca.crt
@ -517,12 +535,32 @@ This setup implements a multi-layered security approach:
### 4.2 Enable and Start Services ### 4.2 Enable and Start Services
```bash ```bash
# Reload systemd and start services
sudo systemctl daemon-reload
# Start as the service user # Start as the service user
sudo -u CI_SERVICE_USER sh -lc 'systemctl --user daemon-reload && systemctl --user enable --now registry.service' sudo -u CI_SERVICE_USER sh -lc 'systemctl --user daemon-reload && systemctl --user enable --now registry.service'
sudo systemctl enable --now registry-proxy.service sudo systemctl enable --now registry-proxy.service
# One-time: ensure host dir ownership matches rootless ID map # One-time: ensure host dir ownership matches rootless ID map
sudo -u CI_SERVICE_USER podman unshare chown -R 100000:100000 /var/lib/registry sudo -u CI_SERVICE_USER podman unshare chown -R 100000:100000 /var/lib/registry
### 4.1 Self-test
```bash
# 1) Listening sockets (should show nginx on the chosen IPs/ports):
sudo ss -ltnp '( sport = :443 or sport = :4443 )'
# 2) From another host on an allowed network:
curl -vk https://REGISTRY_HOST/v2/ | grep -i Docker-Distribution-Api-Version # expect 200 + header
curl -vk https://REGISTRY_HOST/v2/_catalog # expect 403 (blocked)
curl -vk --cert client.crt --key client.key https://REGISTRY_HOST:4443/v2/ | \
grep -i Docker-Distribution-Api-Version # expect 200 + header
# 3) Signature enforcement (on a client with CA + org-cosign.pub + policy.json):
# - Pull unsigned image from your registry -> should FAIL
# - Sign image with your org key, push via 4443, pull via 443 -> should SUCCEED
```
``` ```
## Step 5: Verify Installation ## Step 5: Verify Installation