Skip to content

Commit

Permalink
cert-rotation: allow specifying multiple target certs in CertRotation…
Browse files Browse the repository at this point in the history
…Controller

Instead of defining several controllers managing the same signer/CA
bundle pair and different target certs the same controller can accept
a list of target certs to create.
  • Loading branch information
vrutkovs committed Jun 26, 2024
1 parent 4bb4238 commit d3c0949
Show file tree
Hide file tree
Showing 2 changed files with 484 additions and 24 deletions.
90 changes: 66 additions & 24 deletions pkg/operator/certrotation/client_cert_rotation_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"time"

operatorv1 "github.com/openshift/api/operator/v1"
"k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/wait"

"github.com/openshift/library-go/pkg/controller/factory"
Expand Down Expand Up @@ -65,9 +67,8 @@ type CertRotationController struct {
RotatedSigningCASecret RotatedSigningCASecret
// CABundleConfigMap maintains a CA bundle config map, by adding new CA certs coming from rotatedSigningCASecret, and by removing expired old ones.
CABundleConfigMap CABundleConfigMap
// RotatedSelfSignedCertKeySecret rotates a key and cert signed by a signing CA and stores it in a secret.
RotatedSelfSignedCertKeySecret RotatedSelfSignedCertKeySecret

// RotatedTargetSecrets contains a list of key and cert signed by a signing CA to rotate.
RotatedTargetSecrets []RotatedSelfSignedCertKeySecret
// Plumbing:
StatusReporter StatusReporter
}
Expand All @@ -81,11 +82,11 @@ func NewCertRotationController(
reporter StatusReporter,
) factory.Controller {
c := &CertRotationController{
Name: name,
RotatedSigningCASecret: rotatedSigningCASecret,
CABundleConfigMap: caBundleConfigMap,
RotatedSelfSignedCertKeySecret: rotatedSelfSignedCertKeySecret,
StatusReporter: reporter,
Name: name,
RotatedSigningCASecret: rotatedSigningCASecret,
CABundleConfigMap: caBundleConfigMap,
RotatedTargetSecrets: []RotatedSelfSignedCertKeySecret{rotatedSelfSignedCertKeySecret},
StatusReporter: reporter,
}
return factory.New().
ResyncEvery(time.Minute).
Expand All @@ -101,6 +102,42 @@ func NewCertRotationController(
ToController("CertRotationController", recorder.WithComponentSuffix("cert-rotation-controller").WithComponentSuffix(name))
}

func NewCertRotationControllerMultipleTargets(
name string,
rotatedSigningCASecret RotatedSigningCASecret,
caBundleConfigMap CABundleConfigMap,
rotatedTargetSecrets []RotatedSelfSignedCertKeySecret,
recorder events.Recorder,
reporter StatusReporter,
) factory.Controller {
informers := sets.New[factory.Informer](
rotatedSigningCASecret.Informer.Informer(),
caBundleConfigMap.Informer.Informer(),
)

for _, target := range rotatedTargetSecrets {
informers = informers.Insert(target.Informer.Informer())
}

c := &CertRotationController{
Name: name,
RotatedSigningCASecret: rotatedSigningCASecret,
CABundleConfigMap: caBundleConfigMap,
RotatedTargetSecrets: rotatedTargetSecrets,
StatusReporter: reporter,
}
return factory.New().
ResyncEvery(time.Minute).
WithSync(c.Sync).
WithInformers(
informers.UnsortedList()...,
).
WithPostStartHooks(
c.targetCertRecheckerPostRunHook,
).
ToController("MultipleTargetCertRotationController", recorder.WithComponentSuffix("cert-rotation-controller").WithComponentSuffix(name))
}

func (c CertRotationController) Sync(ctx context.Context, syncCtx factory.SyncContext) error {
syncErr := c.SyncWorker(ctx)

Expand Down Expand Up @@ -132,30 +169,35 @@ func (c CertRotationController) SyncWorker(ctx context.Context) error {
return err
}

if _, err := c.RotatedSelfSignedCertKeySecret.EnsureTargetCertKeyPair(ctx, signingCertKeyPair, cabundleCerts); err != nil {
return err
var errs []error
for _, secret := range c.RotatedTargetSecrets {
if _, err := secret.EnsureTargetCertKeyPair(ctx, signingCertKeyPair, cabundleCerts); err != nil {
errs = append(errs, err)
}
}
if len(errs) != 0 {
return errors.NewAggregate(errs)
}

return nil
}

func (c CertRotationController) targetCertRecheckerPostRunHook(ctx context.Context, syncCtx factory.SyncContext) error {
// If we have a need to force rechecking the cert, use this channel to do it.
refresher, ok := c.RotatedSelfSignedCertKeySecret.CertCreator.(TargetCertRechecker)
if !ok {
return nil
}
targetRefresh := refresher.RecheckChannel()
go wait.Until(func() {
for {
select {
case <-targetRefresh:
syncCtx.Queue().Add(factory.DefaultQueueKey)
case <-ctx.Done():
return
}
for _, target := range c.RotatedTargetSecrets {
if refresher, ok := target.CertCreator.(TargetCertRechecker); ok {
go wait.Until(func() {
for {
select {
case <-refresher.RecheckChannel():
syncCtx.Queue().Add(factory.DefaultQueueKey)
case <-ctx.Done():
return
}
}
}, time.Minute, ctx.Done())
}
}, time.Minute, ctx.Done())
}

<-ctx.Done()
return nil
Expand Down
Loading

0 comments on commit d3c0949

Please sign in to comment.