1
16
17 package writer
18
19 import (
20 "crypto/tls"
21 "crypto/x509"
22 "encoding/pem"
23 "errors"
24 "time"
25
26 "sigs.k8s.io/controller-runtime/pkg/client"
27
28 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/webhook/cert/generator"
29 )
30
31 const (
32
33 CAKeyName = "ca-key.pem"
34
35 CACertName = "ca-cert.pem"
36
37 ServerKeyName = "key.pem"
38
39 ServerCertName = "cert.pem"
40 )
41
42
43 type CertWriter interface {
44
45 EnsureCert(dnsName string) (*generator.Artifacts, bool, error)
46
47
48 Inject(objs ...client.Object) error
49 }
50
51
52
53 func handleCommon(dnsName string, ch certReadWriter) (*generator.Artifacts, bool, error) {
54 if len(dnsName) == 0 {
55 return nil, false, errors.New("dnsName should not be empty")
56 }
57 if ch == nil {
58 return nil, false, errors.New("certReaderWriter should not be nil")
59 }
60
61 certs, changed, err := createIfNotExists(ch)
62 if err != nil {
63 return nil, changed, err
64 }
65
66
67 valid := validCert(certs, dnsName)
68 if !valid {
69 log.Info("cert is invalid or expiring, regenerating a new one")
70 certs, err = ch.overwrite()
71 if err != nil {
72 return nil, false, err
73 }
74 changed = true
75 }
76 return certs, changed, nil
77 }
78
79 func createIfNotExists(ch certReadWriter) (*generator.Artifacts, bool, error) {
80
81 certs, err := ch.read()
82 if isNotFound(err) {
83
84 certs, err = ch.write()
85 switch {
86
87 case isAlreadyExists(err):
88 certs, err = ch.read()
89 return certs, true, err
90 default:
91 return certs, true, err
92 }
93 }
94 return certs, false, err
95 }
96
97
98 type certReadWriter interface {
99
100 read() (*generator.Artifacts, error)
101
102 write() (*generator.Artifacts, error)
103
104 overwrite() (*generator.Artifacts, error)
105 }
106
107
108
109
110 func validCert(certs *generator.Artifacts, dnsName string) bool {
111 if certs == nil {
112 return false
113 }
114
115
116 _, err := tls.X509KeyPair(certs.Cert, certs.Key)
117 if err != nil {
118 return false
119 }
120
121
122 pool := x509.NewCertPool()
123 if !pool.AppendCertsFromPEM(certs.CACert) {
124 return false
125 }
126 block, _ := pem.Decode([]byte(certs.Cert))
127 if block == nil {
128 return false
129 }
130 cert, err := x509.ParseCertificate(block.Bytes)
131 if err != nil {
132 return false
133 }
134 ops := x509.VerifyOptions{
135 DNSName: dnsName,
136 Roots: pool,
137 CurrentTime: time.Now().AddDate(0, 6, 0),
138 }
139 _, err = cert.Verify(ops)
140 if err != nil {
141 return false
142 }
143 return DoesCertificateWorkWithK8sAPIClient(cert)
144 }
145
146
147
148 func DoesCertificateWorkWithK8sAPIClient(cert *x509.Certificate) bool {
149
150
151
152 return len(cert.DNSNames) > 0
153 }
154
View as plain text