Skip to content

Conversation

@gocanto
Copy link
Collaborator

@gocanto gocanto commented Sep 12, 2025

Summary by CodeRabbit

  • New Features

    • Public endpoints no longer restrict access by client IP, improving accessibility across networks.
  • Chores

    • Server TLS configured to use explicit certificate/key paths for mutual TLS (no impact for clients presenting valid certs).
    • Certificate tooling enhanced with a convenient refresh/delete/regenerate task and clearer generation/verification output.

@coderabbitai
Copy link

coderabbitai bot commented Sep 12, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Replaced Caddy internal mTLS listener with explicit server cert/key and simplified client CA trust_pool syntax; removed IP-based gating from PublicMiddleware (deleted HasInvalidIP and its invocation); added a Makefile target caddy-fresh and extended cert generation/removal logic in metal/makefile/caddy.mk.

Changes

Cohort / File(s) Summary of changes
Caddy TLS config update
caddy/Caddyfile.prod
Replaced tls internal { ... } for :8443 with explicit server cert/key: tls /etc/caddy/mtls/server.pem /etc/caddy/mtls/server.key { ... }. Simplified client_auth trust_pool from pem_file block to trust_pool file /etc/caddy/mtls/ca.pem. Other edits are formatting/indentation only.
PublicMiddleware IP check removal
pkg/middleware/public_middleware.go
Removed IP-based access control: deleted HasInvalidIP method and removed its call from Handle. Remaining checks (timestamp validation, duplicate request ID detection) and rate-limiter interactions remain.
Caddy cert Makefile improvements
metal/makefile/caddy.mk
Added .PHONY target caddy-fresh (delete + regenerate certs). Enhanced caddy-gen-certs to fail early on bad CA path, emit status messages, generate server key/CSR/cert if missing, set permissions, verify server cert against CA, and removed output redirections. Extended caddy-del-certs to remove server.pem/server.key. Minor caddy-validate formatting tweak.
Test adjustment
metal/kernel/router_signature_test.go
Removed subtest that asserted production rejection for non-whitelisted IPs; tests validating other PublicMiddleware behaviors remain.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as Client
  participant M as PublicMiddleware
  participant R as RateLimiter
  participant H as AppHandler

  Note over M: IP-based gate removed (HasInvalidIP deleted)

  C->>M: HTTP request
  M->>M: Validate timestamp
  M->>M: Check duplicate request ID
  M->>R: Request rate token / account usage
  alt Allowed
    R-->>M: OK
    M->>H: Forward request
    H-->>M: Response
    M-->>C: Response
  else Rejected (rate/timestamp/duplicate)
    R-->>M: Reject / M forms error
    M-->>C: Error response
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

testing

Poem

I thump at keys with whiskered cheer,
No fences for IPs hopping near.
Certs snug in tins, fresh keys I bake,
Handshakes bloom for every wake.
I nibble logs and stamp “deploy”—huzzah, a secure carrot cake! 🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9371d1a and 175525c.

📒 Files selected for processing (1)
  • metal/kernel/router_signature_test.go (0 hunks)
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch hotfix/caddy-handshake

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @gocanto, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This hotfix addresses an issue with Caddy's TLS handshake by adjusting its mTLS configuration to use explicit certificate and key files. Concurrently, an IP validation check has been removed from a public middleware, streamlining the request handling process and potentially delegating IP-based access control to another system or layer.

Highlights

  • Caddy mTLS Configuration Update: Modified the Caddyfile.prod to explicitly define TLS certificates and keys (/etc/caddy/mtls/ca.pem, /etc/caddy/mtls/ca.key) for the mTLS entrypoint, replacing the tls internal directive.
  • Removal of IP Validation Middleware: Eliminated the HasInvalidIP function and its invocation from pkg/middleware/public_middleware.go, removing IP address validation from this specific public middleware.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gocanto gocanto marked this pull request as draft September 12, 2025 07:01
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request aims to fix a Caddy handshake issue and modifies a middleware. My review found two significant issues:

  1. A critical security vulnerability in caddy/Caddyfile.prod where a CA private key is used as a server key.
  2. In pkg/middleware/public_middleware.go, IP validation logic was removed, but the corresponding tests were not updated, which will likely break the build.

