Skip to content

Add per-identity proxied-data rate limit - #8

Closed
kesavn-13 wants to merge 32 commits into
securitylevel5:mainfrom
kesavn-13:per-identity-rate-limit
Closed

Add per-identity proxied-data rate limit#8
kesavn-13 wants to merge 32 commits into
securitylevel5:mainfrom
kesavn-13:per-identity-rate-limit

Conversation

@kesavn-13

Copy link
Copy Markdown

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 RateLimiter into MakeProxyService.
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:

cargo fmt
cargo fmt --check
cargo test --lib
cargo test

sl5-guy added 30 commits April 13, 2026 12:09
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
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.

3 participants