项目的组件放在`internal/`下
controller(控制器):负责核心业务逻辑的调度和协调,监听 Kubernetes 中 IPBlock 自定义资源的变化,维护和管理其生命周期。
engine(封禁后端):负责封禁命令的实际执行。
notify(通知机制):负责将封禁、解封等事件以多种方式通知给运维人员或其他系统。
trigger(触发器):事件触发中心,负责监听外部告警系统或业务事件(如 Grafana Alert等),并根据 Alert 策略触发相关封禁操作,自动创建 IPBlock CR,且支持自动解封。
policy(封禁策略):定义 IP 封禁的判定规则和执行策略。
### 介绍
封禁后端均被抽象为API,IPBlock-Operator-Plus通过调用API来实现实际的封禁行为。
目前通过`engine/control.py`来实现API,接口列表如下:
| 接口 | 方法 | 说明 | | -------- | ---- | --------------------------------------------- | | /limit | GET | iptables限流接口 | | /unlimit | GET | iptables解限流接口 | | /limits | GET | iptables查看当前限流情况 | | /update | | XDP封禁端口 | | /remove | | XDP解封禁端口 | | /ban | GET | (弃用)可从nginx日志查,返回超过一定次数的IP | | /execute | GET | (弃用)接收IP,对其执行XDP封禁 |
engine支持列表:
- XDP:依赖于[evilsp/xdp_banner: 一个简单的 XDP 小程序,用于 BAN IP](https://github.com/evilsp/xdp_banner)
- iptables:依赖于Linux工具iptables。
规则为 IP 每分钟最多发起10个新连接(可突发20次),否则DROP
```go iptables -A INPUT -s <IP> -p tcp --dport <TARGET_PORT> \ -m state --state NEW \ -m hashlimit --hashlimit 10/min --hashlimit-burst 20 \ --hashlimit-mode srcip --hashlimit-name limit_<IP_REPLACED> \ -j ACCEPT iptables -A INPUT -s <IP> -p tcp --dport <TARGET_PORT> -j DROP
|
扩展开发指南
engine定义了接口,新adapter只需要实现这两个方法即可。
type Adapter interface { Ban(ip string, isParmanent bool, durationSeconds int) (string, error) UnBan(ip string) (string, error) }
|
然后在NewAdapter注册对应的adapter
func NewAdapter(name, gatewayHost string) Adapter { switch name { case "xdp": return &XDPAdapter{GatewayHost: gatewayHost} case "iptables": return &IptablesAdapter{GatewayHost: gatewayHost} default: return &XDPAdapter{GatewayHost: gatewayHost} } }
|
接着在controller.py中要实现对应的API,最后在configmap中engine字段指定对应的adapter名即可。
notify
介绍.
notify支持列表:
扩展开发指南
notify定义了接口,新notify只需要实现这个接口即可。
int Calculate(char e[]) { numStack OPND = InitNumStack(); opStack OPTR = InitOpStack(); PushOp(OPTR, '#');
char ch, op; int a, b, result = 0; int num = 0; int flag = 0;
strcat(e, "#");
for(int i = 0; e[i] != '\0'; i++) { ch = e[i]; if (ch >= '0' && ch <= '9') { num = num * 10 + (ch - '0'); flag = 1; } else { if(flag) { PushNum(OPND, num); num = 0; flag = 0; }
while(getPriority(GetOpTop(OPTR), ch) == '>') { PopOp(OPTR, &op); PopNum(OPND, &b); PopNum(OPND, &a); result = Operate(a, b, op); PushNum(OPND, result); } if (getPriority(GetOpTop(OPTR), ch) == '<') { PushOp(OPTR, ch); } else if (getPriority(GetOpTop(OPTR), ch) == '=') { PopOp(OPTR, &op); } } } PopNum(OPND, &result); return result; }
|
以lark为例,在lark.go中实现两个方法
func NewLarkNotify(webhookURL string, templatePaths map[string]string) (*LarkNotify, error) {}
func (l *LarkNotify) Notify(ctx context.Context, eventType string, vars map[string]string) error {}
|
最后在main.go中watchConfigMap中完善loadNotify。
int main() { char e[MAXSIZE]; char p[MAXSIZE][MAXSIZE]; int count = 0;
printf("输入表达式,每行一个,以\"=\"结束:\n"); while(1) { gets(e); e[strcspn(e,"\n")] = 0;
if(strcmp(e, "=") == 0) { break; }
strcpy(p[count++], e); } printf("计算结果为:\n"); for(int i = 0; i <count; i++) { int result = Calculate(p[i]); printf("%d\n", result); } return 0; }
|
trigger
介绍
trigger支持列表:
- grafana:可以 Grafana Alert 联动,通过 Webhook 进行触发。
扩展开发指南
{0}注意新 trigger 在开发时需要考虑并发问题。具体实现可查看 grafana.go 中的处理逻辑,也可参考核心功能模块开发文档中并发处理的逻辑介绍。
trigger同样定义了接口,新trigger只需要实现接口即可。
go
// Trigger 是封禁事件的触发器接口,Start 启动监听任务,Stop 停止监听任务
type Trigger interface {
Name() string
Start(ctx context.Context) error
Stop(ctx context.Context) error
}
trigger在manager.go中实现了StartAll和StopAll,会启动在configmap中指定的所有trigger。
triggers: # 触发器,目前仅支持 Grafana - name: grafana addr: ":8090" path: "/trigger/grafana" - name: your_trigger other: xxx
|
trigger自定义的配置字段,在main.go中进行配置
type TriggerConfig struct { Name string `yaml:"name"` Addr string `yaml:"addr,omitempty"` Path string `yaml:"path,omitempty"` }
func parseTriggers(yamlStr string) ([]TriggerConfig, error) { var triggers []TriggerConfig err := yaml.Unmarshal([]byte(yamlStr), &triggers) if err != nil { return nil, err } return triggers, nil }
func CreateTriggerByConfig(cfg TriggerConfig, mgr ctrl.Manager) trigger.Trigger { switch cfg.Name { case "grafana": return &trigger.GrafanaTrigger{ Client: mgr.GetClient(), Addr: cfg.Addr, Path: cfg.Path, Debouncer: utils.NewLRUDebouncer(1000, 60*time.Second), IPLocker: utils.NewIPLock(), } default: return nil } }
|
policy支持功能列表:
- whitelist:白名单机制
policy实现比较灵活,下面描述白名单机制的实现流程。
1. 在`policy/watchlist.go`中实现三个函数
```go // 白名单机制 // 单IP白名单 // CIDR白名单 // 标签匹配 type Whitelist struct { ipNets []*net.IPNet // IPNet的指针切片,保存CIDR网段 ips []net.IP // 精确IP白名单 } // 新建白名单 func NewWhitelist(ipList []string) *Whitelist {} // 判断目标IP是否在白名单中 func (w *Whitelist) IsWhitelisted(ip string) bool {} // 打印所有白名单内容 func (w *Whitelist) StringSlice() []string {}
|
在config/loader.go中实现一个LoadWhitelistFromConfigMap,用于加载定义在configmap中的白名单IP。
在main.go的watchConfigMap中来监听白名单的新建和更新情况。