Skip to content

Commit

Permalink
refactor(operator): use builder to construct vulnerability scan jobs (a…
Browse files Browse the repository at this point in the history
…quasecurity#770)

Signed-off-by: Daniel Pacak <pacak.daniel@gmail.com>
  • Loading branch information
danielpacak authored Oct 25, 2021
1 parent 7ef9060 commit 0f2c686
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 76 deletions.
13 changes: 13 additions & 0 deletions pkg/kube/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
81 changes: 19 additions & 62 deletions pkg/operator/controller/vulnerabilityreport.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -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)
}
}

Expand Down Expand Up @@ -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) {
Expand All @@ -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)
Expand Down
15 changes: 1 addition & 14 deletions pkg/vulnerabilityreport/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 0f2c686

Please sign in to comment.