Use more secure TLS settings for the HTTP server

This commit is contained in:
Matthew Penner 2020-08-04 17:19:04 -06:00
parent 0a612a71d9
commit 9ec323350e

View File

@ -6,6 +6,7 @@ import (
"github.com/NYTimes/logrotate" "github.com/NYTimes/logrotate"
"github.com/apex/log/handlers/multi" "github.com/apex/log/handlers/multi"
"github.com/gammazero/workerpool" "github.com/gammazero/workerpool"
"golang.org/x/crypto/acme"
"net/http" "net/http"
"os" "os"
"path" "path"
@ -132,14 +133,15 @@ func rootCmdRun(*cobra.Command, []string) {
config.SetDebugViaFlag(debug) config.SetDebugViaFlag(debug)
if err := c.System.ConfigureDirectories(); err != nil { if err := c.System.ConfigureDirectories(); err != nil {
log.Fatal("failed to configure system directories for pterodactyl") log.WithError(err).Fatal("failed to configure system directories for pterodactyl")
panic(err) os.Exit(1)
return
} }
log.WithField("username", c.System.Username).Info("checking for pterodactyl system user") log.WithField("username", c.System.Username).Info("checking for pterodactyl system user")
if su, err := c.EnsurePterodactylUser(); err != nil { if su, err := c.EnsurePterodactylUser(); err != nil {
log.Error("failed to create pterodactyl system user") log.WithError(err).Error("failed to create pterodactyl system user")
panic(err) os.Exit(1)
return return
} else { } else {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
@ -217,15 +219,19 @@ func rootCmdRun(*cobra.Command, []string) {
// Addresses potentially invalid data in the stored file that can cause Wings to lose // Addresses potentially invalid data in the stored file that can cause Wings to lose
// track of what the actual server state is. // track of what the actual server state is.
s.SetState(server.ProcessOfflineState) _ = s.SetState(server.ProcessOfflineState)
}) })
} }
// Wait until all of the servers are ready to go before we fire up the HTTP server. // Wait until all of the servers are ready to go before we fire up the SFTP and HTTP servers.
pool.StopWait() pool.StopWait()
// Initalize SFTP. // Initialize the SFTP server.
sftp.Initialize(c) if err := sftp.Initialize(c); err != nil {
log.WithError(err).Error("failed to initialize the sftp server")
os.Exit(1)
return
}
// Ensure the archive directory exists. // Ensure the archive directory exists.
if err := os.MkdirAll(c.System.ArchiveDirectory, 0755); err != nil { if err := os.MkdirAll(c.System.ArchiveDirectory, 0755); err != nil {
@ -244,9 +250,46 @@ func rootCmdRun(*cobra.Command, []string) {
"host_port": c.Api.Port, "host_port": c.Api.Port,
}).Info("configuring internal webserver") }).Info("configuring internal webserver")
// Configure the router.
r := router.Configure() r := router.Configure()
addr := fmt.Sprintf("%s:%d", c.Api.Host, c.Api.Port)
s := &http.Server{
Addr: fmt.Sprintf("%s:%d", c.Api.Host, c.Api.Port),
Handler: r,
TLSConfig: &tls.Config{
NextProtos: []string{
"h2", // enable HTTP/2
"http/1.1",
},
// https://blog.cloudflare.com/exposing-go-on-the-internet
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
},
PreferServerCipherSuites: true,
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS13,
CurvePreferences: []tls.CurveID{
tls.X25519,
tls.CurveP256,
},
// END https://blog.cloudflare.com/exposing-go-on-the-internet
},
}
// Check if the server should run with TLS but using autocert.
if useAutomaticTls && len(tlsHostname) > 0 { if useAutomaticTls && len(tlsHostname) > 0 {
m := autocert.Manager{ m := autocert.Manager{
Prompt: autocert.AcceptTOS, Prompt: autocert.AcceptTOS,
@ -255,29 +298,44 @@ func rootCmdRun(*cobra.Command, []string) {
} }
log.WithField("hostname", tlsHostname). log.WithField("hostname", tlsHostname).
Info("webserver is now listening with auto-TLS enabled; certifcates will be automatically generated by Let's Encrypt") Info("webserver is now listening with auto-TLS enabled; certificates will be automatically generated by Let's Encrypt")
// We don't use the autotls runner here since we need to specify a port other than 443 // Hook autocert into the main http server.
// to be using for SSL connections for Wings. s.TLSConfig.GetCertificate = m.GetCertificate
s := &http.Server{Addr: addr, TLSConfig: m.TLSConfig(), Handler: r} s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, acme.ALPNProto) // enable tls-alpn ACME challenges
go http.ListenAndServe(":http", m.HTTPHandler(nil)) // Start the autocert server.
go func() {
if err := http.ListenAndServe(":http", m.HTTPHandler(nil)); err != nil {
log.WithError(err).Error("failed to serve autocert http server")
}
}()
// Start the main http server with TLS using autocert.
if err := s.ListenAndServeTLS("", ""); err != nil { if err := s.ListenAndServeTLS("", ""); err != nil {
log.WithFields(log.Fields{"auto_tls": true, "tls_hostname": tlsHostname, "error": err}). log.WithFields(log.Fields{"auto_tls": true, "tls_hostname": tlsHostname, "error": err}).
Fatal("failed to configure HTTP server using auto-tls") Fatal("failed to configure HTTP server using auto-tls")
os.Exit(1) os.Exit(1)
} }
} else if c.Api.Ssl.Enabled {
if err := r.RunTLS(addr, c.Api.Ssl.CertificateFile, c.Api.Ssl.KeyFile); err != nil { return
}
// Check if main http server should run with TLS.
if c.Api.Ssl.Enabled {
if err := s.ListenAndServeTLS(c.Api.Ssl.CertificateFile, c.Api.Ssl.KeyFile); err != nil {
log.WithFields(log.Fields{"auto_tls": false, "error": err}).Fatal("failed to configure HTTPS server") log.WithFields(log.Fields{"auto_tls": false, "error": err}).Fatal("failed to configure HTTPS server")
os.Exit(1) os.Exit(1)
} }
} else { return
if err := r.Run(addr); err != nil { }
// Run the main http server without TLS.
s.TLSConfig = nil
if err := s.ListenAndServe(); err != nil {
log.WithField("error", err).Fatal("failed to configure HTTP server") log.WithField("error", err).Fatal("failed to configure HTTP server")
os.Exit(1) os.Exit(1)
} }
}
} }
// Execute calls cobra to handle cli commands // Execute calls cobra to handle cli commands