벌써 2020년이 되었네요. 작년 말경에 AWS WAF 의 새로운 UI 가 AWS WAF Version2 (이하 AWS WAFv2)라는 이름으로 새롭게 소개되었습니다. 기존에 제공해왔던 AWS WAF 는 AWS WAF Classic 이라는 이름으로 명명되었구요.
AWS WAFv2 는 여러가지 면에서 WAF Classic 에서 부족했던 부분을 개선하였습니다. 이 포스트는 AWS WAFv2 를 소개하는 것이 목적이 아니므로 AWS WAFv2 의 주요 장점은 시간이 허락한다면 별도의 포스팅을 통해서 다루기로 하고 여기에서는 CloudFormation 을 이용하여 간단하게 AWS WAFv2 WebACL 을 생성하는 방법을 다뤄보도록 하겠습니다.
CloudFormation 은 JSON 이나 YAML 포맷을 이용하여 작성할 수 있는데 저는 YAML 포맷을 사용하도록 하겠습니다
참고로 저는 CloudFormation 은 YAML 포맷으로만 작성할 생각입니다. YAML 포맷이 JSON 보다는 직관적이고 여러가지 장점이 있는 것 같아서 그렇게 결정했어요.
CloudFormation 의 기본 사용방법이나 Sample Code 등은 AWS 문서에 잘 정리되어 있으니 그 부분들은 따로 설명하지 않고 WAFv2 WebACL 을 생성하는 것만 해보도록 하겠습니다.
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_WAFv2.html
먼저 CloudFormation 사용을 위한 기본 포맷입니다.
AWSTemplateFormatVersion: 2010–09–09
Description: ‘’
Metadata: {}
Parameters: {}
Mappings: {}
Conditions: {}
Resources: {}
Outputs: {}
1. IPv4 용 IP Set 을 하나 만들어 보도록 하겠습니다.
sampleIpSetIPv4:
Type: 'AWS::WAFv2::IPSet'
Properties:
Name: sampleIPlistIPv4
Scope: REGIONAL
IPAddressVersion: IPV4
Addresses:
- 1.1.1.1/32
- 2.2.2.2/32
2. IPv6 용 IP Set 을 하나 만들어 보도록 하겠습니다.
sampleIpSetIPv6:
Type: 'AWS::WAFv2::IPSet'
Properties:
Name: sampleIPlistIPv6
Scope: REGIONAL
IPAddressVersion: IPV6
Addresses:
- 2001:220::/32
- 2002:220::/32
3. 정규 표현식 패턴을 하나 만들어 보도록 하겠습니다.
sampleRegexPatternSet:
Type: AWS::WAFv2::RegexPatternSet
Properties:
Name: sampleRegexPatternSet
Scope: REGIONAL
Description: This is an sample RegexPatternSet
RegularExpressionList:
- ^attacker$
- ^script$
여기까지 설명된 Set 들은 이후 WebACL Rule 에서 호출하는 용도로 사용이 됩니다.
여기부터는 WebACL 에 포함될 Rule 부분들입니다.
4. AWS WAFv2 에 새롭게 추가된 AWS Managed Rule 을 사용하도록 합니다.
WebACL 내에 사용될 Rule 이기 때문에 “Priority” 로 순서를 구분합니다.
- Name: RuleWithAWSManagedRules
Priority: 0
OverrideAction:
Count: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: RuleWithAWSManagedRulesMetric
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesCommonRuleSet
ExcludedRules: []
5. String Match Rule 을 하나 생성합니다.
- Name: StringMatch
Priority: 1
Action:
Allow: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: StringMatchMetric
Statement:
ByteMatchStatement:
FieldToMatch:
AllQueryArguments:
{}
PositionalConstraint: CONTAINS
SearchString: firefox
TextTransformations:
- Priority: 1
Type: HTML_ENTITY_DECODE
6. XSS 공격 차단 Rule 을 하나 생성합니다.
- Name: BlockXssAttack
Priority: 2
Action:
Block: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: BlockXssAttackMetric
Statement:
XssMatchStatement:
FieldToMatch:
AllQueryArguments: {}
TextTransformations:
- Priority: 1
Type: NONE
7. SQL Injection 공격 차단 Rule 을 하나 생성합니다.
- Name: BlockSQLinjectionAttack
Priority: 3
Action:
Block: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: BlockSQLinjectionAttackMetric
Statement:
SqliMatchStatement:
FieldToMatch:
AllQueryArguments: {}
TextTransformations:
- Priority: 1
Type: NONE
8. 위에서 생성하였던 IP Set 중 IPv4 Set 을 사용하는 IP Set Rule 을 하나 생성합니다.
- Name: IPlistRuleIPv4
Priority: 4
Action:
Block: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: IPlistRuleIPv4Metric
Statement:
IPSetReferenceStatement:
Arn: !GetAtt sampleIpSetIPv4.Arn
9. 위에서 생성하였던 IP Set 중 IPv6 Set 을 사용하는 IP Set Rule 을 하나 생성합니다.
- Name: IPlistRuleIPv6
Priority: 5
Action:
Block: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: IPlistRuleIPv6Metric
Statement:
IPSetReferenceStatement:
Arn: !GetAtt sampleIpSetIPv6.Arn
10. 위에서 생성하였던 Regex Pattern Set 을 사용하는 Rule 을 하나 생성합니다.
- Name: RegexPatternSetRule
Priority: 6
Action:
Block: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: RegexPatternSetRuleMetric
Statement:
RegexPatternSetReferenceStatement:
Arn: !GetAtt sampleRegexPatternSet.Arn
FieldToMatch:
AllQueryArguments: {}
TextTransformations:
- Priority: 1
Type: NONE
여기까지 WebACL 에 사용될 내용들을 각 구성 요소별로 따로 따로 살펴보았습니다.
아래는 지금까지 나열하였던 모든 구성요소들을 포함하는 CloudFormation 완성본입니다.
AWSTemplateFormatVersion: 2010-09-09
Description: WAFv2 Sample TemplateResources:
sampleIpSetIPv4:
Type: 'AWS::WAFv2::IPSet'
Properties:
Name: sampleIPlistIPv4
Scope: REGIONAL
IPAddressVersion: IPV4
Addresses:
- 1.1.1.1/32
- 2.2.2.2/32
sampleIpSetIPv6:
Type: 'AWS::WAFv2::IPSet'
Properties:
Name: sampleIPlistIPv6
Scope: REGIONAL
IPAddressVersion: IPV6
Addresses:
- 2001:220::/32
- 2002:220::/32
sampleRegexPatternSet:
Type: AWS::WAFv2::RegexPatternSet
Properties:
Name: sampleRegexPatternSet
Scope: REGIONAL
Description: This is an sample RegexPatternSet
RegularExpressionList:
- ^attacker$
- ^script$
sampleWebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: sampleWebACL
Scope: REGIONAL
Description: This is an sample WebACL
DefaultAction:
Allow: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: sampleWebACLMetric
Rules:
- Name: RuleWithAWSManagedRules
Priority: 0
OverrideAction:
Count: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: RuleWithAWSManagedRulesMetric
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesCommonRuleSet
ExcludedRules: []
- Name: StringMatch
Priority: 1
Action:
Allow: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: StringMatchMetric
Statement:
ByteMatchStatement:
FieldToMatch:
AllQueryArguments:
{}
PositionalConstraint: CONTAINS
SearchString: firefox
TextTransformations:
- Priority: 1
Type: HTML_ENTITY_DECODE
- Name: BlockXssAttack
Priority: 2
Action:
Block: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: BlockXssAttackMetric
Statement:
XssMatchStatement:
FieldToMatch:
AllQueryArguments: {}
TextTransformations:
- Priority: 1
Type: NONE
- Name: BlockSQLinjectionAttack
Priority: 3
Action:
Block: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: BlockSQLinjectionAttackMetric
Statement:
SqliMatchStatement:
FieldToMatch:
AllQueryArguments: {}
TextTransformations:
- Priority: 1
Type: NONE
- Name: IPlistRuleIPv4
Priority: 4
Action:
Block: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: IPlistRuleIPv4Metric
Statement:
IPSetReferenceStatement:
Arn: !GetAtt sampleIpSetIPv4.Arn
- Name: IPlistRuleIPv6
Priority: 5
Action:
Block: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: IPlistRuleIPv6Metric
Statement:
IPSetReferenceStatement:
Arn: !GetAtt sampleIpSetIPv6.Arn
- Name: RegexPatternSetRule
Priority: 6
Action:
Block: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: RegexPatternSetRuleMetric
Statement:
RegexPatternSetReferenceStatement:
Arn: !GetAtt sampleRegexPatternSet.Arn
FieldToMatch:
AllQueryArguments: {}
TextTransformations:
- Priority: 1
Type: NONEOutputs:
cfnVersion:
Value: 0.1
accountId:
Value: !Ref AWS::AccountId
Region:
Description: AWS Region
Value: !Ref AWS::Region
완성된 CloudFormation 을 사용하면 아래와 같이 정상적으로 WebACL 과 Rule 들이 생성되는 것을 확인할 수 있습니다.
감사합니다.