Skip to content

Commit

Permalink
- Added WAFv2 Resource
Browse files Browse the repository at this point in the history
  • Loading branch information
gitwater committed Aug 28, 2021
1 parent 619206a commit 53e7077
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/paco/application/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@
from paco.application.reseng_pinpointapplication import PinpointApplicationResourceEngine
from paco.application.reseng_cognito import CognitoIdentityPoolResourceEngine, CognitoUserPoolResourceEngine
from paco.application.reseng_dynamodb import DynamoDBResourceEngine
from paco.application.reseng_wafwebacl import WAFWebACLResourceEngine
16 changes: 16 additions & 0 deletions src/paco/application/reseng_wafwebacl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from paco import cftemplates
from paco.application.res_engine import ResourceEngine


class WAFWebACLResourceEngine(ResourceEngine):
def init_resource(self):

if self.resource.scope == "CLOUDFRONT":
self.aws_region = 'us-east-1'

self.stack_group.add_new_stack(
self.aws_region,
self.resource,
cftemplates.waf.WAFWebACL,
stack_tags=self.stack_tags,
)
1 change: 1 addition & 0 deletions src/paco/cftemplates/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,4 @@
from paco.cftemplates.dynamodb import DynamoDB
from paco.cftemplates.notification_rules import NotificationRules
from paco.cftemplates.vpcendpoints import VPCEndpoints
from paco.cftemplates.waf import WAFWebACL
8 changes: 8 additions & 0 deletions src/paco/cftemplates/cftemplates.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,11 @@ def resource_name_filter(self, name, filter_id, hash_long_names):
if len(name) > 32:
max_name_len = 32
message = "Name must not be longer than 64 characters."
elif filter_id in [
'WAFWebACL.RuleName']:
if len(name) > 128:
max_name_len = 128
message = "Name must not be longer than 128 characters."
else:
message = 'Unknown filter_id'

Expand Down Expand Up @@ -398,6 +403,9 @@ def resource_char_filter(self, ch, filter_id, remove_invalids=False):
elif filter_id in [
'CodeStar.Connection']:
valid_ch_list = '/-'
elif filter_id in [
'WAFWebACL.RuleName']:
valid_ch_list = ' -'
else:
raise StackException(PacoErrorCode.Unknown, message="Invalid filter Id: "+filter_id)

Expand Down
5 changes: 4 additions & 1 deletion src/paco/cftemplates/cloudfront.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,14 @@ def __init__(self, stack, paco_ctx, factory_name):

# Web ACL
if cloudfront_config.webacl_id != None:
webacl_id_value = cloudfront_config.webacl_id
if is_ref(webacl_id_value):
webacl_id_value = cloudfront_config.webacl_id + '.id'
webacl_id_param = self.create_cfn_parameter(
param_type='String',
name='WebAclId',
description='WAF Web Acl ID',
value=cloudfront_config.webacl_id
value=webacl_id_value
)
distribution_config_dict['WebACLId'] = troposphere.Ref(webacl_id_param)

Expand Down
107 changes: 107 additions & 0 deletions src/paco/cftemplates/waf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
from paco.cftemplates.cftemplates import StackTemplate
import troposphere
import troposphere.wafv2
from troposphere import AWSProperty

integer = int

class CustomResponse(AWSProperty):
props = {
'ResponseCode': (integer, True)
}

class BlockAction(AWSProperty):
props = {
'CustomResponse': (CustomResponse, True)
}

troposphere.wafv2.RuleAction.props['Block'] = (BlockAction, False)

class WAFWebACL(StackTemplate):
def __init__(self, stack, paco_ctx):
super().__init__(stack, paco_ctx)
self.set_aws_name('WAFWebACL', self.resource_group_name, self.resource.name)

# Troposphere Template Initialization
self.init_template('WAFWebACL')
if not self.resource.is_enabled():
return

webacl_config = stack.resource
webacl_name = self.create_resource_name(
webacl_config.paco_ref_parts,
filter_id='WAFWebACL.RuleName', hash_long_names=True)
webacl_dict = {
'Name': webacl_name,
'DefaultAction': {
'Allow': {}
},
'Rules': [],
'Scope': webacl_config.scope,
'VisibilityConfig': {
'CloudWatchMetricsEnabled': webacl_config.visibility_config.cloudwatch_metrics_enabled,
'MetricName': webacl_config.visibility_config.metric_name,
'SampledRequestsEnabled': webacl_config.visibility_config.sample_requests_enabled

}
}

if webacl_config.rules != None:
priority_index = 10
for rule_name in webacl_config.rules.keys():
rule_config = webacl_config.rules[rule_name]
if rule_config.statement == None:
continue
rule_name = self.create_resource_name(
f'{webacl_config.paco_ref_parts}.rule_name',
filter_id='WAFWebACL.RuleName', hash_long_names=True)
rule_config_dict = {
'Name': rule_name,
'Priority': priority_index,
'VisibilityConfig': {
'CloudWatchMetricsEnabled': rule_config.visibility_config.cloudwatch_metrics_enabled,
'MetricName': rule_config.visibility_config.metric_name,
'SampledRequestsEnabled': rule_config.visibility_config.sample_requests_enabled
},
'Statement': {}
}
if rule_config.action:
rule_config_dict['Action'] = {
'Block': {
'CustomResponse': {
'ResponseCode': rule_config.action.block.custom_response.response_code
}
}
}
else:
rule_config_dict['OverrideAction'] = {
'None': {}
}
priority_index += 10
if rule_config.statement.managed_rule_group:
statement_config = rule_config.statement.managed_rule_group
rule_config_dict['Statement']['ManagedRuleGroupStatement'] = {
'VendorName': statement_config.vendor,
'Name': statement_config.rule_name
}

rule_config_dict['VisibilityConfig']['CloudWatchMetricsEnabled'] = rule_config.visibility_config.cloudwatch_metrics_enabled
rule_config_dict['VisibilityConfig']['MetricName'] = rule_config.visibility_config.metric_name
rule_config_dict['VisibilityConfig']['SampledRequestsEnabled'] = rule_config.visibility_config.sample_requests_enabled
webacl_dict['Rules'].append(rule_config_dict)


webacl_res = troposphere.wafv2.WebACL.from_dict(
'WAFWebACL',
webacl_dict
)

self.template.add_resource( webacl_res )

# Outputs
self.create_output(
title='WebACLId',
description="WebACL Id.",
value=troposphere.GetAtt(webacl_res, 'Id'),
ref=self.resource.paco_ref_parts + ".id"
)

0 comments on commit 53e7077

Please sign in to comment.