in WAF/WAF-Enhanced-Replicator/wafget.py [0:0]
def getWaf(arguments):
'''
Prints customer account and calls the right WAF function to get customer's resources.
The arguments are a list with the following values: [wafType to be considered (1 = global, 2 = regional), region name, Web ACL ID]
'''
# Staging all files. The first one is the log file. The second one is the Terraform template file.
# The third one is the zip file containing the two previous ones.
listLogTemplate = function.getHomeConfig()
log = stageFile(listLogTemplate[0])
template = stageFile(listLogTemplate[1])
package = listLogTemplate[2]
print("Your WAFER log file is " + listLogTemplate[0])
print("Your Terraform template file is " + listLogTemplate[1])
# Populating first lines of the log file
log.write("*************************************************************************\n")
log.write("WAFER - AWS WAF Enhanced Repicator - Version " + function.getVersion() + "\n")
log.write("*************************************************************************\n")
webAclId = arguments[2]
isRegional = False
suffix = "_"
region = "us-east-1"
if arguments[0] == 2: # This indicates that it will be regional WAF
isRegional = True
suffix = "regional_"
region = arguments[1]
if isRegional:
print("Considering WAF regional resources on " + region + ".\n")
log.write(function.getFormattedDateTime() + "Region: " + region + "\n")
client = boto3.setup_default_session(region_name = region)
client = boto3.client('waf-regional')
else:
print("Considering WAF global resources.\n")
log.write(function.getFormattedDateTime() + "Global WAF\n")
client = boto3.client('waf')
if len(webAclId) == 0:
try:
response = client.list_web_acls()
except:
function.abortMission(log, template, "list_web_acls()")
else:
# In case query is ok, proceed with the code
if len(response) == 0:
if isRegional:
print("You have no Web ACLs on region {}. Exiting...\n".format(region), file=sys.stderr)
else:
print("You have no global Web ACLs.\n", file=sys.stderr)
log.write(function.getFormattedDateTime() + "End of Log.")
function.abortMission(log, template)
else:
print("Choose which Web ACL you want to consider: ")
for i in range(len(response['WebACLs'])):
print("[{}] Id: {}, Name: {}".format(str(i+1), response['WebACLs'][i]['WebACLId'], response['WebACLs'][i]['Name']))
print("[0] Abort")
choice = -1
while (choice < 0 or choice > len(response)):
choice = input("Your choice: ")
if not choice.isdigit():
choice = -1
else:
choice = int(choice)
if choice == 0:
print("Aborting execution.\n", file=sys.stderr)
log.write(function.getFormattedDateTime() + "End of Log.")
function.abortMission(log, template, "")
webAclId = response['WebACLs'][choice-1]['WebACLId']
webAclName = response['WebACLs'][choice-1]['Name']
else:
try:
response = client.get_web_acl(WebACLId = webAclId)
except:
if isRegional:
print("Unable to find the provided Web ACL ID {} on the provided region {}.".format(webAclId, region), file=sys.stderr)
log.write(function.getFormattedDateTime() + "Unable to find the provided Web ACL " + webAclId + " on the provided region " + region + ".\n")
else:
print("Unable to find the provided global Web ACL ID {}.".format(webAclId), file=sys.stderr)
log.write(function.getFormattedDateTime() + "Unable to find the provided global Web ACL " + webAclId + ".\n")
function.abortMission(log, template, "")
webAclName = response['WebACL']['Name']
log.write(function.getFormattedDateTime() + "Web ACL (ID): " + webAclName + " (" + webAclId + ")\n")
print("Grabbing resources for Web ACL {} (ID: {})...".format(webAclName, webAclId))
try:
response1 = client.get_web_acl(WebACLId = webAclId)
except:
function.abortMission(log, template, "get_web_acl()")
metricName = response1['WebACL']['MetricName']
defaultAction = response1['WebACL']['DefaultAction']['Type']
# Starting the template writing.
template.write('provider "aws" {\n')
if isRegional:
template.write(' region = "' + region + '"\n')
else:
template.write(' region = "us-east-1"\n')
template.write('}\n\n')
# Getting all conditions.
conditionsResult = crawlConditions(client, log, template, suffix)
template.write(conditionsResult[1])
template.write("\n\n")
rules = {}
for i in range(len(response1['WebACL']['Rules'])):
finalString = ""
ruleId = response1['WebACL']['Rules'][i]['RuleId']
ruleType = response1['WebACL']['Rules'][i]['Type']
if ruleType == 'GROUP':
try:
groupTemp = client.get_rule_group(RuleGroupId = ruleId)
except:
function.abortMission(log, template, "get_rule_group()")
groupName = groupTemp['RuleGroup']['Name']
print("Rule Group (Id): {} ({})".format(groupName, ruleId))
log.write(function.getFormattedDateTime() + "Group Name: " + groupName + " / Group Id: " + ruleId + "\n")
try:
loopGroup = client.list_activated_rules_in_rule_group(RuleGroupId = ruleId)
except:
function.abortMission(log, template, "list_activated_rules_in_rule_group()")
for j in range(len(loopGroup['ActivatedRules'])):
idTemp = loopGroup['ActivatedRules'][j]['RuleId']
try:
rTemp = client.get_rule(RuleId = idTemp)
except:
function.abortMission(log, template, "get_rule()")
# Checking if the rule was not already recorded
if not idTemp in rules:
index = 0
for key, value in rules.items():
if rules[key][:5] == "rule_":
index += 1
rules[idTemp] = "rule_" + str(index)
nameTemp = rTemp['Rule']['Name']
print(" Rule Name: {} / Rule ID: {}".format(nameTemp, idTemp))
log.write(function.getFormattedDateTime() + " Rule Name: " + nameTemp + " / Rule ID: " + ruleId + "\n")
finalString += "resource \"aws_waf" + suffix + "rule\" \"rule_" + str(index) +"\" {\n"
finalString += " name = \"" + rTemp['Rule']['Name'] + "\"\n"
finalString += " metric_name = \"" + rTemp['Rule']['MetricName'] + "\"\n\n"
for k in range(len(rTemp['Rule']['Predicates'])):
if isRegional:
finalString += " predicate {\n"
else:
finalString += " predicates {\n"
finalString += " type = \"" + rTemp['Rule']['Predicates'][k]['Type'] + "\"\n"
finalString += " negated = " + str(rTemp['Rule']['Predicates'][k]['Negated']).lower() + "\n"
conditionId = rTemp['Rule']['Predicates'][k]['DataId']
finalString += " data_id = \"${aws_waf" + suffix + conditionsResult[0][conditionId][:-2] + "." + conditionsResult[0][conditionId] + ".id}\"\n"
finalString += " }\n"
finalString += "}\n\n"
finalString += "resource \"aws_waf" + suffix + "rule_group\" \"rule_group_" + str(i) +"\" {\n"
rules[ruleId] = "rule_group_" + str(i)
finalString += " name = \"" + groupName + "\"\n"
finalString += " metric_name = \"" + groupTemp['RuleGroup']['MetricName'] + "\"\n\n"
for j in range(len(loopGroup['ActivatedRules'])):
finalString += " activated_rule {\n"
finalString += " action {\n"
finalString += " type = \"" + loopGroup['ActivatedRules'][j]['Action']['Type'] + "\"\n"
finalString += " }\n\n"
finalString += " priority = " + str(loopGroup['ActivatedRules'][j]['Priority']) + "\n"
finalString += " rule_id = \"${aws_waf" + suffix + "rule." + rules[loopGroup['ActivatedRules'][j]['RuleId']] + ".id}\"\n"
finalString += " }\n\n"
finalString += "}\n\n"
template.write(finalString)
elif ruleType == "RATE_BASED":
try:
rTemp = client.get_rate_based_rule(RuleId = ruleId)
except:
function.abortMission(log, template, "get_rate_based_rule()")
ruleName = rTemp['Rule']['Name']
ruleAction = response1['WebACL']['Rules'][i]['Action']['Type']
log.write(function.getFormattedDateTime() + "Rule Name: " + ruleName + " / Rule Id: " + ruleId + "\n")
print("Rule Name: {} / Rule Id: {}".format(ruleName, ruleId))
idTemp = rTemp['Rule']['RuleId']
if not idTemp in rules:
index = 0
for key, value in rules.items():
if rules[key][:5] == "rule_":
index += 1
rules[idTemp] = "rule_" + str(index)
finalString += "resource \"aws_waf" + suffix + "rate_based_rule\" \"rule_" + str(index) +"\" {\n"
finalString += " name = \"" + rTemp['Rule']['Name'] + "\"\n"
finalString += " metric_name = \"" + rTemp['Rule']['MetricName'] + "\"\n\n"
finalString += " rate_key = \"" + rTemp['Rule']['RateKey'] + "\"\n"
finalString += " rate_limit = " + str(rTemp['Rule']['RateLimit']) + "\n\n"
for j in range(len(rTemp['Rule']['MatchPredicates'])):
if isRegional:
finalString += " predicate {\n"
else:
finalString += " predicates {\n"
conditionId = rTemp['Rule']['MatchPredicates'][j]['DataId']
finalString += " data_id = \"${aws_waf" + suffix + conditionsResult[0][conditionId][:-2] + "." + conditionsResult[0][conditionId] + ".id}\"\n"
finalString += " negated = " + str(rTemp['Rule']['MatchPredicates'][j]['Negated']).lower() + "\n"
finalString += " type = \"" + rTemp['Rule']['MatchPredicates'][j]['Type'] + "\"\n"
finalString += " }\n\n"
finalString += "}\n\n"
template.write(finalString)
elif ruleType == "REGULAR":
try:
rTemp = client.get_rule(RuleId = ruleId)
except:
function.abortMission(log, template, "get_rule()")
ruleName = rTemp['Rule']['Name']
ruleAction = response1['WebACL']['Rules'][i]['Action']['Type']
log.write(function.getFormattedDateTime() + "Rule Name: " + ruleName + " / Rule Id: " + ruleId + "\n")
print("Rule Name: {} / Rule Id: {}".format(ruleName, ruleId))
idTemp = rTemp['Rule']['RuleId']
if not idTemp in rules:
index = 0
for key, value in rules.items():
if rules[key][:5] == "rule_":
index += 1
rules[idTemp] = "rule_" + str(index)
finalString += "resource \"aws_waf" + suffix + "rule\" \"rule_" + str(index) +"\" {\n"
finalString += " name = \"" + rTemp['Rule']['Name'] + "\"\n"
finalString += " metric_name = \"" + rTemp['Rule']['MetricName'] + "\"\n\n"
for j in range(len(rTemp['Rule']['Predicates'])):
if isRegional:
finalString += " predicate {\n"
else:
finalString += " predicates {\n"
conditionId = rTemp['Rule']['Predicates'][j]['DataId']
finalString += " data_id = \"${aws_waf" + suffix + conditionsResult[0][conditionId][:-2] + "." + conditionsResult[0][conditionId] + ".id}\"\n"
finalString += " negated = " + str(rTemp['Rule']['Predicates'][j]['Negated']).lower() + "\n"
finalString += " type = \"" + rTemp['Rule']['Predicates'][j]['Type'] + "\"\n"
finalString += " }\n\n"
finalString += "}\n\n"
template.write(finalString)
# Getting all associated resources for the Web ACL.
resourcesResult = getAssociatedResources(client, webAclId, region, log, template, isRegional)
template.write(resourcesResult[1])
finalString = ""
finalString += "resource \"aws_waf" + suffix + "web_acl\" \"web_acl\" {\n"
finalString += ' name = "'+ webAclName + '"\n'
finalString += ' metric_name = "' + metricName + '"\n\n'
finalString += ' default_action {\n'
finalString += ' type = "' + defaultAction + '"\n'
finalString += ' }\n\n'
for i in range(len(response1['WebACL']['Rules'])):
ruleType = response1['WebACL']['Rules'][i]['Type']
if isRegional:
finalString += " rule {\n"
else:
finalString += " rules {\n"
finalString += " priority = " + str(response1['WebACL']['Rules'][i]['Priority']) + "\n"
finalString += " type = \"" + ruleType + "\"\n"
if ruleType == "GROUP":
finalString += " rule_id = \"${aws_waf" + suffix + "rule_group." + rules[response1['WebACL']['Rules'][i]['RuleId']] + ".id}\"\n\n"
finalString += " override_action {\n"
finalString += " type = \"" + response1['WebACL']['Rules'][i]['OverrideAction']['Type'] + "\"\n"
elif ruleType == "REGULAR":
finalString += " rule_id = \"${aws_waf" + suffix + "rule." + rules[response1['WebACL']['Rules'][i]['RuleId']] + ".id}\"\n\n"
finalString += " action {\n"
finalString += " type = \"" + response1['WebACL']['Rules'][i]['Action']['Type'] + "\"\n"
elif ruleType == "RATE_BASED":
finalString += " rule_id = \"${aws_waf" + suffix + "rate_based_rule." + rules[response1['WebACL']['Rules'][i]['RuleId']] + ".id}\"\n\n"
finalString += " action {\n"
finalString += " type = \"" + response1['WebACL']['Rules'][i]['Action']['Type'] + "\"\n"
finalString += " }\n"
finalString += " }\n\n"
finalString += "}\n\n"
# This means there are regional resources associated with the Web ACL. In case it's a Global WAF Web ACL,
# and there is at least one CloudFront distribution associated with it, this was already covered in the
# the corresponding CloudFront block while running the getAssociatedResources() function.
if len(resourcesResult[0]) > 0 and isRegional:
for z in range(len(resourcesResult[0])):
finalString += "resource \"aws_wafregional_web_acl_association\" \"web_acl_association_" + str(z) + "\" {\n"
finalString += " web_acl_id = \"${aws_wafregional_web_acl.web_acl.id}\"\n"
if "alb_dns_name" in resourcesResult[0][z]:
finalString += " resource_arn = \"${aws_lb.waferALB.arn}\"\n" # This means an ALB needs to be associated with the Web ACL
else:
# This means an API Gateway needs to be associated with the Web ACL
finalString += " resource_arn = \"arn:aws:apigateway:" + region + "::/restapis/${aws_api_gateway_rest_api.waferAPI.id}/stages/waferStage\"\n"
finalString += "}\n\n"
# This is the real final part of the template file (the outputs).
finalString += "output \"Web_ACL_Name\" {\n"
finalString += " description = \"Please refer to this Web ACL\"\n"
finalString += " value = \"" + webAclName + "\"\n"
finalString += "}\n\n"
for z in range(len(resourcesResult[0])):
finalString += "output \"" + resourcesResult[0][z][0] + "\" {\n"
finalString += " description = \"" + resourcesResult[0][z][1] + "\"\n"
tail = ""
if "api_gateway_invoke_url" in resourcesResult[0][z]:
tail = "/WAFER" # Adding the stage nane to the final URL.
finalString += " value = " + resourcesResult[0][z][2] + tail + "\n"
finalString += "}\n\n"
template.write(finalString)
log.write(function.getFormattedDateTime() + "End of Log.")
print("All done.")
log.close()
template.close()
# Zipping files.
try:
import zlib
compression = zipfile.ZIP_DEFLATED
except:
compression = zipfile.ZIP_STORED
zf = zipfile.ZipFile(package, mode = "w")
try:
zf.write(listLogTemplate[0], compress_type = compression)
except:
print("Unable to add {} to the zip file!".format(listLogTemplate[0]))
try:
zf.write(listLogTemplate[1], compress_type = compression)
except:
print("Unable to add {} to the zip file!".format(listLogTemplate[1]))
zf.close()
print("\nGenerated ZIP file: {}.".format(package))