@@ -4,6 +4,7 @@ package erserver
44import (
55 "context"
66 "crypto/tls"
7+ "errors"
78 "fmt"
89 "log"
910 "net/http"
@@ -27,12 +28,67 @@ import (
2728 "github.com/function61/gokit/taskrunner"
2829)
2930
31+ const (
32+ ConfigDir = "/etc/edgerouter"
33+ LocalDevCertfilePath = "/etc/edgerouter/dev-cert.pem" // used when CertBus not configured
34+ )
35+
36+ type GetCertificateFn func (* tls.ClientHelloInfo ) (* tls.Certificate , error )
37+
3038func Serve (ctx context.Context , logger * log.Logger ) error {
3139 logl := logex .Levels (logger )
3240
3341 metrics := initMetrics ()
3442
35- certBus , err := makeCertBus (ctx , logex .Prefix ("certbus" , logger ))
43+ waitAlreadyDoneFIXMENOTNEEDEDLONG := false
44+
45+ tasksCtx , tasksCancel := context .WithCancel (ctx )
46+ tasks := taskrunner .New (tasksCtx , logger )
47+ defer func () {
48+ // this defer is only needed for early exits to stop certbus sync task. if we exit from happy
49+ // path at bottom of this fn, this is not needed (but does not hurt to run twice)
50+
51+ if waitAlreadyDoneFIXMENOTNEEDEDLONG {
52+ return
53+ }
54+
55+ // this currently has a bug which is fixed when we can update to new gokit
56+ if err := tasks .Wait (); err != nil {
57+ logl .Error .Printf ("taskrunner early-exit Wait(): %v" , err )
58+ }
59+ }()
60+ defer tasksCancel ()
61+
62+ getCertificateFn , err := func () (GetCertificateFn , error ) {
63+ if os .Getenv ("CERTBUS_CLIENT_PRIVKEY" ) != "" {
64+ certBus , err := makeCertBus (ctx , logex .Prefix ("certbus" , logger ))
65+ if err != nil {
66+ return nil , err
67+ }
68+
69+ tasks .Start ("certbus sync" , func (ctx context.Context ) error { return certBus .Synchronizer (ctx ) })
70+
71+ return certBus .GetCertificateAdapter (), nil
72+ } else {
73+ logl .Info .Printf ("CertBus not configured - assuming local dev-server & using %s" , LocalDevCertfilePath )
74+
75+ // this is expected to be configured with mkcert or similar
76+ keyPair , err := tls .LoadX509KeyPair (LocalDevCertfilePath , LocalDevCertfilePath )
77+ if err != nil {
78+ if errors .Is (err , os .ErrNotExist ) {
79+ return nil , fmt .Errorf (
80+ "certificate not found - run '$ %s setup-devcerts' first: %w" ,
81+ os .Args [0 ],
82+ err )
83+ } else {
84+ return nil , err
85+ }
86+ }
87+
88+ // we're assuming the user only needs one hostname or that it's a wildcard certificate
89+ return alwaysReturnSameCertificate (& keyPair ), nil
90+ }
91+ }()
3692 if err != nil {
3793 return err
3894 }
@@ -148,7 +204,6 @@ func Serve(ctx context.Context, logger *log.Logger) error {
148204
149205 configUpdated := make (chan * frontendMatchers , 1 )
150206
151- tasks := taskrunner .New (ctx , logger )
152207 tasks .Start ("listener :443" , func (ctx context.Context ) error {
153208 srv := & http.Server {
154209 Addr : ":443" ,
@@ -160,7 +215,7 @@ func Serve(ctx context.Context, logger *log.Logger) error {
160215 //nolint:gosec // rationale above
161216 TLSConfig : & tls.Config {
162217 // MinVersion: ... // purposefully unset to follow Go stdlib MinVersion
163- GetCertificate : certBus . GetCertificateAdapter () ,
218+ GetCertificate : getCertificateFn ,
164219 },
165220 Handler : serveRequestWithMetricsCapture ,
166221 }
@@ -177,8 +232,6 @@ func Serve(ctx context.Context, logger *log.Logger) error {
177232 return cancelableServer (ctx , srv , srv .ListenAndServe )
178233 })
179234
180- tasks .Start ("certbus sync" , func (ctx context.Context ) error { return certBus .Synchronizer (ctx ) })
181-
182235 tasks .Start ("configsyncscheduler" , func (ctx context.Context ) error {
183236 return scheduledSync (
184237 ctx ,
@@ -192,6 +245,7 @@ func Serve(ctx context.Context, logger *log.Logger) error {
192245 for {
193246 select {
194247 case err := <- tasks .Done ():
248+ waitAlreadyDoneFIXMENOTNEEDEDLONG = true
195249 return err
196250 case config := <- configUpdated :
197251 currentConfig .Store (config )
@@ -303,6 +357,12 @@ func makeCertBus(ctx context.Context, logger *log.Logger) (*certbus.App, error)
303357 return certBus , nil
304358}
305359
360+ func alwaysReturnSameCertificate (keyPair * tls.Certificate ) GetCertificateFn {
361+ return func (* tls.ClientHelloInfo ) (* tls.Certificate , error ) {
362+ return keyPair , nil
363+ }
364+ }
365+
306366type atomicConfig struct {
307367 atomic.Value // stores *frontendMatchers
308368}
0 commit comments