Skip to content

Commit

Permalink
Rate Limiting PoC
Browse files Browse the repository at this point in the history
Some caveats:

- This doesn't abide yet to the agreed API as declared in linkerd/linkerd2-proxy-api#388 . Instead, this is based on an earlier API proposal using "specifiers" to define the buckets keys.
- The limiting logic has been added directly into the inbound http policy middleware. It relies on [governor](https://docs.rs/governor/latest/governor/). If we're not allowing to configure bursting in the first implementation, we might reconsider implementing something simpler directly ourselves.
- There is actually an additional middleware (`RateLimitPolicyService`) that is currently commented out (used in the initial demo), that implemented a simpler approach, inspired by Tower's own rate-limiting middleware.
  • Loading branch information
alpeb committed Oct 23, 2024
1 parent ef779d0 commit 2d4451f
Show file tree
Hide file tree
Showing 12 changed files with 594 additions and 10 deletions.
124 changes: 122 additions & 2 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,12 @@ dependencies = [
"cfg-if",
]

[[package]]
name = "crossbeam-utils"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"

[[package]]
name = "crypto-common"
version = "0.1.6"
Expand All @@ -389,6 +395,19 @@ dependencies = [
"typenum",
]

[[package]]
name = "dashmap"
version = "5.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
"cfg-if",
"hashbrown 0.14.3",
"lock_api",
"once_cell",
"parking_lot_core",
]

[[package]]
name = "data-encoding"
version = "2.6.0"
Expand Down Expand Up @@ -670,6 +689,17 @@ dependencies = [
"syn",
]

[[package]]
name = "futures-macro"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

[[package]]
name = "futures-sink"
version = "0.3.31"
Expand All @@ -682,6 +712,12 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"

[[package]]
name = "futures-timer"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"

[[package]]
name = "futures-util"
version = "0.3.31"
Expand Down Expand Up @@ -733,6 +769,26 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"

[[package]]
name = "governor"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b"
dependencies = [
"cfg-if",
"dashmap",
"futures",
"futures-timer",
"no-std-compat",
"nonzero_ext",
"parking_lot",
"portable-atomic",
"quanta",
"rand",
"smallvec",
"spinning_top",
]

