[Bug Report] CubeEgress domain allow rules do not bind Host/SNI to the original destination
Summary
For requests that reach CubeEgress's L7 proxy, a matching Host/SNI does not establish that the original destination IP belongs to that name. Client-side hosts or curl --resolve overrides can preserve the allowed name while changing the destination. I am opening this issue to discuss the intended authorization boundary and agree on an approach before proceeding with #1695, as requested in the PR review.
Environment
- Baseline: CubeSandbox commit
62da0187(v0.7.1-rc1). - Relevant components: CubeEgress access policy/proxy routing; CubeVS determines which flows reach L7.
- Reproduction: isolated Docker socket fixture on LinuxKit 6.12.76, OpenResty 1.31.1.1, real DNS and HTTP/TLS backends.
- KVM/deployment mode: not used; this is not a deployed sandbox test. The patched production OpenResty 1.29.2.5 image and the complete guest/TPROXY/eBPF path have not been runtime-verified here.
Steps to Reproduce
- In an isolated fixture, configure an allow rule for
*.example.test; proxy-side DNS resolvesallowed.example.testonly to127.0.0.2. Run a second backend at127.0.0.3. - Keep Host/SNI as
allowed.example.test, but connect to127.0.0.3using a client-container hosts entry or these commands inside the fixture network:
curl --noproxy '*' --resolve allowed.example.test:80:127.0.0.3 http://allowed.example.test/
curl --noproxy '*' --cacert /fixture/cert.pem --resolve allowed.example.test:443:127.0.0.3 https://allowed.example.test/For the HTTPS case, the unrelated backend deliberately presents a certificate valid for the allowed name and trusted by the test proxy. This demonstrates the DNS-binding gap even when upstream certificate verification succeeds; an arbitrary backend without a valid certificate is not claimed to pass HTTPS verification.
- Separately, use an HTTPS Host-only allow rule with
Host: allowed.example.test, SNIblocked.example.test, and a shared destination IP. The policy matches the first name, while nginx uses SNI for upstream TLS and rewrites upstream Host to the second name.
The reproducible harness is in #1695: python3 CubeEgress/tests/dns_auth_integration.py --baseline-ref 62da0187. It retains production access/audit modules and proxy locations but substitutes policy storage, static certificates, direct listeners, and backend ports.
Expected Behavior
A domain-constrained allow should authorize the identity actually used upstream, with an explicit policy for how that identity is bound to the original destination. An unrelated destination or unauthorized Host/SNI identity change should be denied before forwarding or credential injection.
Actual Behavior
The baseline returned 200 for all four HTTP/HTTPS × hosts/--resolve cases. The Host-only HTTPS identity mismatch also returned 200. The proposed implementation in #1695 returns 403 for these cases while normal requests return 200. This evidence applies to the socket fixture, not arbitrary IP reachability through CubeVS. Flows rejected before L7 remain rejected; ordinary SNAT flows are outside this check.
Additional Context: Design Discussion
The current proposal preserves the original IP/port and checks membership against trusted proxy-side DNS, with asynchronous resolution, bounded concurrency/deadlines, validated CNAME ownership and TTL-respecting caching. HTTPS Host constraints must agree with the SNI used upstream.
Points to agree on:
- Is proxy-side DNS membership the desired authorization contract? CDN, split-DNS and rotation can give guest and proxy different valid address sets and cause false denials.
- Should the binding instead use trusted DNS results already observed by CubeVS? This would require defining provenance, expiration and access from CubeEgress.
- If the proxy selects a new resolved IP, the new destination must undergo L4/CIDR authorization again; silently replacing the original IP would bypass that boundary.
- Should HTTPS Host/SNI disagreement be rejected for all Host-constrained allow rules, including rules without credential injection?
DNS membership alone does not prove tenant ownership on shared hosting or restrict an attacker-controlled subdomain already covered by an allowed wildcard. TLS verification and destination restrictions remain necessary. #1695 is a concrete implementation for discussion, not an assumption that these semantics have already been agreed.
Source: TencentCloud/CubeSandbox