Skip to content

Commit

Permalink
feat: Deleting a ConfigAuditReport should trigger rescan (#428)
Browse files Browse the repository at this point in the history
Resolves: #415

Signed-off-by: Daniel Pacak <pacak.daniel@gmail.com>
  • Loading branch information
danielpacak committed Mar 12, 2021
1 parent 30b95b2 commit 004dba6
Show file tree
Hide file tree
Showing 14 changed files with 258 additions and 143 deletions.
99 changes: 69 additions & 30 deletions itest/starboard-operator/starboard_operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"time"

"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
"github.com/aquasecurity/starboard/pkg/kube"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
Expand All @@ -13,6 +14,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
)

const (
Expand All @@ -26,7 +29,43 @@ var _ = Describe("Starboard Operator", func() {
deploymentName = "wordpress"
)

Describe("When a new Deployment is created", func() {
Describe("When unmanaged Pod is created", func() {

ctx := context.Background()
var pod *corev1.Pod

BeforeEach(func() {
pod = &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "unmanaged-nginx",
Namespace: corev1.NamespaceDefault,
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "nginx",
Image: "nginx:1.16",
},
},
},
}
err := kubeClient.Create(ctx, pod)
Expect(err).ToNot(HaveOccurred())
})

It("Should create VulnerabilityReport and ConfigAuditReport", func() {
Eventually(HasConfigAuditReportOwnedBy(pod), assertionTimeout).Should(BeTrue())
Eventually(HasVulnerabilityReportOwnedBy(pod), assertionTimeout).Should(BeTrue())
})

AfterEach(func() {
err := kubeClient.Delete(ctx, pod)
Expect(err).ToNot(HaveOccurred())
})

})

