Skip to content

Commit

Permalink
Add new flag set-read-only-root-filesystem to set readOnlyRootFilesys…
Browse files Browse the repository at this point in the history
…em for EventListener

Add new flag set-read-only-root-filesystem.
Sets container securityContext readOnlyRootFilesystem to true when new flag is set to true

Prior to this it was not possible to set readOnlyRootFilesystem for EventListener container.
Aligns security towards azure aks best practices and industry
  • Loading branch information
kristofferchr committed Jul 2, 2024
1 parent 0681097 commit 1623b5d
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 62 deletions.
20 changes: 11 additions & 9 deletions cmd/controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,16 @@ const (
)

var (
image = flag.String("el-image", elresources.DefaultImage, "The container image for the EventListener Pod.")
port = flag.Int("el-port", elresources.DefaultPort, "The container port for the EventListener to listen on.")
setSecurityContext = flag.Bool("el-security-context", elresources.DefaultSetSecurityContext, "Add a security context to the event listener deployment.")
setEventListenerEvent = flag.String("el-events", elresources.DefaultEventListenerEvent, "Enable events for event listener deployment.")
readTimeOut = flag.Int64("el-readtimeout", elresources.DefaultReadTimeout, "The read timeout for EventListener Server.")
writeTimeOut = flag.Int64("el-writetimeout", elresources.DefaultWriteTimeout, "The write timeout for EventListener Server.")
idleTimeOut = flag.Int64("el-idletimeout", elresources.DefaultIdleTimeout, "The idle timeout for EventListener Server.")
timeOutHandler = flag.Int64("el-timeouthandler", elresources.DefaultTimeOutHandler, "The timeout for Timeout Handler of EventListener Server.")
httpClientReadTimeOut = flag.Int64("el-httpclient-readtimeout", elresources.DefaultHTTPClientReadTimeOut,
image = flag.String("el-image", elresources.DefaultImage, "The container image for the EventListener Pod.")
port = flag.Int("el-port", elresources.DefaultPort, "The container port for the EventListener to listen on.")
setSecurityContext = flag.Bool("el-security-context", elresources.DefaultSetSecurityContext, "Add a security context to the event listener deployment.")
setReadOnlyRootFilesystem = flag.Bool("el-read-only-root-filesystem", elresources.DefaultSetReadOnlyRootFilesystem, "Sets readOnlyRootFilesystem to the provided value for the event listener deployment.")
setEventListenerEvent = flag.String("el-events", elresources.DefaultEventListenerEvent, "Enable events for event listener deployment.")
readTimeOut = flag.Int64("el-readtimeout", elresources.DefaultReadTimeout, "The read timeout for EventListener Server.")
writeTimeOut = flag.Int64("el-writetimeout", elresources.DefaultWriteTimeout, "The write timeout for EventListener Server.")
idleTimeOut = flag.Int64("el-idletimeout", elresources.DefaultIdleTimeout, "The idle timeout for EventListener Server.")
timeOutHandler = flag.Int64("el-timeouthandler", elresources.DefaultTimeOutHandler, "The timeout for Timeout Handler of EventListener Server.")
httpClientReadTimeOut = flag.Int64("el-httpclient-readtimeout", elresources.DefaultHTTPClientReadTimeOut,
"The HTTP Client read timeout for EventListener Server.")
httpClientKeepAlive = flag.Int64("el-httpclient-keep-alive", elresources.DefaultHTTPClientKeepAlive,
"The HTTP Client read timeout for EventListener Server.")
Expand All @@ -71,6 +72,7 @@ func main() {
Image: image,
Port: port,
SetSecurityContext: setSecurityContext,
SetReadOnlyRootFilesystem: setReadOnlyRootFilesystem,
SetEventListenerEvent: setEventListenerEvent,
ReadTimeOut: readTimeOut,
WriteTimeOut: writeTimeOut,
Expand Down
1 change: 1 addition & 0 deletions config/controller.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ spec:
"-el-port",
"8080",
"-el-security-context=true",
"-el-read-only-root-filesystem=true",
"-el-events",
"disable",
"-el-readtimeout",
Expand Down
63 changes: 52 additions & 11 deletions pkg/reconciler/eventlistener/eventlistener_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,10 @@ func makeDeployment(ops ...func(d *appsv1.Deployment)) *appsv1.Deployment {
Drop: []corev1.Capability{"ALL"},
},
// 65532 is the distroless nonroot user ID
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
ReadOnlyRootFilesystem: ptr.Bool(true),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
Expand Down Expand Up @@ -442,9 +443,10 @@ func makeWithPod(ops ...func(d *duckv1.WithPod)) *duckv1.WithPod {
Drop: []corev1.Capability{"ALL"},
},
// 65532 is the distroless nonroot user ID
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
ReadOnlyRootFilesystem: ptr.Bool(true),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
Expand Down Expand Up @@ -593,6 +595,10 @@ func TestReconcile(t *testing.T) {
c.SetSecurityContext = ptr.Bool(false)
})

configWithSetReadOnlyRootFilesystem := resources.MakeConfig(func(c *resources.Config) {
c.SetReadOnlyRootFilesystem = ptr.Bool(false)
})

configWithSetSecurityContext := resources.MakeConfig(func(c *resources.Config) {
c.SetSecurityContext = ptr.Bool(true)
})
Expand Down Expand Up @@ -891,11 +897,30 @@ func TestReconcile(t *testing.T) {
d.Spec.Template.Spec.Containers[0].VolumeMounts = nil
})

deploymentMissingReadOnlyRootFilesystem := makeDeployment(func(d *appsv1.Deployment) {
d.Spec.Template.Spec.SecurityContext = &corev1.PodSecurityContext{
RunAsNonRoot: ptr.Bool(true),
}
d.Spec.Template.Spec.Containers[0].SecurityContext = &corev1.SecurityContext{
AllowPrivilegeEscalation: ptr.Bool(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
RunAsNonRoot: ptr.Bool(true),
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
}
})

deploymentMissingSecurityContext := makeDeployment(func(d *appsv1.Deployment) {
d.Spec.Template.Spec.SecurityContext = &corev1.PodSecurityContext{}
d.Spec.Template.Spec.Containers[0].SecurityContext = &corev1.SecurityContext{
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
ReadOnlyRootFilesystem: ptr.Bool(true),
}
})

Expand All @@ -908,9 +933,10 @@ func TestReconcile(t *testing.T) {
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
RunAsNonRoot: ptr.Bool(true),
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
ReadOnlyRootFilesystem: ptr.Bool(true),
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
Expand Down Expand Up @@ -1371,6 +1397,21 @@ func TestReconcile(t *testing.T) {
Deployments: []*appsv1.Deployment{elDeployment},
Services: []*corev1.Service{elService},
},
}, {
name: "eventlistener with SetReadOnlyRootFilesystem false",
key: reconcileKey,
config: configWithSetReadOnlyRootFilesystem,
startResources: test.Resources{
Namespaces: []*corev1.Namespace{namespaceResource},
EventListeners: []*v1beta1.EventListener{elWithStatus},
Deployments: []*appsv1.Deployment{elDeployment},
},
endResources: test.Resources{
Namespaces: []*corev1.Namespace{namespaceResource},
EventListeners: []*v1beta1.EventListener{elWithStatus},
Deployments: []*appsv1.Deployment{deploymentMissingReadOnlyRootFilesystem}, // ReadOnlyRootFilesystem is not set for container
Services: []*corev1.Service{elService},
},
}, {
name: "eventlistener with SetSecurityContext false",
key: reconcileKey,
Expand Down
14 changes: 9 additions & 5 deletions pkg/reconciler/eventlistener/resources/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ var (
DefaultPort = 8080
// DefaultSetSecurityContext is the SetSecurityContext value used by default.
DefaultSetSecurityContext = true
// DefaultSetReadOnlyRootFilesystem is the SetReadOnlyRootFilesystem value used by default.
DefaultSetReadOnlyRootFilesystem = true
// DefaultEventListenerEvent is the EventListenerEvent value used by default.
DefaultEventListenerEvent = "disable"
// DefaultReadTimeout is the ReadTimeout used by default.
Expand Down Expand Up @@ -63,6 +65,8 @@ type Config struct {
Port *int
// SetSecurityContext defines if the security context is set.
SetSecurityContext *bool
// SetReadOnlyRootFilesystem defines the value for readOnlyRootFilesystem
SetReadOnlyRootFilesystem *bool
// SetEventListenerEvent defines to enable or disable of emitting events for EventListener.
SetEventListenerEvent *string
// ReadTimeOut defines the read timeout for EventListener Server.
Expand Down Expand Up @@ -99,11 +103,11 @@ type ConfigOption func(d *Config)
// It generates a default Config for the EventListener without any flags set and accepts functions for modification.
func MakeConfig(ops ...ConfigOption) *Config {
c := &Config{
Image: &DefaultImage,
Port: &DefaultPort,
SetSecurityContext: &DefaultSetSecurityContext,
SetEventListenerEvent: &DefaultEventListenerEvent,

Image: &DefaultImage,
Port: &DefaultPort,
SetSecurityContext: &DefaultSetSecurityContext,
SetEventListenerEvent: &DefaultEventListenerEvent,
SetReadOnlyRootFilesystem: &DefaultSetReadOnlyRootFilesystem,
ReadTimeOut: &DefaultReadTimeout,
WriteTimeOut: &DefaultWriteTimeout,
IdleTimeOut: &DefaultIdleTimeout,
Expand Down
4 changes: 4 additions & 0 deletions pkg/reconciler/eventlistener/resources/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ func MakeContainer(el *v1beta1.EventListener, configAcc reconcilersource.ConfigA
}
}

if *c.SetReadOnlyRootFilesystem {
containerSecurityContext.ReadOnlyRootFilesystem = ptr.Bool(true)
}

containerSecurityContext.RunAsUser = ptr.Int64(cfg.Defaults.DefaultRunAsUser)
containerSecurityContext.RunAsGroup = ptr.Int64(cfg.Defaults.DefaultRunAsGroup)

Expand Down
49 changes: 28 additions & 21 deletions pkg/reconciler/eventlistener/resources/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,10 @@ func TestContainer(t *testing.T) {
Drop: []corev1.Capability{"ALL"},
},
// 65532 is the distroless nonroot user ID
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
ReadOnlyRootFilesystem: ptr.Bool(true),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
Expand Down Expand Up @@ -166,9 +167,10 @@ func TestContainer(t *testing.T) {
Drop: []corev1.Capability{"ALL"},
},
// 65532 is the distroless nonroot user ID
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
ReadOnlyRootFilesystem: ptr.Bool(true),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
Expand Down Expand Up @@ -219,9 +221,10 @@ func TestContainer(t *testing.T) {
Drop: []corev1.Capability{"ALL"},
},
// 65532 is the distroless nonroot user ID
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
ReadOnlyRootFilesystem: ptr.Bool(true),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
Expand Down Expand Up @@ -281,9 +284,10 @@ func TestContainer(t *testing.T) {
Drop: []corev1.Capability{"ALL"},
},
// 65532 is the distroless nonroot user ID
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
ReadOnlyRootFilesystem: ptr.Bool(true),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
Expand Down Expand Up @@ -344,9 +348,10 @@ func TestContainer(t *testing.T) {
Drop: []corev1.Capability{"ALL"},
},
// 65532 is the distroless nonroot user ID
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
ReadOnlyRootFilesystem: ptr.Bool(true),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
Expand Down Expand Up @@ -407,9 +412,10 @@ func TestContainer(t *testing.T) {
Drop: []corev1.Capability{"ALL"},
},
// 65532 is the distroless nonroot user ID
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
ReadOnlyRootFilesystem: ptr.Bool(true),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
Expand Down Expand Up @@ -471,9 +477,10 @@ func TestContainer(t *testing.T) {
Drop: []corev1.Capability{"ALL"},
},
// 65532 is the distroless nonroot user ID
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
RunAsUser: ptr.Int64(65532),
RunAsGroup: ptr.Int64(65532),
RunAsNonRoot: ptr.Bool(true),
ReadOnlyRootFilesystem: ptr.Bool(true),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
Expand Down
36 changes: 20 additions & 16 deletions pkg/reconciler/eventlistener/resources/custom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,11 @@ func TestCustomObject(t *testing.T) {
"allowPrivilegeEscalation": false,
"capabilities": map[string]interface{}{
"drop": []interface{}{string("ALL")}},
"runAsGroup": int64(65532),
"runAsNonRoot": bool(true),
"runAsUser": int64(65532),
"seccompProfile": map[string]interface{}{"type": string("RuntimeDefault")},
"runAsGroup": int64(65532),
"runAsNonRoot": bool(true),
"readOnlyRootFilesystem": bool(true),
"runAsUser": int64(65532),
"seccompProfile": map[string]interface{}{"type": string("RuntimeDefault")},
},
"resources": map[string]interface{}{},
"readinessProbe": map[string]interface{}{
Expand Down Expand Up @@ -231,10 +232,11 @@ func TestCustomObject(t *testing.T) {
"allowPrivilegeEscalation": false,
"capabilities": map[string]interface{}{
"drop": []interface{}{string("ALL")}},
"runAsGroup": int64(65532),
"runAsNonRoot": bool(true),
"runAsUser": int64(65532),
"seccompProfile": map[string]interface{}{"type": string("RuntimeDefault")},
"runAsGroup": int64(65532),
"runAsNonRoot": bool(true),
"readOnlyRootFilesystem": bool(true),
"runAsUser": int64(65532),
"seccompProfile": map[string]interface{}{"type": string("RuntimeDefault")},
},
"resources": map[string]interface{}{},
"readinessProbe": map[string]interface{}{
Expand Down Expand Up @@ -308,10 +310,11 @@ func TestCustomObject(t *testing.T) {
"allowPrivilegeEscalation": false,
"capabilities": map[string]interface{}{
"drop": []interface{}{string("ALL")}},
"runAsGroup": int64(65532),
"runAsNonRoot": bool(true),
"runAsUser": int64(65532),
"seccompProfile": map[string]interface{}{"type": string("RuntimeDefault")},
"runAsGroup": int64(65532),
"runAsNonRoot": bool(true),
"readOnlyRootFilesystem": bool(true),
"runAsUser": int64(65532),
"seccompProfile": map[string]interface{}{"type": string("RuntimeDefault")},
},
"readinessProbe": map[string]interface{}{
"httpGet": map[string]interface{}{
Expand Down Expand Up @@ -425,10 +428,11 @@ func TestCustomObject(t *testing.T) {
"allowPrivilegeEscalation": false,
"capabilities": map[string]interface{}{
"drop": []interface{}{string("ALL")}},
"runAsGroup": int64(65532),
"runAsNonRoot": bool(true),
"runAsUser": int64(65532),
"seccompProfile": map[string]interface{}{"type": string("RuntimeDefault")},
"runAsGroup": int64(65532),
"runAsNonRoot": bool(true),
"readOnlyRootFilesystem": bool(true),
"runAsUser": int64(65532),
"seccompProfile": map[string]interface{}{"type": string("RuntimeDefault")},
},
"readinessProbe": map[string]interface{}{
"httpGet": map[string]interface{}{
Expand Down

0 comments on commit 1623b5d

Please sign in to comment.