Commit b4061e3b authored by qiuqunfeng's avatar qiuqunfeng
Browse files

Add CRUD operations for Black/White List management in WAF service

- Implement Create, Update, Enable, Delete, and Get methods for managing Black/White Lists
- Introduce new routes in the WAF router for handling Black/White List operations
- Update service and model layers to support new functionality
- Refactor cluster client management to accommodate new Kubernetes client structure
parent 11009cf4
......@@ -27,4 +27,9 @@ func SetWafRouter(e *gin.Engine, clusterClientManager *utils.ClusterClientManage
v2.GET("attack/log/list", wafController.ListAttackLogs)
v2.GET("rules", wafController.ListRules)
v2.PUT("rules", wafController.UpdateRule)
v2.POST("blackwhitelist", wafController.CreateBlackWhiteList)
v2.PUT("blackwhitelist", wafController.UpdateBlackWhiteList)
v2.PUT("blackwhitelist/enabling", wafController.EnableBlackWhiteList)
v2.DELETE("blackwhitelist/{id}", wafController.DeleteBlackWhiteList)
v2.GET("blackwhitelists", wafController.GetBlackWhiteLists)
}
......@@ -12,10 +12,8 @@ import (
"gitlab.com/tensorsecurity-rd/waf-console/internal/service"
es "gitlab.com/tensorsecurity-rd/waf-console/internal/store"
"gitlab.com/tensorsecurity-rd/waf-console/internal/utils"
"gitlab.com/tensorsecurity-rd/waf-console/pkg/generated/clientset/versioned"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"k8s.io/client-go/rest"
)
func NewRootCommand() *cobra.Command {
......@@ -67,17 +65,19 @@ func NewRootCommand() *cobra.Command {
panic(err)
}
}
client := versioned.NewForConfigOrDie(&rest.Config{
Host: regionConfig.ApiServer,
TLSClientConfig: rest.TLSClientConfig{
Insecure: regionConfig.Insecure,
CAData: caData,
CertData: clientCertData,
KeyData: clientKeyData,
},
// BearerToken: "1234567890",
})
clusterClientManager.AddClient(regionConfig.RegionCode, client)
kubeClient := utils.NewKubeClient(regionConfig.ApiServer, caData, clientCertData, clientKeyData, regionConfig.Insecure)
// client := versioned.NewForConfigOrDie(&rest.Config{
// Host: regionConfig.ApiServer,
// TLSClientConfig: rest.TLSClientConfig{
// Insecure: regionConfig.Insecure,
// CAData: caData,
// CertData: clientCertData,
// KeyData: clientKeyData,
// },
// })
clusterClientManager.AddClient(regionConfig.RegionCode, kubeClient)
}
esClient, err := es.CreateEsClientFromEnv()
......
......@@ -45,7 +45,7 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.27.2 // indirect
k8s.io/api v0.27.2
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c // indirect
k8s.io/klog/v2 v2.90.1 // indirect
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
......
......@@ -356,3 +356,44 @@ func getLimitAndOffset(ctx *gin.Context) (int, int, error) {
return limit, offset, nil
}
func (c *WafController) CreateBlackWhiteList(ctx *gin.Context) {
ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
var req service.MatcherExpr
if err := ctx.BindJSON(&req); err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
err := c.service.CreateBlackWhiteList(ctx1, &req)
if err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
utils.AssembleResponse(ctx, nil, nil)
}
func (c *WafController) UpdateBlackWhiteList(ctx *gin.Context) {
// ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// defer cancel()
}
func (c *WafController) EnableBlackWhiteList(ctx *gin.Context) {
// ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// defer cancel()
}
func (c *WafController) DeleteBlackWhiteList(ctx *gin.Context) {
// ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// defer cancel()
}
func (c *WafController) GetBlackWhiteLists(ctx *gin.Context) {
// ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// defer cancel()
}
......@@ -3,6 +3,7 @@ package model
import (
"database/sql/driver"
"encoding/json"
"errors"
"github.com/rs/zerolog/log"
)
......@@ -48,7 +49,7 @@ const (
)
type WafService struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement"`
ID uint32 `gorm:"column:id;primaryKey;autoIncrement"`
GatewayName string `gorm:"column:gateway_name"`
Namespace string `gorm:"column:namespace"`
RegionCode string `gorm:"column:region_code"`
......@@ -130,3 +131,31 @@ type GatewayListener struct {
func (GatewayListener) TableName() string {
return "gateway_listeners"
}
type IntSlice []uint32
func (sl *IntSlice) Scan(value interface{}) error {
b, ok := value.([]byte)
if !ok {
return errors.New("type assertion to []byte failed")
}
return json.Unmarshal(b, &sl)
}
func (sl IntSlice) Value() (driver.Value, error) {
data, err := json.Marshal(sl)
return data, err
}
type MatcherExpr struct {
ID uint32 `gorm:"column:id;primaryKey;autoIncrement"`
Name string `gorm:"column:name"`
Scope IntSlice `gorm:"column:scope"`
Mode string `gorm:"column:mode"`
Expr string `gorm:"column:expr"`
Global bool `gorm:"column:global"`
Status int `gorm:"column:status"`
}
func (MatcherExpr) TableName() string {
return "waf_blackwhitelists"
}
......@@ -17,4 +17,9 @@ type Service interface {
EnableListenerWafs(ctx context.Context, req *EnableListenerWafsReq) error
ListAttackLogs(ctx context.Context, req *AttackLogFilter) ([]AttackLog, string, error)
ListRules(ctx context.Context, regionCode, namespace, gatewayName, language, name string) ([]RuleGroupResp, error)
CreateBlackWhiteList(ctx context.Context, req *MatcherExpr) error
UpdateBlackWhiteList(ctx context.Context, req *MatcherExpr) error
EnableBlackWhiteList(ctx context.Context, req *MatcherExpr) error
DeleteBlackWhiteList(ctx context.Context, req *MatcherExpr) error
GetBlackWhiteLists(ctx context.Context, req *MatcherExpr) ([]MatcherExpr, error)
}
......@@ -352,3 +352,14 @@ type AttackLogFilter struct {
StartTime int64 `json:"start_time"`
EndTime int64 `json:"end_time"`
}
type MatcherExpr struct {
ID uint32 `json:"id"`
Name string `json:"name,omitempty"`
Scope []uint32 `json:"scope,omitempty"`
ScopeName []string `json:"scope_name,omitempty"`
Mode string `json:"mode,omitempty"`
Expr string `json:"expr,omitempty"`
Global bool `json:"global"`
Status int32 `json:"status"`
}
......@@ -21,6 +21,7 @@ import (
"gitlab.com/tensorsecurity-rd/waf-console/internal/utils"
"gitlab.com/tensorsecurity-rd/waf-console/pkg/apis/waf.security.io/v1alpha1"
"gorm.io/gorm"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
)
......@@ -237,7 +238,7 @@ func (s *wafService) CreateWaf(ctx context.Context, req *CreateWafReq) (*WafServ
if client == nil {
return nil, fmt.Errorf("failed to get cluster client for region %s", req.RegionCode)
}
if _, err := client.WafV1alpha1().Services(req.Namespace).Create(ctx, service, metav1.CreateOptions{}); err != nil {
if _, err := client.Versioned.WafV1alpha1().Services(req.Namespace).Create(ctx, service, metav1.CreateOptions{}); err != nil {
return nil, fmt.Errorf("failed to create WAF service: %v", err)
}
......@@ -255,7 +256,7 @@ func (s *wafService) DeleteListenerWaf(ctx context.Context, req *DeleteListenerR
return fmt.Errorf("failed to get cluster client for region %s", req.RegionCode)
}
name := fmt.Sprintf("%s-%d", req.GatewayName, req.Port)
if err := client.WafV1alpha1().Services(req.Namespace).Delete(ctx, name, metav1.DeleteOptions{}); err != nil {
if err := client.Versioned.WafV1alpha1().Services(req.Namespace).Delete(ctx, name, metav1.DeleteOptions{}); err != nil {
return fmt.Errorf("failed to delete WAF service: %v", err)
}
return nil
......@@ -291,7 +292,7 @@ func (s *wafService) UpdateMode(ctx context.Context, req *UpdateModeReq) (*WafSe
if client == nil {
return nil, fmt.Errorf("failed to get cluster client for region %s", req.RegionCode)
}
listenerList, err := client.WafV1alpha1().Services(req.Namespace).List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("apigateway_name=%s", req.GatewayName)})
listenerList, err := client.Versioned.WafV1alpha1().Services(req.Namespace).List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("apigateway_name=%s", req.GatewayName)})
if err != nil {
return nil, fmt.Errorf("failed to get listener list: %v", err)
}
......@@ -303,7 +304,7 @@ func (s *wafService) UpdateMode(ctx context.Context, req *UpdateModeReq) (*WafSe
go func() {
defer wg.Done()
log.Info().Msgf("update WAF service mode: %v", listener.Name)
_, err := client.WafV1alpha1().Services(req.Namespace).Update(ctx, &listener, metav1.UpdateOptions{})
_, err := client.Versioned.WafV1alpha1().Services(req.Namespace).Update(ctx, &listener, metav1.UpdateOptions{})
if err != nil {
log.Error().Msgf("failed to update WAF service mode: %v", err)
}
......@@ -548,7 +549,7 @@ func (s *wafService) DeleteGatewayWaf(ctx context.Context, req *GatewateInfo) er
return fmt.Errorf("failed to get cluster client")
}
labelSelector := fmt.Sprintf("apigateway_name=%s", req.GatewayName)
if err := client.WafV1alpha1().Services(req.Namespace).DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: labelSelector}); err != nil {
if err := client.Versioned.WafV1alpha1().Services(req.Namespace).DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: labelSelector}); err != nil {
return fmt.Errorf("failed to delete WAF service: %v", err)
}
return nil
......@@ -594,7 +595,7 @@ func (s *wafService) ListListenerWafStatus(ctx context.Context, req *GatewateInf
return nil, fmt.Errorf("failed to get cluster client")
}
listenerList, err := client.WafV1alpha1().Services(req.Namespace).List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("apigateway_name=%s", req.GatewayName)})
listenerList, err := client.Versioned.WafV1alpha1().Services(req.Namespace).List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("apigateway_name=%s", req.GatewayName)})
if err != nil {
return nil, fmt.Errorf("failed to get listener list: %v", err)
}
......@@ -642,7 +643,7 @@ func (s *wafService) EnableListenerWafs(ctx context.Context, req *EnableListener
return fmt.Errorf("failed to get cluster client")
}
listenerList, err := client.WafV1alpha1().Services(req.Namespace).List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("apigateway_name=%s", req.GatewayName)})
listenerList, err := client.Versioned.WafV1alpha1().Services(req.Namespace).List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("apigateway_name=%s", req.GatewayName)})
if err != nil {
log.Error().Msgf("failed to get listener list: %v", err)
return err
......@@ -921,3 +922,106 @@ func (s *wafService) ListRules(ctx context.Context, regionCode, namespace, gatew
}
return ruleGroupResp, nil
}
func (s *wafService) getWafServiceMap(ctx context.Context, req *MatcherExpr) (map[string][]model.WafService, error) {
svcMap := make(map[string][]model.WafService)
wafServices := []model.WafService{}
if req.Global {
if err := s.db.WithContext(ctx).Model(&model.WafService{}).Find(&wafServices).Error; err != nil {
return nil, err
}
} else {
if err := s.db.WithContext(ctx).Model(&model.WafService{}).Where("id in ?", req.Scope).Find(&wafServices).Error; err != nil {
return nil, err
}
}
for _, wafService := range wafServices {
svcMap[wafService.RegionCode] = append(svcMap[wafService.RegionCode], wafService)
}
return svcMap, nil
}
func (s *wafService) createConfigMap(ctx context.Context, req *MatcherExpr, regionCode string, wafSvc []model.WafService) error {
client := s.clusterClientManager.GetClient(regionCode)
if client == nil {
return fmt.Errorf("failed to get cluster client")
}
gatewayNames := []string{}
for _, wafSvc := range wafSvc {
gatewayNames = append(gatewayNames, wafSvc.GatewayName)
}
scope := strings.Join(gatewayNames, ",")
matchExpr := v1alpha1.MatchExpression{
ID: req.ID,
Name: req.Name,
Scope: scope,
Mode: req.Mode,
Expr: req.Expr,
Status: req.Status,
}
matchExprJson, err := json.Marshal(matchExpr)
if err != nil {
return fmt.Errorf("failed to marshal match expression: %v", err)
}
name := fmt.Sprintf("waf-black-white-list-%d", req.ID)
_, err = client.Clientset.CoreV1().ConfigMaps(wafSvc[0].Namespace).Create(ctx, &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Data: map[string]string{
"match-expression": string(matchExprJson),
},
}, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("failed to create config map: %v", err)
}
return nil
}
func (s *wafService) CreateBlackWhiteList(ctx context.Context, req *MatcherExpr) error {
tErr := s.db.Transaction(func(tx *gorm.DB) error {
matcherExpr := model.MatcherExpr{
Name: req.Name,
Scope: req.Scope,
Mode: req.Mode,
Expr: req.Expr,
Global: req.Global,
}
err := s.db.WithContext(ctx).Create(&matcherExpr).Error
if err != nil {
return err
}
req.ID = matcherExpr.ID
svcMap, err := s.getWafServiceMap(ctx, req)
if err != nil {
return err
}
for regionCode, wafServices := range svcMap {
err := s.createConfigMap(ctx, req, regionCode, wafServices)
if err != nil {
return err
}
}
return nil
})
return tErr
}
func (s *wafService) UpdateBlackWhiteList(ctx context.Context, req *MatcherExpr) error {
return nil
}
func (s *wafService) EnableBlackWhiteList(ctx context.Context, req *MatcherExpr) error {
return nil
}
func (s *wafService) DeleteBlackWhiteList(ctx context.Context, req *MatcherExpr) error {
return nil
}
func (s *wafService) GetBlackWhiteLists(ctx context.Context, req *MatcherExpr) ([]MatcherExpr, error) {
return nil, nil
}
......@@ -4,23 +4,57 @@ import (
"sync"
"gitlab.com/tensorsecurity-rd/waf-console/pkg/generated/clientset/versioned"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
type KubeClient struct {
*kubernetes.Clientset
Versioned *versioned.Clientset
}
func NewKubeClient(apiServer string, caData []byte, clientCertData []byte, clientKeyData []byte, insecure bool) *KubeClient {
versionedClient := versioned.NewForConfigOrDie(&rest.Config{
Host: apiServer,
TLSClientConfig: rest.TLSClientConfig{
Insecure: insecure,
CAData: caData,
CertData: clientCertData,
KeyData: clientKeyData,
},
})
clientset := kubernetes.NewForConfigOrDie(&rest.Config{
Host: apiServer,
TLSClientConfig: rest.TLSClientConfig{
Insecure: insecure,
CAData: caData,
CertData: clientCertData,
KeyData: clientKeyData,
},
})
return &KubeClient{
Clientset: clientset,
Versioned: versionedClient,
}
}
type ClusterClientManager struct {
clients map[string]*versioned.Clientset
clients map[string]*KubeClient
}
func NewClusterClientManager() *ClusterClientManager {
return &ClusterClientManager{
clients: make(map[string]*versioned.Clientset),
clients: make(map[string]*KubeClient),
}
}
func (c *ClusterClientManager) GetClient(regionCode string) *versioned.Clientset {
func (c *ClusterClientManager) GetClient(regionCode string) *KubeClient {
return c.clients[regionCode]
}
func (c *ClusterClientManager) AddClient(regionCode string, client *versioned.Clientset) {
func (c *ClusterClientManager) AddClient(regionCode string, client *KubeClient) {
c.clients[regionCode] = client
}
......@@ -28,19 +62,19 @@ func (c *ClusterClientManager) RemoveClient(regionCode string) {
delete(c.clients, regionCode)
}
func (c *ClusterClientManager) GetAllClients() map[string]*versioned.Clientset {
func (c *ClusterClientManager) GetAllClients() map[string]*KubeClient {
return c.clients
}
func (c *ClusterClientManager) GetClientByRegionCode(regionCode string) *versioned.Clientset {
func (c *ClusterClientManager) GetClientByRegionCode(regionCode string) *KubeClient {
return c.clients[regionCode]
}
func (c *ClusterClientManager) ForEach(fn func(regionCode string, client *versioned.Clientset)) {
func (c *ClusterClientManager) ForEach(fn func(regionCode string, client *KubeClient)) {
wg := sync.WaitGroup{}
for regionCode, client := range c.clients {
wg.Add(1)
go func(regionCode string, client *versioned.Clientset) {
go func(regionCode string, client *KubeClient) {
defer wg.Done()
fn(regionCode, client)
}(regionCode, client)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment