当前,某客户对于安全较为看重,希望对于所有的进出站都通过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_functionimport osimport jsonimport botocore.vendored.requests as requestsimport boto3print('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 urldef 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提供了一种通知的方式