Please address these issues to improve security and maintain code quality.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
caddy/Caddyfile.prod (3)

101-104: Mirror upstream hardening (timeouts, Host) for the mTLS path

The main site’s proxy sets dial_timeout and response_header_timeout and preserves the Host header. Do the same here to avoid hanging connections and subtle header differences.

     handle_path /api/generate-signature* {
-       reverse_proxy api:8080
+       reverse_proxy api:8080 {
+         header_up Host {host}
+         transport http {
+           dial_timeout 10s
+           response_header_timeout 30s
+         }
+       }
     }

105-107: Consider 404 instead of 403 for non-matching paths

Returning 404 on the internal listener reduces signal to unauthenticated scanners about protected endpoints. Keep 403 if you prefer explicit denial.

-    handle {
-       respond 403
-    }
+    handle {
+       respond 404
+    }

99-99: Minor: compression likely unnecessary on the internal mTLS port

If 8443 only serves /api/generate-signature*, drop encode to save a few CPU cycles. Low impact.

-    encode gzip zstd
+    # encode gzip zstd  # likely unnecessary on this narrow internal endpoint
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e241a5 and 7cb453b.

📒 Files selected for processing (2)
  • caddy/Caddyfile.prod (1 hunks)
  • pkg/middleware/public_middleware.go (0 hunks)
💤 Files with no reviewable changes (1)
  • pkg/middleware/public_middleware.go
🔇 Additional comments (2)
caddy/Caddyfile.prod (2)

92-97: Version pin check: trust_pool shorthand requires Caddy v2.8+

trust_pool file /etc/.../ca.pem (inline form) is valid on v2.8+; older versions expect the block form trust_pool file { pem_file /path }. Ensure your image/tag is ≥ v2.8 or switch to the block syntax. (pkg.go.dev)

If you’re not sure of the running Caddy version, exec into the container and run caddy version.


92-97: Critical: server is presenting CA cert/key — replace with a leaf server cert/key

Using /etc/caddy/mtls/ca.pem and ca.key as the server cert/key is dangerous: the server must present a leaf certificate whose SAN matches the hostname; a CA cert (BasicConstraints CA:TRUE) will fail validation and storing the CA private key on the webserver is a severe secret-management risk. Keep the CA only for client verification via trust_pool.

Verification failed: openssl not found in the environment, so I couldn't confirm whether ca.pem is a CA or whether server.pem has the correct SANs. Install openssl and re-run the check below (or paste its output).

Apply this diff (adjust paths to your actual server leaf cert/key):