Describe("When Deployment is created", func() {

ctx := context.Background()

Expand Down Expand Up @@ -66,20 +105,13 @@ var _ = Describe("Starboard Operator", func() {
Eventually(HasActiveReplicaSet(namespaceName, deploymentName), assertionTimeout).Should(BeTrue())
})

It("Should create VulnerabilityReport", func() {
rs, err := GetActiveReplicaSetForDeployment(namespaceName, deploymentName)
Expect(err).ToNot(HaveOccurred())
Expect(rs).ToNot(BeNil())

Eventually(HasVulnerabilityReportOwnedBy(rs), assertionTimeout).Should(BeTrue())
})

It("Should create ConfigAuditReport", func() {
It("Should create VulnerabilityReport and ConfigAuditReport", func() {
rs, err := GetActiveReplicaSetForDeployment(namespaceName, deploymentName)
Expect(err).ToNot(HaveOccurred())
Expect(rs).ToNot(BeNil())

Eventually(HasConfigAuditReportOwnedBy(rs), assertionTimeout).Should(BeTrue())
Eventually(HasVulnerabilityReportOwnedBy(rs), assertionTimeout).Should(BeTrue())
})

AfterEach(func() {
Expand Down Expand Up @@ -114,37 +146,44 @@ func HasActiveReplicaSet(namespace, name string) func() bool {
}
}

func HasVulnerabilityReportOwnedBy(rs *appsv1.ReplicaSet) func() bool {
func HasVulnerabilityReportOwnedBy(obj client.Object) func() bool {
return func() bool {
list, err := starboardClientset.AquasecurityV1alpha1().VulnerabilityReports(rs.Namespace).
List(context.Background(), metav1.ListOptions{
LabelSelector: labels.Set{
kube.LabelResourceKind: "ReplicaSet",
kube.LabelResourceName: rs.Name,
kube.LabelResourceNamespace: rs.Namespace,
}.String(),
})
gvk, err := apiutil.GVKForObject(obj, scheme)
if err != nil {
// TODO Report error
return false
}
return len(list.Items) == 1
var reportList v1alpha1.VulnerabilityReportList
err = kubeClient.List(context.Background(), &reportList, client.MatchingLabels{
kube.LabelResourceKind: gvk.Kind,
kube.LabelResourceName: obj.GetName(),
kube.LabelResourceNamespace: obj.GetNamespace(),
})
if err != nil {
// TODO Report error
return false
}
return len(reportList.Items) == 1
}
}

func HasConfigAuditReportOwnedBy(rs *appsv1.ReplicaSet) func() bool {
func HasConfigAuditReportOwnedBy(obj client.Object) func() bool {
return func() bool {
list, err := starboardClientset.AquasecurityV1alpha1().ConfigAuditReports(rs.Namespace).
List(context.Background(), metav1.ListOptions{
LabelSelector: labels.Set{
kube.LabelResourceKind: "ReplicaSet",
kube.LabelResourceName: rs.Name,
kube.LabelResourceNamespace: rs.Namespace,
}.String(),
})
gvk, err := apiutil.GVKForObject(obj, scheme)
if err != nil {
// TODO Report error
return false
}
var reportsList v1alpha1.ConfigAuditReportList
err = kubeClient.List(context.Background(), &reportsList, client.MatchingLabels{
kube.LabelResourceKind: gvk.Kind,
kube.LabelResourceName: obj.GetName(),
kube.LabelResourceNamespace: obj.GetNamespace(),
})
if err != nil {
return false
}
return len(list.Items) == 1
return len(reportsList.Items) == 1
}
}

Expand Down
5 changes: 4 additions & 1 deletion itest/starboard-operator/suite_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package starboard_operator

import (
"k8s.io/apimachinery/pkg/runtime"
"path/filepath"
"testing"

Expand Down Expand Up @@ -29,6 +30,7 @@ var (
)

var (
scheme *runtime.Scheme
kubeClientset kubernetes.Interface
kubeClient client.Client
starboardClientset versioned.Interface
Expand Down Expand Up @@ -58,7 +60,8 @@ var _ = BeforeSuite(func(done Done) {
kubeClientset, err = kubernetes.NewForConfig(kubeConfig)
Expect(err).ToNot(HaveOccurred())

kubeClient, err = client.New(kubeConfig, client.Options{Scheme: starboard.NewScheme()})
scheme = starboard.NewScheme()
kubeClient, err = client.New(kubeConfig, client.Options{Scheme: scheme})
Expect(err).ToNot(HaveOccurred())

starboardClientset, err = versioned.NewForConfig(kubeConfig)
Expand Down
56 changes: 29 additions & 27 deletions itest/starboard/starboard_cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ var (
Vendor: "Aqua Security",
Version: "0.16.0",
}
polarisScanner = v1alpha1.Scanner{
Name: "Polaris",
Vendor: "Fairwinds Ops",
Version: "3.0",
}
)

var _ = Describe("Starboard CLI", func() {
Expand All @@ -72,8 +77,7 @@ var _ = Describe("Starboard CLI", func() {
err := cmd.Run(versionInfo, []string{
"starboard",
"init",
"-v",
starboardCLILogLevel,
"-v", starboardCLILogLevel,
}, GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred())
})
Expand Down Expand Up @@ -185,7 +189,7 @@ var _ = Describe("Starboard CLI", func() {

})

Describe("Command find vulnerabilities", func() {
Describe("Command scan vulnerabilityreports", func() {
// TODO 1. Add test cases for other types of Kubernetes controllers (StatefulSets, DaemonSets, etc.)

// containerNameAsIdFn is used as an identifier by the MatchAllElements matcher
Expand Down Expand Up @@ -873,7 +877,7 @@ var _ = Describe("Starboard CLI", func() {
})
})

Describe("Command polaris", func() {
Describe("Command scan configauditreports", func() {
// containerNameAsIDFn is used as an identifier by the MatchAllElements matcher
// to group ConfigAuditReport by container name.
resourceNameAsIDFn := func(element interface{}) string {
Expand All @@ -896,8 +900,9 @@ var _ = Describe("Starboard CLI", func() {
It("should create configaudit resource", func() {
err := cmd.Run(versionInfo, []string{
"starboard",
"polaris", "pod/" + podName,
"-v", starboardCLILogLevel, "--namespace", namespaceItest,
"scan", "configauditreports", "pod/" + podName,
"--namespace", namespaceItest,
"-v", starboardCLILogLevel,
}, GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred())

Expand All @@ -920,18 +925,16 @@ var _ = Describe("Starboard CLI", func() {
kube.LabelResourceNamespace: Equal(podNamespace),
}),
"OwnerReferences": ConsistOf(metav1.OwnerReference{
APIVersion: "v1",
Kind: "Pod",
Name: podName,
UID: pod.UID,
APIVersion: "v1",
Kind: "Pod",
Name: podName,
UID: pod.UID,
Controller: pointer.BoolPtr(true),
BlockOwnerDeletion: pointer.BoolPtr(true),
}),
}),
"Report": MatchFields(IgnoreExtras, Fields{
"Scanner": Equal(v1alpha1.Scanner{
Name: "Polaris",
Vendor: "Fairwinds Ops",
Version: "3.0",
}),
"Scanner": Equal(polarisScanner),
}),
}),
}))
Expand Down Expand Up @@ -960,8 +963,9 @@ var _ = Describe("Starboard CLI", func() {
It("should create configaudit resources", func() {
err := cmd.Run(versionInfo, []string{
"starboard",
"polaris", "pod/" + podName,
"-v", starboardCLILogLevel, "--namespace", namespaceItest,
"scan", "configauditreports", "pod/" + podName,
"--namespace", namespaceItest,
"-v", starboardCLILogLevel,
}, GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred())

Expand All @@ -985,18 +989,16 @@ var _ = Describe("Starboard CLI", func() {
kube.LabelResourceNamespace: Equal(podNamespace),
}),
"OwnerReferences": ConsistOf(metav1.OwnerReference{
APIVersion: "v1",
Kind: "Pod",
Name: podName,
UID: pod.UID,
APIVersion: "v1",
Kind: "Pod",
Name: podName,
UID: pod.UID,
Controller: pointer.BoolPtr(true),
BlockOwnerDeletion: pointer.BoolPtr(true),
}),
}),
"Report": MatchFields(IgnoreExtras, Fields{
"Scanner": Equal(v1alpha1.Scanner{
Name: "Polaris",
Vendor: "Fairwinds Ops",
Version: "3.0",
}),
"Scanner": Equal(polarisScanner),
}),
}),
}))
Expand All @@ -1012,7 +1014,7 @@ var _ = Describe("Starboard CLI", func() {

})

Describe("Command generate ciskubebenchreports", func() {
Describe("Command scan ciskubebenchreports", func() {

It("should run kube-bench", func() {
err := cmd.Run(versionInfo, []string{
Expand Down
28 changes: 14 additions & 14 deletions pkg/configauditreport/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

type Builder interface {
Owner(owner metav1.Object) Builder
Controller(controller metav1.Object) Builder
PodSpecHash(hash string) Builder
Result(result v1alpha1.ConfigAuditResult) Builder
Get() (v1alpha1.ConfigAuditReport, error)
Expand All @@ -25,14 +25,14 @@ func NewBuilder(scheme *runtime.Scheme) Builder {
}

type builder struct {
scheme *runtime.Scheme
owner metav1.Object
hash string
result v1alpha1.ConfigAuditResult
scheme *runtime.Scheme
controller metav1.Object
hash string
result v1alpha1.ConfigAuditResult
}

func (b *builder) Owner(owner metav1.Object) Builder {
b.owner = owner
func (b *builder) Controller(controller metav1.Object) Builder {
b.controller = controller
return b
}

Expand All @@ -47,24 +47,24 @@ func (b *builder) Result(result v1alpha1.ConfigAuditResult) Builder {
}

func (b *builder) reportName() (string, error) {
kind, err := kube.KindForObject(b.owner, b.scheme)
kind, err := kube.KindForObject(b.controller, b.scheme)
if err != nil {
return "", err
}
return fmt.Sprintf("%s-%s", strings.ToLower(kind),
b.owner.GetName()), nil
b.controller.GetName()), nil
}

func (b *builder) Get() (v1alpha1.ConfigAuditReport, error) {
kind, err := kube.KindForObject(b.owner, b.scheme)
kind, err := kube.KindForObject(b.controller, b.scheme)
if err != nil {
return v1alpha1.ConfigAuditReport{}, err
}

labels := map[string]string{
kube.LabelResourceKind: kind,
kube.LabelResourceName: b.owner.GetName(),
kube.LabelResourceNamespace: b.owner.GetNamespace(),
kube.LabelResourceName: b.controller.GetName(),
kube.LabelResourceNamespace: b.controller.GetNamespace(),
}

if b.hash != "" {
Expand All @@ -79,12 +79,12 @@ func (b *builder) Get() (v1alpha1.ConfigAuditReport, error) {
report := v1alpha1.ConfigAuditReport{
ObjectMeta: metav1.ObjectMeta{
Name: reportName,
Namespace: b.owner.GetNamespace(),
Namespace: b.controller.GetNamespace(),
Labels: labels,
},
Report: b.result,
}
err = controllerutil.SetOwnerReference(b.owner, &report, b.scheme)
err = controllerutil.SetControllerReference(b.controller, &report, b.scheme)
if err != nil {
return v1alpha1.ConfigAuditReport{}, err
}
Expand Down

0 comments on commit 004dba6

Please sign in to comment.