in lambda/guardduty_to_acl_lambda.py [0:0]
def update_nacl(netacl_id, host_ip, region):
logger.info("log -- gd2acl entering update_nacl, netacl_id=%s, host_ip=%s" % (netacl_id, host_ip))
ddb = boto3.resource('dynamodb')
table = ddb.Table(ACLMETATABLE)
hostipexists = table.query(
KeyConditionExpression=Key('NetACLId').eq(netacl_id),
FilterExpression=Attr('HostIp').eq(host_ip)
)
# Is HostIp already in table?
if len(hostipexists['Items']) > 0:
logger.info("log -- host IP %s already in table... exiting update." % (host_ip))
return False
else:
# Get current NACL entries in DDB
response = table.query(
KeyConditionExpression=Key('NetACLId').eq(netacl_id)
)
# Get all the entries for NACL
naclentries = response['Items']
# Find oldest rule and available rule numbers from 71-80
if naclentries:
rulecount = response['Count']
rulerange = list(range(71, 81))
ddbrulerange = []
naclrulerange = get_nacl_rules(netacl_id)
for i in naclentries:
ddbrulerange.append(int(i['RuleNo']))
# Check state and exit if NACL rule not in sync with DDB
ddbrulerange.sort()
naclrulerange.sort()
synccheck = set(naclrulerange).symmetric_difference(ddbrulerange)
if ddbrulerange != naclrulerange:
logger.info("log -- current DDB entries, %s." % (ddbrulerange))
logger.info("log -- current NACL entries, %s." % (naclrulerange))
logger.error('NACL rule state mismatch, %s exiting' % (sorted(synccheck)))
exit()
# Determine the NACL rule number and create rule
if rulecount < 10:
# Get the lowest rule number available in the range
newruleno = min([x for x in rulerange if not x in naclrulerange])
# Create new NACL rule, IP set entries and DDB state entry
logger.info("log -- adding new rule %s, HostIP %s, to NACL %s." % (newruleno, host_ip, netacl_id))
create_netacl_rule(netacl_id=netacl_id, host_ip=host_ip, rule_no=newruleno)
create_ddb_rule(netacl_id=netacl_id, host_ip=host_ip, rule_no=newruleno, region=region)
logger.info("log -- all possible NACL rule numbers, %s." % (rulerange))
logger.info("log -- current DDB entries, %s." % (ddbrulerange))
logger.info("log -- current NACL entries, %s." % (naclrulerange))
logger.info("log -- new rule number, %s." % (newruleno))
logger.info("log -- rule count for NACL %s is %s." % (netacl_id, int(rulecount) + 1))
return True
if rulecount >= 10:
# Get oldest entry in DynamoDB table
oldestrule = table.query(
KeyConditionExpression=Key('NetACLId').eq(netacl_id),
ScanIndexForward=True, # true = ascending, false = descending
Limit=1,
)
oldruleno = int((oldestrule)['Items'][0]['RuleNo'])
oldrulets = int((oldestrule)['Items'][0]['CreatedAt'])
oldhostip = oldestrule['Items'][0]['HostIp']
newruleno = oldruleno
# Delete old NACL rule and DDB state entry
logger.info("log -- deleting current rule %s for IP %s from NACL %s." % (oldruleno, oldhostip, netacl_id))
delete_netacl_rule(netacl_id=netacl_id, rule_no=oldruleno)
delete_ddb_rule(netacl_id=netacl_id, created_at=oldrulets)
# check if IP is also recorded in a fresh finding, don't remove IP from blacklist in that case
response_nonexpired = table.scan( FilterExpression=Attr('CreatedAt').gt(oldrulets) & Attr('HostIp').eq(host_ip) )
# Create new NACL rule, IP set entries and DDB state entry
logger.info("log -- adding new rule %s, HostIP %s, to NACL %s." % (newruleno, host_ip, netacl_id))
create_netacl_rule(netacl_id=netacl_id, host_ip=host_ip, rule_no=newruleno)
create_ddb_rule(netacl_id=netacl_id, host_ip=host_ip, rule_no=newruleno, region=region)
logger.info("log -- all possible NACL rule numbers, %s." % (rulerange))
logger.info("log -- current DDB entries, %s." % (ddbrulerange))
logger.info("log -- current NACL entries, %s." % (naclrulerange))
logger.info("log -- rule count for NACL %s is %s." % (netacl_id, int(rulecount)))
return True
else:
# No entries in DDB Table start from 71
naclrulerange = get_nacl_rules(netacl_id)
newruleno = 71
oldruleno = []
rulecount = 0
naclrulerange.sort()
# Error and exit if NACL rules already present
if naclrulerange:
logger.error("log -- NACL %s, has existing entries, %s." % (netacl_id, naclrulerange))
raise RuntimeError("NACL has existing entries.")
# Create new NACL rule, IP set entries and DDB state entry
logger.info("log -- adding new rule %s, HostIP %s, to NACL %s." % (newruleno, host_ip, netacl_id))
create_netacl_rule(netacl_id=netacl_id, host_ip=host_ip, rule_no=newruleno)
create_ddb_rule(netacl_id=netacl_id, host_ip=host_ip, rule_no=newruleno, region=region)
logger.info("log -- rule count for NACL %s is %s." % (netacl_id, int(rulecount) + 1))
return True
if response['ResponseMetadata']['HTTPStatusCode'] == 200:
return True
else:
return False