@@ -14,20 +14,21 @@ See the License for the specific language governing permissions and
14
14
limitations under the License.
15
15
*/
16
16
17
- package certwriter
17
+ package writer
18
18
19
19
import (
20
20
"bytes"
21
+ "crypto/tls"
22
+ "errors"
21
23
"fmt"
24
+ "log"
22
25
"net/url"
23
26
24
27
admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
25
28
apierrors "k8s.io/apimachinery/pkg/api/errors"
26
29
"k8s.io/apimachinery/pkg/runtime"
27
-
28
- "crypto/tls"
29
-
30
- "sigs.k8s.io/controller-runtime/pkg/admission/certgenerator"
30
+ "sigs.k8s.io/controller-runtime/pkg/admission/cert/generator"
31
+ "sigs.k8s.io/controller-runtime/pkg/client"
31
32
)
32
33
33
34
const (
@@ -41,31 +42,60 @@ const (
41
42
42
43
// CertWriter provides method to handle webhooks.
43
44
type CertWriter interface {
44
- // EnsureCert ensures that the webhooks it manages have the right certificates.
45
- EnsureCert () error
45
+ // EnsureCert ensures that the webhooks have proper certificates.
46
+ EnsureCerts (runtime.Object ) error
47
+ }
48
+
49
+ // Options are options for configuring a CertWriter.
50
+ type Options struct {
51
+ Client client.Client
52
+ CertGenerator generator.CertGenerator
53
+ }
54
+
55
+ // NewCertWriter builds a new CertWriter using the provided options.
56
+ // By default, it builds a MultiCertWriter that is composed of a SecretCertWriter and a FSCertWriter.
57
+ func NewCertWriter (ops Options ) (CertWriter , error ) {
58
+ if ops .CertGenerator == nil {
59
+ ops .CertGenerator = & generator.SelfSignedCertGenerator {}
60
+ }
61
+ if ops .Client == nil {
62
+ // TODO: default the client if possible
63
+ return nil , errors .New ("Options.Client is required" )
64
+ }
65
+ s := & SecretCertWriter {
66
+ Client : ops .Client ,
67
+ CertGenerator : ops .CertGenerator ,
68
+ }
69
+ //f := &FSCertWriter{
70
+ // CertGenerator: ops.CertGenerator,
71
+ //}
72
+ return & MultiCertWriter {
73
+ CertWriters : []CertWriter {
74
+ s ,
75
+ //f,
76
+ },
77
+ }, nil
46
78
}
47
79
80
+ // handleCommon ensures the given webhook has a proper certificate.
81
+ // It uses the given certReadWriter to read and (or) write the certificate.
48
82
func handleCommon (webhook * admissionregistrationv1beta1.Webhook , ch certReadWriter ) error {
49
- webhookName := webhook .Name
50
- certs , err := ch .read (webhookName )
51
- if apierrors .IsNotFound (err ) {
52
- certs , err = ch .write (webhookName )
53
- switch {
54
- case apierrors .IsAlreadyExists (err ):
55
- certs , err = ch .read (webhookName )
56
- if err != nil {
57
- return err
58
- }
59
- case err != nil :
60
- return err
61
- }
62
- } else if err != nil {
83
+ if webhook == nil {
84
+ return nil
85
+ }
86
+ if ch == nil {
87
+ return errors .New ("certReaderWriter should not be nil" )
88
+ }
89
+
90
+ certs , err := createIfNotExists (webhook .Name , ch )
91
+ if err != nil {
63
92
return err
64
93
}
65
94
66
95
// Recreate the cert if it's invalid.
67
96
if ! validCert (certs ) {
68
- certs , err = ch .overwrite (webhookName )
97
+ log .Printf ("cert is invalid or expiring, regenerating a new one" )
98
+ certs , err = ch .overwrite (webhook .Name )
69
99
if err != nil {
70
100
return err
71
101
}
@@ -80,17 +110,39 @@ func handleCommon(webhook *admissionregistrationv1beta1.Webhook, ch certReadWrit
80
110
return nil
81
111
}
82
112
83
- // certReadWriter provides methods for handling certificates for webhook.
113
+ func createIfNotExists (webhookName string , ch certReadWriter ) (* generator.Artifacts , error ) {
114
+ // Try to read first
115
+ certs , err := ch .read (webhookName )
116
+ if apierrors .IsNotFound (err ) {
117
+ // Create if not exists
118
+ certs , err = ch .write (webhookName )
119
+ switch {
120
+ // This may happen if there is another racer.
121
+ case apierrors .IsAlreadyExists (err ):
122
+ certs , err = ch .read (webhookName )
123
+ if err != nil {
124
+ return certs , err
125
+ }
126
+ case err != nil :
127
+ return certs , err
128
+ }
129
+ } else if err != nil {
130
+ return certs , err
131
+ }
132
+ return certs , nil
133
+ }
134
+
135
+ // certReadWriter provides methods for reading and writing certificates.
84
136
type certReadWriter interface {
85
137
// read reads a wehbook name and returns the certs for it.
86
- read (webhookName string ) (* certgenerator. CertArtifacts , error )
138
+ read (webhookName string ) (* generator. Artifacts , error )
87
139
// write writes the certs and return the certs it wrote.
88
- write (webhookName string ) (* certgenerator. CertArtifacts , error )
140
+ write (webhookName string ) (* generator. Artifacts , error )
89
141
// overwrite overwrites the existing certs and return the certs it wrote.
90
- overwrite (webhookName string ) (* certgenerator. CertArtifacts , error )
142
+ overwrite (webhookName string ) (* generator. Artifacts , error )
91
143
}
92
144
93
- func validCert (certs * certgenerator. CertArtifacts ) bool {
145
+ func validCert (certs * generator. Artifacts ) bool {
94
146
// TODO:
95
147
// 1) validate the key and the cert are valid pair e.g. call crypto/tls.X509KeyPair()
96
148
// 2) validate the cert with the CA cert
@@ -118,19 +170,18 @@ func getWebhooksFromObject(obj runtime.Object) ([]admissionregistrationv1beta1.W
118
170
}
119
171
}
120
172
121
- func webhookClientConfigToCommonName (config * admissionregistrationv1beta1.WebhookClientConfig ) (string , error ) {
173
+ func dnsNameForWebhook (config * admissionregistrationv1beta1.WebhookClientConfig ) (string , error ) {
122
174
if config .Service != nil && config .URL != nil {
123
175
return "" , fmt .Errorf ("service and URL can't be set at the same time in a webhook: %v" , config )
124
176
}
125
177
if config .Service == nil && config .URL == nil {
126
178
return "" , fmt .Errorf ("one of service and URL need to be set in a webhook: %v" , config )
127
179
}
128
180
if config .Service != nil {
129
- return certgenerator .ServiceToCommonName (config .Service .Namespace , config .Service .Name ), nil
181
+ return generator .ServiceToCommonName (config .Service .Namespace , config .Service .Name ), nil
130
182
}
131
- if config .URL != nil {
132
- u , err := url .Parse (* config .URL )
133
- return u .Host , err
134
- }
135
- return "" , nil
183
+ // config.URL != nil
184
+ u , err := url .Parse (* config .URL )
185
+ return u .Host , err
186
+
136
187
}
0 commit comments