@@ -34,6 +34,7 @@ import (
3434 "github.com/kagenti/kagenti-extensions/authbridge/authlib/shared"
3535 "github.com/kagenti/kagenti-extensions/authbridge/authlib/spiffe"
3636 authtls "github.com/kagenti/kagenti-extensions/authbridge/authlib/tls"
37+ "github.com/kagenti/kagenti-extensions/authbridge/authlib/tlsbridge"
3738
3839 // Only HTTP listeners are compiled in: no extproc/extauthz
3940 // (no gRPC, no envoy types).
@@ -247,6 +248,49 @@ func main() {
247248 slog .Info ("mTLS disabled (no mtls block in config)" )
248249 }
249250
251+ // TLS bridge: when enabled, the forward proxy terminates agent outbound
252+ // TLS (MITM) so the outbound pipeline sees decrypted HTTPS. Constructed
253+ // here and set on fpSrv below (mirroring fpSrv.SkipHosts / fpSrv.Shared).
254+ // A nil *Engine leaves today's blind-tunnel behavior intact.
255+ var bridge * tlsbridge.Engine
256+ if cfg .TLSBridge != nil && cfg .TLSBridge .Enabled {
257+ var src tlsbridge.CASource
258+ if cfg .TLSBridge .CASource == "file" {
259+ src , err = tlsbridge .NewFileSource (cfg .TLSBridge .CACertPath , cfg .TLSBridge .CAKeyPath )
260+ } else {
261+ src , err = tlsbridge .NewEphemeralSource ()
262+ }
263+ if err != nil {
264+ log .Fatalf ("tls-bridge CA init failed: %v" , err )
265+ }
266+ var extra []byte
267+ if cfg .TLSBridge .UpstreamCABundle != "" {
268+ if extra , err = os .ReadFile (cfg .TLSBridge .UpstreamCABundle ); err != nil {
269+ log .Fatalf ("tls-bridge upstream_ca_bundle read failed: %v" , err )
270+ }
271+ }
272+ up , uerr := tlsbridge .NewUpstreamClient (extra )
273+ if uerr != nil {
274+ log .Fatalf ("tls-bridge upstream client failed: %v" , uerr )
275+ }
276+ minter := tlsbridge .NewMinter (src , tlsbridge.MinterOpts {})
277+ scope := tlsbridge .ScopeExternal
278+ if cfg .TLSBridge .Scope == "all" {
279+ scope = tlsbridge .ScopeAll
280+ }
281+ bridge = & tlsbridge.Engine {
282+ Decision : tlsbridge .NewDecision (tlsbridge.DecisionOpts {
283+ Scope : scope , InternalCIDRs : cfg .TLSBridge .InternalCIDRs , SkipHosts : cfg .TLSBridge .SkipHosts ,
284+ }),
285+ Term : tlsbridge .NewTerminator (minter ),
286+ Skip : tlsbridge .NewSkipSet (),
287+ Upstream : up ,
288+ CAPEM : src .CACertPEM (),
289+ }
290+ tlsbridge .RunTrustSelfCheck (bridge .CAPEM )
291+ slog .Info ("tls-bridge enabled" , "scope" , cfg .TLSBridge .Scope , "ca_source" , cfg .TLSBridge .CASource )
292+ }
293+
250294 // Proxy-sidecar: reverse proxy on the inbound path + forward proxy
251295 // on the outbound path.
252296 rpSrv , err := reverseproxy .NewServer (inboundH , sessions , cfg .Listener .ReverseProxyBackend , rpMTLS )
@@ -266,6 +310,7 @@ func main() {
266310 log .Fatalf ("listener.skip_hosts: %v" , err )
267311 }
268312 fpSrv .SkipHosts = skipHosts
313+ fpSrv .TLSBridge = bridge
269314 sharedStore := shared .New ()
270315 defer sharedStore .Close () // stop the TTL janitor on normal main return
271316 rpSrv .Shared = sharedStore
0 commit comments