yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/waf_domain.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package aliyun
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"yunion.io/x/jsonutils"
    21  	"yunion.io/x/pkg/errors"
    22  
    23  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    24  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    25  	"yunion.io/x/cloudmux/pkg/multicloud"
    26  )
    27  
    28  type SWafDomain struct {
    29  	multicloud.SResourceBase
    30  	AliyunTags
    31  	region *SRegion
    32  
    33  	insId           string
    34  	name            string
    35  	Httptouserip    int           `json:"HttpToUserIp"`
    36  	Httpport        []int         `json:"HttpPort"`
    37  	Isaccessproduct int           `json:"IsAccessProduct"`
    38  	Resourcegroupid string        `json:"ResourceGroupId"`
    39  	Readtime        int           `json:"ReadTime"`
    40  	Sourceips       []string      `json:"SourceIps"`
    41  	Ipfollowstatus  int           `json:"IpFollowStatus"`
    42  	Clustertype     int           `json:"ClusterType"`
    43  	Loadbalancing   int           `json:"LoadBalancing"`
    44  	Cname           string        `json:"Cname"`
    45  	Writetime       int           `json:"WriteTime"`
    46  	HTTP2Port       []interface{} `json:"Http2Port"`
    47  	Version         int           `json:"Version"`
    48  	Httpsredirect   int           `json:"HttpsRedirect"`
    49  	Connectiontime  int           `json:"ConnectionTime"`
    50  	Accesstype      string        `json:"AccessType"`
    51  	Httpsport       []interface{} `json:"HttpsPort"`
    52  }
    53  
    54  func (self *SRegion) DescribeDomain(id, domain string) (*SWafDomain, error) {
    55  	params := map[string]string{
    56  		"RegionId":   self.RegionId,
    57  		"InstanceId": id,
    58  		"Domain":     domain,
    59  	}
    60  	resp, err := self.wafRequest("DescribeDomain", params)
    61  	if err != nil {
    62  		return nil, errors.Wrapf(err, "DescribeDomain")
    63  	}
    64  	ret := &SWafDomain{region: self, name: domain, insId: id}
    65  	err = resp.Unmarshal(ret, "Domain")
    66  	if err != nil {
    67  		return nil, errors.Wrapf(err, "resp.Unmarshal")
    68  	}
    69  	return ret, nil
    70  }
    71  
    72  func (self *SRegion) DeleteDomain(id, domain string) error {
    73  	params := map[string]string{
    74  		"RegionId":   self.RegionId,
    75  		"InstanceId": id,
    76  		"Domain":     domain,
    77  	}
    78  	_, err := self.wafRequest("DeleteDomain", params)
    79  	return errors.Wrapf(err, "DeleteDomain")
    80  }
    81  
    82  func (self *SRegion) DescribeDomainNames(id string) ([]string, error) {
    83  	params := map[string]string{
    84  		"RegionId":   self.RegionId,
    85  		"InstanceId": id,
    86  	}
    87  	resp, err := self.wafRequest("DescribeDomainNames", params)
    88  	if err != nil {
    89  		return nil, errors.Wrapf(err, "DescribeDomainNames")
    90  	}
    91  	domains := []string{}
    92  	err = resp.Unmarshal(&domains, "DomainNames")
    93  	return domains, errors.Wrapf(err, "resp.Unmarshal")
    94  }
    95  
    96  func (self *SRegion) SetDomainRuleGroup(insId, domain, ruleGroupId string) error {
    97  	params := map[string]string{
    98  		"RegionId":    self.RegionId,
    99  		"InstanceId":  insId,
   100  		"Domains":     domain,
   101  		"RuleGroupId": ruleGroupId,
   102  	}
   103  	_, err := self.wafRequest("SetDomainRuleGroup", params)
   104  	return err
   105  }
   106  
   107  func (self *SRegion) DescribeDomainRuleGroup(insId, domain string) (string, error) {
   108  	params := map[string]string{
   109  		"RegionId":   self.RegionId,
   110  		"InstanceId": insId,
   111  		"Domain":     domain,
   112  	}
   113  	resp, err := self.wafRequest("DescribeDomainRuleGroup", params)
   114  	if err != nil {
   115  		return "", errors.Wrapf(err, "DescribeDomainRuleGroup")
   116  	}
   117  	return resp.GetString("RuleGroupId")
   118  }
   119  
   120  func (self *SRegion) GetICloudWafInstances() ([]cloudprovider.ICloudWafInstance, error) {
   121  	ins, err := self.DescribeInstanceSpecInfo()
   122  	if err != nil {
   123  		if errors.Cause(err) == cloudprovider.ErrNotFound {
   124  			return []cloudprovider.ICloudWafInstance{}, nil
   125  		}
   126  		return nil, errors.Wrapf(err, "DescribeInstanceSpecInfo")
   127  	}
   128  	domains, err := self.DescribeDomainNames(ins.InstanceId)
   129  	if err != nil {
   130  		return nil, errors.Wrapf(err, "DescribeDomainNames")
   131  	}
   132  	ret := []cloudprovider.ICloudWafInstance{}
   133  	for i := range domains {
   134  		domain, err := self.DescribeDomain(ins.InstanceId, domains[i])
   135  		if err != nil {
   136  			return nil, errors.Wrapf(err, "DescribeDomain %s", domains[i])
   137  		}
   138  		domain.region = self
   139  		domain.insId = ins.InstanceId
   140  		domain.name = domains[i]
   141  		ret = append(ret, domain)
   142  	}
   143  	return ret, nil
   144  }
   145  
   146  func (self *SRegion) GetICloudWafInstanceById(id string) (cloudprovider.ICloudWafInstance, error) {
   147  	ins, err := self.DescribeInstanceSpecInfo()
   148  	if err != nil {
   149  		return nil, errors.Wrapf(err, "DescribeInstanceSpecInfo")
   150  	}
   151  	return self.DescribeDomain(ins.InstanceId, id)
   152  }
   153  
   154  func (self *SWafDomain) GetId() string {
   155  	return self.name
   156  }
   157  
   158  func (self *SWafDomain) GetStatus() string {
   159  	return api.WAF_STATUS_AVAILABLE
   160  }
   161  
   162  func (self *SWafDomain) GetWafType() cloudprovider.TWafType {
   163  	return cloudprovider.WafTypeDefault
   164  }
   165  
   166  func (self *SWafDomain) GetEnabled() bool {
   167  	return true
   168  }
   169  
   170  func (self *SWafDomain) GetName() string {
   171  	return self.name
   172  }
   173  
   174  func (self *SWafDomain) GetGlobalId() string {
   175  	return self.name
   176  }
   177  
   178  func (self *SWafDomain) Delete() error {
   179  	return self.region.DeleteDomain(self.insId, self.name)
   180  }
   181  
   182  func (self *SWafDomain) GetDefaultAction() *cloudprovider.DefaultAction {
   183  	return &cloudprovider.DefaultAction{
   184  		Action:        cloudprovider.WafActionAllow,
   185  		InsertHeaders: map[string]string{},
   186  	}
   187  }
   188  
   189  type ManagedRuleGroup struct {
   190  	waf *SWafDomain
   191  
   192  	insId       string
   193  	domain      string
   194  	ruleGroupId string
   195  }
   196  
   197  func (self *ManagedRuleGroup) GetName() string {
   198  	return "RuleGroup"
   199  }
   200  
   201  func (self *ManagedRuleGroup) GetDesc() string {
   202  	return "规则组"
   203  }
   204  
   205  func (self *ManagedRuleGroup) GetGlobalId() string {
   206  	return fmt.Sprintf("%s-%s", self.insId, self.domain)
   207  }
   208  
   209  func (self *ManagedRuleGroup) GetPriority() int {
   210  	return 0
   211  }
   212  
   213  func (self *ManagedRuleGroup) GetAction() *cloudprovider.DefaultAction {
   214  	return nil
   215  }
   216  
   217  func (self *ManagedRuleGroup) Delete() error {
   218  	return cloudprovider.ErrNotSupported
   219  }
   220  
   221  func (self *ManagedRuleGroup) Update(opts *cloudprovider.SWafRule) error {
   222  	for _, statement := range opts.Statements {
   223  		if len(statement.RuleGroupId) == 0 {
   224  			return self.waf.region.SetDomainRuleGroup(self.insId, self.domain, statement.RuleGroupId)
   225  		} else if len(statement.ManagedRuleGroupName) > 0 {
   226  			switch statement.ManagedRuleGroupName {
   227  			case "严格规则":
   228  				return self.waf.region.SetDomainRuleGroup(self.insId, self.domain, "1011")
   229  			case "中等规则":
   230  				return self.waf.region.SetDomainRuleGroup(self.insId, self.domain, "1012")
   231  			case "宽松规则":
   232  				return self.waf.region.SetDomainRuleGroup(self.insId, self.domain, "1013")
   233  			}
   234  		}
   235  	}
   236  	return nil
   237  }
   238  
   239  func (self *ManagedRuleGroup) GetStatementCondition() cloudprovider.TWafStatementCondition {
   240  	return cloudprovider.WafStatementConditionNone
   241  }
   242  
   243  func (self *ManagedRuleGroup) GetStatements() ([]cloudprovider.SWafStatement, error) {
   244  	groupName := self.ruleGroupId
   245  	switch self.ruleGroupId {
   246  	case "1011":
   247  		groupName = "严格规则"
   248  	case "1012":
   249  		groupName = "中等规则"
   250  	case "1013":
   251  		groupName = "宽松规则"
   252  	}
   253  	return []cloudprovider.SWafStatement{
   254  		cloudprovider.SWafStatement{
   255  			ManagedRuleGroupName: groupName,
   256  			RuleGroupId:          self.ruleGroupId,
   257  		},
   258  	}, nil
   259  }
   260  
   261  type SDefenseTypeRule struct {
   262  	insId       string
   263  	domain      string
   264  	defenseType string
   265  	action      cloudprovider.TWafAction
   266  }
   267  
   268  func (self *SDefenseTypeRule) GetName() string {
   269  	switch self.defenseType {
   270  	case "waf":
   271  		return "正则防护引擎"
   272  	case "dld":
   273  		return "大数据深度学习引擎"
   274  	case "ac_cc":
   275  		return "CC安全防护"
   276  	case "antifraud":
   277  		return "数据风控"
   278  	case "normalized":
   279  		return "主动防御"
   280  	}
   281  	return self.defenseType
   282  }
   283  
   284  func (self *SDefenseTypeRule) GetDesc() string {
   285  	return ""
   286  }
   287  
   288  func (self *SDefenseTypeRule) GetGlobalId() string {
   289  	return fmt.Sprintf("%s-%s-%s", self.insId, self.domain, self.defenseType)
   290  }
   291  
   292  func (self *SDefenseTypeRule) GetPriority() int {
   293  	return 0
   294  }
   295  
   296  func (self *SDefenseTypeRule) GetAction() *cloudprovider.DefaultAction {
   297  	return &cloudprovider.DefaultAction{
   298  		Action: self.action,
   299  	}
   300  }
   301  
   302  func (self *SDefenseTypeRule) GetStatementCondition() cloudprovider.TWafStatementCondition {
   303  	return cloudprovider.WafStatementConditionNone
   304  }
   305  
   306  func (self *SDefenseTypeRule) GetStatements() ([]cloudprovider.SWafStatement, error) {
   307  	return []cloudprovider.SWafStatement{}, nil
   308  }
   309  
   310  func (self *SDefenseTypeRule) Delete() error {
   311  	return cloudprovider.ErrNotSupported
   312  }
   313  
   314  func (self *SDefenseTypeRule) Update(opts *cloudprovider.SWafRule) error {
   315  	return cloudprovider.ErrNotSupported
   316  }
   317  
   318  func (self *SWafDomain) GetRules() ([]cloudprovider.ICloudWafRule, error) {
   319  	ruleGroupId, err := self.region.DescribeDomainRuleGroup(self.insId, self.name)
   320  	if err != nil {
   321  		return nil, errors.Wrapf(err, "DescribeDomainRuleGroup")
   322  	}
   323  	ret := []cloudprovider.ICloudWafRule{}
   324  	ret = append(ret, &ManagedRuleGroup{
   325  		waf:         self,
   326  		insId:       self.insId,
   327  		domain:      self.name,
   328  		ruleGroupId: ruleGroupId,
   329  	})
   330  	for _, defenseType := range []string{
   331  		"waf",
   332  		"dld",
   333  		"ac_cc",
   334  		"antifraud",
   335  		"normalized",
   336  	} {
   337  		act, _ := self.region.DescribeProtectionModuleMode(self.insId, self.name, defenseType)
   338  		ret = append(ret, &SDefenseTypeRule{
   339  			insId:       self.insId,
   340  			domain:      self.name,
   341  			defenseType: defenseType,
   342  			action:      act,
   343  		})
   344  	}
   345  	return ret, nil
   346  }
   347  
   348  type SIpSegement struct {
   349  	IpV6s string
   350  	Ips   string
   351  }
   352  
   353  func (self *SRegion) DescribeWafSourceIpSegment(insId string) (*SIpSegement, error) {
   354  	params := map[string]string{
   355  		"RegionId":   self.RegionId,
   356  		"InstanceId": insId,
   357  	}
   358  	resp, err := self.wafRequest("DescribeWafSourceIpSegment", params)
   359  	if err != nil {
   360  		return nil, errors.Wrapf(err, "DescribeWafSourceIpSegment")
   361  	}
   362  	ret := &SIpSegement{}
   363  	err = resp.Unmarshal(ret)
   364  	if err != nil {
   365  		return nil, errors.Wrapf(err, "")
   366  	}
   367  	return ret, nil
   368  }
   369  
   370  func (self *SRegion) CreateICloudWafInstance(opts *cloudprovider.WafCreateOptions) (cloudprovider.ICloudWafInstance, error) {
   371  	ins, err := self.DescribeInstanceSpecInfo()
   372  	if err != nil {
   373  		return nil, errors.Wrapf(err, "DescribeInstanceSpecInfo")
   374  	}
   375  	waf, err := self.CreateDomain(ins.InstanceId, opts.Name, opts.SourceIps, opts.CloudResources)
   376  	if err != nil {
   377  		return nil, errors.Wrapf(err, "CreateDomain")
   378  	}
   379  	return waf, nil
   380  }
   381  
   382  func (self *SRegion) CreateDomain(insId, domain string, sourceIps []string, cloudResources []cloudprovider.SCloudResource) (*SWafDomain, error) {
   383  	params := map[string]string{
   384  		"RegionId":        self.RegionId,
   385  		"InstanceId":      insId,
   386  		"Domain":          domain,
   387  		"IsAccessProduct": "0",
   388  		"HttpPort":        `["80"]`,
   389  		"HttpsPort":       `["443"]`,
   390  		"Http2Port":       `["80", "443"]`,
   391  	}
   392  	if len(sourceIps) > 0 {
   393  		params["SourceIps"] = jsonutils.Marshal(sourceIps).String()
   394  		params["AccessType"] = "waf-cloud-dns"
   395  	} else if len(cloudResources) > 0 {
   396  		ins := jsonutils.NewArray()
   397  		for _, res := range cloudResources {
   398  			ins.Add(jsonutils.Marshal(map[string]interface{}{"InstanceId": res.Id, "Port": res.Port}))
   399  		}
   400  		params["CloudNativeInstances"] = ins.String()
   401  		params["AccessType"] = "waf-cloud-native"
   402  	} else {
   403  		return nil, errors.Error("missing source ips")
   404  	}
   405  	_, err := self.wafRequest("CreateDomain", params)
   406  	if err != nil {
   407  		return nil, errors.Wrapf(err, "CreateDomain")
   408  	}
   409  	return self.DescribeDomain(insId, domain)
   410  }
   411  
   412  func (self *SWafDomain) AddRule(opts *cloudprovider.SWafRule) (cloudprovider.ICloudWafRule, error) {
   413  	return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "AddRule")
   414  }
   415  
   416  func (self *SWafDomain) Refresh() error {
   417  	domain, err := self.region.DescribeDomain(self.insId, self.name)
   418  	if err != nil {
   419  		return errors.Wrapf(err, "DescribeDomain")
   420  	}
   421  	return jsonutils.Update(self, domain)
   422  }
   423  
   424  func (self *SWafDomain) GetCloudResources() ([]cloudprovider.SCloudResource, error) {
   425  	ret := []cloudprovider.SCloudResource{}
   426  	if len(self.Cname) > 0 {
   427  		ret = append(ret, cloudprovider.SCloudResource{
   428  			Type:          "cname",
   429  			Name:          "CNAME",
   430  			Id:            self.Cname,
   431  			CanDissociate: false,
   432  		})
   433  	}
   434  	ipseg, err := self.region.DescribeWafSourceIpSegment(self.insId)
   435  	if err == nil {
   436  		ret = append(ret, cloudprovider.SCloudResource{
   437  			Type:          "segment_ipv4",
   438  			Name:          "Segment IPv4",
   439  			Id:            ipseg.Ips,
   440  			CanDissociate: false,
   441  		})
   442  		ret = append(ret, cloudprovider.SCloudResource{
   443  			Type:          "segment_ipv6",
   444  			Name:          "Segment IPv6",
   445  			Id:            ipseg.IpV6s,
   446  			CanDissociate: false,
   447  		})
   448  	}
   449  	return ret, nil
   450  }
   451  
   452  func (self *SRegion) DescribeProtectionModuleMode(insId, domain, defenseType string) (cloudprovider.TWafAction, error) {
   453  	params := map[string]string{
   454  		"RegionId":    self.RegionId,
   455  		"Domain":      domain,
   456  		"InstanceId":  insId,
   457  		"DefenseType": defenseType,
   458  	}
   459  	resp, err := self.wafRequest("DescribeProtectionModuleMode", params)
   460  	if err != nil {
   461  		return cloudprovider.WafActionNone, errors.Wrapf(err, "DescribeProtectionModuleMode %s", defenseType)
   462  	}
   463  	if !resp.Contains("Mode") {
   464  		return cloudprovider.WafActionNone, nil
   465  	}
   466  	mode, _ := resp.Int("Mode")
   467  	switch defenseType {
   468  	case "waf":
   469  		if mode == 0 {
   470  			return cloudprovider.WafActionBlock, nil
   471  		}
   472  		if mode == 1 {
   473  			return cloudprovider.WafActionAlert, nil
   474  		}
   475  	case "dld":
   476  		if mode == 0 {
   477  			return cloudprovider.WafActionAlert, nil
   478  		}
   479  		if mode == 1 {
   480  			return cloudprovider.WafActionBlock, nil
   481  		}
   482  	case "ac_cc":
   483  		if mode == 0 {
   484  			return cloudprovider.WafActionAllow, nil
   485  		}
   486  		if mode == 1 {
   487  			return cloudprovider.WafActionBlock, nil
   488  		}
   489  	case "antifraud":
   490  		if mode == 0 {
   491  			return cloudprovider.WafActionAlert, nil
   492  		}
   493  		if mode == 1 || mode == 2 {
   494  			return cloudprovider.WafActionBlock, nil
   495  		}
   496  	case "normalized":
   497  		if mode == 0 {
   498  			return cloudprovider.WafActionAlert, nil
   499  		}
   500  		if mode == 1 {
   501  			return cloudprovider.WafActionBlock, nil
   502  		}
   503  	}
   504  	return cloudprovider.WafActionNone, nil
   505  }