From 029baacb1c00c71ee260bd911b81e3a25986536e Mon Sep 17 00:00:00 2001 From: Paul Butler Date: Fri, 15 Dec 2023 13:39:22 -0500 Subject: [PATCH] Separate routes into /ctrl and /pub --- plane2/src/client/mod.rs | 37 ++++++++++++++++++++---------------- plane2/src/controller/mod.rs | 28 ++++++++++++++++++++------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/plane2/src/client/mod.rs b/plane2/src/client/mod.rs index ec66ea002..15c497b81 100644 --- a/plane2/src/client/mod.rs +++ b/plane2/src/client/mod.rs @@ -67,7 +67,7 @@ impl PlaneClient { } pub async fn status(&self) -> Result<(), PlaneClientError> { - let url = self.base_url.join("/status")?; + let url = self.base_url.join("/ctrl/status")?; let response = self.client.get(url).send().await?; get_response::(response).await?; @@ -77,7 +77,7 @@ impl PlaneClient { pub fn drone_connection(&self, cluster: &ClusterId) -> TypedSocketConnector { let mut url = self .base_url - .join(&format!("/c/{}/drone-socket", cluster)) + .join(&format!("/ctrl/c/{}/drone-socket", cluster)) .expect("url is always valid"); http_to_ws_url(&mut url); TypedSocketConnector::new(url) @@ -86,7 +86,7 @@ impl PlaneClient { pub fn proxy_connection(&self, cluster: &ClusterId) -> TypedSocketConnector { let mut url = self .base_url - .join(&format!("/c/{}/proxy-socket", cluster)) + .join(&format!("/ctrl/c/{}/proxy-socket", cluster)) .expect("url is always valid"); http_to_ws_url(&mut url); TypedSocketConnector::new(url) @@ -95,7 +95,7 @@ impl PlaneClient { pub fn dns_connection(&self) -> TypedSocketConnector { let mut url = self .base_url - .join("/dns-socket") + .join("/ctrl/dns-socket") .expect("url is always valid"); http_to_ws_url(&mut url); TypedSocketConnector::new(url) @@ -106,7 +106,9 @@ impl PlaneClient { cluster: &ClusterId, connect_request: &ConnectRequest, ) -> Result { - let url = self.base_url.join(&format!("/c/{}/connect", cluster))?; + let url = self + .base_url + .join(&format!("/ctrl/c/{}/connect", cluster))?; let respose = self.client.post(url).json(connect_request).send().await?; let connect_response: ConnectResponse = get_response(respose).await?; @@ -120,7 +122,7 @@ impl PlaneClient { ) -> Result<(), PlaneClientError> { let url = self .base_url - .join(&format!("/c/{}/d/{}/drain", cluster, drone))?; + .join(&format!("/ctrl/c/{}/d/{}/drain", cluster, drone))?; let response = self.client.post(url).send().await?; get_response::(response).await?; @@ -132,9 +134,10 @@ impl PlaneClient { cluster: &ClusterId, backend_id: &BackendName, ) -> Result<(), PlaneClientError> { - let url = self - .base_url - .join(&format!("/c/{}/b/{}/soft-terminate", cluster, backend_id))?; + let url = self.base_url.join(&format!( + "/ctrl/c/{}/b/{}/soft-terminate", + cluster, backend_id + ))?; let response = self.client.post(url).send().await?; get_response::(response).await?; @@ -146,9 +149,10 @@ impl PlaneClient { cluster: &ClusterId, backend_id: &BackendName, ) -> Result<(), PlaneClientError> { - let url = self - .base_url - .join(&format!("/c/{}/b/{}/hard-terminate", cluster, backend_id))?; + let url = self.base_url.join(&format!( + "/ctrl/c/{}/b/{}/hard-terminate", + cluster, backend_id + ))?; let response = self.client.post(url).send().await?; get_response::(response).await?; @@ -162,7 +166,7 @@ impl PlaneClient { ) -> Result { let url = self .base_url - .join(&format!("/c/{}/b/{}/status", cluster, backend_id))?; + .join(&format!("/pub/c/{}/b/{}/status", cluster, backend_id))?; let response = self.client.get(url).send().await?; let status: TimestampedBackendStatus = get_response(response).await?; @@ -174,9 +178,10 @@ impl PlaneClient { cluster: &ClusterId, backend_id: &BackendName, ) -> Result, PlaneClientError> { - let url = self - .base_url - .join(&format!("/c/{}/b/{}/status-stream", cluster, backend_id))?; + let url = self.base_url.join(&format!( + "/pub/c/{}/b/{}/status-stream", + cluster, backend_id + ))?; let stream = sse::sse_request(url, self.client.clone()).await?; Ok(stream) diff --git a/plane2/src/controller/mod.rs b/plane2/src/controller/mod.rs index 4d2b130eb..7a5e882d5 100644 --- a/plane2/src/controller/mod.rs +++ b/plane2/src/controller/mod.rs @@ -125,17 +125,17 @@ impl ControllerServer { let heartbeat_handle = HeartbeatSender::start(db.clone(), id.clone()).await?; - let app = Router::new() + // Routes that relate to controlling the system (spawning and terminating drones) + // or that otherwise expose non-public system information. + // + // These routes should not be exposed on the open internet without an authorization + // barrier (such as a reverse proxy) in front. + let control_routes = Router::new() .route("/status", get(status)) .route("/c/:cluster/drone-socket", get(handle_drone_socket)) .route("/c/:cluster/proxy-socket", get(handle_proxy_socket)) .route("/dns-socket", get(handle_dns_socket)) .route("/c/:cluster/connect", post(handle_connect)) - .route("/c/:cluster/b/:backend/status", get(handle_backend_status)) - .route( - "/c/:cluster/b/:backend/status-stream", - get(handle_backend_status_stream), - ) .route("/c/:cluster/d/:drone/drain", post(handle_drain)) .route( "/c/:cluster/b/:backend/soft-terminate", @@ -144,7 +144,21 @@ impl ControllerServer { .route( "/c/:cluster/b/:backend/hard-terminate", post(terminate::handle_hard_terminate), - ) + ); + + // Routes that are may be accessed directly from end-user code. These are placed + // under the /pub/ top-level route to make it easier to expose only these routes, + // using a reverse proxy configuration. + let public_routes = Router::new() + .route("/c/:cluster/b/:backend/status", get(handle_backend_status)) + .route( + "/c/:cluster/b/:backend/status-stream", + get(handle_backend_status_stream), + ); + + let app = Router::new() + .nest("/pub", public_routes) + .nest("/ctrl", control_routes) .layer(trace_layer) .with_state(controller);