yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aws/waf_rules.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 aws
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  
    21  	"github.com/aws/aws-sdk-go/service/wafv2"
    22  
    23  	"yunion.io/x/pkg/errors"
    24  	"yunion.io/x/pkg/utils"
    25  
    26  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    27  )
    28  
    29  type sWafRule struct {
    30  	waf *SWebAcl
    31  	*wafv2.Rule
    32  }
    33  
    34  func (self *sWafRule) GetAction() *cloudprovider.DefaultAction {
    35  	ret := &cloudprovider.DefaultAction{}
    36  	if self.Action == nil {
    37  		ret.Action = cloudprovider.WafActionNone
    38  	} else if self.Action.Allow != nil {
    39  		ret.Action = cloudprovider.WafActionAllow
    40  	} else if self.Action.Block != nil {
    41  		ret.Action = cloudprovider.WafActionBlock
    42  	} else if self.Action.Count != nil {
    43  		ret.Action = cloudprovider.WafActionCount
    44  	}
    45  	return ret
    46  }
    47  
    48  func (self *sWafRule) GetDesc() string {
    49  	return ""
    50  }
    51  
    52  func (self *sWafRule) GetName() string {
    53  	return *self.Rule.Name
    54  }
    55  
    56  func (self *sWafRule) GetGlobalId() string {
    57  	return self.GetName()
    58  }
    59  
    60  func (self *sWafRule) GetPriority() int {
    61  	return int(*self.Rule.Priority)
    62  }
    63  
    64  func (self *sWafRule) Delete() error {
    65  	input := wafv2.UpdateWebACLInput{}
    66  	rules := []*wafv2.Rule{}
    67  	for _, rule := range self.waf.Rules {
    68  		if *rule.Name == *self.Name {
    69  			continue
    70  		}
    71  		rules = append(rules, rule)
    72  	}
    73  	input.SetRules(rules)
    74  	input.SetLockToken(self.waf.LockToken)
    75  	input.SetId(*self.waf.Id)
    76  	input.SetName(*self.waf.Name)
    77  	input.SetScope(self.waf.scope)
    78  	input.SetDescription(*self.waf.Description)
    79  	input.SetDefaultAction(self.waf.DefaultAction)
    80  	input.SetVisibilityConfig(self.waf.WebACL.VisibilityConfig)
    81  	client, err := self.waf.region.getWafClient()
    82  	if err != nil {
    83  		return errors.Wrapf(err, "getWafClient")
    84  	}
    85  	_, err = client.UpdateWebACL(&input)
    86  	return errors.Wrapf(err, "UpdateWebACL")
    87  }
    88  
    89  func (self *sWafRule) Update(opts *cloudprovider.SWafRule) error {
    90  	return cloudprovider.ErrNotImplemented
    91  }
    92  
    93  func (self *sWafRule) GetStatementCondition() cloudprovider.TWafStatementCondition {
    94  	if self.Rule.Statement == nil {
    95  		return cloudprovider.WafStatementConditionNone
    96  	}
    97  	if self.Rule.Statement.AndStatement != nil {
    98  		return cloudprovider.WafStatementConditionAnd
    99  	} else if self.Rule.Statement.OrStatement != nil {
   100  		return cloudprovider.WafStatementConditionOr
   101  	} else if self.Rule.Statement.NotStatement != nil {
   102  		return cloudprovider.WafStatementConditionNot
   103  	}
   104  	return cloudprovider.WafStatementConditionNone
   105  }
   106  
   107  type sWafStatement struct {
   108  	*wafv2.Statement
   109  }
   110  
   111  func (self *sWafStatement) convert() cloudprovider.SWafStatement {
   112  	statement := cloudprovider.SWafStatement{
   113  		Transformations: &cloudprovider.TextTransformations{},
   114  	}
   115  	if self.ByteMatchStatement != nil {
   116  		statement.Type = cloudprovider.WafStatementTypeByteMatch
   117  		if self.ByteMatchStatement.PositionalConstraint != nil {
   118  			operator := strings.ReplaceAll(utils.CamelSplit(*self.ByteMatchStatement.PositionalConstraint, "_"), "_", "")
   119  			if operator == "None" {
   120  				operator = ""
   121  			}
   122  			statement.Operator = cloudprovider.TWafOperator(operator)
   123  		}
   124  		fillStatement(&statement, self.ByteMatchStatement.FieldToMatch)
   125  		statement.SearchString = string(self.ByteMatchStatement.SearchString)
   126  		fillTransformations(&statement, self.ByteMatchStatement.TextTransformations)
   127  	} else if self.GeoMatchStatement != nil {
   128  		statement.Type = cloudprovider.WafStatementTypeGeoMatch
   129  		statement.MatchFieldKey = "CountryCodes"
   130  		values := cloudprovider.TWafMatchFieldValues{}
   131  		for i := range self.GeoMatchStatement.CountryCodes {
   132  			values = append(values, *self.GeoMatchStatement.CountryCodes[i])
   133  		}
   134  		statement.MatchFieldValues = &values
   135  		if self.GeoMatchStatement.ForwardedIPConfig != nil {
   136  			statement.ForwardedIPHeader = *self.GeoMatchStatement.ForwardedIPConfig.HeaderName
   137  		}
   138  	} else if self.IPSetReferenceStatement != nil {
   139  		statement.Type = cloudprovider.WafStatementTypeIPSet
   140  		statement.IPSetId = *self.IPSetReferenceStatement.ARN
   141  		if self.IPSetReferenceStatement.IPSetForwardedIPConfig != nil {
   142  			statement.ForwardedIPHeader = *self.IPSetReferenceStatement.IPSetForwardedIPConfig.HeaderName
   143  		}
   144  	} else if self.ManagedRuleGroupStatement != nil {
   145  		statement.Type = cloudprovider.WafStatementTypeManagedRuleGroup
   146  		statement.ManagedRuleGroupName = *self.ManagedRuleGroupStatement.Name
   147  		fillExcludeRules(&statement, self.ManagedRuleGroupStatement.ExcludedRules)
   148  	} else if self.RateBasedStatement != nil {
   149  		statement.Type = cloudprovider.WafStatementTypeRate
   150  		statement.MatchFieldValues = &cloudprovider.TWafMatchFieldValues{fmt.Sprintf("%d", *self.RateBasedStatement.Limit)}
   151  		if self.RateBasedStatement.ForwardedIPConfig != nil {
   152  			statement.ForwardedIPHeader = *self.RateBasedStatement.ForwardedIPConfig.HeaderName
   153  		}
   154  	} else if self.RegexPatternSetReferenceStatement != nil {
   155  		statement.Type = cloudprovider.WafStatementTypeRegexSet
   156  		statement.RegexSetId = *self.RegexPatternSetReferenceStatement.ARN
   157  		fillStatement(&statement, self.RegexPatternSetReferenceStatement.FieldToMatch)
   158  	} else if self.RuleGroupReferenceStatement != nil {
   159  		statement.Type = cloudprovider.WafStatementTypeRuleGroup
   160  		statement.RuleGroupId = *self.RuleGroupReferenceStatement.ARN
   161  		fillExcludeRules(&statement, self.RuleGroupReferenceStatement.ExcludedRules)
   162  	} else if self.SizeConstraintStatement != nil {
   163  		statement.Type = cloudprovider.WafStatementTypeSize
   164  		statement.Operator = cloudprovider.TWafOperator(*self.SizeConstraintStatement.ComparisonOperator)
   165  		statement.MatchFieldValues = &cloudprovider.TWafMatchFieldValues{fmt.Sprintf("%d", self.SizeConstraintStatement.Size)}
   166  		fillStatement(&statement, self.SizeConstraintStatement.FieldToMatch)
   167  		fillTransformations(&statement, self.SizeConstraintStatement.TextTransformations)
   168  	} else if self.SqliMatchStatement != nil {
   169  		statement.Type = cloudprovider.WafStatementTypeSqliMatch
   170  		fillStatement(&statement, self.SqliMatchStatement.FieldToMatch)
   171  		fillTransformations(&statement, self.SqliMatchStatement.TextTransformations)
   172  	} else if self.XssMatchStatement != nil {
   173  		statement.Type = cloudprovider.WafStatementTypeXssMatch
   174  		fillStatement(&statement, self.XssMatchStatement.FieldToMatch)
   175  		fillTransformations(&statement, self.XssMatchStatement.TextTransformations)
   176  	} else if self.LabelMatchStatement != nil {
   177  		statement.Type = cloudprovider.WafStatementTypeLabelMatch
   178  		if self.LabelMatchStatement.Scope != nil {
   179  			statement.MatchFieldKey = *self.LabelMatchStatement.Scope
   180  		}
   181  		if self.LabelMatchStatement.Key != nil {
   182  			statement.MatchFieldValues = &cloudprovider.TWafMatchFieldValues{*self.LabelMatchStatement.Key}
   183  		}
   184  	} else if self.NotStatement != nil {
   185  		s := &sWafStatement{Statement: self.NotStatement.Statement}
   186  		statement = s.convert()
   187  		statement.Negation = true
   188  	}
   189  	return statement
   190  }
   191  
   192  func fillStatement(statement *cloudprovider.SWafStatement, field *wafv2.FieldToMatch) {
   193  	if field.AllQueryArguments != nil {
   194  		statement.MatchField = cloudprovider.WafMatchFieldQuery
   195  		statement.MatchFieldKey = "AllArguments"
   196  	} else if field.Body != nil {
   197  		statement.MatchField = cloudprovider.WafMatchFieldBody
   198  	} else if field.Method != nil {
   199  		statement.MatchField = cloudprovider.WafMatchFieldMethod
   200  	} else if field.QueryString != nil {
   201  		statement.MatchField = cloudprovider.WafMatchFieldQuery
   202  	} else if field.SingleHeader != nil {
   203  		statement.MatchField = cloudprovider.WafMatchFiledHeader
   204  		statement.MatchFieldKey = *field.SingleHeader.Name
   205  	} else if field.SingleQueryArgument != nil {
   206  		statement.MatchField = cloudprovider.WafMatchFieldQuery
   207  		statement.MatchFieldKey = "SingleArgument"
   208  	} else if field.UriPath != nil {
   209  		statement.MatchField = cloudprovider.WafMatchFiledUriPath
   210  	}
   211  }
   212  
   213  func fillTransformations(statement *cloudprovider.SWafStatement, trans []*wafv2.TextTransformation) {
   214  	values := cloudprovider.TextTransformations{}
   215  	for _, tran := range trans {
   216  		switch *tran.Type {
   217  		case wafv2.TextTransformationTypeNone:
   218  			values = append(values, cloudprovider.WafTextTransformationNone)
   219  		case wafv2.TextTransformationTypeLowercase:
   220  			values = append(values, cloudprovider.WafTextTransformationLowercase)
   221  		case wafv2.TextTransformationTypeCmdLine:
   222  			values = append(values, cloudprovider.WafTextTransformationCmdLine)
   223  		case wafv2.TextTransformationTypeUrlDecode:
   224  			values = append(values, cloudprovider.WafTextTransformationUrlDecode)
   225  		case wafv2.TextTransformationTypeHtmlEntityDecode:
   226  			values = append(values, cloudprovider.WafTextTransformationHtmlEntityDecode)
   227  		case wafv2.TextTransformationTypeCompressWhiteSpace:
   228  			values = append(values, cloudprovider.WafTextTransformationCompressWithSpace)
   229  		default:
   230  			values = append(values, cloudprovider.TWafTextTransformation(*tran.Type))
   231  		}
   232  	}
   233  	statement.Transformations = &values
   234  }
   235  
   236  func fillExcludeRules(statement *cloudprovider.SWafStatement, rules []*wafv2.ExcludedRule) {
   237  	values := cloudprovider.SExcludeRules{}
   238  	for _, rule := range rules {
   239  		values = append(values, cloudprovider.SExcludeRule{Name: *rule.Name})
   240  	}
   241  	statement.ExcludeRules = &values
   242  }
   243  
   244  func (self *sWafRule) GetStatements() ([]cloudprovider.SWafStatement, error) {
   245  	if self.Rule.Statement == nil {
   246  		return []cloudprovider.SWafStatement{}, nil
   247  	}
   248  	ret := []cloudprovider.SWafStatement{}
   249  	if self.Rule.Statement.AndStatement != nil {
   250  		for i := range self.Rule.Statement.AndStatement.Statements {
   251  			statement := sWafStatement{self.Rule.Statement.AndStatement.Statements[i]}
   252  			ret = append(ret, statement.convert())
   253  		}
   254  	} else if self.Rule.Statement.OrStatement != nil {
   255  		for i := range self.Rule.Statement.OrStatement.Statements {
   256  			statement := sWafStatement{self.Rule.Statement.OrStatement.Statements[i]}
   257  			ret = append(ret, statement.convert())
   258  		}
   259  	} else if self.Rule.Statement.NotStatement != nil {
   260  		statement := sWafStatement{self.Rule.Statement.NotStatement.Statement}
   261  		ret = append(ret, statement.convert())
   262  	} else {
   263  		statement := sWafStatement{self.Rule.Statement}
   264  		ret = append(ret, statement.convert())
   265  	}
   266  	return ret, nil
   267  }
   268  
   269  func (self *SWebAcl) GetRules() ([]cloudprovider.ICloudWafRule, error) {
   270  	ret := []cloudprovider.ICloudWafRule{}
   271  	if len(self.Rules) == 0 {
   272  		err := self.Refresh()
   273  		if err != nil {
   274  			return nil, errors.Wrapf(err, "Refresh")
   275  		}
   276  	}
   277  	for i := range self.Rules {
   278  		ret = append(ret, &sWafRule{
   279  			waf:  self,
   280  			Rule: self.Rules[i],
   281  		})
   282  	}
   283  	return ret, nil
   284  }