Skip to content
Open
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
23 changes: 16 additions & 7 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"flag"
"os"
"strings"
"time"

"google.golang.org/grpc"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -53,6 +54,8 @@ var (
providerVolumePath = flag.String("provider-volume", "/provider", "Volume path for provider.")
maxCallRecvMsgSize = flag.Int("max-call-recv-msg-size", 1024*1024*4, "maximum size in bytes of gRPC response from plugins")
versionInfo = flag.Bool("version", false, "Print the version and exit")
enableSecretRotation = flag.Bool("enable-secret-rotation", false, "Enable secret rotation feature [alpha]")
rotationPollInterval = flag.Duration("rotation-poll-interval", 2*time.Minute, "Secret rotation poll interval duration")
)

func init() {
Expand Down Expand Up @@ -116,14 +119,20 @@ func runMain() error {
audiences = []string{}
}

var reconcilerRotationPollInterval time.Duration
if *enableSecretRotation {
reconcilerRotationPollInterval = *rotationPollInterval
}

if err = (&controller.SecretSyncReconciler{
Clientset: kubeClient,
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
TokenClient: tokenClient,
ProviderClients: providerClients,
Audiences: audiences,
EventRecorder: record.NewBroadcaster().NewRecorder(scheme, corev1.EventSource{Component: "secret-sync-controller"}),
Clientset: kubeClient,
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
TokenClient: tokenClient,
ProviderClients: providerClients,
Audiences: audiences,
EventRecorder: record.NewBroadcaster().NewRecorder(scheme, corev1.EventSource{Component: "secret-sync-controller"}),
RotationPollInterval: reconcilerRotationPollInterval,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "SecretSync")
return err
Expand Down
57 changes: 34 additions & 23 deletions internal/controller/secretsync_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,13 @@ type AllClientBuilder interface {
// SecretSyncReconciler reconciles a SecretSync object
type SecretSyncReconciler struct {
client.Client
Audiences []string
Clientset kubernetes.Interface
Scheme *runtime.Scheme
TokenClient *k8s.TokenClient
ProviderClients AllClientBuilder
EventRecorder record.EventRecorder
Audiences []string
Clientset kubernetes.Interface
Scheme *runtime.Scheme
TokenClient *k8s.TokenClient
ProviderClients AllClientBuilder
EventRecorder record.EventRecorder
RotationPollInterval time.Duration
}

//+kubebuilder:rbac:groups=secret-sync.x-k8s.io,resources=secretsyncs,verbs=get;list;watch
Expand All @@ -106,15 +107,25 @@ type SecretSyncReconciler struct {
//+kubebuilder:rbac:groups="",resources=events,verbs=create;patch
//+kubebuilder:rbac:groups=secrets-store.csi.x-k8s.io,resources=secretproviderclasses,verbs=get;list;watch

func (r *SecretSyncReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
func (r *SecretSyncReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) {
logger := log.FromContext(ctx)
logger.Info("Reconciling SecretSync", "namespace", req.NamespacedName.String())

result = ctrl.Result{}

defer func() {
// Update the result
if r.RotationPollInterval > 0 {
logger.Info("re-enqueuing secret for next rotation", "NameSpacedName", req.NamespacedName, "RequeueAfter", r.RotationPollInterval)
result = ctrl.Result{RequeueAfter: r.RotationPollInterval}
}
}()

// get the secret sync object
ss := &secretsyncv1alpha1.SecretSync{}
if err := r.Get(ctx, req.NamespacedName, ss); err != nil {
if err = r.Get(ctx, req.NamespacedName, ss); err != nil {
logger.Error(err, "unable to fetch SecretSync")
return ctrl.Result{}, err
return result, err
}

// update status conditions
Expand All @@ -132,12 +143,12 @@ func (r *SecretSyncReconciler) Reconcile(ctx context.Context, req ctrl.Request)
if err := secretutil.ValidateSecretObject(secretName, secretObj); err != nil {
logger.Error(err, "failed to validate secret object", "secretName", secretName)
r.updateStatusConditions(ctx, ss, ConditionTypeUnknown, conditionType, ConditionReasonUserInputValidationFailed, true)
return ctrl.Result{}, err
return result, err
}

labels, annotations, err := r.prepareLabelsAndAnnotations(ctx, secretObj, ss, conditionType)
if err != nil {
return ctrl.Result{}, err
return result, err
}

// get the service account token
Expand All @@ -152,15 +163,15 @@ func (r *SecretSyncReconciler) Reconcile(ctx context.Context, req ctrl.Request)

r.updateStatusConditions(ctx, ss, ConditionTypeUnknown, conditionType, conditionReason, true)

return ctrl.Result{}, err
return result, err
}

// get the secret provider class object
spc := &secretsstorecsiv1.SecretProviderClass{}
if err := r.Get(ctx, client.ObjectKey{Name: ss.Spec.SecretProviderClassName, Namespace: req.Namespace}, spc); err != nil {
logger.Error(err, "failed to get secret provider class", "name", ss.Spec.SecretProviderClassName)
r.updateStatusConditions(ctx, ss, ConditionTypeUnknown, conditionType, ConditionReasonControllerSpcError, true)
return ctrl.Result{}, err
return result, err
}

// this is to mimic the parameters sent from CSI driver to the provider
Expand All @@ -182,15 +193,15 @@ func (r *SecretSyncReconciler) Reconcile(ctx context.Context, req ctrl.Request)
if err != nil {
logger.Error(err, "failed to marshal parameters")
r.updateStatusConditions(ctx, ss, ConditionTypeUnknown, conditionType, ConditionReasonControllerInternalError, true)
return ctrl.Result{}, err
return result, err
}

providerName := string(spc.Spec.Provider)
providerClient, err := r.ProviderClients.Get(ctx, providerName)
if err != nil {
logger.Error(err, "failed to get provider client", "provider", providerName)
r.updateStatusConditions(ctx, ss, ConditionTypeUnknown, conditionType, ConditionReasonControllerSpcError, true)
return ctrl.Result{}, err
return result, err
}

secretRefData := make(map[string]string)
Expand All @@ -199,7 +210,7 @@ func (r *SecretSyncReconciler) Reconcile(ctx context.Context, req ctrl.Request)
if err != nil {
logger.Error(err, "failed to marshal secret")
r.updateStatusConditions(ctx, ss, ConditionTypeUnknown, conditionType, ConditionReasonControllerInternalError, true)
return ctrl.Result{}, err
return result, err
}

oldObjectVersions := make(map[string]string)
Expand All @@ -208,22 +219,22 @@ func (r *SecretSyncReconciler) Reconcile(ctx context.Context, req ctrl.Request)
if err != nil {
logger.Error(err, "failed to get secrets from provider", "provider", providerName)
r.updateStatusConditions(ctx, ss, ConditionTypeUnknown, conditionType, ConditionReasonFailedProviderError, true)
return ctrl.Result{}, err
return result, err
}

secretType := secretutil.GetSecretType(strings.TrimSpace(secretObj.Type))
var datamap map[string][]byte
if datamap, err = secretutil.GetSecretData(secretObj.Data, secretType, files); err != nil {
logger.Error(err, "failed to get secret data", "secretName", secretName)
r.updateStatusConditions(ctx, ss, ConditionTypeUnknown, conditionType, ConditionReasonUserInputValidationFailed, true)
return ctrl.Result{}, err
return result, err
}

// Compute the hash of the secret
syncHash, err := r.computeSecretDataObjectHash(datamap, spc, ss)
if err != nil {
logger.Error(err, "failed to compute secret data object hash", "secretName", secretName)
return ctrl.Result{}, err
return result, err
}

// Check if the hash has changed.
Expand All @@ -240,7 +251,7 @@ func (r *SecretSyncReconciler) Reconcile(ctx context.Context, req ctrl.Request)

if len(failedCondition.Type) == 0 && !hashChanged {
r.updateStatusConditions(ctx, ss, ConditionTypeUnknown, conditionType, ConditionReasonUpdateNoValueChangeSucceeded, true)
return ctrl.Result{}, nil
return result, nil
}

if conditionType == ConditionTypeCreate {
Expand Down Expand Up @@ -280,7 +291,7 @@ func (r *SecretSyncReconciler) Reconcile(ctx context.Context, req ctrl.Request)
r.updateStatusConditions(ctx, ss, ConditionTypeUnknown, conditionType, ConditionReasonSecretPatchFailedUnknownError, true)
}

return ctrl.Result{}, err
return result, err
}

// No errors found, remove the failed conditions.
Expand All @@ -293,11 +304,11 @@ func (r *SecretSyncReconciler) Reconcile(ctx context.Context, req ctrl.Request)
// Update the status.
err = r.Client.Status().Update(ctx, ss)
if err != nil {
return ctrl.Result{}, err
return result, err
}

logger.V(4).Info("Done... updated status", "syncHash", syncHash, "lastSuccessfulSyncTime", ss.Status.LastSuccessfulSyncTime)
return ctrl.Result{}, nil
return result, nil
}

func (r *SecretSyncReconciler) prepareLabelsAndAnnotations(
Expand Down