From 3d4606d439bb068122aa8635e2f7254edecb947e Mon Sep 17 00:00:00 2001 From: Volodymyr Stoiko Date: Mon, 3 Feb 2025 23:38:41 +0200 Subject: [PATCH] Worker component security context refactoring (#1707) * Add new security context config * Fine-grained template for securityContext --------- Co-authored-by: Alon Girmonsky <1990761+alongir@users.noreply.github.com> --- config/configStruct.go | 54 +++++++------- config/configStructs/tapConfig.go | 21 +++++- .../templates/09-worker-daemon-set.yaml | 70 +++++++++++++++++-- helm-chart/values.yaml | 38 ++++++---- 4 files changed, 138 insertions(+), 45 deletions(-) diff --git a/config/configStruct.go b/config/configStruct.go index 7c48b468d..c1cd3c715 100644 --- a/config/configStruct.go +++ b/config/configStruct.go @@ -51,31 +51,35 @@ func CreateDefaultConfig() ConfigStruct { }, }, }, - Capabilities: configStructs.CapabilitiesConfig{ - NetworkCapture: []string{ - // NET_RAW is required to listen the network traffic - "NET_RAW", - // NET_ADMIN is required to listen the network traffic - "NET_ADMIN", - }, - ServiceMeshCapture: []string{ - // SYS_ADMIN is required to read /proc/PID/net/ns + to install eBPF programs (kernel < 5.8) - "SYS_ADMIN", - // SYS_PTRACE is required to set netns to other process + to open libssl.so of other process - "SYS_PTRACE", - // DAC_OVERRIDE is required to read /proc/PID/environ - "DAC_OVERRIDE", - }, - EBPFCapture: []string{ - // SYS_ADMIN is required to read /proc/PID/net/ns + to install eBPF programs (kernel < 5.8) - "SYS_ADMIN", - // SYS_PTRACE is required to set netns to other process + to open libssl.so of other process - "SYS_PTRACE", - // SYS_RESOURCE is required to change rlimits for eBPF - "SYS_RESOURCE", - // IPC_LOCK is required for ebpf perf buffers allocations after some amount of size buffer size: - // https://github.com/kubeshark/tracer/blob/13e24725ba8b98216dd0e553262e6d9c56dce5fa/main.go#L82) - "IPC_LOCK", + SecurityContext: configStructs.SecurityContextConfig{ + Privileged: true, + // Capabilities used only when running in unprivileged mode + Capabilities: configStructs.CapabilitiesConfig{ + NetworkCapture: []string{ + // NET_RAW is required to listen the network traffic + "NET_RAW", + // NET_ADMIN is required to listen the network traffic + "NET_ADMIN", + }, + ServiceMeshCapture: []string{ + // SYS_ADMIN is required to read /proc/PID/net/ns + to install eBPF programs (kernel < 5.8) + "SYS_ADMIN", + // SYS_PTRACE is required to set netns to other process + to open libssl.so of other process + "SYS_PTRACE", + // DAC_OVERRIDE is required to read /proc/PID/environ + "DAC_OVERRIDE", + }, + EBPFCapture: []string{ + // SYS_ADMIN is required to read /proc/PID/net/ns + to install eBPF programs (kernel < 5.8) + "SYS_ADMIN", + // SYS_PTRACE is required to set netns to other process + to open libssl.so of other process + "SYS_PTRACE", + // SYS_RESOURCE is required to change rlimits for eBPF + "SYS_RESOURCE", + // IPC_LOCK is required for ebpf perf buffers allocations after some amount of size buffer size: + // https://github.com/kubeshark/tracer/blob/13e24725ba8b98216dd0e553262e6d9c56dce5fa/main.go#L82) + "IPC_LOCK", + }, }, }, Auth: configStructs.AuthConfig{ diff --git a/config/configStructs/tapConfig.go b/config/configStructs/tapConfig.go index 4bac6e18a..15277497c 100644 --- a/config/configStructs/tapConfig.go +++ b/config/configStructs/tapConfig.go @@ -251,6 +251,25 @@ type PortMapping struct { DIAMETER []uint16 `yaml:"diameter" json:"diameter"` } +type SecurityContextConfig struct { + Privileged bool `yaml:"privileged" json:"privileged" default:"true"` + AppArmorProfile AppArmorProfileConfig `yaml:"appArmorProfile" json:"appArmorProfile"` + SeLinuxOptions SeLinuxOptionsConfig `yaml:"seLinuxOptions" json:"seLinuxOptions"` + Capabilities CapabilitiesConfig `yaml:"capabilities" json:"capabilities"` +} + +type AppArmorProfileConfig struct { + Type string `yaml:"type" json:"type"` + LocalhostProfile string `yaml:"localhostProfile" json:"localhostProfile"` +} + +type SeLinuxOptionsConfig struct { + Level string `yaml:"level" json:"level"` + Role string `yaml:"role" json:"role"` + Type string `yaml:"type" json:"type"` + User string `yaml:"user" json:"user"` +} + type TapConfig struct { Docker DockerConfig `yaml:"docker" json:"docker"` Proxy ProxyConfig `yaml:"proxy" json:"proxy"` @@ -286,7 +305,6 @@ type TapConfig struct { Sentry SentryConfig `yaml:"sentry" json:"sentry"` DefaultFilter string `yaml:"defaultFilter" json:"defaultFilter" default:"!dns and !error"` LiveConfigMapChangesDisabled bool `yaml:"liveConfigMapChangesDisabled" json:"liveConfigMapChangesDisabled" default:"false"` - Capabilities CapabilitiesConfig `yaml:"capabilities" json:"capabilities"` GlobalFilter string `yaml:"globalFilter" json:"globalFilter" default:""` EnabledDissectors []string `yaml:"enabledDissectors" json:"enabledDissectors"` PortMapping PortMapping `yaml:"portMapping" json:"portMapping"` @@ -294,6 +312,7 @@ type TapConfig struct { Metrics MetricsConfig `yaml:"metrics" json:"metrics"` Pprof PprofConfig `yaml:"pprof" json:"pprof"` Misc MiscConfig `yaml:"misc" json:"misc"` + SecurityContext SecurityContextConfig `yaml:"securityContext" json:"securityContext"` } func (config *TapConfig) PodRegex() *regexp.Regexp { diff --git a/helm-chart/templates/09-worker-daemon-set.yaml b/helm-chart/templates/09-worker-daemon-set.yaml index 6fa4098a9..ac0bcb65f 100644 --- a/helm-chart/templates/09-worker-daemon-set.yaml +++ b/helm-chart/templates/09-worker-daemon-set.yaml @@ -129,23 +129,52 @@ spec: memory: {{ .Values.tap.resources.sniffer.requests.memory }} {{ end }} securityContext: + privileged: {{ .Values.tap.securityContext.privileged }} + {{- if not .Values.tap.securityContext.privileged }} + {{- $aaProfile := .Values.tap.securityContext.appArmorProfile }} + {{- $selinuxOpts := .Values.tap.securityContext.seLinuxOptions }} + {{- if or (ne $aaProfile.type "") (ne $aaProfile.localhostProfile "") }} + appArmorProfile: + {{- if ne $aaProfile.type "" }} + type: {{ $aaProfile.type }} + {{- end }} + {{- if ne $aaProfile.localhostProfile "" }} + localhostProfile: {{ $aaProfile.localhostProfile }} + {{- end }} + {{- end }} + {{- if or (ne $selinuxOpts.level "") (ne $selinuxOpts.role "") (ne $selinuxOpts.type "") (ne $selinuxOpts.user "") }} + seLinuxOptions: + {{- if ne $selinuxOpts.level "" }} + level: {{ $selinuxOpts.level }} + {{- end }} + {{- if ne $selinuxOpts.role "" }} + role: {{ $selinuxOpts.role }} + {{- end }} + {{- if ne $selinuxOpts.type "" }} + type: {{ $selinuxOpts.type }} + {{- end }} + {{- if ne $selinuxOpts.user "" }} + user: {{ $selinuxOpts.user }} + {{- end }} + {{- end }} capabilities: add: - {{- range .Values.tap.capabilities.networkCapture }} + {{- range .Values.tap.securityContext.capabilities.networkCapture }} {{ print "- " . }} {{- end }} {{- if .Values.tap.serviceMesh }} - {{- range .Values.tap.capabilities.serviceMeshCapture }} + {{- range .Values.tap.securityContext.capabilities.serviceMeshCapture }} {{ print "- " . }} {{- end }} {{- end }} - {{- if .Values.tap.capabilities.ebpfCapture }} - {{- range .Values.tap.capabilities.ebpfCapture }} + {{- if .Values.tap.securityContext.capabilities.ebpfCapture }} + {{- range .Values.tap.securityContext.capabilities.ebpfCapture }} {{ print "- " . }} {{- end }} {{- end }} drop: - ALL + {{- end }} readinessProbe: periodSeconds: {{ .Values.tap.probes.sniffer.periodSeconds }} failureThreshold: {{ .Values.tap.probes.sniffer.failureThreshold }} @@ -222,16 +251,45 @@ spec: memory: {{ .Values.tap.resources.tracer.requests.memory }} {{ end }} securityContext: + privileged: {{ .Values.tap.securityContext.privileged }} + {{- if not .Values.tap.securityContext.privileged }} + {{- $aaProfile := .Values.tap.securityContext.appArmorProfile }} + {{- $selinuxOpts := .Values.tap.securityContext.seLinuxOptions }} + {{- if or (ne $aaProfile.type "") (ne $aaProfile.localhostProfile "") }} + appArmorProfile: + {{- if ne $aaProfile.type "" }} + type: {{ $aaProfile.type }} + {{- end }} + {{- if ne $aaProfile.localhostProfile "" }} + localhostProfile: {{ $aaProfile.localhostProfile }} + {{- end }} + {{- end }} + {{- if or (ne $selinuxOpts.level "") (ne $selinuxOpts.role "") (ne $selinuxOpts.type "") (ne $selinuxOpts.user "") }} + seLinuxOptions: + {{- if ne $selinuxOpts.level "" }} + level: {{ $selinuxOpts.level }} + {{- end }} + {{- if ne $selinuxOpts.role "" }} + role: {{ $selinuxOpts.role }} + {{- end }} + {{- if ne $selinuxOpts.type "" }} + type: {{ $selinuxOpts.type }} + {{- end }} + {{- if ne $selinuxOpts.user "" }} + user: {{ $selinuxOpts.user }} + {{- end }} + {{- end }} capabilities: add: - {{- range .Values.tap.capabilities.ebpfCapture }} + {{- range .Values.tap.securityContext.capabilities.ebpfCapture }} {{ print "- " . }} {{- end }} - {{- range .Values.tap.capabilities.networkCapture }} + {{- range .Values.tap.securityContext.capabilities.networkCapture }} {{ print "- " . }} {{- end }} drop: - ALL + {{- end }} volumeMounts: - mountPath: /hostproc name: proc diff --git a/helm-chart/values.yaml b/helm-chart/values.yaml index 73aa18a5c..418f29650 100644 --- a/helm-chart/values.yaml +++ b/helm-chart/values.yaml @@ -138,19 +138,6 @@ tap: environment: production defaultFilter: "!dns and !error" liveConfigMapChangesDisabled: false - capabilities: - networkCapture: - - NET_RAW - - NET_ADMIN - serviceMeshCapture: - - SYS_ADMIN - - SYS_PTRACE - - DAC_OVERRIDE - ebpfCapture: - - SYS_ADMIN - - SYS_PTRACE - - SYS_RESOURCE - - IPC_LOCK globalFilter: "" enabledDissectors: - amqp @@ -200,6 +187,29 @@ tap: duplicateTimeframe: 200ms detectDuplicates: false staleTimeoutSeconds: 30 + securityContext: + privileged: true + appArmorProfile: + type: "" + localhostProfile: "" + seLinuxOptions: + level: "" + role: "" + type: "" + user: "" + capabilities: + networkCapture: + - NET_RAW + - NET_ADMIN + serviceMeshCapture: + - SYS_ADMIN + - SYS_PTRACE + - DAC_OVERRIDE + ebpfCapture: + - SYS_ADMIN + - SYS_PTRACE + - SYS_RESOURCE + - IPC_LOCK logs: file: "" grep: "" @@ -209,6 +219,8 @@ pcapdump: maxTime: 1h maxSize: 500MB time: time + debug: false + dest: "" kube: configPath: "" context: ""