From a43f2003d02fe1a7b296eb1ee7192bf2f582a957 Mon Sep 17 00:00:00 2001 From: continuist Date: Sun, 13 Jul 2025 10:53:33 -0400 Subject: [PATCH] Improve Caddyfile and use registry config file --- CI_CD_PIPELINE_SETUP_GUIDE.md | 41 +++++++++--------------- registry/Caddyfile | 60 ++++++++++++++++++++++++++++------- registry/README.md | 15 +++++++++ registry/config.yml | 19 +++++++++++ 4 files changed, 98 insertions(+), 37 deletions(-) create mode 100644 registry/config.yml diff --git a/CI_CD_PIPELINE_SETUP_GUIDE.md b/CI_CD_PIPELINE_SETUP_GUIDE.md index 8bb27db..2bd672d 100644 --- a/CI_CD_PIPELINE_SETUP_GUIDE.md +++ b/CI_CD_PIPELINE_SETUP_GUIDE.md @@ -692,7 +692,7 @@ sudo cp /opt/APP_NAME/registry/docker-compose.registry.yml docker-compose.yml sudo cp /opt/APP_NAME/registry/Caddyfile Caddyfile # Update Caddyfile with your actual IP address -sudo sed -i "s/registry.example.com/YOUR_CI_CD_IP/g" Caddyfile +sudo sed -i "s/YOUR_CI_CD_IP/YOUR_ACTUAL_IP_ADDRESS/g" Caddyfile # Create environment file for registry authentication # First, create a secure password hash @@ -716,28 +716,11 @@ sudo chmod 600 .env sudo mkdir -p /opt/registry/data sudo chown registry:registry /opt/registry/data -# Create registry configuration (no authentication needed - Caddy handles it) -sudo tee /opt/registry/config.yml << 'EOF' -version: 0.1 -log: - level: debug -storage: - filesystem: - rootdirectory: /var/lib/registry - delete: - enabled: true -http: - addr: :5000 - headers: - X-Content-Type-Options: [nosniff] -middleware: - repository: - - name: AwsEc2PublicBlock - storage: - - name: Redirect - options: - baseurl: https://YOUR_CI_CD_IP -EOF +# Copy registry configuration from repository +sudo cp /opt/APP_NAME/registry/config.yml /opt/registry/config.yml + +# Update the baseurl with your actual IP address +sudo sed -i "s/YOUR_CI_CD_IP/YOUR_ACTUAL_IP_ADDRESS/g" /opt/registry/config.yml # Set proper permissions sudo chown registry:registry /opt/registry/config.yml @@ -802,8 +785,8 @@ sudo journalctl -u docker-registry.service -f The Docker Registry is now configured with the following access model: **Authentication Model:** -- **Pulls**: Unauthenticated (public read access) -- **Pushes**: Require authentication with `registry-user` credentials +- **Pulls**: Unauthenticated (public read access) - `/v2/*/blobs/*`, `/v2/*/manifests/*`, `/v2/_catalog`, `/v2/*/tags/list` +- **Pushes**: Require authentication with `registry-user` credentials - `/v2/*/blobs/uploads/*`, `/v2/*/manifests/*` (PUT/POST/PATCH/DELETE) **Registry Credentials:** - **Username**: `registry-user` @@ -811,7 +794,13 @@ The Docker Registry is now configured with the following access model: **Registry URL**: `https://YOUR_CI_CD_IP` -**Note**: The authentication is handled by Caddy using the environment variables in the `.env` file. The Docker Registry itself runs without authentication, but Caddy enforces authentication for push operations. +**Security Features:** +- **URL-based access control**: Different paths require different authentication levels +- **Method-based restrictions**: Push operations (PUT/POST/PATCH/DELETE) require authentication +- **Path validation**: Prevents method spoofing by validating both URL patterns and HTTP methods +- **Security headers**: X-Content-Type-Options, X-Frame-Options for additional protection + +**Note**: The authentication is handled by Caddy using the environment variables in the `.env` file. The Docker Registry itself runs without authentication, but Caddy enforces authentication for push operations based on URL patterns and HTTP methods. #### 5.8 Test Registry Setup diff --git a/registry/Caddyfile b/registry/Caddyfile index 6485d6c..fcae3d0 100644 --- a/registry/Caddyfile +++ b/registry/Caddyfile @@ -1,25 +1,63 @@ - (registry_auth) { basicauth { {env.REGISTRY_USERNAME} {env.REGISTRY_PASSWORD_HASH} } } -https://registry.example.com { - import registry_auth - reverse_proxy registry:5000 +YOUR_CI_CD_IP { + # Security headers header { X-Content-Type-Options nosniff + X-Frame-Options DENY } - @push method POST PUT PATCH DELETE - handle @push { + # Handle registry operations based on URL patterns + @push_operations { + path /v2/*/blobs/uploads/* + path /v2/*/manifests/* + method PUT POST PATCH DELETE + } + + @pull_operations { + path /v2/*/blobs/* + path /v2/*/manifests/* + path /v2/_catalog + path /v2/*/tags/list + method GET HEAD OPTIONS + } + + # Require authentication for push operations + handle @push_operations { import registry_auth - reverse_proxy registry:5000 + reverse_proxy registry:5000 { + header_up Authorization {http.request.header.Authorization} + header_up X-Forwarded-For {remote_host} + header_up X-Forwarded-Proto {scheme} + header_up X-Forwarded-Host {host} + } } - @pull method GET HEAD OPTIONS - handle @pull { - reverse_proxy registry:5000 + # Allow unauthenticated pull operations + handle @pull_operations { + reverse_proxy registry:5000 { + header_up X-Forwarded-For {remote_host} + header_up X-Forwarded-Proto {scheme} + header_up X-Forwarded-Host {host} + } } -} \ No newline at end of file + + # Block all other requests + handle { + respond "Registry operation not allowed" 405 + } + + # Logging + log { + output file /var/log/caddy/registry.log + format json + level INFO + } + + # Compression + encode zstd gzip +} diff --git a/registry/README.md b/registry/README.md index 3a09ba4..307e4fa 100644 --- a/registry/README.md +++ b/registry/README.md @@ -6,6 +6,7 @@ This folder contains the configuration files for the Docker Registry setup used - **`docker-compose.registry.yml`**: Docker Compose configuration for the registry and Caddy reverse proxy - **`Caddyfile`**: Caddy configuration for HTTPS and authentication +- **`config.yml`**: Docker Registry configuration file - **`README.md`**: This documentation file ## Architecture @@ -18,7 +19,20 @@ The registry setup uses: ## Authentication Model - **Pulls**: Unauthenticated (public read access) + - `/v2/*/blobs/*` - Download image layers + - `/v2/*/manifests/*` - Download image manifests + - `/v2/_catalog` - List repositories + - `/v2/*/tags/list` - List image tags - **Pushes**: Require authentication with `registry-user` credentials + - `/v2/*/blobs/uploads/*` - Upload image layers + - `/v2/*/manifests/*` (PUT/POST/PATCH/DELETE) - Upload/update manifests + +## Security Features + +- **URL-based access control**: Different paths require different authentication levels +- **Method-based restrictions**: Push operations require authentication +- **Path validation**: Prevents method spoofing by validating both URL patterns and HTTP methods +- **Security headers**: X-Content-Type-Options, X-Frame-Options for additional protection ## Configuration @@ -26,6 +40,7 @@ The setup is configured through: 1. **Environment Variables**: Stored in `.env` file (created during setup) 2. **Caddyfile**: Handles HTTPS and authentication 3. **Docker Compose**: Orchestrates the registry and Caddy services +4. **Registry Config**: `config.yml` contains the Docker Registry configuration ## Usage diff --git a/registry/config.yml b/registry/config.yml new file mode 100644 index 0000000..bc28ab4 --- /dev/null +++ b/registry/config.yml @@ -0,0 +1,19 @@ +version: 0.1 +log: + level: debug +storage: + filesystem: + rootdirectory: /var/lib/registry + delete: + enabled: true +http: + addr: :5000 + headers: + X-Content-Type-Options: [nosniff] +middleware: + repository: + - name: AwsEc2PublicBlock + storage: + - name: Redirect + options: + baseurl: https://YOUR_CI_CD_IP \ No newline at end of file