Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to disable KeyRotation #659

Merged
merged 2 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/encryptionkeyrotation.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,29 @@ itself by adding the `csiaddons.openshift.io/state: "unmanaged"` annotation.
CSI Addons will not perform any further modifications on the `EncryptionKeyRotationCronJob` with the `unmanaged` state.

To have a custom schedule the user can then modify the `schedule` field of the `EncryptionKeyRotationCronJob` spec.

## Disabling Key Rotation

### Disabling Key Rotation for a Specific PersistentVolumeClaim

To disable key rotation for a specific PersistentVolumeClaim (PVC), edit the `EncryptionKeyRotationCronJob` custom resource (CR) associated with that PVC. Follow these steps:

1. **Identify the `EncryptionKeyRotationCronJob` CR**: Run the following command to retrieve the name of the `EncryptionKeyRotationCronJob` CR associated with the PVC:

```bash
kubectl get encryptionkeyrotationcronjob -o jsonpath='{range .items[?(@.spec.jobTemplate.spec.target.persistentVolumeClaim=="<PVC_NAME>")]}{.metadata.name}{"\n"}{end}'
```

Replace `<PVC_NAME>` with the name of your PVC.

2. **Edit the `EncryptionKeyRotationCronJob` CR**: Use the following settings in the CR to disable key rotation for this specific PVC:
- Update the `csiaddons.openshift.io/state` annotation from `"managed"` to `"unmanaged"`.
- Add `suspend: true` under the `spec` field.

These changes will disable key rotation for the specified PVC.

### Disabling Key Rotation for All PersistentVolumeClaims in a StorageClass

To disable key rotation for all PVCs in a particular StorageClass, annotate the StorageClass with `keyrotation.csiaddons.openshift.io/enable: "false"`.

This action will disable key rotation across all PVCs in that StorageClass and remove any existing `EncryptionKeyRotationCronJob` CRs for PVCs within it.
99 changes: 97 additions & 2 deletions internal/controller/csiaddons/persistentvolumeclaim_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ var (
rsCronJobNameAnnotation = "reclaimspace." + csiaddonsv1alpha1.GroupVersion.Group + "/cronjob"
rsCSIAddonsDriverAnnotation = "reclaimspace." + csiaddonsv1alpha1.GroupVersion.Group + "/drivers"

krEnableAnnotation = "keyrotation." + csiaddonsv1alpha1.GroupVersion.Group + "/enable"
krcJobScheduleTimeAnnotation = "keyrotation." + csiaddonsv1alpha1.GroupVersion.Group + "/schedule"
krcJobNameAnnotation = "keyrotation." + csiaddonsv1alpha1.GroupVersion.Group + "/cronjob"
krCSIAddonsDriverAnnotation = "keyrotation." + csiaddonsv1alpha1.GroupVersion.Group + "/drivers"
Expand Down Expand Up @@ -296,6 +297,7 @@ func (r *PersistentVolumeClaimReconciler) storageClassEventHandler() handler.Eve
annotationsToWatch := []string{
rsCronJobScheduleTimeAnnotation,
krcJobScheduleTimeAnnotation,
krEnableAnnotation,
}

var requests []reconcile.Request
Expand Down Expand Up @@ -370,8 +372,8 @@ func (r *PersistentVolumeClaimReconciler) SetupWithManager(mgr ctrl.Manager, ctr
return err
}

pvcPred := createAnnotationPredicate(rsCronJobScheduleTimeAnnotation, krcJobScheduleTimeAnnotation)
scPred := createAnnotationPredicate(rsCronJobScheduleTimeAnnotation, krcJobScheduleTimeAnnotation)
pvcPred := createAnnotationPredicate(rsCronJobScheduleTimeAnnotation, krcJobScheduleTimeAnnotation, krEnableAnnotation)
scPred := createAnnotationPredicate(rsCronJobScheduleTimeAnnotation, krcJobScheduleTimeAnnotation, krEnableAnnotation)

return ctrl.NewControllerManagedBy(mgr).
For(&corev1.PersistentVolumeClaim{}).
Expand Down Expand Up @@ -754,6 +756,25 @@ func (r *PersistentVolumeClaimReconciler) processKeyRotation(
}
}

disabled, err := r.checkDisabledByAnnotation(ctx, logger, pvc, krEnableAnnotation)
if err != nil {
return err
}

if disabled {
if krcJob != nil {
err = r.Delete(ctx, krcJob)
if client.IgnoreNotFound(err) != nil {
errMsg := "failed to delete EncryptionKeyRotationCronJob"
logger.Error(err, errMsg)
return fmt.Errorf("%w: %s", err, errMsg)
}
}

logger.Info("EncryptionKeyRotationCronJob is disabled by annotation, exiting reconcile")
return nil
}

// Determine schedule
sched, err := r.determineScheduleAndRequeue(ctx, logger, pvc, pv.Spec.CSI.Driver, krcJobScheduleTimeAnnotation)
if errors.Is(err, ErrScheduleNotFound) {
Expand Down Expand Up @@ -976,3 +997,77 @@ func (r *PersistentVolumeClaimReconciler) getScheduleFromPVC(

return ""
}

// checkAnnotationForValue checks if the given object has the specified annotation
// with the expected value.
func checkAnnotationForValue(obj metav1.Object, key, expected string) bool {
if val, ok := obj.GetAnnotations()[key]; ok && val == expected {
return true
}
return false
}

// hasValidStorageClassName checks if the provided PersistentVolumeClaim has a non-empty StorageClassName.
func hasValidStorageClassName(pvc *corev1.PersistentVolumeClaim) bool {
return pvc.Spec.StorageClassName != nil && len(*pvc.Spec.StorageClassName) > 0
}

// checkDisabledByAnnotation checks if the given object has an annotation
// that disables the functionality represented by the provided annotationKey.
func (r *PersistentVolumeClaimReconciler) checkDisabledByAnnotation(
ctx context.Context,
logger *logr.Logger,
pvc *corev1.PersistentVolumeClaim,
annotationKey string) (bool, error) {
isDisabledOnSC := func() (bool, error) {
// Not an error, static PVs
if !hasValidStorageClassName(pvc) {
return false, nil
}

storageClassName := *pvc.Spec.StorageClassName
storageClass := &storagev1.StorageClass{}

err := r.Client.Get(ctx, client.ObjectKey{Name: storageClassName}, storageClass)
if err != nil {
logger.Error(err, "Failed to get StorageClass", "StorageClass", storageClassName)
return false, err
}

return checkAnnotationForValue(storageClass, annotationKey, "false"), nil
}

if r.SchedulePrecedence == util.ScheduleSCOnly {
disabled, err := isDisabledOnSC()
if err != nil {
return false, err
}

return disabled, nil
}

// Else, we follow the regular precedence
// Check on PVC
if checkAnnotationForValue(pvc, annotationKey, "false") {
return true, nil
}

// Check on Namespace
ns := &corev1.Namespace{}
err := r.Client.Get(ctx, types.NamespacedName{Name: pvc.Namespace}, ns)
if err != nil {
logger.Error(err, "Failed to get Namespace", "Namespace", pvc.Namespace)
return false, err
}
if checkAnnotationForValue(ns, annotationKey, "false") {
return true, nil
}

// Check on SC
black-dragon74 marked this conversation as resolved.
Show resolved Hide resolved
disabled, err := isDisabledOnSC()
if err != nil {
return false, err
}

return disabled, nil
}
Loading