diff --git a/pkg/kube/secrets.go b/pkg/kube/secrets.go index ee8944c49..bba59f5a4 100644 --- a/pkg/kube/secrets.go +++ b/pkg/kube/secrets.go @@ -112,6 +112,7 @@ type SecretsReader interface { ListByLocalObjectReferences(ctx context.Context, refs []corev1.LocalObjectReference, ns string) ([]corev1.Secret, error) ListByServiceAccount(ctx context.Context, name string, ns string) ([]corev1.Secret, error) ListImagePullSecretsByPodSpec(ctx context.Context, spec corev1.PodSpec, ns string) ([]corev1.Secret, error) + CredentialsByWorkload(ctx context.Context, workload client.Object) (map[string]docker.Auth, error) } // NewSecretsReader constructs a new SecretsReader which is using the client @@ -169,3 +170,15 @@ func (r *secretsReader) ListImagePullSecretsByPodSpec(ctx context.Context, spec return append(secrets, serviceAccountSecrets...), nil } + +func (r *secretsReader) CredentialsByWorkload(ctx context.Context, workload client.Object) (map[string]docker.Auth, error) { + spec, err := GetPodSpec(workload) + if err != nil { + return nil, fmt.Errorf("getting Pod template: %w", err) + } + imagePullSecrets, err := r.ListImagePullSecretsByPodSpec(ctx, spec, workload.GetNamespace()) + if err != nil { + return nil, err + } + return MapContainerNamesToDockerAuths(GetContainerImagesFromPodSpec(spec), imagePullSecrets) +} diff --git a/pkg/operator/controller/vulnerabilityreport.go b/pkg/operator/controller/vulnerabilityreport.go index 03e3bd4b0..2437346d4 100644 --- a/pkg/operator/controller/vulnerabilityreport.go +++ b/pkg/operator/controller/vulnerabilityreport.go @@ -8,7 +8,6 @@ import ( "reflect" "github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1" - "github.com/aquasecurity/starboard/pkg/docker" "github.com/aquasecurity/starboard/pkg/kube" "github.com/aquasecurity/starboard/pkg/operator/etc" "github.com/aquasecurity/starboard/pkg/starboard" @@ -20,7 +19,6 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/pointer" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" @@ -162,7 +160,7 @@ func (r *VulnerabilityReportReconciler) reconcileWorkload(workloadKind kube.Kind return ctrl.Result{RequeueAfter: r.Config.ScanJobRetryAfter}, nil } - return ctrl.Result{}, r.submitScanJob(ctx, podSpec, workloadObj, containerImages, hash) + return ctrl.Result{}, r.submitScanJob(ctx, workloadObj) } } @@ -206,75 +204,42 @@ func (r *VulnerabilityReportReconciler) hasActiveScanJob(ctx context.Context, ow return false, nil, nil } -func (r *VulnerabilityReportReconciler) submitScanJob(ctx context.Context, spec corev1.PodSpec, owner client.Object, images kube.ContainerImages, hash string) error { - credentials, err := r.getCredentials(ctx, spec, owner.GetNamespace()) +func (r *VulnerabilityReportReconciler) submitScanJob(ctx context.Context, owner client.Object) error { + credentials, err := r.CredentialsByWorkload(ctx, owner) if err != nil { return err } - templateSpec, secrets, err := r.Plugin.GetScanJobSpec(r.PluginContext, spec, credentials) + scanJobTolerations, err := r.GetScanJobTolerations() if err != nil { - return err - } - - scanJobTolerations, err := r.ConfigData.GetScanJobTolerations() - if err != nil { - return err + return fmt.Errorf("getting scan job tolerations: %w", err) } - templateSpec.Tolerations = append(templateSpec.Tolerations, scanJobTolerations...) - scanJobAnnotations, err := r.ConfigData.GetScanJobAnnotations() + scanJobAnnotations, err := r.GetScanJobAnnotations() if err != nil { - return err - } - - containerImagesAsJSON, err := images.AsJSON() - if err != nil { - return err + return fmt.Errorf("getting scan job annotations: %w", err) } - templateSpec.ServiceAccountName = r.Config.ServiceAccount + scanJob, secrets, err := vulnerabilityreport.NewScanJobBuilder(). + WithPlugin(r.Plugin). + WithPluginContext(r.PluginContext). + WithTimeout(r.Config.ScanJobTimeout). + WithObject(owner). + WithTolerations(scanJobTolerations). + WithAnnotations(scanJobAnnotations). + WithCredentials(credentials). + Get() for _, secret := range secrets { - secret.Namespace = r.Config.Namespace err := r.Client.Create(ctx, secret) if err != nil { + if errors.IsAlreadyExists(err) { + return nil + } return fmt.Errorf("creating secret: %w", err) } } - labels := map[string]string{ - starboard.LabelResourceKind: owner.GetObjectKind().GroupVersionKind().Kind, - starboard.LabelResourceName: owner.GetName(), - starboard.LabelResourceNamespace: owner.GetNamespace(), - starboard.LabelResourceSpecHash: hash, - starboard.LabelK8SAppManagedBy: starboard.AppStarboard, - starboard.LabelVulnerabilityReportScanner: "true", - } - - scanJob := &batchv1.Job{ - ObjectMeta: metav1.ObjectMeta{ - Name: vulnerabilityreport.GetScanJobName(owner), - Namespace: r.Config.Namespace, - Labels: labels, - Annotations: map[string]string{ - starboard.AnnotationContainerImages: containerImagesAsJSON, - }, - }, - Spec: batchv1.JobSpec{ - BackoffLimit: pointer.Int32Ptr(0), - Completions: pointer.Int32Ptr(1), - ActiveDeadlineSeconds: kube.GetActiveDeadlineSeconds(r.Config.ScanJobTimeout), - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: labels, - Annotations: scanJobAnnotations, - }, - Spec: templateSpec, - }, - }, - } - err = r.Client.Create(ctx, scanJob) if err != nil { if errors.IsAlreadyExists(err) { @@ -298,14 +263,6 @@ func (r *VulnerabilityReportReconciler) submitScanJob(ctx context.Context, spec return nil } -func (r *VulnerabilityReportReconciler) getCredentials(ctx context.Context, spec corev1.PodSpec, ns string) (map[string]docker.Auth, error) { - imagePullSecrets, err := r.SecretsReader.ListImagePullSecretsByPodSpec(ctx, spec, ns) - if err != nil { - return nil, err - } - return kube.MapContainerNamesToDockerAuths(kube.GetContainerImagesFromPodSpec(spec), imagePullSecrets) -} - func (r *VulnerabilityReportReconciler) reconcileJobs() reconcile.Func { return func(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { log := r.Logger.WithValues("job", req.NamespacedName) diff --git a/pkg/vulnerabilityreport/scanner.go b/pkg/vulnerabilityreport/scanner.go index 1060e80ca..51b9d91de 100644 --- a/pkg/vulnerabilityreport/scanner.go +++ b/pkg/vulnerabilityreport/scanner.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1" - "github.com/aquasecurity/starboard/pkg/docker" "github.com/aquasecurity/starboard/pkg/kube" "github.com/aquasecurity/starboard/pkg/runner" "github.com/aquasecurity/starboard/pkg/starboard" @@ -87,7 +86,7 @@ func (s *Scanner) Scan(ctx context.Context, workload kube.Object) ([]v1alpha1.Vu klog.V(3).Infof("Scanning with options: %+v", s.opts) - credentials, err := s.getCredentials(ctx, owner) + credentials, err := s.secretsReader.CredentialsByWorkload(ctx, owner) if err != nil { return nil, err } @@ -128,18 +127,6 @@ func (s *Scanner) Scan(ctx context.Context, workload kube.Object) ([]v1alpha1.Vu return s.getVulnerabilityReportsByScanJob(ctx, job, owner) } -func (s *Scanner) getCredentials(ctx context.Context, workload client.Object) (map[string]docker.Auth, error) { - spec, err := kube.GetPodSpec(workload) - if err != nil { - return nil, fmt.Errorf("getting Pod template: %w", err) - } - imagePullSecrets, err := s.secretsReader.ListImagePullSecretsByPodSpec(ctx, spec, workload.GetNamespace()) - if err != nil { - return nil, err - } - return kube.MapContainerNamesToDockerAuths(kube.GetContainerImagesFromPodSpec(spec), imagePullSecrets) -} - // TODO To make this method look the same as the one used by the operator we // should resolve the owner based on labels set on the given job instead of // passing owner directly. The goal is for CLI and operator to create jobs