Skip to content
This repository was archived by the owner on Oct 14, 2020. It is now read-only.

Commit c54e8ee

Browse files
authored
feat: Use deterministic names for VulnerabilityReports (#43)
Signed-off-by: Daniel Pacak <[email protected]>
1 parent c28cfe1 commit c54e8ee

File tree

14 files changed

+267
-208
lines changed

14 files changed

+267
-208
lines changed

CONTRIBUTING.md

+51-16
Original file line numberDiff line numberDiff line change
@@ -182,22 +182,57 @@ the operator in the same namespace as supervised workloads.
182182
You'll need an OperatorGroup to denote which namespaces the operator should watch. It must exist in the namespace
183183
where you want to deploy the operator.
184184

185-
3. Create the Subscription resource:
186-
187-
```
188-
cat << EOF | kubectl apply -f -
189-
apiVersion: operators.coreos.com/v1alpha1
190-
kind: Subscription
191-
metadata:
192-
name: starboard-operator
193-
namespace: marketplace
194-
spec:
195-
channel: alpha
196-
name: starboard-operator
197-
source: $QUAY_NAMESPACE-operators
198-
sourceNamespace: marketplace
199-
EOF
200-
```
185+
3. Create the Subscription resource
186+
1. with Trivy scanner, which is enabled by default:
187+
188+
```
189+
$ cat << EOF | kubectl apply -f -
190+
apiVersion: operators.coreos.com/v1alpha1
191+
kind: Subscription
192+
metadata:
193+
name: starboard-operator
194+
namespace: marketplace
195+
spec:
196+
channel: alpha
197+
name: starboard-operator
198+
source: $QUAY_NAMESPACE-operators
199+
sourceNamespace: marketplace
200+
EOF
201+
```
202+
2. with Aqua CSP scanner:
203+
204+
```
205+
$ kubectl create secret generic starboard-operator \
206+
--namespace marketplace \
207+
--from-literal OPERATOR_SCANNER_AQUA_CSP_USERNAME=$AQUA_CONSOLE_USERNAME \
208+
--from-literal OPERATOR_SCANNER_AQUA_CSP_PASSWORD=$AQUA_CONSOLE_PASSWORD \
209+
--from-literal OPERATOR_SCANNER_AQUA_CSP_VERSION=$AQUA_VERSION \
210+
--from-literal OPERATOR_SCANNER_AQUA_CSP_HOST=http://csp-console-svc.aqua:8080
211+
```
212+
213+
```
214+
$ cat << EOF | kubectl apply -f -
215+
apiVersion: operators.coreos.com/v1alpha1
216+
kind: Subscription
217+
metadata:
218+
name: starboard-operator
219+
namespace: marketplace
220+
spec:
221+
channel: alpha
222+
name: starboard-operator
223+
source: $QUAY_NAMESPACE-operators
224+
sourceNamespace: marketplace
225+
config:
226+
env:
227+
- name: OPERATOR_SCANNER_TRIVY_ENABLED
228+
value: "false"
229+
- name: OPERATOR_SCANNER_AQUA_CSP_ENABLED
230+
value: "true"
231+
envFrom:
232+
- secretRef:
233+
name: starboard-operator
234+
EOF
235+
```
201236
202237
A Subscription links the previous steps together by selecting an operator and one of its channels. OLM uses this
203238
information to start the corresponding operator Pod. The example above creates a new Subscription to the `alpha`

Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ modules:
1919
build: operator scanner
2020

2121
scanner: $(SOURCES)
22-
go build -o bin/scanner cmd/scanner/main.go
22+
GOOS=linux go build -o bin/scanner cmd/scanner/main.go
2323

2424
operator: $(SOURCES)
25-
go build -o bin/operator cmd/operator/main.go
25+
GOOS=linux go build -o bin/operator cmd/operator/main.go
2626

2727
.PHONY: test
2828
test:

cmd/operator/main.go

+21-13
Original file line numberDiff line numberDiff line change
@@ -81,36 +81,44 @@ func run() error {
8181

8282
targetNamespaces := config.Operator.GetTargetNamespaces()
8383

84-
setupLog.Info("Resolving multitenancy support",
85-
"operatorNamespace", operatorNamespace,
86-
"targetNamespaces", targetNamespaces)
87-
88-
installMode, err := etc.ResolveInstallMode(operatorNamespace, targetNamespaces)
84+
installMode, err := config.Operator.GetInstallMode()
8985
if err != nil {
90-
return fmt.Errorf("resolving install mode: %w", err)
86+
return fmt.Errorf("getting install mode: %w", err)
9187
}
92-
setupLog.Info("Resolving install mode", "mode", installMode)
88+
setupLog.Info("Resolving install mode", "installMode", installMode,
89+
"operatorNamespace", operatorNamespace,
90+
"targetNamespaces", targetNamespaces)
9391

9492
// Set the default manager options.
9593
options := manager.Options{
9694
Scheme: scheme,
9795
}
9896

99-
if len(targetNamespaces) == 1 && targetNamespaces[0] == operatorNamespace {
100-
// Add support for OwnNamespace set in STARBOARD_TARGET_NAMESPACES (e.g. ns1).
97+
switch installMode {
98+
case etc.InstallModeOwnNamespace:
99+
// Add support for OwnNamespace set in STARBOARD_NAMESPACE (e.g. marketplace) and STARBOARD_TARGET_NAMESPACES (e.g. marketplace)
101100
setupLog.Info("Constructing single-namespaced cache", "namespace", targetNamespaces[0])
102101
options.Namespace = targetNamespaces[0]
103-
} else if len(targetNamespaces) > 0 {
104-
// Add support for SingleNamespace and MultiNamespace set in STARBOARD_TARGET_NAMESPACES (e.g. ns1,ns2).
102+
case etc.InstallModeSingleNamespace:
103+
// Add support for SingleNamespace set in STARBOARD_NAMESPACE (e.g. marketplace) and STARBOARD_TARGET_NAMESPACES (e.g. foo)
104+
cachedNamespaces := append(targetNamespaces, operatorNamespace)
105+
setupLog.Info("Constructing multi-namespaced cache", "namespaces", cachedNamespaces)
106+
options.Namespace = targetNamespaces[0]
107+
options.NewCache = cache.MultiNamespacedCacheBuilder(cachedNamespaces)
108+
case etc.InstallModeMultiNamespace:
109+
// Add support for MultiNamespace set in STARBOARD_NAMESPACE (e.g. marketplace) and STARBOARD_TARGET_NAMESPACES (e.g. foo,bar).
105110
// Note that we may face performance issues when using this with a high number of namespaces.
106111
// More: https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/cache#MultiNamespacedCacheBuilder
107112
cachedNamespaces := append(targetNamespaces, operatorNamespace)
108113
setupLog.Info("Constructing multi-namespaced cache", "namespaces", cachedNamespaces)
109114
options.Namespace = ""
110115
options.NewCache = cache.MultiNamespacedCacheBuilder(cachedNamespaces)
111-
} else if len(targetNamespaces) == 0 {
112-
setupLog.Info("Disabling cache and watching all namespaces")
116+
case etc.InstallModeAllNamespaces:
117+
// Add support for AllNamespaces set in STARBOARD_NAMESPACE (e.g. marketplace) and STARBOARD_TARGET_NAMESPACES left blank.
118+
setupLog.Info("Watching all namespaces")
113119
options.Namespace = ""
120+
default:
121+
return fmt.Errorf("unrecognized install mode: %v", installMode)
114122
}
115123

116124
kubernetesConfig, err := ctrl.GetConfig()

go.mod

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ module github.com/aquasecurity/starboard-operator
33
go 1.14
44

55
require (
6-
github.com/aquasecurity/starboard v0.3.1-0.20200915085831-05e4ce57da65
6+
github.com/aquasecurity/starboard v0.4.1-0.20200923101908-ca60574a118f
7+
github.com/beorn7/perks v1.0.1 // indirect
78
github.com/caarlos0/env/v6 v6.2.2
89
github.com/go-logr/logr v0.1.0
910
github.com/google/go-containerregistry v0.1.1
@@ -16,7 +17,7 @@ require (
1617
k8s.io/apimachinery v0.19.0-alpha.3
1718
k8s.io/client-go v0.19.0-alpha.3
1819
k8s.io/utils v0.0.0-20200603063816-c1c6865ac451
19-
sigs.k8s.io/controller-runtime v0.6.2
20+
sigs.k8s.io/controller-runtime v0.6.3
2021
)
2122

2223
replace (

go.sum

+6-5
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ github.com/apex/log v1.3.0/go.mod h1:jd8Vpsr46WAe3EZSQ/IUMs2qQD/GOycT5rPWCO1yGcs
103103
github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
104104
github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
105105
github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
106-
github.com/aquasecurity/starboard v0.3.1-0.20200915085831-05e4ce57da65 h1:uRoIOcMb/uTZwlnFZtEKL373eojYTW24UpFSnwW1w5g=
107-
github.com/aquasecurity/starboard v0.3.1-0.20200915085831-05e4ce57da65/go.mod h1:Xdodbl8+u6Na3ah5DoeBONtVavbCrwMA7CcpKYDBizo=
106+
github.com/aquasecurity/starboard v0.4.1-0.20200923101908-ca60574a118f h1:rrdkeHqSnE6z/og/Pse54kKnMF1l/bD6SJVlRIPlIKI=
107+
github.com/aquasecurity/starboard v0.4.1-0.20200923101908-ca60574a118f/go.mod h1:Xdodbl8+u6Na3ah5DoeBONtVavbCrwMA7CcpKYDBizo=
108108
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
109109
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
110110
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@@ -192,8 +192,9 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
192192
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
193193
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
194194
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
195-
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
196195
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
196+
github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
197+
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
197198
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
198199
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
199200
github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
@@ -1123,8 +1124,8 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
11231124
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
11241125
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
11251126
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0=
1126-
sigs.k8s.io/controller-runtime v0.6.2 h1:jkAnfdTYBpFwlmBn3pS5HFO06SfxvnTZ1p5PeEF/zAA=
1127-
sigs.k8s.io/controller-runtime v0.6.2/go.mod h1:vhcq/rlnENJ09SIRp3EveTaZ0yqH526hjf9iJdbUJ/E=
1127+
sigs.k8s.io/controller-runtime v0.6.3 h1:SBbr+inLPEKhvlJtrvDcwIpm+uhDvp63Bl72xYJtoOE=
1128+
sigs.k8s.io/controller-runtime v0.6.3/go.mod h1:WlZNXcM0++oyaQt4B7C2lEE5JYRs8vJUzRP4N4JpdAY=
11281129
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
11291130
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
11301131
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU=

pkg/aqua/scanner.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func NewScanner(version etc.VersionInfo, config etc.ScannerAquaCSP) scanner.Vuln
3737
}
3838
}
3939

40-
func (s *aquaScanner) NewScanJob(resource kube.Object, spec corev1.PodSpec, options scanner.Options) (*batchv1.Job, *corev1.Secret, error) {
40+
func (s *aquaScanner) NewScanJob(resource kube.Object, spec corev1.PodSpec, options scanner.Options) (*batchv1.Job, error) {
4141
jobName := uuid.New().String()
4242
initContainerName := jobName
4343

@@ -50,7 +50,7 @@ func (s *aquaScanner) NewScanJob(resource kube.Object, spec corev1.PodSpec, opti
5050

5151
containerImagesAsJSON, err := containerImages.AsJSON()
5252
if err != nil {
53-
return nil, nil, err
53+
return nil, err
5454
}
5555

5656
return &batchv1.Job{
@@ -122,7 +122,7 @@ func (s *aquaScanner) NewScanJob(resource kube.Object, spec corev1.PodSpec, opti
122122
},
123123
},
124124
},
125-
}, nil, nil
125+
}, nil
126126
}
127127

128128
func (s *aquaScanner) newScanJobContainer(podContainer corev1.Container) corev1.Container {

pkg/controllers/job_controller.go

+6-41
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ package controllers
33
import (
44
"context"
55
"fmt"
6-
"reflect"
76

7+
"github.com/aquasecurity/starboard-operator/pkg/resources"
88
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
99

1010
"github.com/aquasecurity/starboard-operator/pkg/etc"
@@ -55,7 +55,7 @@ func (r *JobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
5555
}
5656

5757
if len(job.Status.Conditions) == 0 {
58-
log.Info("Ignoring Job with unknown status condition")
58+
log.Info("Ignoring Job without status conditions")
5959
return ctrl.Result{}, nil
6060
}
6161

@@ -85,12 +85,12 @@ func (r *JobReconciler) processCompleteScanJob(ctx context.Context, scanJob *bat
8585
return fmt.Errorf("getting workload from scan job labels set: %w", err)
8686
}
8787

88-
containerImages, err := r.getContainerImagesFrom(scanJob)
88+
containerImages, err := resources.GetContainerImagesFromJob(scanJob)
8989
if err != nil {
90-
return err
90+
return fmt.Errorf("getting container images: %w", err)
9191
}
9292

93-
hasVulnerabilityReports, err := r.hasVulnerabilityReports(ctx, workload, containerImages)
93+
hasVulnerabilityReports, err := r.Store.HasVulnerabilityReports(ctx, workload, containerImages)
9494
if err != nil {
9595
return err
9696
}
@@ -146,41 +146,6 @@ func (r *JobReconciler) GetPodControlledBy(ctx context.Context, job *batchv1.Job
146146
return podList.Items[0].DeepCopy(), nil
147147
}
148148

149-
func (r *JobReconciler) hasVulnerabilityReports(ctx context.Context, owner kube.Object, containerImages kube.ContainerImages) (bool, error) {
150-
vulnerabilityReports, err := r.Store.Read(ctx, owner)
151-
if err != nil {
152-
return false, err
153-
}
154-
155-
actual := map[string]bool{}
156-
for containerName, _ := range vulnerabilityReports {
157-
actual[containerName] = true
158-
}
159-
160-
expected := map[string]bool{}
161-
for containerName, _ := range containerImages {
162-
expected[containerName] = true
163-
}
164-
165-
return reflect.DeepEqual(actual, expected), nil
166-
}
167-
168-
// TODO We have similar code in other places
169-
func (r *JobReconciler) getContainerImagesFrom(job *batchv1.Job) (kube.ContainerImages, error) {
170-
var containerImagesAsJSON string
171-
var ok bool
172-
173-
if containerImagesAsJSON, ok = job.Annotations[kube.AnnotationContainerImages]; !ok {
174-
return nil, fmt.Errorf("scan job does not have required annotation: %s", kube.AnnotationContainerImages)
175-
}
176-
containerImages := kube.ContainerImages{}
177-
err := containerImages.FromJSON(containerImagesAsJSON)
178-
if err != nil {
179-
return nil, fmt.Errorf("reading scan job annotation: %s: %w", kube.AnnotationContainerImages, err)
180-
}
181-
return containerImages, nil
182-
}
183-
184149
func (r *JobReconciler) processFailedScanJob(ctx context.Context, scanJob *batchv1.Job) error {
185150
pod, err := r.GetPodControlledBy(ctx, scanJob)
186151
if err != nil {
@@ -194,7 +159,7 @@ func (r *JobReconciler) processFailedScanJob(ctx context.Context, scanJob *batch
194159
r.Log.Error(nil, "Scan job container", "container", container, "status.reason", status.Reason, "status.message", status.Message)
195160
}
196161
r.Log.Info("Deleting failed scan job")
197-
return r.Client.Delete(ctx, scanJob)
162+
return r.Client.Delete(ctx, scanJob, client.PropagationPolicy(metav1.DeletePropagationBackground))
198163
}
199164

200165
func (r *JobReconciler) SetupWithManager(mgr ctrl.Manager) error {

0 commit comments

Comments
 (0)