Merge branch '15583-no-count'
[arvados.git] / services / keepstore / server.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package main
6
7 import (
8         "crypto/tls"
9         "net"
10         "net/http"
11         "os"
12         "os/signal"
13         "syscall"
14 )
15
16 type server struct {
17         http.Server
18
19         // channel (size=1) with the current keypair
20         currentCert chan *tls.Certificate
21 }
22
23 func (srv *server) Serve(l net.Listener) error {
24         if theConfig.TLSCertificateFile == "" && theConfig.TLSKeyFile == "" {
25                 return srv.Server.Serve(l)
26         }
27         // https://blog.gopheracademy.com/advent-2016/exposing-go-on-the-internet/
28         srv.TLSConfig = &tls.Config{
29                 GetCertificate:           srv.getCertificate,
30                 PreferServerCipherSuites: true,
31                 CurvePreferences: []tls.CurveID{
32                         tls.CurveP256,
33                         tls.X25519,
34                 },
35                 MinVersion: tls.VersionTLS12,
36                 CipherSuites: []uint16{
37                         tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
38                         tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
39                         tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
40                         tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
41                         tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
42                         tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
43                 },
44         }
45         srv.currentCert = make(chan *tls.Certificate, 1)
46         go srv.refreshCertificate(theConfig.TLSCertificateFile, theConfig.TLSKeyFile)
47         return srv.Server.ServeTLS(l, "", "")
48 }
49
50 func (srv *server) refreshCertificate(certfile, keyfile string) {
51         cert, err := tls.LoadX509KeyPair(certfile, keyfile)
52         if err != nil {
53                 log.WithError(err).Fatal("error loading X509 key pair")
54         }
55         srv.currentCert <- &cert
56
57         reload := make(chan os.Signal, 1)
58         signal.Notify(reload, syscall.SIGHUP)
59         for range reload {
60                 cert, err := tls.LoadX509KeyPair(certfile, keyfile)
61                 if err != nil {
62                         log.WithError(err).Warn("error loading X509 key pair")
63                         continue
64                 }
65                 // Throw away old cert and start using new one
66                 <-srv.currentCert
67                 srv.currentCert <- &cert
68         }
69 }
70
71 func (srv *server) getCertificate(*tls.ClientHelloInfo) (*tls.Certificate, error) {
72         if srv.currentCert == nil {
73                 panic("srv.currentCert not initialized")
74         }
75         cert := <-srv.currentCert
76         srv.currentCert <- cert
77         return cert, nil
78 }