Add per-identity proxied-data rate limit - #8
Closed
kesavn-13 wants to merge 32 commits into
Closed
Conversation
Proxy accepts HTTP/2 CONNECT requests over mTLS, extracts a custom X.509 extension from the client certificate, and evaluates it against a TOML policy to authorize connections to requested destinations. Allowed connections are tunneled as opaque TCP via bidirectional byte copy. Includes structured logging (tracing), OpenTelemetry export, Prometheus metrics, and a comprehensive test suite (38 integration + 8 e2e tests covering tunnel success, policy denial, extension enforcement, mTLS fail-closed, unreachable destinations, and method rejection).
Tested end-to-end: client connects to proxy over mTLS h2, sends CONNECT, tunnels TLS to the destination, and receives an echoed JSON response. The client uses h2 + ssl.MemoryBIO to perform TLS-over-h2-tunnel (validate_outbound_headers disabled to work around h2's incorrect CONNECT pseudo-header validation).
generate-certs.sh creates the certs/ directory with all certificates needed to run the proxy locally. README quick-start section documents the workflow. Sample client hardened against livelock (bounded fast-recv loops), SSLWantWriteError during handshake/send/recv, and unexpected ConnectionTerminated frames from the proxy.
Replace all wildcard ("*") dependency versions with semver-compatible
pins: "MAJOR" for 1.x+ crates, "0.MINOR" for 0.x crates.
OpenTelemetry tracing is sufficient. Drop the metrics and metrics-exporter-prometheus crates, the metrics_bind config field, the PrometheusBuilder listener, and the corresponding docs. Add a regression test ensuring metrics_bind is rejected as unknown.
Record source identity, source peer, destination authority, gateway endpoint, and tunnel outcomes directly on gateway and sidecar events so logs are self-contained.
Support disabling stdout logging while keeping OTLP export active, and document the TPM cert reissue behavior in the sidecar connection flow.
Store only the signing key public DER and enforce uniqueness on that source value instead of carrying a derived hash that can drift.
Create principal signing keys through tpm2-pkcs11 so enrollment stores only the TPM public key while keeping the private key on the principal machine.
Let admins grant principal signing keys destination delegation authority without binding grants to individual agent identities.
Bind authorization to the presented client certificate key in Postgres so client CA bundles are no longer a trust root.
Keep registry-backed policy details behind the policy construction boundary and trim unused dependency features so the gateway exposes less non-core surface.
Move the former examples into purpose-specific homes so demo scaffolding and registry mutation commands are not presented as sample code.
Change cargo clippy to pedantic and switch sqlx to use query macros for compile-time type checks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds a simple per-identity data limit for traffic proxied through the gateway. The limiter is keyed by the same source identity already used by the gateway policy path, so the limit is attached to the agent identity rather than something weaker like IP address.
Why I chose this design
I treated the gateway as the right place for this feature because it is already the enforcement point. It sees the mTLS identity, checks policy, and then moves the actual proxied bytes. The dashboard and demo repos are useful for visibility and local setup, but the data-limit decision belongs in the gateway itself.
I kept the first version intentionally small: an in-memory fixed-window byte counter per identity. My current SPAR work is around secure infrastructure and local/offline agent workflows, and one thing I have been learning there is that security controls are easier to trust when they are small, auditable, and placed at clear boundaries. For this task, I preferred a simple local limiter over adding another dependency or service too early.
Implementation
Added
src/rate_limit.rs.Added optional
[rate_limit]config.Wired a shared
RateLimiterintoMakeProxyService.Replaced the tunnel copy path with a small bidirectional copy loop that counts proxied bytes.
Updated integration test setup to pass a disabled limiter so existing tests keep their previous behavior.
The limiter counts traffic in both directions. If an identity exceeds its configured byte budget during the current window, the gateway closes the tunnel and logs the rate-limit event.
Testing
Ran: