Skip to content

Commit

Permalink
feat: add support for security context
Browse files Browse the repository at this point in the history
Signed-off-by: Moritz Wiesinger <[email protected]>
  • Loading branch information
mowies authored and arttor committed Mar 15, 2023
1 parent 55d9c9d commit 8642244
Show file tree
Hide file tree
Showing 9 changed files with 216 additions and 5 deletions.
4 changes: 2 additions & 2 deletions examples/app/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ spec:
initialDelaySeconds: 5
periodSeconds: 10
resources: {{- toYaml .Values.myapp.app.resources | nindent 10 }}
securityContext:
allowPrivilegeEscalation: false
securityContext: {{- toYaml .Values.myapp.app.containerSecurityContext | nindent
8 }}
volumeMounts:
- mountPath: /my_config.yaml
name: manager-config
Expand Down
2 changes: 2 additions & 0 deletions examples/app/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ mySecretVars:
var2: ""
myapp:
app:
containerSecurityContext:
allowPrivilegeEscalation: false
image:
repository: controller
tag: latest
Expand Down
4 changes: 2 additions & 2 deletions examples/operator/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ spec:
periodSeconds: 10
resources: {{- toYaml .Values.controllerManager.manager.resources | nindent 10
}}
securityContext:
allowPrivilegeEscalation: false
securityContext: {{- toYaml .Values.controllerManager.manager.containerSecurityContext
| nindent 8 }}
volumeMounts:
- mountPath: /controller_manager_config.yaml
name: manager-config
Expand Down
11 changes: 11 additions & 0 deletions examples/operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ controllerManager:
repository: gcr.io/kubebuilder/kube-rbac-proxy
tag: v0.8.0
manager:
containerSecurityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 65532
seccompProfile:
type: RuntimeDefault
env:
var2: ciao
var3MyEnv: ciao
Expand Down
3 changes: 3 additions & 0 deletions pkg/processor/deployment/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ func (d deployment) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstr
imagePullSecrets.ProcessSpecMap(specMap, &values)
}

securityContext.ProcessContainerSecurityContext(nameCamel, specMap, &values)

// process nodeSelector if presented:
if len(depl.Spec.Template.Spec.NodeSelector) != 0 {
err = unstructured.SetNestedField(specMap, fmt.Sprintf(`{{- toYaml .Values.%s.nodeSelector | nindent 8 }}`, nameCamel), "nodeSelector")
Expand All @@ -179,6 +181,7 @@ func (d deployment) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstr
if err != nil {
return true, nil, err
}

spec = strings.ReplaceAll(spec, "'", "")

return true, &result{
Expand Down
1 change: 0 additions & 1 deletion pkg/processor/imagePullSecrets/imagePullSecrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,4 @@ func ProcessSpecMap(specMap map[string]interface{}, values *helmify.Values) {
specMap["imagePullSecrets"] = helmExpression
(*values)["imagePullSecrets"] = []string{}
}

}
40 changes: 40 additions & 0 deletions pkg/processor/security-context/container_security_context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package security_context

import (
"fmt"

"github.com/arttor/helmify/pkg/helmify"
"github.com/iancoleman/strcase"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

const (
sc = "securityContext"
cscValueName = "containerSecurityContext"
helmTemplate = "{{- toYaml .Values.%[1]s.%[2]s.containerSecurityContext | nindent 8 }}"
)

// ProcessContainerSecurityContext adds 'securityContext' to the podSpec in specMap, if it doesn't have one already defined.
func ProcessContainerSecurityContext(nameCamel string, specMap map[string]interface{}, values *helmify.Values) {
if _, defined := specMap["containers"]; defined {
containers, _, _ := unstructured.NestedSlice(specMap, "containers")
for _, container := range containers {
castedContainer := container.(map[string]interface{})
containerName := strcase.ToLowerCamel(castedContainer["name"].(string))
if _, defined2 := castedContainer["securityContext"]; defined2 {
setSecContextValue(nameCamel, containerName, castedContainer, values)
}
}
unstructured.SetNestedSlice(specMap, containers, "containers")
}
}

func setSecContextValue(resourceName string, containerName string, castedContainer map[string]interface{}, values *helmify.Values) {
if castedContainer["securityContext"] != nil {
unstructured.SetNestedField(*values, castedContainer["securityContext"], resourceName, containerName, cscValueName)

valueString := fmt.Sprintf(helmTemplate, resourceName, containerName)

unstructured.SetNestedField(castedContainer, valueString, sc)
}
}
147 changes: 147 additions & 0 deletions pkg/processor/security-context/container_security_context_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package security_context

import (
"testing"

"github.com/arttor/helmify/pkg/helmify"
"github.com/stretchr/testify/assert"
)

func TestProcessContainerSecurityContext(t *testing.T) {
type args struct {
nameCamel string
specMap map[string]interface{}
values *helmify.Values
}
tests := []struct {
name string
args args
want *helmify.Values
}{
{
name: "test with empty specMap",
args: args{
nameCamel: "someResourceName",
specMap: map[string]interface{}{},
values: &helmify.Values{},
},
want: &helmify.Values{},
},
{
name: "test with single container",
args: args{
nameCamel: "someResourceName",
specMap: map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "SomeContainerName",
"securityContext": map[string]interface{}{
"privileged": true,
},
},
},
},
values: &helmify.Values{},
},
want: &helmify.Values{
"someResourceName": map[string]interface{}{
"someContainerName": map[string]interface{}{
"containerSecurityContext": map[string]interface{}{
"privileged": true,
},
},
},
},
},
{
name: "test with multiple containers",
args: args{
nameCamel: "someResourceName",
specMap: map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "FirstContainer",
"securityContext": map[string]interface{}{
"privileged": true,
},
},
map[string]interface{}{
"name": "SecondContainer",
"securityContext": map[string]interface{}{
"allowPrivilegeEscalation": true,
},
},
},
},
values: &helmify.Values{},
},
want: &helmify.Values{
"someResourceName": map[string]interface{}{
"firstContainer": map[string]interface{}{
"containerSecurityContext": map[string]interface{}{
"privileged": true,
},
},
"secondContainer": map[string]interface{}{
"containerSecurityContext": map[string]interface{}{
"allowPrivilegeEscalation": true,
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ProcessContainerSecurityContext(tt.args.nameCamel, tt.args.specMap, tt.args.values)
assert.Equal(t, tt.want, tt.args.values)
})
}
}

func Test_setSecContextValue(t *testing.T) {
type args struct {
resourceName string
containerName string
castedContainer map[string]interface{}
values *helmify.Values
fieldName string
useRenderedHelmTemplate bool
}
tests := []struct {
name string
args args
want *helmify.Values
}{
{
name: "simple test with single container and single value",
args: args{
resourceName: "someResource",
containerName: "someContainer",
castedContainer: map[string]interface{}{
"securityContext": map[string]interface{}{
"someField": "someValue",
},
},
values: &helmify.Values{},
fieldName: "someField",
useRenderedHelmTemplate: false,
},
want: &helmify.Values{
"someResource": map[string]interface{}{
"someContainer": map[string]interface{}{
"containerSecurityContext": map[string]interface{}{
"someField": "someValue",
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
setSecContextValue(tt.args.resourceName, tt.args.containerName, tt.args.castedContainer, tt.args.values)
assert.Equal(t, tt.want, tt.args.values)
})
}
}
9 changes: 9 additions & 0 deletions test_data/k8s-operator-kustomize.output
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,15 @@ spec:
memory: 20Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 65532
seccompProfile:
type: RuntimeDefault
securityContext:
runAsNonRoot: true
nodeSelector:
Expand Down

0 comments on commit 8642244

Please sign in to comment.