agones.dev/agones@v1.53.0/pkg/util/https/server.go (about) 1 // Copyright 2019 Google LLC All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package https 16 17 import ( 18 "context" 19 cryptotls "crypto/tls" 20 "net/http" 21 "sync" 22 "time" 23 24 "agones.dev/agones/pkg/util/fswatch" 25 "agones.dev/agones/pkg/util/runtime" 26 "github.com/pkg/errors" 27 "github.com/sirupsen/logrus" 28 ) 29 30 const ( 31 tlsDir = "/certs/" 32 ) 33 34 // tls is a http server interface to enable easier testing 35 type tls interface { 36 Shutdown(context.Context) error 37 ListenAndServeTLS(certFile, keyFile string) error 38 } 39 40 // certServer holds the Server certificate 41 type certServer struct { 42 certs *cryptotls.Certificate 43 certMu sync.Mutex 44 } 45 46 // Server is a HTTPs server that conforms to the runner interface 47 // we use in /cmd/controller, and has a public Mux that can be updated 48 // has a default 404 handler, to make discovery of k8s services a bit easier. 49 type Server struct { 50 certServer certServer 51 logger *logrus.Entry 52 Mux *http.ServeMux 53 tls tls 54 certFile string 55 keyFile string 56 port string 57 } 58 59 // NewServer returns a Server instance. 60 func NewServer(certFile, keyFile string, port string) *Server { 61 mux := http.NewServeMux() 62 63 wh := &Server{ 64 Mux: mux, 65 certFile: certFile, 66 keyFile: keyFile, 67 port: port, 68 } 69 wh.logger = runtime.NewLoggerWithType(wh) 70 wh.setupServer() 71 wh.Mux.HandleFunc("/", wh.defaultHandler) 72 73 return wh 74 } 75 76 func (s *Server) setupServer() { 77 s.tls = &http.Server{ 78 Addr: ":" + s.port, 79 Handler: s.Mux, 80 TLSConfig: &cryptotls.Config{ 81 GetCertificate: s.getCertificate, 82 }, 83 } 84 85 tlsCert, err := cryptotls.LoadX509KeyPair(tlsDir+"server.crt", tlsDir+"server.key") 86 if err != nil { 87 s.logger.WithError(err).Error("could not load Initial TLS certs; keeping old one") 88 return 89 } 90 91 s.certServer.certMu.Lock() 92 defer s.certServer.certMu.Unlock() 93 s.certServer.certs = &tlsCert 94 } 95 96 // getCertificate returns the current TLS certificate 97 func (s *Server) getCertificate(_ *cryptotls.ClientHelloInfo) (*cryptotls.Certificate, error) { 98 s.certServer.certMu.Lock() 99 defer s.certServer.certMu.Unlock() 100 return s.certServer.certs, nil 101 } 102 103 // WatchForCertificateChanges watches for changes in the certificate files 104 func (s *Server) WatchForCertificateChanges() (func(), error) { 105 106 cancelTLS, err := fswatch.Watch(s.logger, tlsDir, time.Second, func() { 107 // Load the new TLS certificate 108 s.logger.Info("TLS certs changed, reloading") 109 tlsCert, err := cryptotls.LoadX509KeyPair(tlsDir+"server.crt", tlsDir+"server.key") 110 if err != nil { 111 s.logger.WithError(err).Error("could not load TLS certs; keeping old one") 112 return 113 } 114 s.certServer.certMu.Lock() 115 defer s.certServer.certMu.Unlock() 116 s.certServer.certs = &tlsCert 117 s.logger.Info("TLS certs updated") 118 }) 119 if err != nil { 120 s.logger.WithError(err).Fatal("could not create watcher for TLS certs") 121 return nil, err 122 } 123 return cancelTLS, nil 124 } 125 126 // Run runs the webhook server, starting a https listener. 127 // Will close the http server on stop channel close. 128 func (s *Server) Run(ctx context.Context, _ int) error { 129 go func() { 130 <-ctx.Done() 131 _ = s.tls.Shutdown(context.Background()) 132 }() 133 134 s.logger.WithField("server", s).Infof("https server started on port :%s", s.port) 135 136 err := s.tls.ListenAndServeTLS(s.certFile, s.keyFile) 137 if err == http.ErrServerClosed { 138 s.logger.WithError(err).Info("https server closed") 139 return nil 140 } 141 142 return errors.Wrap(err, "Could not listen on :"+s.port) 143 } 144 145 // defaultHandler Handles all the HTTP requests 146 // useful for debugging requests 147 func (s *Server) defaultHandler(w http.ResponseWriter, r *http.Request) { 148 // "/" is the default health check used by APIServers 149 if r.URL.Path == "/" { 150 w.WriteHeader(http.StatusOK) 151 return 152 } 153 154 FourZeroFour(s.logger, w, r) 155 }