diff --git a/cmd/controller/main.go b/cmd/controller/main.go index fc4e8805a..19fe79ac5 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -49,6 +49,8 @@ func bindControllerFlags(f *controller.Flags, fs *flag.FlagSet) { fs.BoolVar(&f.SkipRecreate, "skip-recreate", false, "if true the controller will skip listening for managed secret changes to recreate them. This helps on limited permission environments.") + fs.BoolVar(&f.LogInfoToStdout, "log-info-stdout", false, "if true the controller will log info to stdout.") + fs.DurationVar(&f.KeyRenewPeriod, "rotate-period", defaultKeyRenewPeriod, "") _ = fs.MarkDeprecated("rotate-period", "please use key-renew-period instead") } diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index cc63af658..b052edf47 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -6,7 +6,6 @@ import ( "encoding/json" "errors" "fmt" - "log" "reflect" "time" @@ -33,6 +32,7 @@ import ( ssscheme "github.com/bitnami-labs/sealed-secrets/pkg/client/clientset/versioned/scheme" ssv1alpha1client "github.com/bitnami-labs/sealed-secrets/pkg/client/clientset/versioned/typed/sealedsecrets/v1alpha1" ssinformer "github.com/bitnami-labs/sealed-secrets/pkg/client/informers/externalversions" + "github.com/bitnami-labs/sealed-secrets/pkg/log" "github.com/bitnami-labs/sealed-secrets/pkg/multidocyaml" ) @@ -81,7 +81,7 @@ func NewController(clientset kubernetes.Interface, ssclientset ssclientset.Inter utilruntime.Must(ssscheme.AddToScheme(scheme.Scheme)) eventBroadcaster := record.NewBroadcaster() - eventBroadcaster.StartLogging(log.Printf) + eventBroadcaster.StartLogging(log.Infof) eventBroadcaster.StartRecordingToSink(&v1.EventSinkImpl{Interface: clientset.CoreV1().Events("")}) recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: "sealed-secrets"}) @@ -124,7 +124,7 @@ func watchSealedSecrets(ssinformer ssinformer.SharedInformerFactory, queue workq if sealedSecretChanged(oldObj, newObj) { queue.Add(key) } else { - log.Printf("update suppressed, no changes in sealed secret spec of %v", key) + log.Infof("update suppressed, no changes in sealed secret spec of %v", key) } } }, @@ -162,20 +162,20 @@ func watchSecrets(sinformer informers.SharedInformerFactory, ssclientset ssclien DeleteFunc: func(obj interface{}) { skey, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) if err != nil { - log.Printf("failed to fetch Secret key: %v", err) + log.Errorf("failed to fetch Secret key: %v", err) return } ns, name, err := cache.SplitMetaNamespaceKey(skey) if err != nil { - log.Printf("failed to get namespace and name from key: %v", err) + log.Errorf("failed to get namespace and name from key: %v", err) return } ssecret, err := ssclientset.BitnamiV1alpha1().SealedSecrets(ns).Get(context.Background(), name, metav1.GetOptions{}) if err != nil { if !k8serrors.IsNotFound(err) { - log.Printf("failed to get SealedSecret: %v", err) + log.Errorf("failed to get SealedSecret: %v", err) } return } @@ -186,7 +186,7 @@ func watchSecrets(sinformer informers.SharedInformerFactory, ssclientset ssclien sskey, err := cache.MetaNamespaceKeyFunc(ssecret) if err != nil { - log.Printf("failed to fetch SealedSecret key: %v", err) + log.Errorf("failed to fetch SealedSecret key: %v", err) return } @@ -241,7 +241,7 @@ func (c *Controller) Run(stopCh <-chan struct{}) { c.runWorker(context.Background()) }, time.Second, stopCh) - log.Printf("Shutting down controller") + log.Errorf("Shutting down controller") } func (c *Controller) runWorker(ctx context.Context) { @@ -262,11 +262,11 @@ func (c *Controller) processNextItem(ctx context.Context) bool { // No error, reset the ratelimit counters c.queue.Forget(key) } else if c.queue.NumRequeues(key) < maxRetries { - log.Printf("Error updating %s, will retry: %v", key, err) + log.Errorf("Error updating %s, will retry: %v", key, err) c.queue.AddRateLimited(key) } else { // err != nil and too many retries - log.Printf("Error updating %s, giving up: %v", key, err) + log.Errorf("Error updating %s, giving up: %v", key, err) c.queue.Forget(key) utilruntime.HandleError(err) } @@ -278,7 +278,7 @@ func (c *Controller) unseal(ctx context.Context, key string) (unsealErr error) { unsealRequestsTotal.Inc() obj, exists, err := c.ssInformer.GetIndexer().GetByKey(key) if err != nil { - log.Printf("Error fetching object with key %s from store: %v", key, err) + log.Errorf("Error fetching object with key %s from store: %v", key, err) unsealErrorsTotal.WithLabelValues("fetch", "").Inc() return err } @@ -289,7 +289,7 @@ func (c *Controller) unseal(ctx context.Context, key string) (unsealErr error) { // TODO: remove this feature flag in a subsequent release. if c.oldGCBehavior { - log.Printf("SealedSecret %s has gone, deleting Secret", key) + log.Infof("SealedSecret %s has gone, deleting Secret", key) ns, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { return err @@ -306,7 +306,7 @@ func (c *Controller) unseal(ctx context.Context, key string) (unsealErr error) { if err != nil { return err } - log.Printf("Updating %s", key) + log.Infof("Updating %s", key) // any exit of this function at this point will cause an update to the status subresource // of the SealedSecret custom resource. The return value of the unseal function is available @@ -315,7 +315,7 @@ func (c *Controller) unseal(ctx context.Context, key string) (unsealErr error) { defer func() { if err := c.updateSealedSecretStatus(ssecret, unsealErr); err != nil { // Non-fatal. Log and continue. - log.Printf("Error updating SealedSecret %s status: %v", key, err) + log.Errorf("Error updating SealedSecret %s status: %v", key, err) unsealErrorsTotal.WithLabelValues("status", ssecret.GetNamespace()).Inc() } else { ObserveCondition(ssecret) @@ -375,7 +375,7 @@ func convertSealedSecret(obj any) (*ssv1alpha1.SealedSecret, error) { } if sealedSecret.APIVersion == "" || sealedSecret.Kind == "" { // https://github.com/operator-framework/operator-sdk/issues/727 - log.Printf("WARNING: Empty API version & kind, filling it...") + log.Errorf("WARNING: Empty API version & kind, filling it...") gv := schema.GroupVersion{Group: ssv1alpha1.GroupName, Version: "v1alpha1"} gvk := gv.WithKind("SealedSecret") sealedSecret.APIVersion = gvk.GroupVersion().String() diff --git a/pkg/controller/keyregistry.go b/pkg/controller/keyregistry.go index aaccb887c..cb56c6c2c 100644 --- a/pkg/controller/keyregistry.go +++ b/pkg/controller/keyregistry.go @@ -6,11 +6,11 @@ import ( "crypto/x509" "encoding/pem" "fmt" - "log" "sync" "time" "github.com/bitnami-labs/sealed-secrets/pkg/crypto" + "github.com/bitnami-labs/sealed-secrets/pkg/log" "k8s.io/client-go/kubernetes" certUtil "k8s.io/client-go/util/cert" ) @@ -61,8 +61,8 @@ func (kr *KeyRegistry) generateKey(ctx context.Context, validFor time.Duration, if err := kr.registerNewKey(generatedName, key, cert, time.Now()); err != nil { return "", err } - log.Printf("New key written to %s/%s\n", kr.namespace, generatedName) - log.Printf("Certificate is \n%s\n", pem.EncodeToMemory(&pem.Block{Type: certUtil.CertificateBlockType, Bytes: cert.Raw})) + log.Infof("New key written to %s/%s\n", kr.namespace, generatedName) + log.Infof("Certificate is \n%s\n", pem.EncodeToMemory(&pem.Block{Type: certUtil.CertificateBlockType, Bytes: cert.Raw})) return generatedName, nil } diff --git a/pkg/controller/main.go b/pkg/controller/main.go index b02d7669d..9e67339be 100644 --- a/pkg/controller/main.go +++ b/pkg/controller/main.go @@ -5,7 +5,6 @@ import ( "crypto/rand" "crypto/x509" "io" - "log" "os" "os/signal" "sort" @@ -26,6 +25,7 @@ import ( "github.com/bitnami-labs/sealed-secrets/pkg/client/clientset/versioned" sealedsecrets "github.com/bitnami-labs/sealed-secrets/pkg/client/clientset/versioned" ssinformers "github.com/bitnami-labs/sealed-secrets/pkg/client/informers/externalversions" + "github.com/bitnami-labs/sealed-secrets/pkg/log" ) var ( @@ -50,6 +50,7 @@ type Flags struct { OldGCBehavior bool UpdateStatus bool SkipRecreate bool + LogInfoToStdout bool } func initKeyPrefix(keyPrefix string) (string, error) { @@ -57,7 +58,7 @@ func initKeyPrefix(keyPrefix string) (string, error) { } func initKeyRegistry(ctx context.Context, client kubernetes.Interface, r io.Reader, namespace, prefix, label string, keysize int) (*KeyRegistry, error) { - log.Printf("Searching for existing private keys") + log.Infof("Searching for existing private keys") secretList, err := client.CoreV1().Secrets(namespace).List(ctx, metav1.ListOptions{ LabelSelector: keySelector.String(), }) @@ -80,12 +81,12 @@ func initKeyRegistry(ctx context.Context, client kubernetes.Interface, r io.Read for _, secret := range items { key, certs, err := readKey(secret) if err != nil { - log.Printf("Error reading key %s: %v", secret.Name, err) + log.Errorf("Error reading key %s: %v", secret.Name, err) } if err := keyRegistry.registerNewKey(secret.Name, key, certs[0], certs[0].NotBefore); err != nil { return nil, err } - log.Printf("----- %s", secret.Name) + log.Infof("----- %s", secret.Name) } return keyRegistry, nil } @@ -120,7 +121,7 @@ func initKeyRenewal(ctx context.Context, registry *KeyRegistry, period, validFor // wrapper function to log error thrown by generateKey function keyGenFunc := func() { if _, err := registry.generateKey(ctx, validFor, cn); err != nil { - log.Printf("Failed to generate new key : %v\n", err) + log.Errorf("Failed to generate new key : %v\n", err) } } if period == 0 { @@ -139,6 +140,10 @@ func initKeyRenewal(ctx context.Context, registry *KeyRegistry, period, validFor func Main(f *Flags, version string) error { registerMetrics(version) + if f.LogInfoToStdout { + log.SetInfoToStdout() + } + config, err := rest.InClusterConfig() if err != nil { return err @@ -186,7 +191,7 @@ func Main(f *Flags, version string) error { namespace := v1.NamespaceAll if !f.NamespaceAll || f.AdditionalNamespaces != "" { namespace = myNamespace() - log.Printf("Starting informer for namespace: %s\n", namespace) + log.Infof("Starting informer for namespace: %s\n", namespace) } var tweakopts func(*metav1.ListOptions) = nil @@ -214,7 +219,7 @@ func Main(f *Flags, version string) error { for _, ns := range addNS { if _, err := clientset.CoreV1().Namespaces().Get(ctx, ns, metav1.GetOptions{}); err != nil { if errors.IsNotFound(err) { - log.Printf("Warning: namespace '%s' doesn't exist\n", ns) + log.Errorf("Warning: namespace '%s' doesn't exist\n", ns) continue } return err @@ -226,7 +231,7 @@ func Main(f *Flags, version string) error { } ctlr.oldGCBehavior = f.OldGCBehavior ctlr.updateStatus = f.UpdateStatus - log.Printf("Starting informer for namespace: %s\n", ns) + log.Infof("Starting informer for namespace: %s\n", ns) go ctlr.Run(stop) } } diff --git a/pkg/controller/server.go b/pkg/controller/server.go index fec44fa96..2d886caaf 100644 --- a/pkg/controller/server.go +++ b/pkg/controller/server.go @@ -4,12 +4,12 @@ import ( "crypto/x509" "encoding/pem" "io" - "log" "net/http" "time" "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/bitnami-labs/sealed-secrets/pkg/log" flag "github.com/spf13/pflag" "github.com/throttled/throttled" "github.com/throttled/throttled/store/memstore" @@ -49,14 +49,14 @@ func httpserver(cp certProvider, sc secretChecker, sr secretRotator, burst int, mux.Handle("/v1/verify", Instrument("/v1/verify", httpRateLimiter.RateLimit(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { content, err := io.ReadAll(r.Body) if err != nil { - log.Printf("Error handling /v1/verify request: %v", err) + log.Errorf("Error handling /v1/verify request: %v", err) w.WriteHeader(http.StatusBadRequest) return } valid, err := sc(content) if err != nil { - log.Printf("Error validating secret: %v", err) + log.Errorf("Error validating secret: %v", err) w.WriteHeader(http.StatusInternalServerError) return } @@ -72,14 +72,14 @@ func httpserver(cp certProvider, sc secretChecker, sr secretRotator, burst int, mux.Handle("/v1/rotate", Instrument("/v1/rotate", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { content, err := io.ReadAll(r.Body) if err != nil { - log.Printf("Error handling /v1/rotate request: %v", err) + log.Errorf("Error handling /v1/rotate request: %v", err) w.WriteHeader(http.StatusBadRequest) return } newSecret, err := sr(content) if err != nil { - log.Printf("Error rotating secret: %v", err) + log.Errorf("Error rotating secret: %v", err) w.WriteHeader(http.StatusInternalServerError) return } @@ -92,7 +92,7 @@ func httpserver(cp certProvider, sc secretChecker, sr secretRotator, burst int, mux.Handle("/v1/cert.pem", Instrument("/v1/cert.pem", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { certs, err := cp() if err != nil { - log.Printf("cannot get certificates: %v", err) + log.Errorf("cannot get certificates: %v", err) http.Error(w, "cannot get certificate", http.StatusInternalServerError) return } @@ -111,10 +111,10 @@ func httpserver(cp certProvider, sc secretChecker, sr secretRotator, burst int, WriteTimeout: *writeTimeout, } - log.Printf("HTTP server serving on %s", server.Addr) + log.Infof("HTTP server serving on %s", server.Addr) go func() { err := server.ListenAndServe() - log.Printf("HTTP server exiting: %v", err) + log.Errorf("HTTP server exiting: %v", err) }() return &server } diff --git a/pkg/log/log.go b/pkg/log/log.go new file mode 100644 index 000000000..032bba35c --- /dev/null +++ b/pkg/log/log.go @@ -0,0 +1,36 @@ +package log + +import ( + "log" + "os" +) + +var ( + infoLogger *log.Logger + errorLogger *log.Logger +) + +func init() { + infoLogger = log.New(os.Stderr, "", 0) + errorLogger = log.New(os.Stderr, "", 0) +} + +func SetInfoToStdout() { + infoLogger.SetOutput(os.Stdout) +} + +func Infof(format string, v ...interface{}) { + infoLogger.Printf(format, v...) +} + +func Errorf(format string, v ...interface{}) { + errorLogger.Printf(format, v...) +} + +func Fatal(v ...any) { + errorLogger.Fatal(v...) +} + +func Panic(v ...any) { + errorLogger.Panic(v...) +}