Skip to content

Commit

Permalink
feat: allow configuring pod template labels attached to scan jobs (#902)
Browse files Browse the repository at this point in the history
  • Loading branch information
cgroschupp committed Jan 18, 2022
1 parent b834584 commit b2a8c0d
Show file tree
Hide file tree
Showing 15 changed files with 213 additions and 50 deletions.
3 changes: 3 additions & 0 deletions deploy/helm/templates/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ data:
{{- with .Values.starboard.scanJobAnnotations }}
scanJob.annotations: {{ . | quote }}
{{- end }}
{{- with .Values.starboard.scanJobPodTemplateLabels }}
scanJob.podTemplateLabels: {{ . | quote }}
{{- end }}
{{- if .Values.operator.vulnerabilityScannerEnabled }}
vulnerabilityReports.scanner: {{ .Values.starboard.vulnerabilityReportsPlugin | quote }}
{{- end }}
Expand Down
4 changes: 4 additions & 0 deletions deploy/helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ starboard:
# annotated with. Example: `foo=bar,env=stage` will annotate the scanner pods with the annotations `foo: bar` and `env: stage`
scanJobAnnotations: ""

# scanJobPodTemplateLabels comma-separated representation of the labels which the user wants the scanner pods to be
# labeled with. Example: `foo=bar,env=stage` will labeled the scanner pods with the labels `foo: bar` and `env: stage`
scanJobPodTemplateLabels: ""

trivy:
# createConfig indicates whether to create config objects
createConfig: true
Expand Down
1 change: 1 addition & 0 deletions docs/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ configuration settings for common use cases. For example, switch Trivy from [Sta
| `configAuditReports.scanner` | `Polaris` | The name of the plugin that generates config audit reports. Either `Polaris` or `Conftest`. |
| `scanJob.tolerations` | N/A | JSON representation of the [tolerations] to be applied to the scanner pods so that they can run on nodes with matching taints. Example: `'[{"key":"key1", "operator":"Equal", "value":"value1", "effect":"NoSchedule"}]'` |
| `scanJob.annotations` | N/A | One-line comma-separated representation of the annotations which the user wants the scanner pods to be annotated with. Example: `foo=bar,env=stage` will annotate the scanner pods with the annotations `foo: bar` and `env: stage` |
| `scanJob.templateLabel` | N/A | One-line comma-separated representation of the template labels which the user wants the scanner pods to be labeled with. Example: `foo=bar,env=stage` will labeled the scanner pods with the labels `foo: bar` and `env: stage` |
| `kube-bench.imageRef` | `docker.io/aquasec/kube-bench:v0.6.5` | kube-bench image reference |
| `kube-hunter.imageRef` | `docker.io/aquasec/kube-hunter:0.6.3` | kube-hunter image reference |
| `kube-hunter.quick` | `"false"` | Whether to use kube-hunter's "quick" scanning mode (subnet 24). Set to `"true"` to enable. |
Expand Down
51 changes: 33 additions & 18 deletions pkg/configauditreport/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/utils/pointer"
Expand All @@ -20,12 +21,13 @@ import (
)

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

func NewScanJobBuilder() *ScanJobBuilder {
Expand Down Expand Up @@ -62,6 +64,11 @@ func (s *ScanJobBuilder) WithAnnotations(annotations map[string]string) *ScanJob
return s
}

func (s *ScanJobBuilder) WithPodTemplateLabels(podTemplateLabels labels.Set) *ScanJobBuilder {
s.podTemplateLabels = podTemplateLabels
return s
}

func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
jobSpec, secrets, err := s.plugin.GetScanJobSpec(s.pluginContext, s.object)
if err != nil {
Expand All @@ -80,18 +87,26 @@ func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
return nil, nil, err
}

labels := map[string]string{
labelsSet := labels.Set{
starboard.LabelResourceSpecHash: resourceSpecHash,
starboard.LabelPluginConfigHash: pluginConfigHash,
starboard.LabelConfigAuditReportScanner: s.pluginContext.GetName(),
starboard.LabelK8SAppManagedBy: starboard.AppStarboard,
}

podTemplateLabelsSet := make(labels.Set)
for index, element := range labelsSet {
podTemplateLabelsSet[index] = element
}
for index, element := range s.podTemplateLabels {
podTemplateLabelsSet[index] = element
}

job := &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Name: GetScanJobName(s.object),
Namespace: s.pluginContext.GetNamespace(),
Labels: labels,
Labels: labelsSet,
Annotations: s.annotations,
},
Spec: batchv1.JobSpec{
Expand All @@ -100,7 +115,7 @@ func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
ActiveDeadlineSeconds: kube.GetActiveDeadlineSeconds(s.timeout),
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
Labels: podTemplateLabelsSet,
Annotations: s.annotations,
},
Spec: jobSpec,
Expand All @@ -122,7 +137,7 @@ func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
if secret.Labels == nil {
secret.Labels = make(map[string]string)
}
for k, v := range labels {
for k, v := range labelsSet {
secret.Labels[k] = v
}
err = kube.ObjectToObjectMetadata(s.object, &secret.ObjectMeta)
Expand Down Expand Up @@ -184,18 +199,18 @@ func (b *ReportBuilder) reportName() string {
}

func (b *ReportBuilder) GetClusterReport() (v1alpha1.ClusterConfigAuditReport, error) {
labels := make(map[string]string)
labelsSet := make(labels.Set)
if b.resourceSpecHash != "" {
labels[starboard.LabelResourceSpecHash] = b.resourceSpecHash
labelsSet[starboard.LabelResourceSpecHash] = b.resourceSpecHash
}
if b.pluginConfigHash != "" {
labels[starboard.LabelPluginConfigHash] = b.pluginConfigHash
labelsSet[starboard.LabelPluginConfigHash] = b.pluginConfigHash
}

report := v1alpha1.ClusterConfigAuditReport{
ObjectMeta: metav1.ObjectMeta{
Name: b.reportName(),
Labels: labels,
Labels: labelsSet,
},
Report: b.data,
}
Expand All @@ -220,19 +235,19 @@ func (b *ReportBuilder) GetClusterReport() (v1alpha1.ClusterConfigAuditReport, e
}

func (b *ReportBuilder) GetReport() (v1alpha1.ConfigAuditReport, error) {
labels := make(map[string]string)
labelsSet := make(labels.Set)
if b.resourceSpecHash != "" {
labels[starboard.LabelResourceSpecHash] = b.resourceSpecHash
labelsSet[starboard.LabelResourceSpecHash] = b.resourceSpecHash
}
if b.pluginConfigHash != "" {
labels[starboard.LabelPluginConfigHash] = b.pluginConfigHash
labelsSet[starboard.LabelPluginConfigHash] = b.pluginConfigHash
}

report := v1alpha1.ConfigAuditReport{
ObjectMeta: metav1.ObjectMeta{
Name: b.reportName(),
Namespace: b.controller.GetNamespace(),
Labels: labels,
Labels: labelsSet,
},
Report: b.data,
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/configauditreport/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ func (s *Scanner) Scan(ctx context.Context, partial kube.ObjectRef) (*ReportBuil
return nil, fmt.Errorf("getting scan job annotations: %w", err)
}

scanJobPodTemplateLabels, err := s.config.GetScanJobPodTemplateLabels()
if err != nil {
return nil, fmt.Errorf("getting scan job template labels: %w", err)
}

klog.V(3).Infof("Scanning with options: %+v", s.opts)
job, secrets, err := NewScanJobBuilder().
WithPlugin(s.plugin).
Expand All @@ -85,6 +90,7 @@ func (s *Scanner) Scan(ctx context.Context, partial kube.ObjectRef) (*ReportBuil
WithObject(owner).
WithTolerations(scanJobTolerations).
WithAnnotations(scanJobAnnotations).
WithPodTemplateLabels(scanJobPodTemplateLabels).
Get()
if err != nil {
return nil, fmt.Errorf("constructing scan job: %w", err)
Expand Down
28 changes: 20 additions & 8 deletions pkg/kubebench/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,25 +120,37 @@ func (s *Scanner) prepareKubeBenchJob(node corev1.Node) (*batchv1.Job, error) {
return nil, err
}

scanJobPodTemplateLabels, err := s.config.GetScanJobPodTemplateLabels()
if err != nil {
return nil, err
}

labelsSet := labels.Set{
starboard.LabelResourceKind: string(kube.KindNode),
starboard.LabelResourceName: node.Name,
}

podTemplateLabelsSet := make(labels.Set)
for index, element := range labelsSet {
podTemplateLabelsSet[index] = element
}
for index, element := range scanJobPodTemplateLabels {
podTemplateLabelsSet[index] = element
}

return &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Name: "scan-cisbenchmark-" + kube.ComputeHash(node.Name),
Namespace: starboard.NamespaceName,
Labels: labels.Set{
starboard.LabelResourceKind: string(kube.KindNode),
starboard.LabelResourceName: node.Name,
},
Labels: labelsSet,
},
Spec: batchv1.JobSpec{
BackoffLimit: pointer.Int32Ptr(0),
Completions: pointer.Int32Ptr(1),
ActiveDeadlineSeconds: kube.GetActiveDeadlineSeconds(s.opts.ScanJobTimeout),
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels.Set{
starboard.LabelResourceKind: string(kube.KindNode),
starboard.LabelResourceName: node.Name,
},
Labels: podTemplateLabelsSet,
Annotations: scanJobAnnotations,
},
Spec: templateSpec,
Expand Down
6 changes: 6 additions & 0 deletions pkg/kubehunter/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ func (s *Scanner) prepareKubeHunterJob() (*batchv1.Job, error) {
return nil, err
}

scanJobPodTemplateLabels, err := s.config.GetScanJobPodTemplateLabels()
if err != nil {
return nil, err
}

var (
podSecurityContext *corev1.PodSecurityContext
containerSecurityContext *corev1.SecurityContext
Expand Down Expand Up @@ -156,6 +161,7 @@ func (s *Scanner) prepareKubeHunterJob() (*batchv1.Job, error) {
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Annotations: scanJobAnnotations,
Labels: scanJobPodTemplateLabels,
},
Spec: corev1.PodSpec{
ServiceAccountName: starboard.ServiceAccountName,
Expand Down
34 changes: 22 additions & 12 deletions pkg/operator/controller/ciskubebenchreport.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,29 +169,39 @@ func (r *CISKubeBenchReportReconciler) newScanJob(node *corev1.Node) (*batchv1.J
return nil, err
}

scanJobPodTemplateLabels, err := r.ConfigData.GetScanJobPodTemplateLabels()
if err != nil {
return nil, err
}

labelsSet := labels.Set{
starboard.LabelResourceKind: string(kube.KindNode),
starboard.LabelResourceName: node.Name,
starboard.LabelK8SAppManagedBy: starboard.AppStarboard,
starboard.LabelKubeBenchReportScanner: "true",
}

podTemplateLabelsSet := make(labels.Set)
for index, element := range labelsSet {
podTemplateLabelsSet[index] = element
}
for index, element := range scanJobPodTemplateLabels {
podTemplateLabelsSet[index] = element
}

return &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Name: r.getScanJobName(node),
Namespace: r.Config.Namespace,
Labels: labels.Set{
starboard.LabelResourceKind: string(kube.KindNode),
starboard.LabelResourceName: node.Name,
starboard.LabelK8SAppManagedBy: starboard.AppStarboard,
starboard.LabelKubeBenchReportScanner: "true",
},
Labels: labelsSet,
},
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.Set{
starboard.LabelResourceKind: string(kube.KindNode),
starboard.LabelResourceName: node.Name,
starboard.LabelK8SAppManagedBy: starboard.AppStarboard,
starboard.LabelKubeBenchReportScanner: "true",
},
Labels: podTemplateLabelsSet,
Annotations: scanJobAnnotations,
},
Spec: templateSpec,
Expand Down
6 changes: 6 additions & 0 deletions pkg/operator/controller/configauditreport.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,19 @@ func (r *ConfigAuditReportReconciler) reconcileResource(resourceKind kube.Kind)
return ctrl.Result{}, fmt.Errorf("getting scan job annotations: %w", err)
}

scanJobPodTemplateLabels, err := r.GetScanJobPodTemplateLabels()
if err != nil {
return ctrl.Result{}, fmt.Errorf("getting scan job template labels: %w", err)
}

job, secrets, err := configauditreport.NewScanJobBuilder().
WithPlugin(r.Plugin).
WithPluginContext(r.PluginContext).
WithTimeout(r.Config.ScanJobTimeout).
WithObject(resource).
WithTolerations(scanJobTolerations).
WithAnnotations(scanJobAnnotations).
WithPodTemplateLabels(scanJobPodTemplateLabels).
Get()
if err != nil {
return ctrl.Result{}, fmt.Errorf("constructing scan job: %w", err)
Expand Down
6 changes: 6 additions & 0 deletions pkg/operator/controller/vulnerabilityreport.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,19 @@ func (r *VulnerabilityReportReconciler) submitScanJob(ctx context.Context, owner
return fmt.Errorf("getting scan job annotations: %w", err)
}

scanJobPodTemplateLabels, err := r.GetScanJobPodTemplateLabels()
if err != nil {
return fmt.Errorf("getting scan job template labels: %w", err)
}

scanJob, secrets, err := vulnerabilityreport.NewScanJobBuilder().
WithPlugin(r.Plugin).
WithPluginContext(r.PluginContext).
WithTimeout(r.Config.ScanJobTimeout).
WithObject(owner).
WithTolerations(scanJobTolerations).
WithAnnotations(scanJobAnnotations).
WithPodTemplateLabels(scanJobPodTemplateLabels).
WithCredentials(credentials).
Get()

Expand Down
19 changes: 19 additions & 0 deletions pkg/starboard/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,25 @@ func (c ConfigData) GetScanJobAnnotations() (map[string]string, error) {
return scanJobAnnotationsMap, nil
}

func (c ConfigData) GetScanJobPodTemplateLabels() (labels.Set, error) {
scanJobPodTemplateLabelsStr, found := c[AnnotationScanJobPodTemplateLabels]
if !found || strings.TrimSpace(scanJobPodTemplateLabelsStr) == "" {
return labels.Set{}, nil
}

scanJobPodTemplateLabelsMap := map[string]string{}
for _, annotation := range strings.Split(scanJobPodTemplateLabelsStr, ",") {
sepByEqual := strings.Split(annotation, "=")
if len(sepByEqual) != 2 {
return labels.Set{}, fmt.Errorf("custom template labels found to be wrongfully provided: %s", scanJobPodTemplateLabelsStr)
}
key, value := sepByEqual[0], sepByEqual[1]
scanJobPodTemplateLabelsMap[key] = value
}

return scanJobPodTemplateLabelsMap, nil
}

func (c ConfigData) GetKubeBenchImageRef() (string, error) {
return c.GetRequiredData("kube-bench.imageRef")
}
Expand Down

0 comments on commit b2a8c0d

Please sign in to comment.