Skip to content

Commit fe86df4

Browse files
authored
feat: add terminateOnSuccess flag to iptables monitor (#3995)
* initial refactor without tests * refactor helper functions * add test * address linter * change bpf map path default since iptables block already exists there * fix cosmetic issue * update readme (noop) * add timeout to context
1 parent 2e10059 commit fe86df4

File tree

4 files changed

+569
-102
lines changed

4 files changed

+569
-102
lines changed

azure-iptables-monitor/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ Follow the steps below to build and run the program:
3333
- The `-events` flag enables Kubernetes event creation for rule violations. Default: `false`
3434
- The `-ipv6` flag enables IPv6 ip6tables monitoring using the IPv6 allowlists. Default: `false`
3535
- The `-checkMap` flag enables checking the pinned bpf map specified in mapPath for increases. Default: `false`
36-
- The `-mapPath` flag specifies the pinned bpf map path to check. Default: `/azure-block-iptables/iptables_block_event_counter`
36+
- The `-mapPath` flag specifies the pinned bpf map path to check. Default: `/azure-block-iptables-bpf-map/iptables_block_event_counter`
37+
- The `-terminateOnSuccess` flag, when set, will exit the program once there are no longer user iptables rules detected. Default: `false`
3738
- The program must be in a k8s environment and `NODE_NAME` must be a set environment variable with the current node.
3839

3940
5. The program will set the `kubernetes.azure.com/user-iptables-rules` label to `true` on the specified ciliumnode resource if unexpected rules are found, or `false` if all rules match expected patterns. Proper RBAC is required for patching (patch for ciliumnodes, create for events, get for nodes).
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package main
2+
3+
import (
4+
"context"
5+
6+
corev1 "k8s.io/api/core/v1"
7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
"k8s.io/apimachinery/pkg/runtime/schema"
9+
"k8s.io/apimachinery/pkg/types"
10+
"k8s.io/client-go/dynamic"
11+
"k8s.io/client-go/kubernetes"
12+
)
13+
14+
// FileLineReader interface for reading lines from files
15+
type FileLineReader interface {
16+
Read(filename string) ([]string, error)
17+
}
18+
19+
// IPTablesClient interface for iptables operations
20+
type IPTablesClient interface {
21+
ListChains(table string) ([]string, error)
22+
List(table, chain string) ([]string, error)
23+
}
24+
25+
// KubeClient interface with direct methods for testing
26+
type KubeClient interface {
27+
GetNode(ctx context.Context, name string) (*corev1.Node, error)
28+
CreateEvent(ctx context.Context, namespace string, event *corev1.Event) (*corev1.Event, error)
29+
}
30+
31+
// DynamicClient interface with direct method for testing
32+
type DynamicClient interface {
33+
PatchResource(ctx context.Context, gvr schema.GroupVersionResource, name string, patchType types.PatchType, data []byte) error
34+
}
35+
36+
// EBPFClient interface for eBPF operations
37+
type EBPFClient interface {
38+
GetBPFMapValue(pinPath string) (uint64, error)
39+
}
40+
41+
// Dependencies struct holds all external dependencies
42+
type Dependencies struct {
43+
KubeClient KubeClient
44+
DynamicClient DynamicClient
45+
IPTablesV4 IPTablesClient
46+
IPTablesV6 IPTablesClient
47+
EBPFClient EBPFClient
48+
FileReader FileLineReader
49+
}
50+
51+
// Config struct holds runtime configuration
52+
type Config struct {
53+
ConfigPath4 string
54+
ConfigPath6 string
55+
CheckInterval int
56+
SendEvents bool
57+
IPv6Enabled bool
58+
CheckMap bool
59+
PinPath string
60+
NodeName string
61+
TerminateOnSuccess bool
62+
}
63+
64+
// Implementation types that wrap real k8s clients
65+
66+
// realKubeClient wraps kubernetes.Interface to implement our KubeClient interface
67+
type realKubeClient struct {
68+
client kubernetes.Interface
69+
}
70+
71+
func NewKubeClient(client kubernetes.Interface) KubeClient {
72+
return &realKubeClient{client: client}
73+
}
74+
75+
func (k *realKubeClient) GetNode(ctx context.Context, name string) (*corev1.Node, error) {
76+
return k.client.CoreV1().Nodes().Get(ctx, name, metav1.GetOptions{}) // nolint
77+
}
78+
79+
func (k *realKubeClient) CreateEvent(ctx context.Context, namespace string, event *corev1.Event) (*corev1.Event, error) {
80+
return k.client.CoreV1().Events(namespace).Create(ctx, event, metav1.CreateOptions{}) // nolint
81+
}
82+
83+
// realDynamicClient wraps dynamic.Interface
84+
type realDynamicClient struct {
85+
client dynamic.Interface
86+
}
87+
88+
func NewDynamicClient(client dynamic.Interface) DynamicClient {
89+
return &realDynamicClient{client: client}
90+
}
91+
92+
func (d *realDynamicClient) PatchResource(ctx context.Context, gvr schema.GroupVersionResource, name string, patchType types.PatchType, data []byte) error {
93+
_, err := d.client.Resource(gvr).Patch(ctx, name, patchType, data, metav1.PatchOptions{})
94+
return err // nolint
95+
}

0 commit comments

Comments
 (0)