From 7bb58be546feea32da3f6e99f229bb5c1792c96b Mon Sep 17 00:00:00 2001 From: Erik Grinaker Date: Wed, 30 Apr 2025 10:38:44 +0200 Subject: [PATCH] Use `authorization` header instead of `neon-auth-token` --- pageserver/client_grpc/src/lib.rs | 14 +++++++------ pageserver/page_api/proto/page_service.proto | 8 ++++---- pageserver/src/compute_service_grpc.rs | 21 ++++++++++++++------ 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/pageserver/client_grpc/src/lib.rs b/pageserver/client_grpc/src/lib.rs index 384994ba38..6785defba4 100644 --- a/pageserver/client_grpc/src/lib.rs +++ b/pageserver/client_grpc/src/lib.rs @@ -61,7 +61,7 @@ impl PageserverClient { _auth_token: auth_token.clone(), shard_map, channels: RwLock::new(HashMap::new()), - auth_interceptor: AuthInterceptor::new(tenant_id, timeline_id, auth_token.as_ref()), + auth_interceptor: AuthInterceptor::new(tenant_id, timeline_id, auth_token.as_deref()), } } @@ -206,15 +206,17 @@ struct AuthInterceptor { tenant_id: AsciiMetadataValue, timeline_id: AsciiMetadataValue, - auth_token: Option, + auth_header: Option, // including "Bearer " prefix } impl AuthInterceptor { - fn new(tenant_id: &str, timeline_id: &str, auth_token: Option<&String>) -> Self { + fn new(tenant_id: &str, timeline_id: &str, auth_token: Option<&str>) -> Self { Self { tenant_id: tenant_id.parse().expect("could not parse tenant id"), timeline_id: timeline_id.parse().expect("could not parse timeline id"), - auth_token: auth_token.map(|x| x.parse().expect("could not parse auth token")), + auth_header: auth_token + .map(|t| format!("Bearer {t}")) + .map(|t| t.parse().expect("could not parse auth token")), } } } @@ -225,9 +227,9 @@ impl tonic::service::Interceptor for AuthInterceptor { .insert("neon-tenant-id", self.tenant_id.clone()); req.metadata_mut() .insert("neon-timeline-id", self.timeline_id.clone()); - if let Some(auth_token) = &self.auth_token { + if let Some(auth_header) = &self.auth_header { req.metadata_mut() - .insert("neon-auth-token", auth_token.clone()); + .insert("authorization", auth_header.clone()); } Ok(req) diff --git a/pageserver/page_api/proto/page_service.proto b/pageserver/page_api/proto/page_service.proto index 295b689c38..445b1cb711 100644 --- a/pageserver/page_api/proto/page_service.proto +++ b/pageserver/page_api/proto/page_service.proto @@ -1,9 +1,9 @@ // Page service presented by pageservers, for computes. // -// Each request must come with the following metadata: -// - neon-tenant-id -// - neon-timeline-id -// - neon-auth-token (if auth is enabled) +// Request metadata: +// - authorization: JWT token ("Bearer "), if auth is enabled +// - neon-tenant-id: tenant ID ("7c4a1f9e3bd6470c8f3e21a65bd2e980") +// - neon-timeline-id: timeline ID ("f08c4e9a2d5f76b1e3a7c2d8910f4b3e") // // TODO: what else? Priority? OpenTelemetry tracing? // diff --git a/pageserver/src/compute_service_grpc.rs b/pageserver/src/compute_service_grpc.rs index 33087fc311..f9a2d2c08b 100644 --- a/pageserver/src/compute_service_grpc.rs +++ b/pageserver/src/compute_service_grpc.rs @@ -722,13 +722,22 @@ impl tonic::service::Interceptor for PageServiceAuthenticator { return Ok(req); }; - let jwt = req + let authorization = req .metadata() - .get("neon-auth-token") - .ok_or(tonic::Status::unauthenticated("no neon-auth-token"))?; - let jwt = jwt.to_str().map_err(|_| { - tonic::Status::invalid_argument("invalid UTF-8 characters in neon-auth-token metadata") - })?; + .get("authorization") + .ok_or(tonic::Status::unauthenticated("no authorization header"))? + .to_str() + .map_err(|_| { + tonic::Status::invalid_argument( + "invalid UTF-8 characters in authorization metadata", + ) + })?; + if &authorization[0..7] != "Bearer " { + return Err(tonic::Status::unauthenticated( + "authorization header must start with 'Bearer '", + )); + } + let jwt = &authorization[7..].trim(); let jwtdata: TokenData = auth .decode(jwt)