@@ -8,6 +8,7 @@ use std::{
88 } ,
99} ;
1010
11+ use axum_extra:: extract:: cookie:: Key ;
1112use defguard_version:: {
1213 get_tracing_variables,
1314 server:: { grpc:: DefguardVersionInterceptor , DefguardVersionLayer } ,
@@ -31,6 +32,7 @@ use crate::{
3132
3233// connected clients
3334type ClientMap = HashMap < SocketAddr , mpsc:: UnboundedSender < Result < CoreRequest , Status > > > ;
35+ static COOKIE_KEY_HEADER : & str = "dg-cookie-key-bin" ;
3436
3537#[ derive( Debug , Clone , Default ) ]
3638pub ( crate ) struct Configuration {
@@ -42,6 +44,7 @@ pub(crate) struct ProxyServer {
4244 current_id : Arc < AtomicU64 > ,
4345 clients : Arc < Mutex < ClientMap > > ,
4446 results : Arc < Mutex < HashMap < u64 , oneshot:: Sender < core_response:: Payload > > > > ,
47+ http_channel : mpsc:: UnboundedSender < Key > ,
4548 pub ( crate ) connected : Arc < AtomicBool > ,
4649 pub ( crate ) core_version : Arc < Mutex < Option < Version > > > ,
4750 config : Arc < Mutex < Option < Configuration > > > ,
@@ -51,8 +54,9 @@ pub(crate) struct ProxyServer {
5154impl ProxyServer {
5255 #[ must_use]
5356 /// Create new `ProxyServer`.
54- pub ( crate ) fn new ( ) -> Self {
57+ pub ( crate ) fn new ( http_channel : mpsc :: UnboundedSender < Key > ) -> Self {
5558 Self {
59+ http_channel,
5660 current_id : Arc :: new ( AtomicU64 :: new ( 1 ) ) ,
5761 clients : Arc :: new ( Mutex :: new ( HashMap :: new ( ) ) ) ,
5862 results : Arc :: new ( Mutex :: new ( HashMap :: new ( ) ) ) ,
@@ -189,6 +193,7 @@ impl Clone for ProxyServer {
189193 results : Arc :: clone ( & self . results ) ,
190194 connected : Arc :: clone ( & self . connected ) ,
191195 core_version : Arc :: clone ( & self . core_version ) ,
196+ http_channel : self . http_channel . clone ( ) ,
192197 config : Arc :: clone ( & self . config ) ,
193198 setup_in_progress : Arc :: clone ( & self . setup_in_progress ) ,
194199 }
@@ -228,6 +233,30 @@ impl proxy_server::Proxy for ProxyServer {
228233
229234 info ! ( "Defguard Core gRPC client connected from: {address}" ) ;
230235
236+ // Retrieve private cookies key from the header.
237+ let cookie_key = request. metadata ( ) . get_bin ( COOKIE_KEY_HEADER ) ;
238+ let key = match cookie_key {
239+ Some ( key) => Key :: from ( & key. to_bytes ( ) . map_err ( |err| {
240+ error ! ( "Failed to decode private cookie key: {err:?}" ) ;
241+ Status :: internal ( "Failed to decode private cookie key" )
242+ } ) ?) ,
243+ // If the header is missing, fall back to generating a local key.
244+ // This preserves compatibility with older Core versions that did not
245+ // provide a shared cookie key. In this mode, cookie-based sessions will
246+ // not be shared across proxy instances and HA won't work.
247+ None => {
248+ warn ! (
249+ "Private cookie key not provided by Core; falling back to a locally generated key. \
250+ This typically indicates an older Core version and disables cookie sharing across proxies."
251+ ) ;
252+ Key :: generate ( )
253+ }
254+ } ;
255+ self . http_channel . send ( key) . map_err ( |err| {
256+ error ! ( "Failed to send private cookies key to HTTP server: {err:?}" ) ;
257+ Status :: internal ( "Failed to send private cookies key to HTTP server" )
258+ } ) ?;
259+
231260 let ( tx, rx) = mpsc:: unbounded_channel ( ) ;
232261 self . clients
233262 . lock ( )
0 commit comments