AWS FMS: SecurityServicePolicyData rendering entirely as JSON
By AWS CloudFormation documentation, the YAML representation of the SecurityServicePolicyData has two child nodes... Type and ManagedServiceData. They are represented in YAML as follows:
PolicyWAFv2:
Type: AWS::FMS::Policy
Properties:
ExcludeResourceTags: false
PolicyName: Policy
RemediationEnabled: false
ResourceType: AWS::ElasticLoadBalancingV2::LoadBalancer
SecurityServicePolicyData:
Type: WAFV2
ManagedServiceData: !Sub '{"type":"WAFV2",
"preProcessRuleGroups":[{
"ruleGroupType":"RuleGroup",
"ruleGroupArn":"${RuleGroup.Arn}",
"overrideAction":{"type":"NONE"}}],
"postProcessRuleGroups":[],
"defaultAction":{"type":"BLOCK"}}'
The ManagedServiceData property is the only item of the node that is supposed to be JSON based, but in the FMS::Policy troposphere object, the entire thing is coded/output as JSON, which results in outputs like this:
BaseProtectionsIntPolicy:
Properties:
DeleteAllPolicyResources: true
ExcludeResourceTags: false
IncludeMap:
ACCOUNT:
- '123456789012'
ORGUNIT: []
PolicyName: Base-Protections-Int-Policy
RemediationEnabled: false
ResourceType: ResourceTypeList
ResourceTypeList:
- AWS::ElasticLoadBalancingV2::LoadBalancer
- AWS::ApiGateway::Stage
SecurityServicePolicyData: >-
{"type": "WAFV2", "ManagedServiceData": "{\"type\": \"WAFV2\", \"preProcessRuleGroups\":
[{\"ruleGroupArn\": null, \"overrideAction\": {\"type\": \"COUNT\"}, \"managedRuleGroupIdentifier\":
{\"version\": null, \"vendorName\": \"AWS\", \"managedRuleGroupName\": \"AWSManagedRulesCommonRuleSet\"},
\"ruleGroupType\": \"ManagedRuleGroup\"}, {\"ruleGroupArn\": null, \"overrideAction\":
{\"type\": \"COUNT\"}, \"managedRuleGroupIdentifier\": {\"version\": null,
\"vendorName\": \"AWS\", \"managedRuleGroupName\": \"AWSManagedRulesAmazonIpReputationList\"},
\"ruleGroupType\": \"ManagedRuleGroup\"}, {\"ruleGroupArn\": \"${BaseIntRuleGroup.Arn}\",
\"overrideAction\": {\"type\": \"NONE\"}, \"ruleGroupType\": \"RuleGroup\"}],
\"postProcessRuleGroups\": [], \"defaultAction\": {\"type\": \"ALLOW\"}}"}
Type: AWS::FMS::Policy
Furthermore, attempting to add a troposphere Sub() object around the ManagedServiceData string results in an error that the Sub() object is not JSON Serializable.
I propose that an additional helper object be defined in FMS.py that allows further breakout of these items and moves the json_checker validation to the ManagedServiceData definition under the new object.
I'm curious to know if anyone has this working as is.
Thanks!
Not sure how to tie json_checker validation into the ManagedServiceData property and still allow Sub() usage. Open for input on that.
The attached pull request results in the format covered in the AWS Documentation:
BaseProtectionsIntPolicy:
Properties:
DeleteAllPolicyResources: true
ExcludeResourceTags: false
IncludeMap:
ACCOUNT:
- '123456789012'
ORGUNIT: []
PolicyName: Base-Protections-Int-Policy
RemediationEnabled: false
ResourceType: ResourceTypeList
ResourceTypeList:
- AWS::ElasticLoadBalancingV2::LoadBalancer
- AWS::ApiGateway::Stage
SecurityServicePolicyData:
ManagedServiceData: !Sub '{"type": "WAFV2", "preProcessRuleGroups": [{"ruleGroupArn":
null, "overrideAction": {"type": "COUNT"}, "managedRuleGroupIdentifier":
{"version": null, "vendorName": "AWS", "managedRuleGroupName": "AWSManagedRulesCommonRuleSet"},
"ruleGroupType": "ManagedRuleGroup"}, {"ruleGroupArn": null, "overrideAction":
{"type": "COUNT"}, "managedRuleGroupIdentifier": {"version": null, "vendorName":
"AWS", "managedRuleGroupName": "AWSManagedRulesAmazonIpReputationList"},
"ruleGroupType": "ManagedRuleGroup"}, {"ruleGroupArn": "${BaseIntRuleGroup.Arn}",
"overrideAction": {"type": "NONE"}, "ruleGroupType": "RuleGroup"}], "postProcessRuleGroups":
[], "defaultAction": {"type": "ALLOW"}}'
Type: WAFV2
Type: AWS::FMS::Policy
When used as follows:
from troposphere import fms, Sub
# ... redacted ...
policy_obj = fms.Policy(
title="BaseProtectionsIntPolicy",
PolicyName="Base-Protections-Int-Policy",
DeleteAllPolicyResources=True,
ExcludeResourceTags=False,
RemediationEnabled=False,
ResourceType="ResourceTypeList",
ResourceTypeList=["AWS::ElasticLoadBalancingV2::LoadBalancer", "AWS::ApiGateway::Stage"],
IncludeMap=fms.IEMap(
ACCOUNT=[ "123456789012" ],
ORGUNIT=[]
),
SecurityServicePolicyData=fms.SecurityServicePolicyData(
Type="WAFV2",
ManagedServiceData=Sub(generated_managed_service_data)
)
)