@@ -216,18 +216,20 @@ func startEdgeTunnelClientIfConfigured(appCtx context.Context, cfg *config.Confi
216216 EdgeAgent : cfg .EdgeAgent ,
217217 EdgeTransport : cfg .EdgeTransport ,
218218 EdgeReconnectInterval : cfg .EdgeReconnectInterval ,
219+ EdgeMTLSMode : cfg .EdgeMTLSMode ,
220+ EdgeMTLSAutoGenerate : cfg .EdgeMTLSAutoGenerate ,
221+ EdgeMTLSCAFile : cfg .EdgeMTLSCAFile ,
222+ EdgeMTLSCertFile : cfg .EdgeMTLSCertFile ,
223+ EdgeMTLSKeyFile : cfg .EdgeMTLSKeyFile ,
224+ EdgeMTLSServerName : cfg .EdgeMTLSServerName ,
225+ EdgeMTLSAssetsDir : cfg .EdgeMTLSAssetsDir ,
219226 ManagerApiUrl : cfg .ManagerApiUrl ,
220227 AgentToken : cfg .AgentToken ,
221228 Port : cfg .Port ,
222229 Listen : cfg .Listen ,
223230 }
224231
225- slog .InfoContext (appCtx , "Starting edge tunnel client" ,
226- "transport_mode" , edge .NormalizeEdgeTransport (edgeCfg .EdgeTransport ),
227- "live_tunnel_attempt_grpc" , edge .UseGRPCEdgeTransport (edgeCfg ) || (edge .UsePollEdgeTransport (edgeCfg ) && strings .TrimSpace (edgeCfg .GetManagerGRPCAddr ()) != "" ),
228- "live_tunnel_attempt_websocket" , edge .UseWebSocketEdgeTransport (edgeCfg ) || (edge .UsePollEdgeTransport (edgeCfg ) && strings .TrimSpace (edgeCfg .GetManagerBaseURL ()) != "" ),
229- "manager_url" , cfg .ManagerApiUrl ,
230- )
232+ slog .InfoContext (appCtx , "Starting edge agent session client" , edge .StartupLogAttrs (edgeCfg )... )
231233 errCh , err := edge .StartTunnelClientWithErrors (appCtx , edgeCfg , router )
232234 if err != nil {
233235 slog .ErrorContext (appCtx , "Failed to start edge tunnel client" , "error" , err )
@@ -257,6 +259,23 @@ func handleAgentBootstrapPairing(ctx context.Context, cfg *config.Config, httpCl
257259
258260 req .Header .Set ("X-API-Key" , cfg .AgentToken )
259261
262+ if cfg .EdgeAgent && strings .TrimSpace (cfg .ManagerApiUrl ) != "" {
263+ edgeClient , edgeErr := edge .NewManagerHTTPClient (& edge.Config {
264+ ManagerApiUrl : cfg .ManagerApiUrl ,
265+ EdgeMTLSMode : cfg .EdgeMTLSMode ,
266+ EdgeMTLSAutoGenerate : cfg .EdgeMTLSAutoGenerate ,
267+ EdgeMTLSCAFile : cfg .EdgeMTLSCAFile ,
268+ EdgeMTLSCertFile : cfg .EdgeMTLSCertFile ,
269+ EdgeMTLSKeyFile : cfg .EdgeMTLSKeyFile ,
270+ EdgeMTLSServerName : cfg .EdgeMTLSServerName ,
271+ EdgeMTLSAssetsDir : cfg .EdgeMTLSAssetsDir ,
272+ }, 10 * time .Second )
273+ if edgeErr != nil {
274+ return fmt .Errorf ("failed to configure edge pairing client: %w" , edgeErr )
275+ }
276+ httpClient = edgeClient
277+ }
278+
260279 resp , err := httpClient .Do (req ) //nolint:gosec // intentional request to configured manager pairing endpoint
261280 if err != nil {
262281 return fmt .Errorf ("pairing request failed: %w" , err )
@@ -301,45 +320,17 @@ func runServices(appCtx context.Context, cfg *config.Config, router http.Handler
301320 }
302321
303322 listenAddr := cfg .ListenAddr ()
304- httpHandler := router
305- useTLS := cfg .TLSEnabled
306- tlsCertFile := strings .TrimSpace (cfg .TLSCertFile )
307- tlsKeyFile := strings .TrimSpace (cfg .TLSKeyFile )
308-
309- if useTLS && (tlsCertFile == "" || tlsKeyFile == "" ) {
310- return fmt .Errorf ("TLS_ENABLED requires both TLS_CERT_FILE and TLS_KEY_FILE" )
311- }
312-
313- var grpcServer * grpc.Server
314- if ! cfg .AgentMode && tunnelServer != nil {
315- grpcServer = grpc .NewServer (tunnelServer .GRPCServerOptions (appCtx )... )
316- tunnelpb .RegisterTunnelServiceServer (grpcServer , tunnelServer )
317-
318- httpHandler = http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
319- if isTunnelGRPCRequestInternal (r ) {
320- grpcReq := normalizeTunnelGRPCRequestPathInternal (r )
321- grpcServer .ServeHTTP (w , grpcReq )
322- return
323- }
324- router .ServeHTTP (w , r )
325- })
326- slog .InfoContext (appCtx , "Using shared HTTP/gRPC listener for edge tunnel" , "addr" , listenAddr )
323+ useTLS , tlsCertFile , tlsKeyFile , edgeCfg , err := prepareServerTLSInternal (cfg )
324+ if err != nil {
325+ return err
327326 }
328327
329- var protocols http.Protocols
330- protocols .SetHTTP1 (true )
331- if useTLS {
332- protocols .SetHTTP2 (true )
333- } else {
334- protocols .SetUnencryptedHTTP2 (true )
335- httpHandler = h2c .NewHandler (httpHandler , & http2.Server {})
336- }
328+ httpHandler , grpcServer := configureTunnelServerInternal (appCtx , cfg , router , tunnelServer , listenAddr )
329+ httpHandler , protocols := configureHTTPProtocolsInternal (useTLS , httpHandler )
337330
338- srv := & http.Server {
339- Addr : listenAddr ,
340- Handler : httpHandler ,
341- Protocols : & protocols ,
342- ReadHeaderTimeout : 5 * time .Second ,
331+ srv , err := newHTTPServerInternal (listenAddr , httpHandler , protocols , useTLS , edgeCfg )
332+ if err != nil {
333+ return err
343334 }
344335
345336 go func () {
@@ -389,6 +380,109 @@ func runServices(appCtx context.Context, cfg *config.Config, router http.Handler
389380 return nil
390381}
391382
383+ func prepareServerTLSInternal (cfg * config.Config ) (bool , string , string , * edge.Config , error ) {
384+ useTLS := cfg .TLSEnabled
385+ tlsCertFile := strings .TrimSpace (cfg .TLSCertFile )
386+ tlsKeyFile := strings .TrimSpace (cfg .TLSKeyFile )
387+ edgeCfg := buildEdgeRuntimeConfigInternal (cfg )
388+ if useTLS && (tlsCertFile == "" || tlsKeyFile == "" ) {
389+ return false , "" , "" , nil , fmt .Errorf ("TLS_ENABLED requires both TLS_CERT_FILE and TLS_KEY_FILE" )
390+ }
391+
392+ if cfg .AgentMode {
393+ return useTLS , tlsCertFile , tlsKeyFile , edgeCfg , nil
394+ }
395+
396+ if err := edge .PrepareManagerMTLSAssets (edgeCfg ); err != nil {
397+ return false , "" , "" , nil , err
398+ }
399+
400+ if edge .NormalizeEdgeMTLSMode (cfg .EdgeMTLSMode ) != edge .EdgeMTLSModeDisabled {
401+ if ! useTLS {
402+ return false , "" , "" , nil , fmt .Errorf ("EDGE_MTLS_MODE requires TLS_ENABLED=true on the manager" )
403+ }
404+ if err := edge .ValidateManagerMTLSConfig (edgeCfg ); err != nil {
405+ return false , "" , "" , nil , err
406+ }
407+ }
408+
409+ return useTLS , tlsCertFile , tlsKeyFile , edgeCfg , nil
410+ }
411+
412+ func configureTunnelServerInternal (appCtx context.Context , cfg * config.Config , router http.Handler , tunnelServer * edge.TunnelServer , listenAddr string ) (http.Handler , * grpc.Server ) {
413+ httpHandler := router
414+ var grpcServer * grpc.Server
415+
416+ if ! cfg .AgentMode && tunnelServer != nil {
417+ grpcServer = grpc .NewServer (tunnelServer .GRPCServerOptions (appCtx )... )
418+ tunnelpb .RegisterTunnelServiceServer (grpcServer , tunnelServer )
419+
420+ httpHandler = http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
421+ if isTunnelGRPCRequestInternal (r ) {
422+ grpcReq := normalizeTunnelGRPCRequestPathInternal (r )
423+ grpcServer .ServeHTTP (w , grpcReq )
424+ return
425+ }
426+ router .ServeHTTP (w , r )
427+ })
428+ slog .InfoContext (appCtx , "Using shared HTTP/gRPC listener for edge tunnel" , "addr" , listenAddr )
429+ }
430+
431+ return httpHandler , grpcServer
432+ }
433+
434+ func configureHTTPProtocolsInternal (useTLS bool , handler http.Handler ) (http.Handler , * http.Protocols ) {
435+ var protocols http.Protocols
436+ protocols .SetHTTP1 (true )
437+ if useTLS {
438+ protocols .SetHTTP2 (true )
439+ return handler , & protocols
440+ }
441+
442+ protocols .SetUnencryptedHTTP2 (true )
443+ return h2c .NewHandler (handler , & http2.Server {}), & protocols
444+ }
445+
446+ func newHTTPServerInternal (listenAddr string , handler http.Handler , protocols * http.Protocols , useTLS bool , edgeCfg * edge.Config ) (* http.Server , error ) {
447+ srv := & http.Server {
448+ Addr : listenAddr ,
449+ Handler : handler ,
450+ Protocols : protocols ,
451+ ReadHeaderTimeout : 5 * time .Second ,
452+ }
453+ if ! useTLS {
454+ return srv , nil
455+ }
456+
457+ tlsConfig , err := edge .BuildManagerServerTLSConfig (edgeCfg )
458+ if err != nil {
459+ return nil , err
460+ }
461+ if tlsConfig != nil {
462+ srv .TLSConfig = tlsConfig
463+ }
464+ return srv , nil
465+ }
466+
467+ func buildEdgeRuntimeConfigInternal (cfg * config.Config ) * edge.Config {
468+ return & edge.Config {
469+ EdgeAgent : cfg .EdgeAgent ,
470+ EdgeTransport : cfg .EdgeTransport ,
471+ EdgeReconnectInterval : cfg .EdgeReconnectInterval ,
472+ EdgeMTLSMode : cfg .EdgeMTLSMode ,
473+ EdgeMTLSAutoGenerate : cfg .EdgeMTLSAutoGenerate ,
474+ EdgeMTLSCAFile : cfg .EdgeMTLSCAFile ,
475+ EdgeMTLSCertFile : cfg .EdgeMTLSCertFile ,
476+ EdgeMTLSKeyFile : cfg .EdgeMTLSKeyFile ,
477+ EdgeMTLSServerName : cfg .EdgeMTLSServerName ,
478+ EdgeMTLSAssetsDir : cfg .EdgeMTLSAssetsDir ,
479+ ManagerApiUrl : cfg .ManagerApiUrl ,
480+ AgentToken : cfg .AgentToken ,
481+ Port : cfg .Port ,
482+ Listen : cfg .Listen ,
483+ }
484+ }
485+
392486func normalizeTunnelGRPCRequestPathInternal (r * http.Request ) * http.Request {
393487 if r == nil {
394488 return nil
0 commit comments