引言

在现代网络环境中,Web 应用程序面临着日益严峻的网络威胁。为了确保 Web 应用程序的可用性和安全性,AWS 提供了一套全面的解决方案,其中包括  AWS Shield Advanced。Shield Advanced 是一项托管的 DDoS 防护服务,旨在保护您的应用程序免受网络攻击的影响。

本文将介绍如何使用 AWS SDK for Python(Boto3)以及一些实用的脚本,来自动化地开发和使用 AWS Shield Advanced 服务,特别是保护应用负载均衡器(ALB)免受 DDoS 攻击的影响。

1. 为什么选择开发 Shield 防护 ALB?

1.1 网络攻击的威胁

网络攻击已经成为日常运维中不可忽视的一部分。DDoS(分布式拒绝服务)攻击是一种通过使用多个计算机系统向目标系统发动攻击,从而使目标系统无法提供正常服务的网络攻击方式。这些攻击可能导致系统故障、服务不可用以及数据泄露。

1.2 AWS Shield Advanced 的优势

AWS Shield Advanced 是 AWS 提供的一项全面的 DDoS 防护服务,提供以下优势:

  • 全球网络规模: Shield Advanced 利用 AWS 全球基础设施,能够在全球多个区域提供高效的 DDoS 防护服务。
  • 实时监控与威胁情报: Shield Advanced 提供实时的网络流量监控,同时整合 AWS 的威胁情报服务,能够更快地响应新兴的网络威胁。
  • 自动化的防御机制: Shield Advanced 不仅能够检测 DDoS 攻击,还能够自动执行必要的防御措施,确保您的应用程序保持高可用性。

2. 开发 Shield 防护 ALB 的脚本示例

下面是一组使用 Boto3(AWS SDK for Python)编写的脚本示例,用于自动化地添加和移除 AWS Shield 防护 ALB。

2.1 批量添加 Shield 防护

注:

已经在对应区开启AWS Shield Advanced功能

新增保护返回状态200,空白说明已经受保护,作者是在us-east-1使用,如果不是请自行修改

import boto3
from datetime import datetime

def get_load_balancer_arns():
    elbv2 = boto3.client('elbv2', region_name='us-east-1')
    response = elbv2.describe_load_balancers()
    load_balancer_arns = [lb['LoadBalancerArn'] for lb in response['LoadBalancers'] if
                          lb['Type'] == 'application' and not lb['Scheme'] == 'internal' and lb[
                              'LoadBalancerName'] not in ['in-hk-test-alb', 'CL-Pr-LoadB-26SNF9ERPK26']]
    return load_balancer_arns

def create_cloudwatch_alarm(alarm_name, load_balancer_name):
    cloudwatch = boto3.client('cloudwatch', region_name='us-east-1')
    response = cloudwatch.put_metric_alarm(
        AlarmName=alarm_name,
        MetricName='TargetResponseTime',
        Namespace='AWS/ApplicationELB',
        Statistic='Average',
        Dimensions=[
            {
                'Name': 'LoadBalancer',
                'Value': load_balancer_name
            },
        ],
        Period=60,
        EvaluationPeriods=20,
        DatapointsToAlarm=1,
        Threshold=5.0,
        ComparisonOperator='GreaterThanOrEqualToThreshold',
        TreatMissingData='notBreaching', #notBreaching缺失数据不告警;missing缺失数据告警
        Unit='Seconds'
    )

def create_route53_health_check(alarm_name):
    route53 = boto3.client('route53')
    current_time = datetime.now().strftime("%Y-%m-%d-%H:%M:%S")
    response = route53.create_health_check(
        CallerReference=f'{current_time}',
        HealthCheckConfig={
            'Type': 'CLOUDWATCH_METRIC',
            'Inverted': False,
            'Disabled': False,
            'AlarmIdentifier': {
                'Region': 'us-east-1',
                'Name': f'{alarm_name}'
            },
            'InsufficientDataHealthStatus': 'LastKnownStatus'
        }
    )
    health_check_arn = response["HealthCheck"]["Id"]
    return health_check_arn

def shield_is_alb_protected(alb_arn):
    shield = boto3.client('shield')
    protected_resources = []

    response = shield.list_protections(MaxResults=100)
    protected_resources.extend([protection['ResourceArn'] for protection in response['Protections']])

    while 'NextToken' in response:
        response = shield.list_protections(MaxResults=100, NextToken=response['NextToken'])
        protected_resources.extend([protection['ResourceArn'] for protection in response['Protections']])

    return alb_arn in protected_resources


def create_shield_protection(alb_arn, protection_name):
    shield = boto3.client('shield')
    response = shield.create_protection(
        Name=protection_name,
        ResourceArn=alb_arn
    )
    return response


