def getWaf()

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))