CleanUp ACME challenges after issuing and on delete using finalizer

Signed-off-by: James Munnelly <james@munnelly.eu>
This commit is contained in:
James Munnelly 2018-11-28 21:29:24 +00:00
parent 76f2eaff24
commit dd8f98768b
3 changed files with 84 additions and 18 deletions

View File

@ -31,3 +31,7 @@ const (
// Default duration before certificate expiration if Issuer.spec.renewBefore is not set
DefaultRenewBefore = time.Hour * 24 * 30
)
const (
ACMEFinalizer = "finalizer.acme.cert-manager.io"
)

View File

@ -53,8 +53,7 @@ type solver interface {
}
// Sync will process this ACME Challenge.
// It is the core control function for ACME challenges, and handles:
// - TODO
// It is the core control function for ACME challenges.
func (c *Controller) Sync(ctx context.Context, ch *cmapi.Challenge) (err error) {
oldChal := ch
ch = ch.DeepCopy()
@ -67,7 +66,7 @@ func (c *Controller) Sync(ctx context.Context, ch *cmapi.Challenge) (err error)
defer func() {
// TODO: replace with more efficient comparison
if reflect.DeepEqual(oldChal.Status, ch.Status) {
if reflect.DeepEqual(oldChal.Status, ch.Status) && len(oldChal.Finalizers) == len(ch.Finalizers) {
return
}
_, updateErr := c.CMClient.CertmanagerV1alpha1().Challenges(ch.Namespace).Update(ch)
@ -76,12 +75,8 @@ func (c *Controller) Sync(ctx context.Context, ch *cmapi.Challenge) (err error)
}
}()
// if a challenge is in a final state, we bail out early as there is nothing
// left for us to do here.
if acme.IsFinalState(ch.Status.State) {
// we set processing to false now, as this item has finished being processed.
ch.Status.Processing = false
return nil
if ch.DeletionTimestamp != nil {
return c.handleFinalizer(ctx, ch)
}
genericIssuer, err := c.helper.GetGenericIssuer(ch.Spec.IssuerRef, ch.Namespace)
@ -89,6 +84,30 @@ func (c *Controller) Sync(ctx context.Context, ch *cmapi.Challenge) (err error)
return fmt.Errorf("error reading (cluster)issuer %q: %v", ch.Spec.IssuerRef.Name, err)
}
// if a challenge is in a final state, we bail out early as there is nothing
// left for us to do here.
if acme.IsFinalState(ch.Status.State) {
if ch.Status.Presented {
solver, err := c.solverFor(ch.Spec.Type)
if err != nil {
glog.Errorf("Error getting solver for challenge %q (type %q): %v", ch.Name, ch.Spec.Type, err)
return err
}
err = solver.CleanUp(ctx, genericIssuer, ch)
if err != nil {
glog.Errorf("Error cleaning up challenge %q on deletion: %v", ch.Name, err)
return err
}
ch.Status.Presented = false
}
ch.Status.Processing = false
return nil
}
cl, err := c.acmeHelper.ClientForIssuer(genericIssuer)
if err != nil {
return err
@ -153,10 +172,34 @@ func (c *Controller) Sync(ctx context.Context, ch *cmapi.Challenge) (err error)
return err
}
glog.Infof("Cleaning up challenge %s/%s", ch.Namespace, ch.Name)
return nil
}
func (c *Controller) handleFinalizer(ctx context.Context, ch *cmapi.Challenge) error {
genericIssuer, err := c.helper.GetGenericIssuer(ch.Spec.IssuerRef, ch.Namespace)
if err != nil {
return fmt.Errorf("error reading (cluster)issuer %q: %v", ch.Spec.IssuerRef.Name, err)
}
if len(ch.Finalizers) == 0 {
return nil
}
if ch.Finalizers[0] != cmapi.ACMEFinalizer {
glog.V(4).Infof("Waiting to run challenge %q finalization...", ch.Name)
return nil
}
ch.Finalizers = ch.Finalizers[1:]
solver, err := c.solverFor(ch.Spec.Type)
if err != nil {
glog.Errorf("Error getting solver for challenge %q (type %q): %v", ch.Name, ch.Spec.Type, err)
return nil
}
err = solver.CleanUp(ctx, genericIssuer, ch)
if err != nil {
return err
glog.Errorf("Error cleaning up challenge %q on deletion: %v", ch.Name, err)
return nil
}
return nil

View File

@ -100,6 +100,19 @@ func (c *Controller) Sync(ctx context.Context, o *cmapi.Order) (err error) {
// TODO: we should find a way to periodically update the state of the resource
// to reflect the current/actual state in the ACME server.
if acme.IsFinalState(o.Status.State) {
existingChallenges, err := c.listChallengesForOrder(o)
if err != nil {
return err
}
// Cleanup challenge resources once a final state has been reached
for _, ch := range existingChallenges {
err := c.CMClient.CertmanagerV1alpha1().Challenges(ch.Namespace).Delete(ch.Name, nil)
if err != nil {
return err
}
}
return nil
}
@ -162,14 +175,8 @@ func (c *Controller) Sync(ctx context.Context, o *cmapi.Order) (err error) {
return fmt.Errorf("unknown order state %q", o.Status.State)
}
// create a selector that we can use to find all existing Challenges for the order
sel, err := challengeSelectorForOrder(o)
if err != nil {
return err
}
// get the list of exising challenges for this order
existingChallenges, err := c.challengeLister.Challenges(o.Namespace).List(sel)
existingChallenges, err := c.listChallengesForOrder(o)
if err != nil {
return err
}
@ -252,6 +259,17 @@ func (c *Controller) Sync(ctx context.Context, o *cmapi.Order) (err error) {
return nil
}
func (c *Controller) listChallengesForOrder(o *cmapi.Order) ([]*cmapi.Challenge, error) {
// create a selector that we can use to find all existing Challenges for the order
sel, err := challengeSelectorForOrder(o)
if err != nil {
return nil, err
}
// get the list of exising challenges for this order
return c.challengeLister.Challenges(o.Namespace).List(sel)
}
const (
orderNameLabelKey = "acme.cert-manager.io/order-name"
)
@ -393,6 +411,7 @@ func buildChallenge(i int, o *cmapi.Order, chalSpec cmapi.ChallengeSpec) *cmapi.
Namespace: o.Namespace,
Labels: challengeLabelsForOrder(o),
OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(o, orderGvk)},
Finalizers: []string{cmapi.ACMEFinalizer},
},
Spec: chalSpec,
}