在 AWS 上部署容器化应用时,使用 ECS Fargate 是一个很好的选择。Fargate 是一种无需管理底层基础设施的容器化计算引擎,可以轻松运行容器,而无需预置或管理 EC2 实例。
然而,默认情况下,Fargate 任务使用公共子网,这意味着容器可以直接访问互联网。虽然这对某些应用程序来说是必需的,但从安全角度来看,最好将容器与互联网隔离开来,只允许出站流量。
在本文中,我们将介绍如何使用 Python 脚本批量禁止 ECS Fargate 服务的公网访问,并使用 NAT 网关解决镜像拉取问题。
先决条件
- AWS 账户和适当的 IAM 权限
- Python 3.x 及其
boto3
库 - 已创建的 ECS 集群和服务
脚本概述
我们将编写一个 Python 脚本,该脚本可以:
- 列出指定 ECS 集群中的所有服务
- 检查每个服务的网络配置
- 如果服务使用公共子网,则更新其配置以使用私有子网和 NAT 网关
- 在更新配置后,等待一段时间再处理下一个服务,以避免频繁更新导致的问题
脚本代码
import boto3
import time
ecs_client = boto3.client('ecs', region_name='us-east-1')
ec2_client = boto3.client('ec2', region_name='us-east-1')
# 定义睡眠时间(以秒为单位)
sleep_time = 60
# 定义 VPC 对应的私有子网和安全组配置
vpc_config = {
'vpc-97f8a9f1': {
'subnets': ['subnet-03271df83933bc34c', 'subnet-0ba1ee5da9fa8a5fe'],
'security_groups': ['sg-023218fbc132324f0']
},
'vpc-01bc326c162920649': {
'subnets': ['subnet-0406036d337ad20aa', 'subnet-01f8076d8bb161937', 'subnet-0b7927873dfe98061'],
'security_groups': ['sg-011d6a642cf4adddb']
}
}
def get_cluster_services(cluster):
services = []
next_token = None
while True:
if next_token:
response = ecs_client.list_services(cluster=cluster, nextToken=next_token)
else:
response = ecs_client.list_services(cluster=cluster)
services.extend(response['serviceArns'])
if 'nextToken' in response:
next_token = response['nextToken']
else:
break
return services
def get_vpc_id_from_subnet(subnet_id):
response = ec2_client.describe_subnets(SubnetIds=[subnet_id])
vpc_id = response['Subnets'][0]['VpcId']
return vpc_id
def update_service_subnet(cluster, service):
# 获取服务信息
response = ecs_client.describe_services(
cluster=cluster,
services=[service]
)
service_info = response['services'][0]
# 获取服务所在的子网
subnet_ids = service_info.get('networkConfiguration', {}).get('awsvpcConfiguration', {}).get('subnets', [])
# 如果服务关联了子网
if subnet_ids:
# 获取 VPC ID
vpc_id = get_vpc_id_from_subnet(subnet_ids[0])
# 如果服务所在的 VPC ID 在配置中存在
if vpc_id in vpc_config:
vpc_config_data = vpc_config[vpc_id]
subnets = vpc_config_data['subnets']
security_groups = vpc_config_data['security_groups']
# 更新服务的子网和安全组配置
response = ecs_client.update_service(
cluster=cluster,
service=service,
networkConfiguration={
'awsvpcConfiguration': {
'subnets': subnets,
'securityGroups': security_groups,
'assignPublicIp': 'DISABLED'
}
}
)
print(f"Updated service {service} subnet and security groups for cluster {cluster}")
time.sleep(sleep_time)
else:
print(f"VPC ID {vpc_id} not found in the configuration")
else:
print(f"Service {service} is not associated with any subnet")
# 示例用法
clusters = ['cluster1','cluster2','cluster3']
for cluster in clusters:
services = get_cluster_services(cluster)
for service in services:
update_service_subnet(cluster, service)
脚本解释
- 首先,我们导入必要的 AWS SDK 库并初始化 ECS 和 EC2 客户端。
- 定义一个睡眠时间变量,用于在更新每个服务后等待一段时间,避免频繁更新导致的问题。
- 定义一个
vpc_config
字典,用于存储每个 VPC 对应的私有子网和安全组配置。你需要根据实际情况填写正确的子网 ID 和安全组 ID。 get_cluster_services
函数用于列出指定 ECS 集群中的所有服务 ARN。get_vpc_id_from_subnet
函数用于从子网 ID 获取 VPC ID。update_service_subnet
函数是主要逻辑所在。它会获取服务的网络配置,如果服务使用公共子网,则根据vpc_config
中的配置更新服务的子网和安全组,并禁用公网 IP。更新后,它会等待指定的睡眠时间。- 最后,我们定义了一个示例集群列表,并遍历每个集群和服务,调用
update_service_subnet
函数进行更新。
使用说明
- 将上述脚本保存为 Python 文件,例如
update_ecs_service_subnets.py
。 - 根据实际情况,在
vpc_config
字典中填写正确的私有子网 ID 和安全组 ID。 - 根据需要,修改
clusters
列表中的集群名称。 - 确保您的 AWS 凭证已正确配置,或者使用适当的角色或实例配置文件。
- 运行脚本:
python update_ecs_service_subnets.py
- 脚本将逐个处理每个集群中的服务,如果服务使用公共子网,则更新其配置以使用私有子网和 NAT 网关。
- 更新完成后,您的 ECS Fargate 服务将无法直接访问互联网,但可以通过 NAT 网关拉取 Docker 镜像和访问其他出站资源。
通过执行此脚本,您可以批量禁止 ECS Fargate 服务的公网访问,提高应用程序的安全性,同时使用 NAT 网关解决镜像拉取问题。请注意,根据您的服务数量和集群规模,此过程可能需要一些时间。