...
1 package server
2
3 import (
4 "bytes"
5 "crypto/tls"
6 "crypto/x509"
7 "encoding/pem"
8 "flag"
9 "fmt"
10 "strings"
11 "sync"
12 "time"
13
14 "golang.conradwood.net/apis/certmanager"
15 "golang.conradwood.net/go-easyops/authremote"
16 )
17
18 var (
19 BuiltinCert []byte
20 BuiltinKey []byte
21 BuiltinTLSCert tls.Certificate
22 certmap = &certmapper{}
23 dynamic_certs = flag.Bool("ge_retrieve_missing_https_certificates", true, "if true, retrieve missing https certificates")
24 )
25
26 type certmapper struct {
27 sync.Mutex
28 certmap map[string]*tls.Certificate
29 }
30
31 func (cm *certmapper) ByHostname(hostname string) *tls.Certificate {
32 hm := strings.ToLower(hostname)
33 cm.Lock()
34 if cm.certmap == nil {
35 cm.certmap = make(map[string]*tls.Certificate)
36 }
37 tcert := cm.certmap[hm]
38 if tcert != nil {
39 cm.Unlock()
40 return tcert
41 }
42 cm.Unlock()
43 ctx := authremote.Context()
44 cert, err := certmanager.GetCertManagerClient().GetLocalCertificate(ctx, &certmanager.LocalCertificateRequest{Subject: hm})
45 if err != nil {
46 fmt.Printf("[go-easyops] certs failed to get cert for \"%s\": %s\n", hm, err)
47 return nil
48 }
49
50 cm.Lock()
51 tcert = cm.certmap[hm]
52 if tcert != nil {
53 cm.Unlock()
54 return tcert
55 }
56
57
58 tc, err := tls.X509KeyPair([]byte(cert.PemCertificate), []byte(cert.PemPrivateKey))
59 if err != nil {
60 fmt.Printf("[go-easyops] certs Failed to parse cert %s: %s\n", hm, err)
61 cm.Unlock()
62 return nil
63 }
64
65 block, _ := pem.Decode([]byte(cert.PemCA))
66 if block == nil {
67 fmt.Printf("[go-easyops] certs certificate %s has no CA certificate\n", cert.Host)
68 } else {
69 xcert, xerr := x509.ParseCertificate(block.Bytes)
70 if xerr != nil {
71 fmt.Printf("[go-easyops] certs Cannot parse certificate %s: %s\n", cert.Host, err)
72 cm.Unlock()
73 return nil
74 }
75 now := time.Now()
76 if now.After(xcert.NotAfter) {
77 fmt.Printf("[go-easyops] certs certificate for \"%s\" expired on %v\n", hm, xcert.NotAfter)
78 cm.Unlock()
79 return nil
80 }
81
82 b := &bytes.Buffer{}
83 err = pem.Encode(b, block)
84 if err != nil {
85 cm.Unlock()
86 fmt.Printf("[go-easyops] certs cert for \"%s\" failed to encode: %s\n", hm, err)
87 return nil
88 }
89 tc.Certificate = append(tc.Certificate, block.Bytes)
90 }
91 fmt.Printf("[go-easyops] certs retrieved certificate for host \"%s\"\n", hm)
92 cm.certmap[hm] = &tc
93 cm.Unlock()
94
95 return &tc
96 }
97
98 func getcert(chi *tls.ClientHelloInfo) (*tls.Certificate, error) {
99 hostname := chi.ServerName
100 if hostname == "rfc-client" {
101 return &BuiltinTLSCert, nil
102 }
103 if !*dynamic_certs {
104 fmt.Printf("[go-easyops] certs not retrieving for host \"%s\", because flag -ge_retrieve_missing_https_certificates is false\n", hostname)
105 return &BuiltinTLSCert, nil
106 }
107 cert := certmap.ByHostname(hostname)
108 if cert != nil {
109 return cert, nil
110 }
111 fmt.Printf("[go-easyops] certs No cert for host \"%s\"\n", hostname)
112 return &BuiltinTLSCert, nil
113 }
114
View as plain text