-    tls /etc/caddy/mtls/ca.pem /etc/caddy/mtls/ca.key {
+    tls /etc/caddy/mtls/server.pem /etc/caddy/mtls/server.key {
        client_auth {
           mode require_and_verify
           trust_pool file /etc/caddy/mtls/ca.pem
        }
     }

Run after installing openssl:

#!/bin/bash
set -euo pipefail
echo "CA basic constraints for /etc/caddy/mtls/ca.pem:"
openssl x509 -in /etc/caddy/mtls/ca.pem -noout -text | sed -n '/X509v3 Basic Constraints/,/X509v3/p' || true
echo
echo "Server cert SANs for /etc/caddy/mtls/server.pem:"
openssl x509 -in /etc/caddy/mtls/server.pem -noout -text | sed -n '/Subject Alternative Name/,/X509v3/p' || true

@gocanto gocanto marked this pull request as ready for review September 12, 2025 07:46
@gocanto gocanto merged commit 45a945a into main Sep 12, 2025
1 check passed
@gocanto gocanto deleted the hotfix/caddy-handshake branch September 12, 2025 07:51
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
caddy/Caddyfile.prod (1)

102-104: Correct: enforce mTLS on a dedicated listener, not by path.

TLS client auth can’t vary by path since the handshake precedes HTTP routing; a separate :8443 site is the right approach. Optionally mirror upstream timeouts here as on the public /api/* block for parity. (caddy.community)

     handle_path /api/generate-signature* {
-       reverse_proxy api:8080
+       reverse_proxy api:8080 {
+         transport http {
+           dial_timeout 10s
+           response_header_timeout 30s
+         }
+       }
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7cb453b and 9371d1a.

📒 Files selected for processing (2)
  • caddy/Caddyfile.prod (1 hunks)
  • metal/makefile/caddy.mk (1 hunks)
🔇 Additional comments (8)
caddy/Caddyfile.prod (3)

92-99: mTLS config is syntactically correct for Caddy v2.10; keep using the new trust_pool shorthand.

tls /etc/caddy/mtls/server.pem /etc/caddy/mtls/server.key with client_auth { mode require_and_verify; trust_pool file /etc/caddy/mtls/ca.pem } is valid and preferred over deprecated fields. (caddy.community)


100-100: Compression on :8443 is fine.

No issues; harmless for the protected listener.


106-108: Default-deny fallback looks good.

403 catch-all on :8443 prevents accidental exposure of non-protected routes.

metal/makefile/caddy.mk (5)

1-1: PHONY updated correctly.

Including caddy-fresh avoids stale targets.


7-9: Nice QoL target.

caddy-fresh chaining delete+gen is handy for local resets.


47-48: Potential permission issue inside the caddy container.

chmod 600 server.key may block the (non-root) caddy user from reading the key when bind-mounted. Consider 640 and setting group to match the container’s effective GID, or run the container as root explicitly. Please confirm your runtime user.


57-62: Good: cleanup includes server key/cert.

Removes all relevant artifacts; avoids partial state.


65-68: Validate with the same Caddy version you run.

You target caddy:2.10.0 here; ensure production uses 2.10+ so the trust_pool syntax is recognized. (caddy.community)

Comment on lines +92 to 99
tls /etc/caddy/mtls/server.pem /etc/caddy/mtls/server.key {
client_auth {
mode require_and_verify
trust_pool file {
pem_file /etc/caddy/mtls/ca.pem
}
# The client must present a cert trusted by the CA
trust_pool file /etc/caddy/mtls/ca.pem
}
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Blocking issue: server.pem must have SANs matching the SNI clients use.

Your Makefile generates a server cert with only CN=oullin_proxy_prod and no subjectAltName. Modern clients (Chrome 58+, Go 1.15+) ignore CN for hostname verification; without SANs, the TLS handshake will fail even before HTTP routing/mTLS verification. See my Makefile comment with a patch to add SAN/EKU. (alexanderzeitler.com)

🤖 Prompt for AI Agents
In caddy/Caddyfile.prod around lines 92 to 99, the server certificate file
server.pem was created with only a CN and no subjectAltName (SAN), which modern
TLS clients ignore for hostname verification; update the Makefile target that
generates server.pem to include proper SANs (DNS names and any IPs) that match
the SNI hostnames clients use and ensure the certificate includes the serverAuth
EKU; implement this by adding a custom OpenSSL config or command-line flags to
inject subjectAltName and extendedKeyUsage when creating/signing the server cert
(or reissue the cert via the CA), then regenerate server.pem and server.key and
verify the SANs match the service hostnames used by clients.

Comment on lines +24 to +34
openssl genrsa -out "$(CADDY_MTLS_DIR)/ca.key" 4096; \
printf "$(BLUE)📜 Creating self-signed CA certificate...$(NC)\n"; \
openssl req -x509 -new -key "$(CADDY_MTLS_DIR)/ca.key" -sha256 -days 3650 \
-subj "/CN=oullin-mtls-ca" -out "$(CADDY_MTLS_DIR)/ca.pem" >/dev/null 2>&1; \
-subj "/CN=oullin-mtls-ca" -out "$(CADDY_MTLS_DIR)/ca.pem"; \
printf '01\n' > "$(CADDY_MTLS_DIR)/ca.srl"; \
chmod 600 "$(CADDY_MTLS_DIR)/ca.key"; \
chmod 644 "$(CADDY_MTLS_DIR)/ca.pem" "$(CADDY_MTLS_DIR)/ca.srl"; \
printf "$(GREEN)✅ CA written to %s$(NC)\n" "$(CADDY_MTLS_DIR)"; \
printf "$(WHITE)🔍 CA fingerprint:$(NC)\n"; \
openssl x509 -noout -fingerprint -sha256 -in "$(CADDY_MTLS_DIR)/ca.pem" | sed 's/^/ /'; \
fi
fi; \
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

CA certificate lacks essential v3 extensions.

As written, the CA may be missing basicConstraints/keyUsage, which some stacks expect on CAs. Add v3 CA extensions at issuance. (github.com)

-  openssl genrsa -out "$(CADDY_MTLS_DIR)/ca.key" 4096; \
-  printf "$(BLUE)📜 Creating self-signed CA certificate...$(NC)\n"; \
-  openssl req -x509 -new -key "$(CADDY_MTLS_DIR)/ca.key" -sha256 -days 3650 \
-    -subj "/CN=oullin-mtls-ca" -out "$(CADDY_MTLS_DIR)/ca.pem"; \
+  openssl genrsa -out "$(CADDY_MTLS_DIR)/ca.key" 4096; \
+  printf "$(BLUE)📜 Creating self-signed CA certificate...$(NC)\n"; \
+  openssl req -x509 -new -key "$(CADDY_MTLS_DIR)/ca.key" -sha256 -days 3650 \
+    -subj "/CN=oullin-mtls-ca" \
+    -addext "basicConstraints=critical,CA:TRUE" \
+    -addext "keyUsage=critical,keyCertSign,cRLSign" \
+    -addext "subjectKeyIdentifier=hash" \
+    -out "$(CADDY_MTLS_DIR)/ca.pem"; \
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
openssl genrsa -out "$(CADDY_MTLS_DIR)/ca.key" 4096; \
printf "$(BLUE)📜 Creating self-signed CA certificate...$(NC)\n"; \
openssl req -x509 -new -key "$(CADDY_MTLS_DIR)/ca.key" -sha256 -days 3650 \
-subj "/CN=oullin-mtls-ca" -out "$(CADDY_MTLS_DIR)/ca.pem" >/dev/null 2>&1; \
-subj "/CN=oullin-mtls-ca" -out "$(CADDY_MTLS_DIR)/ca.pem"; \
printf '01\n' > "$(CADDY_MTLS_DIR)/ca.srl"; \
chmod 600 "$(CADDY_MTLS_DIR)/ca.key"; \
chmod 644 "$(CADDY_MTLS_DIR)/ca.pem" "$(CADDY_MTLS_DIR)/ca.srl"; \
printf "$(GREEN)✅ CA written to %s$(NC)\n" "$(CADDY_MTLS_DIR)"; \
printf "$(WHITE)🔍 CA fingerprint:$(NC)\n"; \
openssl x509 -noout -fingerprint -sha256 -in "$(CADDY_MTLS_DIR)/ca.pem" | sed 's/^/ /'; \
fi
fi; \
openssl genrsa -out "$(CADDY_MTLS_DIR)/ca.key" 4096; \
printf "$(BLUE)📜 Creating self-signed CA certificate...$(NC)\n"; \
openssl req -x509 -new -key "$(CADDY_MTLS_DIR)/ca.key" -sha256 -days 3650 \
-subj "/CN=oullin-mtls-ca" \
-addext "basicConstraints=critical,CA:TRUE" \
-addext "keyUsage=critical,keyCertSign,cRLSign" \
-addext "subjectKeyIdentifier=hash" \
-out "$(CADDY_MTLS_DIR)/ca.pem"; \
printf '01\n' > "$(CADDY_MTLS_DIR)/ca.srl"; \
chmod 600 "$(CADDY_MTLS_DIR)/ca.key"; \
chmod 644 "$(CADDY_MTLS_DIR)/ca.pem" "$(CADDY_MTLS_DIR)/ca.srl"; \
printf "$(GREEN)✅ CA written to %s$(NC)\n" "$(CADDY_MTLS_DIR)"; \
printf "$(WHITE)🔍 CA fingerprint:$(NC)\n"; \
openssl x509 -noout -fingerprint -sha256 -in "$(CADDY_MTLS_DIR)/ca.pem" | sed 's/^/ /'; \
fi; \
🤖 Prompt for AI Agents
In metal/makefile/caddy.mk around lines 24 to 34, the CA is created without v3
CA extensions; update the OpenSSL invocation to include standard CA v3
extensions (basicConstraints=CA:TRUE, keyUsage=critical,keyCertSign,cRLSign, and
recommended subjectKeyIdentifier/authorityKeyIdentifier) by either supplying an
-extfile with a small temporary config section (with an [ v3_ca ] stanza) or
using -addext flags when running openssl req/x509 so the issued ca.pem contains
the proper basicConstraints/keyUsage and related extensions.

Comment on lines +35 to +53
printf "$(YELLOW)⚠️ Server certificate already exists.$(NC)\n"; \
else \
umask 077; \
printf "$(BLUE)🔑 Generating Server private key...$(NC)\n"; \
openssl genrsa -out "$(CADDY_MTLS_DIR)/server.key" 4096; \
printf "$(WHITE)📜 Creating Server signing request...$(NC)\n"; \
openssl req -new -key "$(CADDY_MTLS_DIR)/server.key" -subj "/CN=oullin_proxy_prod" -out "$(CADDY_MTLS_DIR)/server.csr"; \
printf "$(NC)🖊️ Signing Server certificate with CA...$(NC)\n"; \
openssl x509 -req -in "$(CADDY_MTLS_DIR)/server.csr" \
-CA "$(CADDY_MTLS_DIR)/ca.pem" -CAkey "$(CADDY_MTLS_DIR)/ca.key" -CAserial "$(CADDY_MTLS_DIR)/ca.srl" \
-out "$(CADDY_MTLS_DIR)/server.pem" -days 1095 -sha256; \
chmod 600 "$(CADDY_MTLS_DIR)/server.key"; \
chmod 644 "$(CADDY_MTLS_DIR)/server.pem"; \
rm "$(CADDY_MTLS_DIR)/server.csr"; \
printf "$(GREEN)✅ Server certificate written to %s$(NC)\n" "$(CADDY_MTLS_DIR)"; \
fi; \
printf "$(NC)🔎 Verifying server cert against CA...$(NC)\n"; \
openssl verify -CAfile "$(CADDY_MTLS_DIR)/ca.pem" "$(CADDY_MTLS_DIR)/server.pem"

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Blocking issue: server cert is missing SAN and EKU—clients will reject it.

Without SANs, hostname verification fails; add SAN plus key usages for a TLS server. Go and modern browsers require SANs. (github.com)

-  openssl x509 -req -in "$(CADDY_MTLS_DIR)/server.csr" \
-    -CA "$(CADDY_MTLS_DIR)/ca.pem" -CAkey "$(CADDY_MTLS_DIR)/ca.key" -CAserial "$(CADDY_MTLS_DIR)/ca.srl" \
-    -out "$(CADDY_MTLS_DIR)/server.pem" -days 1095 -sha256; \
+  openssl x509 -req -in "$(CADDY_MTLS_DIR)/server.csr" \
+    -CA "$(CADDY_MTLS_DIR)/ca.pem" -CAkey "$(CADDY_MTLS_DIR)/ca.key" -CAserial "$(CADDY_MTLS_DIR)/ca.srl" \
+    -days 1095 -sha256 \
+    -addext "subjectAltName=${CADDY_SERVER_SANS}" \
+    -addext "keyUsage=critical,digitalSignature,keyEncipherment" \
+    -addext "extendedKeyUsage=serverAuth" \
+    -out "$(CADDY_MTLS_DIR)/server.pem"; \

Add this variable once near the top (outside this hunk) to control SANs:

# e.g., DNS names clients/SNI will use; add IPs if connecting by IP
CADDY_SERVER_SANS ?= DNS:oullin.io

If your OpenSSL lacks -addext, use -extfile with a v3 ext stanza; I can provide that variant if needed.

🤖 Prompt for AI Agents
metal/makefile/caddy.mk around lines 35-53: the generated server certificate
lacks SAN and EKU which causes modern clients (including Go and browsers) to
reject it; add a new variable near the top such as CADDY_SERVER_SANS ?=
DNS:oullin.io (allowing IP: entries as needed), then when creating/signing the
server cert generate or reference an OpenSSL extfile that sets subjectAltName =
${CADDY_SERVER_SANS} and extendedKeyUsage = serverAuth and pass that extfile to
openssl x509 using -extfile (or use -addext if you know the OpenSSL supports
it); ensure the Make rule creates the extfile with secure permissions, uses it
in the signing step, and removes it after signing so the resulting server.pem
includes both SAN and TLS server EKU.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants