Skip to content

Commit

Permalink
feat: setup securityContext on plugins (#362)
Browse files Browse the repository at this point in the history
At Veepee we only permit pods to run as non root. Plugin works properly as non root, add variables to setup it as non root and permit to customize UID
  • Loading branch information
nerzhul committed Jul 20, 2022
1 parent 0f886e2 commit 6916d7b
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 2 deletions.
3 changes: 3 additions & 0 deletions deploy/helm/templates/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ data:
{{- with .Values.trivyOperator.scanJobPodTemplateLabels }}
scanJob.podTemplateLabels: {{ . | quote }}
{{- end }}
{{- with .Values.trivyOperator.scanJobPodTemplateSecurityContext }}
scanJob.podTemplateSecurityContext: {{ . | toJson | quote }}
{{- end }}
{{- if .Values.operator.vulnerabilityScannerEnabled }}
vulnerabilityReports.scanner: {{ .Values.trivyOperator.vulnerabilityReportsPlugin | quote }}
{{- end }}
Expand Down
7 changes: 7 additions & 0 deletions deploy/helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ trivyOperator:
# labeled with. Example: `foo=bar,env=stage` will labeled the scanner pods with the labels `foo: bar` and `env: stage`
scanJobPodTemplateLabels: ""

# scanJobPodTemplateSecurityContext podSecurityContext the user wants the scanner pods to be amended with.
# Example:
# RunAsUser: 10000
# RunAsGroup: 10000
# RunAsNonRoot: true
scanJobPodTemplateSecurityContext: ""

trivy:
# createConfig indicates whether to create config objects
createConfig: true
Expand Down
1 change: 1 addition & 0 deletions docs/operator/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ To change the target namespace from all namespaces to the `default` namespace ed
| `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`|
| `scanJob.podTemplateSecurityContext`| N/A| One-line JSON representation of the template securityContext which the user wants the scanner pods to be secured with. Example: `{"RunAsUser": 1000, "RunAsGroup": 1000, "RunAsNonRoot": true}`|

## Example - patch ConfigMap

Expand Down
1 change: 1 addition & 0 deletions docs/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ configuration settings for common use cases. For example, switch Trivy from [Sta
| `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` |
| `scanJob.podTemplateSecurityContext` | N/A | One-line JSON representation of the template securityContext which the user wants the scanner pods to be secured with. Example: `{"RunAsUser": 1000, "RunAsGroup": 1000, "RunAsNonRoot": true}`|
| `compliance.failEntriesLimit` | `"10"` | Limit the number of fail entries per control check in the cluster compliance detail report. |

!!! tip
Expand Down
15 changes: 15 additions & 0 deletions pkg/trivyoperator/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const (
keyConfigAuditReportsScanner = "configAuditReports.scanner"
keyScanJobTolerations = "scanJob.tolerations"
keyScanJobAnnotations = "scanJob.annotations"
keyScanJobPodSecurityContext = "scanJob.podTemplateSecurityContext"
keyScanJobPodTemplateLabels = "scanJob.podTemplateLabels"
keyComplianceFailEntriesLimit = "compliance.failEntriesLimit"
)
Expand Down Expand Up @@ -118,6 +119,20 @@ func (c ConfigData) GetScanJobTolerations() ([]corev1.Toleration, error) {
return scanJobTolerations, err
}

func (c ConfigData) GetScanJobPodSecurityContext() (*corev1.PodSecurityContext, error) {
if c[keyScanJobPodSecurityContext] == "" {
return nil, nil
}

scanJobPodSecurityContext := &corev1.PodSecurityContext{}
err := json.Unmarshal([]byte(c[keyScanJobPodSecurityContext]), scanJobPodSecurityContext)
if err != nil {
return nil, fmt.Errorf("failed parsing incorrectly formatted custom scan pod template securityContext: %s", c[keyScanJobPodSecurityContext])
}

return scanJobPodSecurityContext, nil
}

func (c ConfigData) GetScanJobAnnotations() (map[string]string, error) {
scanJobAnnotationsStr, found := c[keyScanJobAnnotations]
if !found || strings.TrimSpace(scanJobAnnotationsStr) == "" {
Expand Down
55 changes: 53 additions & 2 deletions pkg/trivyoperator/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,12 @@ func TestConfigData_GetScanJobPodTemplateLabels(t *testing.T) {
},
},
{
name: "gracefully deal with unprovided annotations",
name: "gracefully deal with unprovided labels",
config: trivyoperator.ConfigData{},
expected: labels.Set{},
},
{
name: "raise an error on being provided with annotations in wrong format",
name: "raise an error on being provided with labels in wrong format",
config: trivyoperator.ConfigData{
"scanJob.podTemplateLabels": "foo",
},
Expand Down Expand Up @@ -256,6 +256,57 @@ func TestConfigData_GetScanJobPodTemplateLabels(t *testing.T) {
})
}
}

func TestConfigData_GetScanJobPodSecurityContext(t *testing.T) {
expectedUid := int64(1258)
expectedGid := int64(55589)
expectedNonRoot := true

testCases := []struct {
name string
config trivyoperator.ConfigData
expected *corev1.PodSecurityContext
expectError string
}{
{
name: "scan job template podSecurityContext can be fetched successfully",
config: trivyoperator.ConfigData{
"scanJob.podTemplateSecurityContext": "{\"RunAsUser\": 1258, \"RunAsGroup\": 55589, \"RunAsNonRoot\": true}",
},
expected: &corev1.PodSecurityContext{
RunAsUser: &expectedUid,
RunAsGroup: &expectedGid,
RunAsNonRoot: &expectedNonRoot,
},
},
{
name: "gracefully deal with unprovided securityContext",
config: trivyoperator.ConfigData{},
expected: nil,
},
{
name: "raise an error on being provided with securityContext in wrong format",
config: trivyoperator.ConfigData{
"scanJob.podTemplateSecurityContext": "foo",
},
expected: nil,
expectError: "failed parsing incorrectly formatted custom scan pod template securityContext: foo",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
scanJobPodSecurityContext, err := tc.config.GetScanJobPodSecurityContext()
if tc.expectError != "" {
assert.EqualError(t, err, tc.expectError, tc.name)
} else {
assert.NoError(t, err, tc.name)
assert.Equal(t, tc.expected, scanJobPodSecurityContext, tc.name)
}
})
}
}

func TestConfigData_GetComplianceFailEntriesLimit(t *testing.T) {
testCases := []struct {
name string
Expand Down
9 changes: 9 additions & 0 deletions pkg/vulnerabilityreport/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type ScanJobBuilder struct {
tolerations []corev1.Toleration
annotations map[string]string
podTemplateLabels map[string]string
securityContext *corev1.PodSecurityContext
}

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

func (s *ScanJobBuilder) WithPodSecurityContext(securityContext *corev1.PodSecurityContext) *ScanJobBuilder {
s.securityContext = securityContext
return s
}

func (s *ScanJobBuilder) WithPodTemplateLabels(podTemplateLabels map[string]string) *ScanJobBuilder {
s.podTemplateLabels = podTemplateLabels
return s
Expand All @@ -86,6 +92,9 @@ func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
return nil, nil, err
}
templateSpec.Tolerations = append(templateSpec.Tolerations, s.tolerations...)
if s.securityContext != nil {
templateSpec.SecurityContext = s.securityContext
}

containerImagesAsJSON, err := kube.GetContainerImagesFromPodSpec(spec).AsJSON()
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions pkg/vulnerabilityreport/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,11 @@ func (r *WorkloadController) submitScanJob(ctx context.Context, owner client.Obj
return fmt.Errorf("getting scan job annotations: %w", err)
}

scanJobSecurityContext, err := r.GetScanJobPodSecurityContext()
if err != nil {
return fmt.Errorf("getting scan job securityContext: %w", err)
}

scanJobPodTemplateLabels, err := r.GetScanJobPodTemplateLabels()
if err != nil {
return fmt.Errorf("getting scan job template labels: %w", err)
Expand All @@ -303,6 +308,7 @@ func (r *WorkloadController) submitScanJob(ctx context.Context, owner client.Obj
WithObject(owner).
WithTolerations(scanJobTolerations).
WithAnnotations(scanJobAnnotations).
WithPodSecurityContext(scanJobSecurityContext).
WithPodTemplateLabels(scanJobPodTemplateLabels).
WithCredentials(credentials).
Get()
Expand Down

0 comments on commit 6916d7b

Please sign in to comment.