Skip to content

Commit

Permalink
refactor: use builder to construct vulnerability scan jobs (#768)
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Pacak <pacak.daniel@gmail.com>
  • Loading branch information
danielpacak authored Oct 22, 2021
1 parent c1c93d7 commit f4b4678
Show file tree
Hide file tree
Showing 9 changed files with 250 additions and 79 deletions.
2 changes: 1 addition & 1 deletion pkg/configauditreport/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type ScanJobBuilder struct {
annotations map[string]string
}

func NewScanJob() *ScanJobBuilder {
func NewScanJobBuilder() *ScanJobBuilder {
return &ScanJobBuilder{}
}

Expand Down
5 changes: 2 additions & 3 deletions pkg/configauditreport/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func TestScanJobBuilder(t *testing.T) {

t.Run("Should build scan job for resource with simple name", func(t *testing.T) {
g := NewGomegaWithT(t)
job, _, err := configauditreport.NewScanJob().
job, _, err := configauditreport.NewScanJobBuilder().
WithPlugin(&testPlugin{
configHash: "hash-test",
}).
Expand All @@ -173,7 +173,6 @@ func TestScanJobBuilder(t *testing.T) {
}).
Get()
g.Expect(err).ToNot(HaveOccurred())
g.Expect(job).NotTo(BeNil())
g.Expect(job).To(Equal(&batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Name: "scan-configauditreport-fcc9884cb",
Expand Down Expand Up @@ -212,7 +211,7 @@ func TestScanJobBuilder(t *testing.T) {

t.Run("Should build scan job for resource with special name", func(t *testing.T) {
g := NewGomegaWithT(t)
job, _, err := configauditreport.NewScanJob().
job, _, err := configauditreport.NewScanJobBuilder().
WithPlugin(&testPlugin{
configHash: "hash-test",
}).
Expand Down
2 changes: 1 addition & 1 deletion pkg/configauditreport/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (s *Scanner) Scan(ctx context.Context, partial kube.Object) (*ReportBuilder
}

klog.V(3).Infof("Scanning with options: %+v", s.opts)
job, secrets, err := NewScanJob().
job, secrets, err := NewScanJobBuilder().
WithPlugin(s.plugin).
WithPluginContext(s.pluginContext).
WithTimeout(s.opts.ScanJobTimeout).
Expand Down
2 changes: 1 addition & 1 deletion pkg/operator/controller/configauditreport.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func (r *ConfigAuditReportReconciler) reconcileResource(resourceKind kube.Kind)
return ctrl.Result{}, fmt.Errorf("getting scan job annotations: %w", err)
}

job, secrets, err := configauditreport.NewScanJob().
job, secrets, err := configauditreport.NewScanJobBuilder().
WithPlugin(r.Plugin).
WithPluginContext(r.PluginContext).
WithTimeout(r.Config.ScanJobTimeout).
Expand Down
10 changes: 6 additions & 4 deletions pkg/plugin/trivy/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,9 @@ func (p *plugin) GetScanJobSpec(ctx starboard.PluginContext, spec corev1.PodSpec
}
switch mode {
case Standalone:
return p.getPodSpecForStandaloneMode(config, spec, credentials)
return p.getPodSpecForStandaloneMode(ctx, config, spec, credentials)
case ClientServer:
return p.getPodSpecForClientServerMode(config, spec, credentials)
return p.getPodSpecForClientServerMode(ctx, config, spec, credentials)
default:
return corev1.PodSpec{}, nil, fmt.Errorf("unrecognized trivy mode: %v", mode)
}
Expand Down Expand Up @@ -246,7 +246,7 @@ const (
//
// trivy --skip-update --cache-dir /var/lib/trivy \
// --format json <container image>
func (p *plugin) getPodSpecForStandaloneMode(config Config, spec corev1.PodSpec, credentials map[string]docker.Auth) (corev1.PodSpec, []*corev1.Secret, error) {
func (p *plugin) getPodSpecForStandaloneMode(ctx starboard.PluginContext, config Config, spec corev1.PodSpec, credentials map[string]docker.Auth) (corev1.PodSpec, []*corev1.Secret, error) {
var secret *corev1.Secret
var secrets []*corev1.Secret

Expand Down Expand Up @@ -557,6 +557,7 @@ func (p *plugin) getPodSpecForStandaloneMode(config Config, spec corev1.PodSpec,
return corev1.PodSpec{
Affinity: starboard.LinuxNodeAffinity(),
RestartPolicy: corev1.RestartPolicyNever,
ServiceAccountName: ctx.GetServiceAccountName(),
AutomountServiceAccountToken: pointer.BoolPtr(false),
Volumes: volumes,
InitContainers: []corev1.Container{initContainer},
Expand All @@ -572,7 +573,7 @@ func (p *plugin) getPodSpecForStandaloneMode(config Config, spec corev1.PodSpec,
//
// trivy client --remote <server URL> \
// --format json <container image ref>
func (p *plugin) getPodSpecForClientServerMode(config Config, spec corev1.PodSpec, credentials map[string]docker.Auth) (corev1.PodSpec, []*corev1.Secret, error) {
func (p *plugin) getPodSpecForClientServerMode(ctx starboard.PluginContext, config Config, spec corev1.PodSpec, credentials map[string]docker.Auth) (corev1.PodSpec, []*corev1.Secret, error) {
var secret *corev1.Secret
var secrets []*corev1.Secret
var volumeMounts []corev1.VolumeMount
Expand Down Expand Up @@ -824,6 +825,7 @@ func (p *plugin) getPodSpecForClientServerMode(config Config, spec corev1.PodSpe
return corev1.PodSpec{
Affinity: starboard.LinuxNodeAffinity(),
RestartPolicy: corev1.RestartPolicyNever,
ServiceAccountName: ctx.GetServiceAccountName(),
AutomountServiceAccountToken: pointer.BoolPtr(false),
Containers: containers,
Volumes: volumes,
Expand Down
7 changes: 7 additions & 0 deletions pkg/plugin/trivy/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
expectedJobSpec: corev1.PodSpec{
Affinity: starboard.LinuxNodeAffinity(),
RestartPolicy: corev1.RestartPolicyNever,
ServiceAccountName: "starboard-sa",
AutomountServiceAccountToken: pointer.BoolPtr(false),
Volumes: []corev1.Volume{
{
Expand Down Expand Up @@ -679,6 +680,7 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
expectedJobSpec: corev1.PodSpec{
Affinity: starboard.LinuxNodeAffinity(),
RestartPolicy: corev1.RestartPolicyNever,
ServiceAccountName: "starboard-sa",
AutomountServiceAccountToken: pointer.BoolPtr(false),
Volumes: []corev1.Volume{
{
Expand Down Expand Up @@ -934,6 +936,7 @@ CVE-2019-1543`,
expectedJobSpec: corev1.PodSpec{
Affinity: starboard.LinuxNodeAffinity(),
RestartPolicy: corev1.RestartPolicyNever,
ServiceAccountName: "starboard-sa",
AutomountServiceAccountToken: pointer.BoolPtr(false),
Volumes: []corev1.Volume{
{
Expand Down Expand Up @@ -1209,6 +1212,7 @@ CVE-2019-1543`,
expectedJobSpec: corev1.PodSpec{
Affinity: starboard.LinuxNodeAffinity(),
RestartPolicy: corev1.RestartPolicyNever,
ServiceAccountName: "starboard-sa",
AutomountServiceAccountToken: pointer.BoolPtr(false),
Volumes: []corev1.Volume{
{
Expand Down Expand Up @@ -1457,6 +1461,7 @@ CVE-2019-1543`,
expectedJobSpec: corev1.PodSpec{
Affinity: starboard.LinuxNodeAffinity(),
RestartPolicy: corev1.RestartPolicyNever,
ServiceAccountName: "starboard-sa",
AutomountServiceAccountToken: pointer.BoolPtr(false),
Containers: []corev1.Container{
{
Expand Down Expand Up @@ -1635,6 +1640,7 @@ CVE-2019-1543`,
expectedJobSpec: corev1.PodSpec{
Affinity: starboard.LinuxNodeAffinity(),
RestartPolicy: corev1.RestartPolicyNever,
ServiceAccountName: "starboard-sa",
AutomountServiceAccountToken: pointer.BoolPtr(false),
Containers: []corev1.Container{
{
Expand Down Expand Up @@ -1821,6 +1827,7 @@ CVE-2019-1543`,
expectedJobSpec: corev1.PodSpec{
Affinity: starboard.LinuxNodeAffinity(),
RestartPolicy: corev1.RestartPolicyNever,
ServiceAccountName: "starboard-sa",
AutomountServiceAccountToken: pointer.BoolPtr(false),
Volumes: []corev1.Volume{
{
Expand Down
114 changes: 114 additions & 0 deletions pkg/vulnerabilityreport/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,131 @@ package vulnerabilityreport
import (
"fmt"
"strings"
"time"

"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/starboard"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

type ScanJobBuilder struct {
plugin Plugin
pluginContext starboard.PluginContext
timeout time.Duration
object client.Object
credentials map[string]docker.Auth
tolerations []corev1.Toleration
annotations map[string]string
}

func NewScanJobBuilder() *ScanJobBuilder {
return &ScanJobBuilder{}
}

func (s *ScanJobBuilder) WithPlugin(plugin Plugin) *ScanJobBuilder {
s.plugin = plugin
return s
}

func (s *ScanJobBuilder) WithPluginContext(pluginContext starboard.PluginContext) *ScanJobBuilder {
s.pluginContext = pluginContext
return s
}

func (s *ScanJobBuilder) WithTimeout(timeout time.Duration) *ScanJobBuilder {
s.timeout = timeout
return s
}

func (s *ScanJobBuilder) WithObject(object client.Object) *ScanJobBuilder {
s.object = object
return s
}

func (s *ScanJobBuilder) WithTolerations(tolerations []corev1.Toleration) *ScanJobBuilder {
s.tolerations = tolerations
return s
}

func (s *ScanJobBuilder) WithAnnotations(annotations map[string]string) *ScanJobBuilder {
s.annotations = annotations
return s
}

func (s *ScanJobBuilder) WithCredentials(credentials map[string]docker.Auth) *ScanJobBuilder {
s.credentials = credentials
return s
}

func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
spec, err := kube.GetPodSpec(s.object)
if err != nil {
return nil, nil, err
}

templateSpec, secrets, err := s.plugin.GetScanJobSpec(s.pluginContext, spec, s.credentials)
if err != nil {
return nil, nil, err
}
templateSpec.Tolerations = append(templateSpec.Tolerations, s.tolerations...)

containerImagesAsJSON, err := kube.GetContainerImagesFromPodSpec(spec).AsJSON()
if err != nil {
return nil, nil, err
}

podSpecHash := kube.ComputeHash(spec)

labels := map[string]string{
starboard.LabelResourceSpecHash: podSpecHash,
starboard.LabelK8SAppManagedBy: starboard.AppStarboard,
starboard.LabelVulnerabilityReportScanner: s.pluginContext.GetName(),
}

job := &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Name: GetScanJobName(s.object),
Namespace: s.pluginContext.GetNamespace(),
Labels: labels,
Annotations: map[string]string{
starboard.AnnotationContainerImages: containerImagesAsJSON,
},
},
Spec: batchv1.JobSpec{
BackoffLimit: pointer.Int32Ptr(0),
Completions: pointer.Int32Ptr(1),
ActiveDeadlineSeconds: kube.GetActiveDeadlineSeconds(s.timeout),
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
Annotations: s.annotations,
},
Spec: templateSpec,
},
},
}

err = kube.ObjectToObjectMetadata(s.object, &job.ObjectMeta)
if err != nil {
return nil, nil, err
}

err = kube.ObjectToObjectMetadata(s.object, &job.Spec.Template.ObjectMeta)
if err != nil {
return nil, nil, err
}

return job, secrets, nil
}

func GetScanJobName(obj client.Object) string {
return fmt.Sprintf("scan-vulnerabilityreport-%s", kube.ComputeHash(kube.Object{
Kind: kube.Kind(obj.GetObjectKind().GroupVersionKind().Kind),
Expand Down
Loading

0 comments on commit f4b4678

Please sign in to comment.