[[package]]
name = "gzip-header"
version = "1.0.0"
Expand Down Expand Up @@ -1255,13 +1311,17 @@ dependencies = [
"arbitrary",
"bytes",
"futures",
"governor",
"http",
"hyper",
"libfuzzer-sys",
"linkerd-app-core",
"linkerd-app-test",
"linkerd-dns-name",
"linkerd-error",
"linkerd-http-access-log",
"linkerd-http-metrics",
"linkerd-identity",
"linkerd-idle-cache",
"linkerd-io",
"linkerd-meshtls",
Expand Down Expand Up @@ -2385,8 +2445,6 @@ dependencies = [
[[package]]
name = "linkerd2-proxy-api"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26c72fb98d969e1e94e95d52a6fcdf4693764702c369e577934256e72fb5bc61"
dependencies = [
"h2",
"http",
Expand Down Expand Up @@ -2530,6 +2588,12 @@ dependencies = [
"libc",
]

[[package]]
name = "no-std-compat"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"

[[package]]
name = "nom"
version = "7.1.3"
Expand All @@ -2540,6 +2604,12 @@ dependencies = [
"minimal-lexical",
]

[[package]]
name = "nonzero_ext"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"

[[package]]
name = "nu-ansi-term"
version = "0.46.0"
Expand Down Expand Up @@ -2764,6 +2834,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"

[[package]]
name = "portable-atomic"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265"

[[package]]
name = "powerfmt"
version = "0.2.0"
Expand Down Expand Up @@ -2920,6 +2996,21 @@ dependencies = [
"prost",
]

[[package]]
name = "quanta"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5"
dependencies = [
"crossbeam-utils",
"libc",
"once_cell",
"raw-cpuid",
"wasi",
"web-sys",
"winapi",
]

[[package]]
name = "quick-error"
version = "1.2.3"
Expand Down Expand Up @@ -2980,6 +3071,15 @@ version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684"

[[package]]
name = "raw-cpuid"
version = "11.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb9ee317cfe3fbd54b36a511efc1edd42e216903c9cd575e686dd68a2ba90d8d"
dependencies = [
"bitflags 2.4.2",
]

[[package]]
name = "rcgen"
version = "0.12.1"
Expand Down Expand Up @@ -3290,6 +3390,15 @@ version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"

[[package]]
name = "spinning_top"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300"
dependencies = [
"lock_api",
]

[[package]]
name = "stable_deref_trait"
version = "1.2.0"
Expand Down Expand Up @@ -3864,6 +3973,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"

[[package]]
name = "web-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
dependencies = [
"js-sys",
"wasm-bindgen",
]

[[package]]
>>>>>>> dca153b2 (wip)
name = "widestring"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
Expand Down
10 changes: 10 additions & 0 deletions linkerd/app/core/src/errors/respond.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@ impl SyntheticHttpResponse {
}
}

pub fn rate_limited(msg: impl ToString) -> Self {
Self {
http_status: http::StatusCode::TOO_MANY_REQUESTS,
grpc_status: tonic::Code::ResourceExhausted,
close_connection: false,
message: Cow::Owned(msg.to_string()),
location: None,
}
}

pub fn loop_detected(msg: impl ToString) -> Self {
Self {
http_status: http::StatusCode::LOOP_DETECTED,
Expand Down
4 changes: 4 additions & 0 deletions linkerd/app/inbound/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ test-util = [
bytes = "1"
http = "0.2"
futures = { version = "0.3", default-features = false }
governor = { version = "0.6", features = ["std"] }
linkerd-app-core = { path = "../core" }
linkerd-app-test = { path = "../test", optional = true }
linkerd-dns-name = { path = "../../dns/name" }
linkerd-error = { path = "../../error" }
linkerd-identity = { path = "../../identity" }
linkerd-http-access-log = { path = "../../http/access-log" }
linkerd-idle-cache = { path = "../../idle-cache" }
linkerd-meshtls = { path = "../../meshtls", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion linkerd/app/inbound/src/http.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod router;
pub mod router;
mod server;
mod set_identity_header;
#[cfg(test)]
Expand Down
3 changes: 2 additions & 1 deletion linkerd/app/inbound/src/http/router.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{policy, stack_labels, Inbound};
use crate::{/*limit, */policy, stack_labels, Inbound};
use linkerd_app_core::{
classify, errors, http_tracing, metrics, profiles,
proxy::{http, tap},
Expand Down Expand Up @@ -241,6 +241,7 @@ impl<C> Inbound<C> {
.check_new_service::<(policy::HttpRoutePermit, T), http::Request<http::BoxBody>>()
.push(svc::ArcNewService::layer())
.push(policy::NewHttpPolicy::layer(rt.metrics.http_authz.clone()))
//.push(limit::NewRateLimitPolicy::layer())
// Used by tap.
.push_http_insert_target::<tls::ConditionalServerTls>()
.push_http_insert_target::<Remote<ClientAddr>>()
Expand Down
4 changes: 4 additions & 0 deletions linkerd/app/inbound/src/http/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ impl errors::HttpRescue<Error> for ServerRescue {
));
}

if errors::is_caused_by::<policy::http::RateLimitError>(&*error) {
return Ok(errors::SyntheticHttpResponse::rate_limited(error));
}

if errors::is_caused_by::<crate::GatewayDomainInvalid>(&*error) {
return Ok(errors::SyntheticHttpResponse::not_found(error));
}
Expand Down
1 change: 1 addition & 0 deletions linkerd/app/inbound/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod accept;
mod detect;
pub mod direct;
mod http;
mod limit;
mod metrics;
pub mod policy;
mod server;
Expand Down
Loading

0 comments on commit 2d4451f

Please sign in to comment.