core/autocert: fix filter chain, handshake (#5151)

core/autocert: fix filter chain, handshake (#5150)

* core/autocert: fix filter chain, handshake

* only enable http challenges on port 80

Co-authored-by: Caleb Doxsey <cdoxsey@pomerium.com>
This commit is contained in:
backport-actions-token[bot] 2024-06-26 11:26:53 -06:00 committed by GitHub
parent 4c7c4320af
commit 0733f1ab4b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 76 additions and 8 deletions

View file

@ -150,6 +150,8 @@ func (b *Builder) buildMainListener(
li.Address = buildAddress(cfg.Options.Addr, 443)
li.ListenerFilters = append(li.ListenerFilters, TLSInspectorFilter())
li.FilterChains = append(li.FilterChains, b.buildACMETLSALPNFilterChain())
allCertificates, err := getAllCertificates(cfg)
if err != nil {
return nil, err

View file

@ -46,12 +46,16 @@ type Manager struct {
src config.Source
acmeTemplate certmagic.ACMEIssuer
mu sync.RWMutex
config *config.Config
certmagic *certmagic.Config
acmeMgr atomic.Pointer[certmagic.ACMEIssuer]
srv *http.Server
mu sync.RWMutex
config *config.Config
certmagic *certmagic.Config
acmeMgr atomic.Pointer[certmagic.ACMEIssuer]
srv *http.Server
acmeTLSALPNLock sync.Mutex
acmeTLSALPNPort string
acmeTLSALPNListener net.Listener
acmeTLSALPNConfig *tls.Config
*ocspCache
@ -155,6 +159,7 @@ func (mgr *Manager) getCertMagicConfig(ctx context.Context, cfg *config.Config)
}
}
acmeMgr := certmagic.NewACMEIssuer(mgr.certmagic, mgr.acmeTemplate)
acmeMgr.DisableHTTPChallenge = !shouldEnableHTTPChallenge(cfg)
err = configureCertificateAuthority(acmeMgr, cfg.Options.AutocertOptions)
if err != nil {
return nil, err
@ -342,20 +347,34 @@ func (mgr *Manager) updateServer(ctx context.Context, cfg *config.Config) {
}
func (mgr *Manager) updateACMETLSALPNServer(ctx context.Context, cfg *config.Config) {
addr := net.JoinHostPort("127.0.0.1", cfg.ACMETLSALPNPort)
mgr.acmeTLSALPNLock.Lock()
defer mgr.acmeTLSALPNLock.Unlock()
// store the updated TLS config
mgr.acmeTLSALPNConfig = mgr.certmagic.TLSConfig().Clone()
// if the port hasn't changed, we're done
if mgr.acmeTLSALPNPort == cfg.ACMETLSALPNPort {
return
}
// store the updated port
mgr.acmeTLSALPNPort = cfg.ACMETLSALPNPort
if mgr.acmeTLSALPNListener != nil {
_ = mgr.acmeTLSALPNListener.Close()
mgr.acmeTLSALPNListener = nil
}
tlsConfig := mgr.certmagic.TLSConfig()
ln, err := tls.Listen("tcp", addr, tlsConfig)
// start the listener
addr := net.JoinHostPort("127.0.0.1", cfg.ACMETLSALPNPort)
ln, err := net.Listen("tcp", addr)
if err != nil {
log.Error(ctx).Err(err).Msg("failed to run acme tls alpn server")
return
}
mgr.acmeTLSALPNListener = ln
// accept connections
go func() {
for {
conn, err := ln.Accept()
@ -364,6 +383,20 @@ func (mgr *Manager) updateACMETLSALPNServer(ctx context.Context, cfg *config.Con
} else if err != nil {
continue
}
// initiate the TLS handshake
mgr.acmeTLSALPNLock.Lock()
tlsConfig := mgr.acmeTLSALPNConfig.Clone()
mgr.acmeTLSALPNLock.Unlock()
orig := tlsConfig.GetCertificate
tlsConfig.GetCertificate = func(chi *tls.ClientHelloInfo) (*tls.Certificate, error) {
log.Info(ctx).Str("server-name", chi.ServerName).
Msg("received request for ACME TLS ALPN certificate")
return orig(chi)
}
_ = tls.Server(conn, tlsConfig).HandshakeContext(ctx)
_ = conn.Close()
}
}()
@ -469,3 +502,16 @@ func sourceHostnames(cfg *config.Config) []string {
return h
}
func shouldEnableHTTPChallenge(cfg *config.Config) bool {
if cfg == nil || cfg.Options == nil {
return false
}
_, p, err := net.SplitHostPort(cfg.Options.HTTPRedirectAddr)
if err != nil {
return false
}
return p == "80"
}

View file

@ -630,3 +630,23 @@ func Test_configureTrustedRoots(t *testing.T) {
})
}
}
func TestShouldEnableHTTPChallenge(t *testing.T) {
t.Parallel()
assert.False(t, shouldEnableHTTPChallenge(nil))
assert.False(t, shouldEnableHTTPChallenge(&config.Config{}))
assert.False(t, shouldEnableHTTPChallenge(&config.Config{Options: &config.Options{}}))
assert.False(t, shouldEnableHTTPChallenge(&config.Config{Options: &config.Options{
HTTPRedirectAddr: ":8080",
}}))
assert.False(t, shouldEnableHTTPChallenge(&config.Config{Options: &config.Options{
HTTPRedirectAddr: "127.0.0.1:8080",
}}))
assert.True(t, shouldEnableHTTPChallenge(&config.Config{Options: &config.Options{
HTTPRedirectAddr: ":80",
}}))
assert.True(t, shouldEnableHTTPChallenge(&config.Config{Options: &config.Options{
HTTPRedirectAddr: "127.0.0.1:80",
}}))
}