Skip to content

Implement the HTTP/3 CONNECT-IP edge service #980

Closed

Description

@privateip

Parent: #970

Deliverable

A runnable edge service that accepts authenticated CONNECT-IP requests over HTTP/3 on UDP/443 and forwards packets through the gVPC attachment.

Dependencies

#973, #975, #976, #977, #978, #979; resolve the #991 exposure blockers and applicable #989 findings before wiring the externally reachable listener.

Galactic Edge integration (#992)

Implement this milestone as a consumer of the Galactic Edge provider contract. #992 owns provider authorization, host attachment lifecycle, shared-state fencing and maintenance, independently enforced forwarding expiry, prefix conflict arbitration/publication, and gVPC traffic policy. MASQUE owns client authentication, connector /96 assignment and retention, session packet checks, transport behavior and its provider adapter. Use the foundation's versioned contract and existing provider helpers; do not introduce a second host-networking controller, lease store or BGP publisher. Any required foundation change must be tracked and qualified under #992 before this milestone claims integrated acceptance.

Work

  • Integrate the selected QUIC/HTTP/3 stack with TLS configuration, CONNECT-IP negotiation, HTTP datagrams and required control capsules.
  • Wire requests to common admission, prefix assignment, ownership, packet policy and return-routing components.
  • Support concurrent requests with bounded resources and independent cancellation; release request-owned resources without affecting other connectors.
  • Provide buildable service artifacts, internal configuration and a runnable development fixture. Document startup and shutdown for engineering verification, without production rollout work.

Acceptance criteria

  • Independent clients complete connect/send/receive/disconnect/reconnect against real gVPC workloads in both directions.
  • Tests verify certificate/hostname validation, invalid credentials, denied gVPC selection and cancellation isolation.
  • Assigned /96 addresses and subdivisions receive return traffic; expired ownership cannot continue forwarding.
  • CONNECT-IP runs natively over HTTP/3/QUIC without requiring a proprietary backend transport.

Additional integration acceptance

Scope follows #970: CONNECT-IP with HTTP/2 fallback; no public API development, plugin/portal integration, product-client development or production rollout.

Activity

  1. changed the title [-]MASQUE: implement the HTTP/3 CONNECT-IP edge service[/-] [+]Implement the HTTP/3 CONNECT-IP edge service[/+] on Oct 22, 2026
  2. added theissue type on Oct 22, 2026
  3. self-assigned this
    on Oct 28, 2026
  4. privateip commented on Oct 28, 2026

    @privateip
    CollaboratorAuthor

    Verdict: valid, and blocked on its own prerequisites. Checked against main at 15a1b5a.

    Main has no CONNECT-IP service you can deploy. The only process that serves internal/edge/connectip over HTTP/3 is the conformance fixture in tests/edgeconformance/masqueprovider. It authenticates with static test credentials unless a grant authority is configured, and nothing builds or publishes it as an image.

    This issue says not to wire an externally reachable listener until #991 is resolved, and it depends on #976 and #979. All three are still open:

    #991 goes first. Work on this issue resumes once #976, #979 and #991 are closed.

  5. privateip commented on Oct 28, 2026

    @privateip
    CollaboratorAuthor

    Updated verdict: valid, and now unblocked enough to build on. Checked against main at 7988c31 and #1201's head ff154e0.

    What changed since the last comment:

    What #980 still lacks:

    1. No service binary. go list ./cmd/... has no CONNECT-IP provider. The only process that serves internal/edge/connectip is the conformance fixture in tests/edgeconformance/masqueprovider. It accepts static bearer credentials from its config file, which a deployed listener must not.
    2. No artifacts. .github/workflows/publish.yaml publishes neither a provider nor a masque-authority image, and config/ has no manifests for either. masque-authority.md lists the image and manifests as Implement the HTTP/3 CONNECT-IP edge service #980's work.
    3. Contract limits that fix(connectip): Bound CONNECT-IP work before admission #1201 leaves open. The budget table asks for 8 connections per source IP, a 5 s handshake deadline, an 8 KiB header limit, 2 admissions per credential and a 3 s admission deadline. None is enforced:
      • quic-go v0.63.0 allows the handshake twice HandshakeIdleTimeout, so 10 s by default.
      • http3.Server.MaxHeaderBytes is unset, so the limit is http.DefaultMaxHeaderBytes (1 MiB).
      • Admit runs with the request's context and no deadline of its own.
    4. No lab run against the grant authority. TestMASQUE runs the fixture with static credentials only. No lab row uses cmd/masque-authority.
  6. privateip commented on Oct 28, 2026

    @privateip
    CollaboratorAuthor

    Fix plan (approved). Three stacked PRs on top of #1201:

    1. Remaining transport and admission limits (internal/edge/connectip). Cap connections at 8 per source IP and close a QUIC handshake that hasn't finished in 5 s. Limit request headers to 8 KiB. Allow 2 admissions in progress per credential digest, checked after the connection and global caps. Give Admit a 3 s deadline. Unit tests cover each cap.
    2. cmd/masque-provider. The fixture's run loop moves into a shared package, so the fixture and the service run the same code. The service authorizes only through masque-authority, never with static credentials. It reloads its certificate when the file changes. It serves /readyz, ready once it holds the instance Lease and the listener is up, and it serves metrics. Dockerfiles and publish.yaml jobs for masque-provider and masque-authority.
    3. Manifests and operator guide. Kustomize bases under config/ for the authority (the RBAC in masque-authority.md) and the provider (Deployment on UDP/443, TUN device-plugin resource, probes), plus an EdgeProvider example. A guide covers startup, shutdown and configuration.

    Risk: nothing deploys these manifests, so no running cluster changes. The limits change only the server that the fixture already runs.

    Verification: task ci, the envtest suites under internal/edge/masque/..., and the root TUN tests. No lab run in this stack. The acceptance rows that need real gVPC workloads under the grant authority stay open, so the stack references this issue without closing it.

  7. privateip commented on Oct 29, 2026

    @privateip
    CollaboratorAuthor

    Every acceptance criterion now has evidence, so I'm closing this. The service merged as the #1205 stack: transport limits in #1202, the masque-provider service in #1203 and its manifests in #1204. #1238 runs that shipped service and its grant authority on the containerlab lab, and all of its rows passed.

    Criterion Evidence
    Clients connect, send, receive, disconnect and reconnect against real gVPC workloads in both directions lifecycle-h3: two VPCs at once. Each round, 500/500 1280-byte replies from an edge-node workload and from a compute-node workload, and 40/40 pings from each workload to the connector. The claim was released 0 to 300 ms after disconnect. h2-lifecycle (#1240) does the same over HTTP/2
    Certificate and hostname validation tls-validation: the client refused another CA and another name, on both HTTP/3 and HTTP/2
    Invalid credentials, denied gVPC selection authorization-h3: an unknown credential got 401, and a credential that selects another VPC got 403. h2-authz-isolation repeats this over HTTP/2
    Cancellation isolation Unit tests: a cancelled request leaves its sibling running, and multiplexed requests stay in their own VPC. grant-disable: the other connector answered 1500/1500
    /96 addresses and subdivisions receive return traffic subdivisions: four addresses in two /112s, toward the edge-node workload, the compute-node workload and an off-fabric host through NAT, 250/250 each
    Expired ownership cannot keep forwarding grant-expiry: the last reply came 2.02 s before credential expiry, and the next request got 401. grant-disable: the last reply came 348 ms after the disable, within a 7 s bound
    Native HTTP/3 over QUIC The service serves CONNECT-IP over HTTP/3 with no other backend transport. HTTP/2 is the fallback from #981
    Separate Edge provider on the foundation-backed path, with no unfenced backend The service runs as its own Edge provider through the adapter from #975 and the instance Lease. The core stays protocol-independent
    Limits before exposure (#991) Connection, stream, admission and session caps from #1201 and #1202, with unit tests for each cap
    Readiness, claim acceptance, grant loss, drain and process restart against real foundation artifacts lease-readiness: /readyz failed at 14.99 s against a 15 s lease. process-restart: the lease was retaken at 17.2 s and both connectors were served at about 20 s on their adopted attachments. drain: the claim, attachment and lease were released 200 ms after SIGTERM

    Capacity qualification stays with #984 and #1242. One related bug stays open under #970. The process-restart row exposed it: if a connector reconnects within the clock-skew window before its grant's deadline, the authority renews the grant but core keeps the attachment refused for about 30 s (#1236).

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

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

Fields

Priority

None yet

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions