Skip to content

Commit

Permalink
Add env var to disable admin shutdown endpoint (#3014)
Browse files Browse the repository at this point in the history
The /shutdown admin endpoint of the proxy can potentially be a DOS vector, for example, in the case of a SSRF attack.

We add a LINKERD2_PROXY_SHUTDOWN_ENDPOINT_ENABLED environment variable to control if the /shutdown endpoint is enabled. Disabling this endpoint removes this DOS vector.

Signed-off-by: Alex Leong <alex@buoyant.io>
  • Loading branch information
adleong authored Jun 14, 2024
1 parent 3458c94 commit 49336fd
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 2 deletions.
12 changes: 11 additions & 1 deletion linkerd/app/admin/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub struct Admin<M> {
tracing: trace::Handle,
ready: Readiness,
shutdown_tx: mpsc::UnboundedSender<()>,
enable_shutdown: bool,
#[cfg(feature = "pprof")]
pprof: Option<crate::pprof::Pprof>,
}
Expand All @@ -51,12 +52,14 @@ impl<M> Admin<M> {
metrics: M,
ready: Readiness,
shutdown_tx: mpsc::UnboundedSender<()>,
enable_shutdown: bool,
tracing: trace::Handle,
) -> Self {
Self {
metrics: metrics::Serve::new(metrics),
ready,
shutdown_tx,
enable_shutdown,
tracing,

#[cfg(feature = "pprof")]
Expand Down Expand Up @@ -140,6 +143,13 @@ impl<M> Admin<M> {
}

fn shutdown(&self) -> Response<Body> {
if !self.enable_shutdown {
return Response::builder()
.status(StatusCode::NOT_FOUND)
.header(http::header::CONTENT_TYPE, "text/plain")
.body("shutdown endpoint is not enabled\n".into())
.expect("builder with known status code must not fail");
}
if self.shutdown_tx.send(()).is_ok() {
Response::builder()
.status(StatusCode::OK)
Expand Down Expand Up @@ -315,7 +325,7 @@ mod tests {

let (_, t) = trace::Settings::default().build();
let (s, _) = mpsc::unbounded_channel();
let admin = Admin::new((), r, s, t);
let admin = Admin::new((), r, s, true, t);
macro_rules! call {
() => {{
let r = Request::builder()
Expand Down
3 changes: 2 additions & 1 deletion linkerd/app/admin/src/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub struct Config {
pub metrics_retain_idle: Duration,
#[cfg(feature = "pprof")]
pub enable_profiling: bool,
pub enable_shutdown: bool,
}

pub struct Task {
Expand Down Expand Up @@ -100,7 +101,7 @@ impl Config {
let (ready, latch) = crate::server::Readiness::new();

#[cfg_attr(not(feature = "pprof"), allow(unused_mut))]
let admin = crate::server::Admin::new(report, ready, shutdown, trace);
let admin = crate::server::Admin::new(report, ready, shutdown, self.enable_shutdown, trace);

#[cfg(feature = "pprof")]
let admin = admin.with_profiling(self.enable_profiling);
Expand Down
5 changes: 5 additions & 0 deletions linkerd/app/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ pub const ENV_ADMIN_LISTEN_ADDR: &str = "LINKERD2_PROXY_ADMIN_LISTEN_ADDR";

pub const ENV_METRICS_RETAIN_IDLE: &str = "LINKERD2_PROXY_METRICS_RETAIN_IDLE";

pub const ENV_SHUTDOWN_ENDPOINT_ENABLED: &str = "LINKERD2_PROXY_SHUTDOWN_ENDPOINT_ENABLED";

const ENV_INGRESS_MODE: &str = "LINKERD2_PROXY_INGRESS_MODE";

const ENV_INBOUND_HTTP_QUEUE_CAPACITY: &str = "LINKERD2_PROXY_INBOUND_HTTP_QUEUE_CAPACITY";
Expand Down Expand Up @@ -397,6 +399,8 @@ pub fn parse_config<S: Strings>(strings: &S) -> Result<super::Config, EnvError>

let control_receive_limits = control::mk_receive_limits(strings)?;

let shutdown_endpoint_enabled = parse(strings, ENV_SHUTDOWN_ENDPOINT_ENABLED, parse_bool);

// DNS

let resolv_conf_path = strings.get(ENV_RESOLV_CONF);
Expand Down Expand Up @@ -773,6 +777,7 @@ pub fn parse_config<S: Strings>(strings: &S) -> Result<super::Config, EnvError>
// configuration.
#[cfg(feature = "pprof")]
enable_profiling: true,
enable_shutdown: shutdown_endpoint_enabled?.unwrap_or_default(),
};

let dns = dns::Config {
Expand Down

0 comments on commit 49336fd

Please sign in to comment.