def protect_alb(alb_arn):
    protection_name = alb_arn.split("/")[-1]
    response = create_shield_protection(alb_arn, protection_name)
    protection_id = response['ProtectionId']
    return protection_id

def associate_health_check(health_check_arn, protection_id):
    shield = boto3.client('shield')
    response = shield.associate_health_check(
        ProtectionId=protection_id,
        HealthCheckArn=health_check_arn
    )
    return response

def enable_shield_automatic_response(resource_arn, action):
    shield = boto3.client('shield')
    response = shield.enable_application_layer_automatic_response(ResourceArn=resource_arn,Action={f'{action}':{}})
    return response

# Usage
# Check if ALB is protected
load_balancer_arns = get_load_balancer_arns()
for alb_arn in load_balancer_arns:
    alarm_name = f'TargetResponseTime-{alb_arn.split("/")[-1]}'
    load_balancer_name = '/'.join(alb_arn.split("/")[+1:])
    is_protected = is_alb_protected(alb_arn)
    if not is_protected:
        create_cloudwatch_alarm(alarm_name, load_balancer_name)
        health_check_id = create_route53_health_check(alarm_name)
        protection_id = protect_alb(alb_arn)
        health_check_arn = "arn:aws:route53:::healthcheck/" + health_check_id
        response = associate_health_check(health_check_arn,protection_id)
        action = 'Count'
        response = enable_shield_automatic_response(alb_arn, action)
        print(response["ResponseMetadata"]["HTTPStatusCode"])
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.

这段代码用于批量检查 ALB 是否已经受到 AWS Shield 防护。如果没有受到防护,将创建 CloudWatch 告警、Route 53 健康检查,并开启 Shield 防护,以确保 ALB 在受到 DDoS 攻击时能够得到及时的防御。

2.2 批量移除 Shield 防护

import boto3

def get_load_balancer_arns():
    elbv2 = boto3.client('elbv2', region_name='us-east-1')
    response = elbv2.describe_load_balancers()
    load_balancer_arns = [lb['LoadBalancerArn'] for lb in response['LoadBalancers'] if
                          lb['Type'] == 'application' and not lb['Scheme'] == 'internal' and lb[
                              'LoadBalancerName'] not in ['in-hk-test-alb', 'CL-Pr-LoadB-26SNF9ERPK26']]
    return load_balancer_arns

def describe_shield_protection(resource_arn):
    shield = boto3.client('shield')
    response = shield.describe_protection(
        ResourceArn=resource_arn
    )
    return response

def delete_protection(protection_id):
    shield = boto3.client('shield')
    response = shield.delete_protection(ProtectionId=f'{protection_id}')
    return response


def delete_health_check(health_check_id):
    route53 = boto3.client('route53')
    response = route53.delete_health_check(
        HealthCheckId=health_check_id
    )
    return response

def delete_alarms(alarm_name):
    cloudwatch = boto3.client('cloudwatch')
    response = cloudwatch.delete_alarms(
        AlarmNames=[
            f'{alarm_name}',
        ]
    )
    return response

def is_alb_protected(alb_arn):
    shield = boto3.client('shield')
    response = shield.list_protections()
    protected_resources = [protection['ResourceArn'] for protection in response['Protections']]
    return alb_arn in protected_resources

# Usage
load_balancer_arns = get_load_balancer_arns()
for resource_arn in load_balancer_arns:
    is_protected = is_alb_protected(resource_arn)
    if is_protected:
        alarm_name = f'TargetResponseTime-{resource_arn.split("/")[-1]}'
        response = describe_shield_protection(resource_arn)
        protection_id = response['Protection']['Id']
        health_check_id = response['Protection']['HealthCheckIds'][0]
        delete_protection(protection_id)
        delete_health_check(health_check_id)
        delete_alarms(alarm_name)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.

这段代码用于批量检查 ALB 是否已经受到 AWS Shield 防护。如果已经受到防护,将获取防护的详细信息,并通过 AWS SDK 移除 Shield 防护,同时删除相关的 CloudWatch 告警、Route 53 健康检查。

3. 结语

AWS Shield Advanced 提供了一个强大的解决方案,确保您的 Web 应用程序能够抵御不断演化的网络威胁。通过使用 Boto3 编写脚本,您可以轻松地集成 Shield 防护到您的自动化工作流中,提高整个应用架构的安全性和可用性。在日益复杂的网络环境中,积极采取措施保护您的应用程序是至关重要的,而 AWS Shield Advanced 则是一个可靠的选择。

希望这些脚本和示例能够帮助您更好地理解和使用 AWS Shield 防护服务,提升您的 Web 应用程序的安全性。