当前,某客户对于安全较为看重,希望对于所有的进出站都通过IP控制,那对于亚马逊云科技来说,是有提供公有的IP池,同时会记录在一个ip-range (https://ip-ranges.amazonaws.com/ip-ranges.json)文件,但是对于这些IP不是永久不变的,在一些服务更新的情况下,IP可能会发生增加,那此时依靠人力去过滤是比较浪费时间,那可以通过以下方法,实现自动化通知的方式。
该方法的整体思路是将更改通知的SNS主题设定为AWS Lambda的触发器,Lambda获取到ip-range的链接发生变更时,会将其与存储在AWS S3上的文本文件中的IP进行对比,如果IP发生更改时,函数会使用新的IP更新S3文本文件,并发送SNS通知。
创建一个SNS设定邮箱可以接收发生变更的通知,在与后面相同的Lambda区域创建SNS,并设定邮箱,并验证。本次创建一个SNS-IP的主题并设定通知名称为IP-List。
本次在弗吉尼亚区域创建lambda函数并使用Python 3.7版本,对于函数名称可以自定义,对于函数内容如下,对于这个函数,在函数的最后,可以设定SNS通知的样式,如本次是查看us-east-1区域API GATEWAY的公网IP段。
from __future__ import print_function
import os
import json
import botocore.vendored.requests as requests
import boto3
print('Loading function')
def lambda_handler(event, context):
#print("Received event: " + json.dumps(event, indent=2))
#Read the json url key from the AWS SNS IP ranges notification.
#url = event['url']
#print("From SNS url: " + url)
url = 'https://ip-ranges.amazonaws.com/ip-ranges.json'
#Load the json content from the url
r = requests.get(url)
data = json.loads(r.content)
#print(data)
ipv4addresses = data["prefixes"]
newIps = []
# Iterate over the ip addresses and filter the required ip addresses.
# The region and service are supplied as environment variables to the lambda function
for item in ipv4addresses:
ip = item['ip_prefix']
region = item['region']
service = item['service']
if region == os.environ['region'] and service == os.environ['service'] :
print("ip:" + ip + " Region:" + region + " Service:" + service)
newIps.append(ip)
# Print the new IP ranges for S3 service
for ip in newIps:
print("New Ip: ", ip)
# Load the previous/current IPs stored in the S3 text file.
s3 = boto3.client('s3')
bucket = os.environ['bucket']
key = os.environ['key']
print("bucket: "+ bucket + " File: "+key)
data = s3.get_object(Bucket=bucket, Key=key)
contents = data['Body'].read().decode('utf-8')
currentIps = contents.split('\n')
for ip in currentIps:
print("Current Ip: ", ip)
#check if exisitngs ips in s3 file and current ips are same.
ifset(newIps) == set(currentIps) :
print("There are no changes in S3 IP Ranges")
else:
print("S3 IP Ranges changed")
newIpsLength = len(newIps)
index = 0
# Write the new IPS to a temporary file in Lambda.
with open('/tmp/awsips.txt', 'w') as data:
for ip in newIps:
if index == (newIpsLength - 1) :
data.write(ip)
else:
data.write(ip+ "\n")
index = index + 1
# Upload the temporary file to S3
with open('/tmp/awsips.txt', "rb") as f:
s3.upload_fileobj(f, bucket, key)
print("S3 File upload successful.")
# Send SNS notification to notify about the IP address changes.
publishToSNSTopic(newIps)
return url
def publishToSNSTopic(s3ips):
message = {"foo": "bar"}
arn = os.environ['snsarn']
client = boto3.client('sns')
response = client.publish(
TargetArn=arn,
Message=json.dumps({'default': json.dumps(message),'email': 'AWS API-GATEWAY IP Ranges Changed. New IPs are in "awss3ips" s3 bucket. New Ips: '+ ', '.join(s3ips)}),
Subject='AWS API-GATEWAY IPs Changed',
MessageStructure='json'
)
对于该Lambda所使用的权限,参考以下权限,其中S3是存放您存储了IP的txt文档的存储桶,Lambda函数需要调用这个桶中的txt文件进行对比,如果有差异,将新的IP写入桶中的这个文件,同时需要调用SNS服务。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets",
"s3:GetBucketLocation"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::awsapiips",
"arn:aws:s3:::awsapiips/*"
]
},
{
"Action": [
"sns:Publish",
"sns:Subscribe"
],
"Effect": "Allow",
"Resource": [
"*"
]
}
]
}
对于触发器,官方提供了一个SNS主题
“arn:aws:sns:us-east-1:806199016981:AmazonIpSpaceChanged”,当发生了更改时,可以借助这个SNS主题进行触发Lambda函数
参考链接:
https://docs.aws.amazon.com/vpc/latest/userguide/aws-ip-ranges.html#subscribe-notifications
对于上述的Lambda函数,需要设定一些环境变量给与函数的引用,变量内容如下
bucket:存储着txt文件的存储桶
key:存放ip的txt文档
region:需要获取ip地址更新的区域
service:需要获取ip地址更新的服务
snsarn:需要进行接收通知的SNS,SNS为之前建立的SNS的arn
根据上述变量,在同名桶中上传同名文件,本次只上传空文件,txt文件中没有任何内容,可以通过大小0B判断这个txt是空的
该代码可以直接进行测试,代码会获取ip range的链接“https://ip-ranges.amazonaws.com/ip-ranges.json”并将获取到需要的IP与txt文本中的内容进行对比
测试完成后会,会显示“执行结果:成功”,并且在日志输出会显示需要的IP段
这时查看S3桶中的文件,该文件大小发生改变,说明文件发生了更改,同时查看文件内容,发现已经将对应的IP填入其中
同时设定的接受通知的邮箱,可以发现已经接收到了更改的邮件
通过以上方法,可以在ip-range发生更改时,做到及时通知,并可以获取到指定服务的公网IP,对于某一些特殊场景需要指定Public IP提供了一种通知的方式