diff --git a/cmd/tetra/debug/dump.go b/cmd/tetra/debug/dump.go index 21e85c0b76c..5d949a28e94 100644 --- a/cmd/tetra/debug/dump.go +++ b/cmd/tetra/debug/dump.go @@ -200,18 +200,20 @@ func PolicyfilterState(fname string) { fmt.Printf("%d: %s\n", polId, strings.Join(ids, ",")) } - fmt.Println("--- CgroupID to PolicyIDs mapping ---") + if data.Cgroup != nil { + fmt.Println("--- CgroupID to PolicyIDs mapping ---") - if len(data.Cgroup) == 0 { - fmt.Printf("(empty)\n") - } + if len(data.Cgroup) == 0 { + fmt.Printf("(empty)\n") + } - for cgIDs, polIds := range data.Cgroup { - ids := make([]string, 0, len(polIds)) - for id := range polIds { - ids = append(ids, strconv.FormatUint(uint64(id), 10)) + for cgIDs, polIds := range data.Cgroup { + ids := make([]string, 0, len(polIds)) + for id := range polIds { + ids = append(ids, strconv.FormatUint(uint64(id), 10)) + } + fmt.Printf("%d: %s\n", cgIDs, strings.Join(ids, ",")) } - fmt.Printf("%d: %s\n", cgIDs, strings.Join(ids, ",")) } } diff --git a/docs/content/en/docs/reference/helm-chart.md b/docs/content/en/docs/reference/helm-chart.md index 14b25b94148..17b7ce67e53 100644 --- a/docs/content/en/docs/reference/helm-chart.md +++ b/docs/content/en/docs/reference/helm-chart.md @@ -79,6 +79,7 @@ To use [the values available](#values), with `helm install` or `helm upgrade`, u | tetragon.enableKeepSensorsOnExit | bool | `false` | Persistent enforcement to allow the enforcement policy to continue running even when its Tetragon process is gone. | | tetragon.enableMsgHandlingLatency | bool | `false` | Enable latency monitoring in message handling | | tetragon.enablePolicyFilter | bool | `true` | Enable policy filter. This is required for K8s namespace and pod-label filtering. | +| tetragon.enablePolicyFilterCgroupMap | bool | `false` | Enable policy filter cgroup map. | | tetragon.enablePolicyFilterDebug | bool | `false` | Enable policy filter debug messages. | | tetragon.enableProcessCred | bool | `false` | Enable Capabilities visibility in exec and kprobe events. | | tetragon.enableProcessNs | bool | `false` | Enable Namespaces visibility in exec and kprobe events. | diff --git a/docs/data/tetragon_flags.yaml b/docs/data/tetragon_flags.yaml index 835f0919802..7a27fa4c60d 100644 --- a/docs/data/tetragon_flags.yaml +++ b/docs/data/tetragon_flags.yaml @@ -69,6 +69,9 @@ options: - name: enable-policy-filter default_value: "false" usage: Enable policy filter code + - name: enable-policy-filter-cgroup-map + default_value: "false" + usage: Enable cgroup mappings for policy filter maps - name: enable-policy-filter-debug default_value: "false" usage: Enable policy filter debug messages diff --git a/install/kubernetes/tetragon/README.md b/install/kubernetes/tetragon/README.md index 7c8c30ac2ff..df4fd283bd2 100644 --- a/install/kubernetes/tetragon/README.md +++ b/install/kubernetes/tetragon/README.md @@ -61,6 +61,7 @@ Helm chart for Tetragon | tetragon.enableKeepSensorsOnExit | bool | `false` | Persistent enforcement to allow the enforcement policy to continue running even when its Tetragon process is gone. | | tetragon.enableMsgHandlingLatency | bool | `false` | Enable latency monitoring in message handling | | tetragon.enablePolicyFilter | bool | `true` | Enable policy filter. This is required for K8s namespace and pod-label filtering. | +| tetragon.enablePolicyFilterCgroupMap | bool | `false` | Enable policy filter cgroup map. | | tetragon.enablePolicyFilterDebug | bool | `false` | Enable policy filter debug messages. | | tetragon.enableProcessCred | bool | `false` | Enable Capabilities visibility in exec and kprobe events. | | tetragon.enableProcessNs | bool | `false` | Enable Namespaces visibility in exec and kprobe events. | diff --git a/install/kubernetes/tetragon/templates/tetragon_configmap.yaml b/install/kubernetes/tetragon/templates/tetragon_configmap.yaml index ce73beb6814..67e93b59a49 100644 --- a/install/kubernetes/tetragon/templates/tetragon_configmap.yaml +++ b/install/kubernetes/tetragon/templates/tetragon_configmap.yaml @@ -59,6 +59,9 @@ data: {{- if .Values.tetragon.enablePolicyFilter }} enable-policy-filter: "true" {{- end }} +{{- if .Values.tetragon.enablePolicyFilterCgroupMap }} + enable-policy-filter-cgroup-map: "true" +{{- end }} {{- if .Values.tetragon.enablePolicyFilterDebug }} enable-policy-filter-debug: "true" {{- end }} diff --git a/install/kubernetes/tetragon/values.yaml b/install/kubernetes/tetragon/values.yaml index f09d11dec2b..90c2c9cc9e6 100644 --- a/install/kubernetes/tetragon/values.yaml +++ b/install/kubernetes/tetragon/values.yaml @@ -193,6 +193,8 @@ tetragon: port: 6060 # -- Enable policy filter. This is required for K8s namespace and pod-label filtering. enablePolicyFilter: True + # -- Enable policy filter cgroup map. + enablePolicyFilterCgroupMap: false # -- Enable policy filter debug messages. enablePolicyFilterDebug: false # -- Enable latency monitoring in message handling diff --git a/pkg/option/config.go b/pkg/option/config.go index 2b57b0f761d..30871885afc 100644 --- a/pkg/option/config.go +++ b/pkg/option/config.go @@ -77,8 +77,9 @@ type config struct { ReleasePinned bool - EnablePolicyFilter bool - EnablePolicyFilterDebug bool + EnablePolicyFilter bool + EnablePolicyFilterCgroupMap bool + EnablePolicyFilterDebug bool EnablePidSetFilter bool diff --git a/pkg/option/flags.go b/pkg/option/flags.go index a2c8117cef9..05a72d0e2a4 100644 --- a/pkg/option/flags.go +++ b/pkg/option/flags.go @@ -81,8 +81,9 @@ const ( KeyReleasePinnedBPF = "release-pinned-bpf" - KeyEnablePolicyFilter = "enable-policy-filter" - KeyEnablePolicyFilterDebug = "enable-policy-filter-debug" + KeyEnablePolicyFilter = "enable-policy-filter" + KeyEnablePolicyFilterCgroupMap = "enable-policy-filter-cgroup-map" + KeyEnablePolicyFilterDebug = "enable-policy-filter-debug" KeyEnablePidSetFilter = "enable-pid-set-filter" @@ -202,6 +203,7 @@ func ReadAndSetFlags() error { Config.ReleasePinned = viper.GetBool(KeyReleasePinnedBPF) Config.EnablePolicyFilter = viper.GetBool(KeyEnablePolicyFilter) + Config.EnablePolicyFilterCgroupMap = viper.GetBool(KeyEnablePolicyFilterCgroupMap) Config.EnablePolicyFilterDebug = viper.GetBool(KeyEnablePolicyFilterDebug) Config.EnableMsgHandlingLatency = viper.GetBool(KeyEnableMsgHandlingLatency) @@ -378,6 +380,7 @@ func AddFlags(flags *pflag.FlagSet) { // Provide option to enable policy filtering. Because the code is new, // this is set to false by default. flags.Bool(KeyEnablePolicyFilter, false, "Enable policy filter code") + flags.Bool(KeyEnablePolicyFilterCgroupMap, false, "Enable cgroup mappings for policy filter maps") flags.Bool(KeyEnablePolicyFilterDebug, false, "Enable policy filter debug messages") // Provide option to enable the pidSet export filters. diff --git a/pkg/policyfilter/k8s_test.go b/pkg/policyfilter/k8s_test.go index 65612c279f9..77a4c169973 100644 --- a/pkg/policyfilter/k8s_test.go +++ b/pkg/policyfilter/k8s_test.go @@ -739,7 +739,7 @@ func TestK8s(t *testing.T) { // testState implements cgFinder ts := newTestState(client) - st, err := newState(log, ts) + st, err := newState(log, ts, true) if err != nil { t.Skipf("failed to initialize policy filter state: %s", err) } diff --git a/pkg/policyfilter/map.go b/pkg/policyfilter/map.go index d8d2702e724..cd4bfd1bdd1 100644 --- a/pkg/policyfilter/map.go +++ b/pkg/policyfilter/map.go @@ -60,7 +60,7 @@ func openMap(spec *ebpf.CollectionSpec, mapName string, innerMaxEntries uint32) } // newMap returns a new policy filter map. -func newPfMap() (PfMap, error) { +func newPfMap(enableCgroupMap bool) (PfMap, error) { // use the generic kprobe program, to find the policy filter map spec objName, _ := kernels.GenericKprobeObjs() objPath := path.Join(option.Config.HubbleLib, objName) @@ -73,14 +73,23 @@ func newPfMap() (PfMap, error) { if ret.policyMap, err = openMap(spec, MapName, polMapSize); err != nil { return PfMap{}, fmt.Errorf("opening map %s failed: %w", MapName, err) } - if ret.cgroupMap, err = openMap(spec, CgroupMapName, polMaxPolicies); err != nil { - releaseMap(ret.policyMap) - return PfMap{}, fmt.Errorf("opening cgroup map %s failed: %w", MapName, err) + + if enableCgroupMap { + if ret.cgroupMap, err = openMap(spec, CgroupMapName, polMaxPolicies); err != nil { + releaseMap(ret.policyMap) + return PfMap{}, fmt.Errorf("opening cgroup map %s failed: %w", MapName, err) + } } + return ret, nil } func releaseMap(m *ebpf.Map) error { + // this may happen in the case where the cgroup map is not enabled + if m == nil { + return nil + } + if err := m.Close(); err != nil { return err } @@ -111,6 +120,11 @@ func (m polMap) addPolicyIDs(polID PolicyID, cgIDs []CgroupID) error { } func addPolicyIDMapping(m *ebpf.Map, polID PolicyID, cgID CgroupID) error { + // cgroup map does not exist, so nothing to do here + if m == nil { + return nil + } + var id uint32 err := m.Lookup(cgID, &id) if err == nil { // inner map exists @@ -218,6 +232,11 @@ func getMapSize(m *ebpf.Map) (uint32, error) { } func (m PfMap) deletePolicyIDInCgroupMap(polID PolicyID) error { + // cgroup map does not exist, so nothing to do here + if m.cgroupMap == nil { + return nil + } + var key CgroupID var id uint32 @@ -315,9 +334,12 @@ func (m PfMap) readAll() (PfMapDump, error) { return PfMapDump{}, fmt.Errorf("error reading direct map: %w", err) } - r, err := readAll[CgroupID, PolicyID](m.cgroupMap) - if err != nil { - return PfMapDump{}, fmt.Errorf("error reading cgroup map: %w", err) + var r map[CgroupID]map[PolicyID]struct{} + if m.cgroupMap != nil { + r, err = readAll[CgroupID, PolicyID](m.cgroupMap) + if err != nil { + return PfMapDump{}, fmt.Errorf("error reading cgroup map: %w", err) + } } return PfMapDump{Policy: d, Cgroup: r}, nil @@ -362,6 +384,11 @@ func (m polMap) addCgroupIDs(cgIDs []CgroupID) error { // delCgroupIDs delete cgroups ids from the policy map // todo: use batch operations when supported func (m polMap) delCgroupIDs(polID PolicyID, cgIDs []CgroupID) error { + // cgroup map does not exist, so nothing to do here + if m.cgroupMap == nil { + return nil + } + rmRevCgIDs := []CgroupID{} for i, cgID := range cgIDs { if err := m.Inner.Delete(&cgID); err != nil { @@ -425,13 +452,19 @@ func OpenMap(fname string) (PfMap, error) { dir := filepath.Dir(fname) cgroupMapPath := filepath.Join(dir, CgroupMapName) - r, err := ebpf.LoadPinnedMap(cgroupMapPath, &ebpf.LoadPinOptions{ - ReadOnly: true, - }) - if err != nil { - d.Close() - return PfMap{}, err + // check if the cgroup map exists + // the cgroup map may not exist in the case where + // enable-policy-filter-cgroup-map is false + var r *ebpf.Map + if _, err := os.Stat(cgroupMapPath); err == nil { + r, err = ebpf.LoadPinnedMap(cgroupMapPath, &ebpf.LoadPinOptions{ + ReadOnly: true, + }) + if err != nil { + d.Close() + return PfMap{}, err + } } return PfMap{policyMap: d, cgroupMap: r}, err @@ -439,7 +472,9 @@ func OpenMap(fname string) (PfMap, error) { func (m PfMap) Close() { m.policyMap.Close() - m.cgroupMap.Close() + if m.cgroupMap != nil { + m.cgroupMap.Close() + } } func (m PfMap) Dump() (PfMapDump, error) { diff --git a/pkg/policyfilter/map_test.go b/pkg/policyfilter/map_test.go index 33f353d40c6..9538c655ac4 100644 --- a/pkg/policyfilter/map_test.go +++ b/pkg/policyfilter/map_test.go @@ -40,7 +40,7 @@ func TestPfMapOps(t *testing.T) { if !bpffsReady { t.Skip("failed to initialize bpffs") } - pfm, err := newPfMap() + pfm, err := newPfMap(true) require.NoError(t, err) defer pfm.release() diff --git a/pkg/policyfilter/policyfilter.go b/pkg/policyfilter/policyfilter.go index ef83288481f..441a375c81f 100644 --- a/pkg/policyfilter/policyfilter.go +++ b/pkg/policyfilter/policyfilter.go @@ -25,7 +25,7 @@ func GetState() (State, error) { setGlobalPf.Do(func() { if option.Config.EnablePolicyFilter { logger.GetLogger().Info("Enabling policy filtering") - glblState, glblError = New() + glblState, glblError = New(option.Config.EnablePolicyFilterCgroupMap) } else { glblState = &disabled{} glblError = nil @@ -45,7 +45,7 @@ func resetStateOnlyForTesting() { } if option.Config.EnablePolicyFilter { logger.GetLogger().Info("Enabling policy filtering") - glblState, glblError = New() + glblState, glblError = New(true) } else { glblState = &disabled{} glblError = nil diff --git a/pkg/policyfilter/state.go b/pkg/policyfilter/state.go index 9d0ea6e205c..e17aaad5797 100644 --- a/pkg/policyfilter/state.go +++ b/pkg/policyfilter/state.go @@ -269,17 +269,19 @@ type state struct { // allocated resources (namely the bpf map). // //revive:disable:unexported-return -func New() (*state, error) { +func New(enableCgroupMap bool) (*state, error) { log := logger.GetLogger().WithField("subsystem", "policy-filter") return newState( log, &cgfsFinder{fsscan.New(), log}, + enableCgroupMap, ) } func newState( log logrus.FieldLogger, cgidFinder cgidFinder, + enableCgroupMap bool, ) (*state, error) { var err error ret := &state{ @@ -288,7 +290,7 @@ func newState( DebugLogger: logger.NewDebugLogger(log, option.Config.EnablePolicyFilterDebug), } - ret.pfMap, err = newPfMap() + ret.pfMap, err = newPfMap(enableCgroupMap) if err != nil { return nil, err } diff --git a/pkg/policyfilter/state_test.go b/pkg/policyfilter/state_test.go index bc3805702ab..e40a4cc7905 100644 --- a/pkg/policyfilter/state_test.go +++ b/pkg/policyfilter/state_test.go @@ -11,7 +11,7 @@ import ( ) func TestState(t *testing.T) { - s, err := New() + s, err := New(true) if err != nil { t.Skipf("failed to inialize policy filter state: %s", err) }