Implementing Capsule certificate validation (#44)

This commit is contained in:
Dario Tranchitella
2020-08-07 16:19:23 +02:00
committed by GitHub
parent ef51e6dee0
commit 1767bcee12
3 changed files with 76 additions and 43 deletions

View File

@@ -20,6 +20,7 @@ import (
"bytes"
"context"
"errors"
"sync"
"time"
"github.com/go-logr/logr"
@@ -49,6 +50,50 @@ func (r *CaReconciler) SetupWithManager(mgr ctrl.Manager) error {
Complete(r)
}
func (r CaReconciler) UpdateValidatingWebhookConfiguration(wg *sync.WaitGroup, ch chan error, caBundle []byte) {
defer wg.Done()
var err error
ch <- retry.RetryOnConflict(retry.DefaultBackoff, func() error {
vw := &v1.ValidatingWebhookConfiguration{}
err = r.Get(context.TODO(), types.NamespacedName{Name: "capsule-validating-webhook-configuration"}, vw)
if err != nil {
r.Log.Error(err, "cannot retrieve ValidatingWebhookConfiguration")
return err
}
for i, w := range vw.Webhooks {
// Updating CABundle only in case of an internal service reference
if w.ClientConfig.Service != nil {
vw.Webhooks[i].ClientConfig.CABundle = caBundle
}
}
return r.Update(context.TODO(), vw, &client.UpdateOptions{})
})
}
func (r CaReconciler) UpdateMutatingWebhookConfiguration(wg *sync.WaitGroup, ch chan error, caBundle []byte) {
defer wg.Done()
var err error
ch <- retry.RetryOnConflict(retry.DefaultBackoff, func() error {
mw := &v1.MutatingWebhookConfiguration{}
err = r.Get(context.TODO(), types.NamespacedName{Name: "capsule-mutating-webhook-configuration"}, mw)
if err != nil {
r.Log.Error(err, "cannot retrieve MutatingWebhookConfiguration")
return err
}
for i, w := range mw.Webhooks {
// Updating CABundle only in case of an internal service reference
if w.ClientConfig.Service != nil {
mw.Webhooks[i].ClientConfig.CABundle = caBundle
}
}
return r.Update(context.TODO(), mw, &client.UpdateOptions{})
})
}
func (r CaReconciler) Reconcile(request ctrl.Request) (ctrl.Result, error) {
var err error
@@ -93,48 +138,21 @@ func (r CaReconciler) Reconcile(request ctrl.Request) (ctrl.Result, error) {
certSecretKey: crt.Bytes(),
privateKeySecretKey: key.Bytes(),
}
// Updating ValidatingWebhookConfiguration CA bundle
err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
vw := &v1.ValidatingWebhookConfiguration{}
err = r.Get(context.TODO(), types.NamespacedName{Name: "capsule-validating-webhook-configuration"}, vw)
wg := &sync.WaitGroup{}
wg.Add(2)
ch := make(chan error, 2)
go r.UpdateMutatingWebhookConfiguration(wg, ch, crt.Bytes())
go r.UpdateValidatingWebhookConfiguration(wg, ch, crt.Bytes())
wg.Wait()
close(ch)
for err = range ch {
if err != nil {
r.Log.Error(err, "cannot retrieve ValidatingWebhookConfiguration")
return err
return reconcile.Result{}, err
}
for i, w := range vw.Webhooks {
// Updating CABundle only in case of an internal service reference
if w.ClientConfig.Service != nil {
vw.Webhooks[i].ClientConfig.CABundle = instance.Data[certSecretKey]
}
}
err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
return r.Update(context.TODO(), vw, &client.UpdateOptions{})
})
if err != nil {
r.Log.Error(err, "cannot update MutatingWebhookConfiguration webhooks CA bundle")
return err
}
return r.Update(context.TODO(), vw, &client.UpdateOptions{})
})
// Updating MutatingWebhookConfiguration CA bundle
err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
mw := &v1.MutatingWebhookConfiguration{}
err = r.Get(context.TODO(), types.NamespacedName{Name: "capsule-mutating-webhook-configuration"}, mw)
if err != nil {
r.Log.Error(err, "cannot retrieve MutatingWebhookConfiguration")
return err
}
for i, w := range mw.Webhooks {
// Updating CABundle only in case of an internal service reference
if w.ClientConfig.Service != nil {
mw.Webhooks[i].ClientConfig.CABundle = instance.Data[certSecretKey]
}
}
return r.Update(context.TODO(), mw, &client.UpdateOptions{})
})
if err != nil {
r.Log.Error(err, "cannot update MutatingWebhookConfiguration webhooks CA bundle")
return reconcile.Result{}, err
}
}

View File

@@ -72,6 +72,7 @@ func (r TlsReconciler) Reconcile(request ctrl.Request) (ctrl.Result, error) {
for _, key := range []string{certSecretKey, privateKeySecretKey} {
if _, ok := instance.Data[key]; !ok {
shouldCreate = true
break
}
}
@@ -99,9 +100,11 @@ func (r TlsReconciler) Reconcile(request ctrl.Request) (ctrl.Result, error) {
return reconcile.Result{}, err
}
rq = time.Duration(c.NotAfter.Unix()-time.Now().Unix()) * time.Second
if time.Now().After(c.NotAfter) {
r.Log.Info("Capsule TLS is expired, cleaning to obtain a new one")
rq = time.Until(c.NotAfter)
err = ca.ValidateCert(c)
if err != nil {
r.Log.Info("Capsule TLS is expired or invalid, cleaning to obtain a new one")
instance.Data = map[string][]byte{}
}
}

View File

@@ -32,6 +32,7 @@ type Ca interface {
CaCertificatePem() (b *bytes.Buffer, err error)
CaPrivateKeyPem() (b *bytes.Buffer, err error)
ExpiresIn(now time.Time) (time.Duration, error)
ValidateCert(certificate *x509.Certificate) error
}
type CapsuleCa struct {
@@ -39,6 +40,17 @@ type CapsuleCa struct {
privateKey *rsa.PrivateKey
}
func (c CapsuleCa) ValidateCert(certificate *x509.Certificate) (err error) {
pool := x509.NewCertPool()
pool.AddCert(c.ca)
_, err = certificate.Verify(x509.VerifyOptions{
Roots: pool,
CurrentTime: time.Time{},
})
return
}
func (c CapsuleCa) isAlreadyValid(now time.Time) bool {
return now.After(c.ca.NotBefore)
}