Skip to content

Commit

Permalink
refactor: kubebench package (#329)
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Pacak <pacak.daniel@gmail.com>
  • Loading branch information
danielpacak committed Jan 11, 2021
1 parent ad07435 commit 69e885c
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 127 deletions.
3 changes: 2 additions & 1 deletion itest/starboard/starboard_cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,8 @@ var _ = Describe("Starboard CLI", func() {
It("should run kube-bench", func() {
err := cmd.Run(versionInfo, []string{
"starboard",
"kube-bench",
"generate",
"ciskubebenchreports",
"-v", starboardCLILogLevel,
}, GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred())
Expand Down
13 changes: 5 additions & 8 deletions pkg/cmd/scan_ciskubebench.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@ import (
"fmt"
"sync"

"github.com/aquasecurity/starboard/pkg/starboard"

corev1 "k8s.io/api/core/v1"

apis "github.com/aquasecurity/starboard/pkg/generated/clientset/versioned"
"github.com/aquasecurity/starboard/pkg/generated/clientset/versioned"
"github.com/aquasecurity/starboard/pkg/kubebench"
"github.com/aquasecurity/starboard/pkg/kubebench/crd"
"github.com/aquasecurity/starboard/pkg/starboard"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/kubernetes"
Expand Down Expand Up @@ -50,7 +47,7 @@ func ScanKubeBenchReports(cf *genericclioptions.ConfigFlags) func(cmd *cobra.Com
if err != nil {
return err
}
starboardClientset, err := apis.NewForConfig(kubernetesConfig)
starboardClientset, err := versioned.NewForConfig(kubernetesConfig)
if err != nil {
return err
}
Expand All @@ -65,7 +62,7 @@ func ScanKubeBenchReports(cf *genericclioptions.ConfigFlags) func(cmd *cobra.Com

scheme := starboard.NewScheme()
scanner := kubebench.NewScanner(scheme, kubernetesClientset, config, opts)
writer := crd.NewReadWriter(scheme, starboardClientset)
writer := kubebench.NewReadWriter(scheme, starboardClientset)

var wg sync.WaitGroup

Expand Down
72 changes: 0 additions & 72 deletions pkg/kubebench/crd/writer.go

This file was deleted.

2 changes: 2 additions & 0 deletions pkg/kubebench/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// This package provides primitives for working with CIS Kubernetes benchmarks.
package kubebench
33 changes: 9 additions & 24 deletions pkg/kubebench/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,60 +56,45 @@ func NewScanner(
}
}

func (s *Scanner) Scan(ctx context.Context, node corev1.Node) (report v1alpha1.CISKubeBenchOutput, err error) {
func (s *Scanner) Scan(ctx context.Context, node corev1.Node) (v1alpha1.CISKubeBenchOutput, error) {
// 1. Prepare descriptor for the Kubernetes Job which will run kube-bench
job, err := s.prepareKubeBenchJob(node)
if err != nil {
return report, err
return v1alpha1.CISKubeBenchOutput{}, err
}

// 2. Run the prepared Job and wait for its completion or failure
err = runner.New().Run(ctx, kube.NewRunnableJob(s.scheme, s.clientset, job))
if err != nil {
err = fmt.Errorf("running kube-bench job: %w", err)
return
return v1alpha1.CISKubeBenchOutput{}, fmt.Errorf("running kube-bench job: %w", err)
}

defer func() {
if !s.opts.DeleteScanJob {
klog.V(3).Infof("Skipping scan job deletion: %s/%s", job.Namespace, job.Name)
return
}
// 6. Delete the kube-bench Job
// 5. Delete the kube-bench Job
klog.V(3).Infof("Deleting job: %s/%s", job.Namespace, job.Name)
background := metav1.DeletePropagationBackground
_ = s.clientset.BatchV1().Jobs(job.Namespace).Delete(ctx, job.Name, metav1.DeleteOptions{
PropagationPolicy: &background,
})
}()

// 3. Get the Pod controlled by the kube-bench Job
kubeBenchPod, err := s.pods.GetPodByJob(ctx, job)
if err != nil {
err = fmt.Errorf("getting kube-bench pod: %w", err)
return
}

// 4. Get kube-bench JSON output from the kube-bench Pod
// 3. Get kube-bench JSON output from the kube-bench Pod
klog.V(3).Infof("Getting logs for %s container in job: %s/%s", kubeBenchContainerName,
job.Namespace, job.Name)
logsReader, err := s.pods.GetPodLogs(ctx, kubeBenchPod, kubeBenchContainerName)
logsReader, err := s.pods.GetContainerLogsByJob(ctx, job, kubeBenchContainerName)
if err != nil {
err = fmt.Errorf("getting logs: %w", err)
return
return v1alpha1.CISKubeBenchOutput{}, fmt.Errorf("getting logs: %w", err)
}
defer func() {
_ = logsReader.Close()
}()

// 5. Parse the CISBenchmarkReport from the logs Reader
report, err = s.converter.Convert(s.config, logsReader)
if err != nil {
err = fmt.Errorf("parsing CIS benchmark report: %w", err)
return
}

return
// 4. Parse the CISBenchmarkReport from the logs Reader
return s.converter.Convert(s.config, logsReader)
}

func (s *Scanner) prepareKubeBenchJob(node corev1.Node) (*batchv1.Job, error) {
Expand Down
66 changes: 61 additions & 5 deletions pkg/kubebench/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,77 @@ package kubebench
import (
"context"

"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
"github.com/aquasecurity/starboard/pkg/generated/clientset/versioned"
"github.com/aquasecurity/starboard/pkg/kube"

starboard "github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
core "k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

type Writer interface {
Write(ctx context.Context, report starboard.CISKubeBenchOutput, node *core.Node) error
Write(ctx context.Context, report v1alpha1.CISKubeBenchOutput, node *corev1.Node) error
}

type Reader interface {
Read(ctx context.Context, node kube.Object) (starboard.CISKubeBenchOutput, error)
Read(ctx context.Context, node kube.Object) (v1alpha1.CISKubeBenchOutput, error)
}

type ReadWriter interface {
Writer
Reader
}

type rw struct {
scheme *runtime.Scheme
clientset versioned.Interface
}

func NewReadWriter(scheme *runtime.Scheme, clientset versioned.Interface) ReadWriter {
return &rw{
scheme: scheme,
clientset: clientset,
}
}

func (w *rw) Write(ctx context.Context, report v1alpha1.CISKubeBenchOutput, node *corev1.Node) error {
reportExisting, err := w.clientset.AquasecurityV1alpha1().CISKubeBenchReports().Get(ctx, node.Name, metav1.GetOptions{})
if err != nil && errors.IsNotFound(err) {
klog.V(3).Infof("Creating CISKubeBenchReport for %s node", node.Name)
report := &v1alpha1.CISKubeBenchReport{
ObjectMeta: metav1.ObjectMeta{
Name: node.Name,
Labels: map[string]string{
kube.LabelResourceKind: string(kube.KindNode),
kube.LabelResourceName: node.Name,
},
},
Report: report,
}
err = controllerutil.SetOwnerReference(node, report, w.scheme)
if err != nil {
return err
}
_, err = w.clientset.AquasecurityV1alpha1().CISKubeBenchReports().Create(ctx, report, metav1.CreateOptions{})
return err
}
if err != nil {
return err
}
klog.V(3).Infof("Updating existing CISKubeBenchReport for %s node", node.Name)
reportCopied := reportExisting.DeepCopy()
reportCopied.Report = report
_, err = w.clientset.AquasecurityV1alpha1().CISKubeBenchReports().Update(ctx, reportCopied, metav1.UpdateOptions{})
return err
}

func (w *rw) Read(ctx context.Context, node kube.Object) (v1alpha1.CISKubeBenchOutput, error) {
report, err := w.clientset.AquasecurityV1alpha1().CISKubeBenchReports().Get(ctx, node.Name, metav1.GetOptions{})
if err != nil {
return v1alpha1.CISKubeBenchOutput{}, err
}
return report.Report, nil
}
27 changes: 12 additions & 15 deletions pkg/kubebench/crd/writer_test.go → pkg/kubebench/writer_test.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
package crd_test
package kubebench_test

import (
"context"
"testing"

"github.com/aquasecurity/starboard/pkg/starboard"

"k8s.io/apimachinery/pkg/labels"

"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
starboardClientset "github.com/aquasecurity/starboard/pkg/generated/clientset/versioned"
starboardClientsetFake "github.com/aquasecurity/starboard/pkg/generated/clientset/versioned/fake"
"github.com/aquasecurity/starboard/pkg/generated/clientset/versioned"
"github.com/aquasecurity/starboard/pkg/generated/clientset/versioned/fake"
"github.com/aquasecurity/starboard/pkg/kube"
"github.com/aquasecurity/starboard/pkg/kubebench/crd"
"github.com/aquasecurity/starboard/pkg/kubebench"
"github.com/aquasecurity/starboard/pkg/starboard"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gstruct"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

func TestReadWriter(t *testing.T) {
Expand All @@ -45,14 +42,14 @@ var _ = Describe("ReadWriter", func() {

var (
objects []runtime.Object
clientset starboardClientset.Interface
rw *crd.ReadWriter
clientset versioned.Interface
rw kubebench.ReadWriter
)

BeforeEach(func() {
objects = []runtime.Object{}
clientset = starboardClientsetFake.NewSimpleClientset(objects...)
rw = crd.NewReadWriter(starboard.NewScheme(), clientset)
clientset = fake.NewSimpleClientset(objects...)
rw = kubebench.NewReadWriter(starboard.NewScheme(), clientset)
})

Describe("Writing report", func() {
Expand Down
3 changes: 1 addition & 2 deletions pkg/vulnerabilityreport/doc.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
// Package vulnerabilityreport provides primitives for working with vulnerability
// scanners.
// This package provides primitives for working with vulnerability scanners.
package vulnerabilityreport

0 comments on commit 69e885c

Please sign in to comment.