Trying to return multiple values in output - python

I'm trying to get running hours on an EC2 tagged instance with (Tag-periods - active) in an sns email notification, however I'm new to Python. Nevertheless, even though I have more than 5 instances with these tag values, I only returned one of them. I tried hundreds more times, but I still couldn't attain an acceptable result.
import json
import boto3
from datetime import datetime
from datetime import timedelta
region ='ap-south-1'
ec2 = boto3.resource('ec2',region)
client = boto3.client('ec2',region)
def lambda_handler(event, context):
ec2 = boto3.resource('ec2')
sns = boto3.client('sns')
instances = ec2.instances.filter(Filters=[{'Name':'tag:Period', 'Values':['active']}])
active = ''
for instance in instances:
instanceStartTime = instance.launch_time.strftime("%Y-%m-%d %H:%M:%S")
currentTime = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
date_time_obj1 = datetime.strptime(instanceStartTime, '%Y-%m-%d %H:%M:%S')
date_time_obj2 = datetime.strptime(currentTime, '%Y-%m-%d %H:%M:%S')
timeDiff = (date_time_obj2 - date_time_obj1).total_seconds() / 3600.0
active += '\n Instance Id : ' + instance.id
active += '\n Instance Start Time : ' + instanceStartTime
active += '\n current Time : ' + currentTime
active += '\n Running Time : ' + str(timeDiff) + '\n\n'
for x in active:
if str(timeDiff)>='08.0':
response = sns.publish(
TopicArn='arn:aws:sns:ap-south-1:123456789:SNS-Notification',
Message='Current Active Instances ' + active,
)
return response
output:
enter image description here

In this block:
for x in active:
if str(timeDiff)>='08.0':
response = sns.publish(
TopicArn='arn:aws:sns:ap-south-1:123456789:SNS-Notification',
Message='Current Active Instances ' + active,
)
return response
You're returning after the first iteration that executes the if statement: in Python a function exits from execution after returning.
Try this instead:
for x in active:
if str(timeDiff)>='08.0':
sns.publish(
TopicArn='arn:aws:sns:ap-south-1:123456789:SNS-Notification',
Message='Current Active Instances ' + active,
)
(Also: why are you iterating over active, which is a string? And what's that time comparison as a string?)

Related

AWS Lambda limiting Python output

I have a lambda which i want to run every morning showing the users with AccessKeys older than 90 days. What i am noticing is that the return of users is limited
import boto3, json, time, datetime, sys, pprint
sns = boto3.client('sns')
usernames = []
mylist = []
sts_client = boto3.client('sts')
assumed_role_object=sts_client.assume_role(
RoleArn="arn:aws:iam::11111111:role/lambda_role",
RoleSessionName="AssumedRoleSession4"
)
credentials=assumed_role_object['Credentials']
client=boto3.client(
'iam',
aws_access_key_id=credentials['AccessKeyId'],
aws_secret_access_key=credentials['SecretAccessKey'],
aws_session_token=credentials['SessionToken'],
)
def lambda_handler(event, context):
users = client.list_users()
for key in users['Users']:
a = str(key['UserName'])
usernames.append(a)
for username in usernames:
try:
res = client.list_access_keys(UserName=username)
accesskeydate = res['AccessKeyMetadata'][0]['CreateDate']
accesskeydate = accesskeydate.strftime("%Y-%m-%d %H:%M:%S")
currentdate = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
accesskeyd = time.mktime(datetime.datetime.strptime(accesskeydate, "%Y-%m-%d %H:%M:%S").timetuple())
currentd = time.mktime(datetime.datetime.strptime(currentdate, "%Y-%m-%d %H:%M:%S").timetuple())
active_days = (currentd - accesskeyd)/60/60/24 ### We get the data in seconds. converting it to days
if 90 < active_days:
a = str(username)
c = int(int(round(active_days)))
mylist.append(a)
mylist.append(c)
except:
f = str('')
print(mylist)
finallist = ''.join(str(mylist))
finallist = finallist
sns_message = (finallist)
response = sns.publish(
TopicArn='arn:aws:sns:eu-west-2:111111:sns',
Message= sns_message,
Subject='Access Keys which need rotating',
)
How do i ensure all the users are captured in the python query and then emailed out via SNS?
Thanks
If you read the IAM list_users() documentation, you will see that results can be truncated and you need to paginate. The response you get back will include IsTruncated=True in which case you need to re-issue the list_users() call, supplying Marker, which you retrieve from the previous response.
Alternatively, and probably preferably, you can use a built-in paginator.

How can I add the authentication step in my script?

I have a script below which I would like to schedule to run it everyday through SQL Server and store the calendar events to database but the problem is I would need to have my outlook open in order to run this script, how can I add my credential in the script so I don't have to open outlook and have the script run without keeping my outlook opened? Thank you
import win32com.client, datetime
from datetime import date
from dateutil.parser import *
import calendar
import pandas as pd
import pyodbc
Outlook = win32com.client.Dispatch("Outlook.Application")
ns = Outlook.GetNamespace("MAPI")
Item = Outlook.CreateItem ( 1 )
Recip = Item.Recipients.Add ( 'Corporate Master Calendar' )
appts = ns.GetSharedDefaultFolder(Recip,9).Items
appts.Sort("[Start]")
appts.IncludeRecurrences = "False"
eoy=date(date.today().year, 12, 31)
eoy=eoy.strftime("%m/%d/%Y")
begin = date.today()
begin = begin.strftime("%m/%d/%Y")
appts = appts.Restrict("[Start] >= '" +begin+ "' AND [Start] <= '" +eoy+ "'")
apptDict = {}
item = 0
for indx, a in enumerate(appts):
organizer = str(a.Organizer)
start = a.Start
end = a.End
subject = str(a.Subject)
location = str(a.Location)
categories = str(a.Categories)
body=str(a.Body)
itemid=str(a.GlobalAppointmentId)
lmt=str(a.LastModificationTime)
apptDict[item] = {"GlobalAppointmentId": itemid, "Organizer": organizer, "Subject": subject, "Location": location, "Start": start, "End": end, "Body": body,"Categories": categories, "LMT":lmt}
item = item + 1
You can't - with MFA, even storing the credentials in the keyring (which only deals with basic credentials) won't do anything.

Alert for Old Access Keys in AWS

I didn't get an answer to my original question, but I've tweaked my code and I'm leaving this here in case anyone is trying to figure this out in the future. I'm new to Python, but this worked. This is a Python script I created for a Lambda function that checks the users in your AWS account and publishes a notification to an SNS topic. I've scheduled a CloudWatch rule with a cron expression to run it every day.
import boto3, json, time, datetime, sys, re
iam_client = boto3.client('iam')
sns_client = boto3.client('sns')
users = iam_client.list_users()
user_list = []
for key in users['Users']:
user_list = key['UserName']
accesskeys = iam_client.list_access_keys(UserName=key['UserName'])
for items in user_list.split('\n'):
for key in accesskeys['AccessKeyMetadata']:
accesskeydate = accesskeys['AccessKeyMetadata'][0]['CreateDate']
accesskeydate = accesskeydate.strftime("%Y-%m-%d %H:%M:%S")
currentdate = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
accesskeyd = time.mktime(datetime.datetime.strptime(accesskeydate, "%Y-%m-%d %H:%M:%S").timetuple())
currentd = time.mktime(datetime.datetime.strptime(currentdate, "%Y-%m-%d %H:%M:%S").timetuple())
active_days = (currentd - accesskeyd)/60/60/24
message = (key['UserName'],int(round(active_days))),
message = re.sub(r'[^a-zA-Z0-9 ]', "", str(message))
message = re.sub(r' ', ' is ', str(message))
if active_days >= 90:
sns_client.publish(
TopicArn='arn:aws:sns:us-west-2:xxxxxxxxxxxxx:topic-name',
Subject='User with Old Access Key Detected',
Message="The access key for " + str(message) + " days old. This user access key should be replaced ASAP.",
)

Lambda function to check if specific tag do NOT exists-python

I'm trying to get following:
Get all EC2 instances that either:
are Tagged with tag Owner and value Unknown or unknown
are missing tag Owner
I'm able to accomplish 1) but no idea how to get 2)
import boto3
import collections
import datetime
import time
import sys
ec = boto3.client('ec2', 'eu-west-1')
ec2 = boto3.resource('ec2', 'eu-west-1')
def lambda_handler(event, context):
instance_ids = []
reservations = ec.describe_instances(
Filters=[
{'Name': 'tag:Owner', 'Values': ['Unknown', 'unknown']},
]
).get('Reservations', [])
for reservation in reservations:
instances = reservation['Instances']
for instance in instances:
instance_ids.append(instance['InstanceId'])
print("Stopping instances: {}".format(','.join(instance_ids)))
Like I said in the comment you want to forgo the Owner filter so your response includes instances without Owner tag as well, and then you get to filtering locally.
reservations = ec.describe_instances().get('Reservations', [])
for reservation in reservations:
for instance in reservation['Instances']:
tags = {}
for tag in instance['Tags']:
tags[tag['Key']] = tag['Value']
if not 'Owner' in tags:
print instance['InstanceId'] + " does not have Owner tag"
elif tags['Owner'] in ['Unknown', 'unknown']:
print instance['InstanceId'] + " has [U|u]nknown Owner tag"
If you have a large number of instances in your account, the response to describe_instances may be paginated, and you'll have to deal with that as well.
Combining code from my question and #Rage answer i managed to get what i want
Thanks again RaGe !!
import boto3
import collections
import datetime
import time
import sys
ses = boto3.client('ses')
email_from = 'Email'
email_to = 'Email'
email_cc = 'Email'
emaiL_subject = 'Subject'
email_body = 'Body'
ec = boto3.client('ec2', 'eu-west-1')
ec2 = boto3.resource('ec2', 'eu-west-1')
from datetime import datetime
from dateutil.relativedelta import relativedelta
#create date variables
date_after_month = datetime.now()+ relativedelta(days=7)
#date_after_month.strftime('%d/%m/%Y')
today=datetime.now().strftime('%d/%m/%Y')
def lambda_handler(event, context):
#Get instances with Owner Taggs and values Unknown/known
instance_ids = []
reservations = ec.describe_instances().get('Reservations', [])
for reservation in reservations:
for instance in reservation['Instances']:
tags = {}
for tag in instance['Tags']:
tags[tag['Key']] = tag['Value']
if not 'Owner' in tags or tags['Owner']=='unknown' or tags['Owner']=='Unknown':
instance_ids.append(instance['InstanceId'])
#Check if "TerminateOn" tag exists:
if 'TerminateOn' in tags:
#compare TerminteOn value with current date
if tags["TerminateOn"]==today:
#Check if termination protection is enabled
terminate_protection=ec.describe_instance_attribute(InstanceId =instance['InstanceId'] ,Attribute = 'disableApiTermination')
protection_value=(terminate_protection['DisableApiTermination']['Value'])
#if enabled disable it
if protection_value == True:
ec.modify_instance_attribute(InstanceId=instance['InstanceId'],Attribute="disableApiTermination",Value= "False" )
#terminate instance
ec.terminate_instances(InstanceIds=instance_ids)
print "terminated" + str(instance_ids)
#send email that instance is terminated
else:
#Send an email to engineering that this instance will be removed X amount of days (calculate the date based on today's date and the termination date."
now=datetime.now()
future=tags["TerminateOn"]
TerminateOn = datetime.strptime(future, "%d/%m/%Y")
days= (TerminateOn-now).days
print str(instance_ids) + " will be removed in "+ str(days) + " days"
else:
if not 'TerminateOn' in tags:#, create it
ec2.create_tags(Resources=instance_ids,Tags=[{'Key':'TerminateOn','Value':date_after_month.strftime('%d/%m/%Y')}])
ec.stop_instances(InstanceIds=instance_ids)
print "was shut down "+format(','.join(instance_ids))

Send an email only if # isn't in csv

I have two CSV files, one with IOC hits and a second that is a watchfile. The watchfile adds an # to the file along with the IOC domain and last seen date. I'm trying to send one email when an IOC hit for that day, but I can't seem to get my loop right. Currently it emails every time, even though the # is present in the watchfile.csv. I've printed the values for val and emailed and they show up in the correct format, but it still emails every time the script is ran.
finIOChit.csv
last: 2017-01-17 query: rabbitons.pw,
watchfile.csv
last: 2017-01-17 query: # rabbitons.pw,
import smtplib
import csv
import os
import re
from datetime import *
today = date.today()
today = datetime.combine(today, datetime.min.time())
# Setup email alerting
sender = 'server#company.com'
receivers = ['user#company.com']
patn = re.compile('20\d{2}-\d{2}-\d{2}')
watchfile = open('watchfile.csv', 'r+w')
alreadyemailed = re.compile('#')
with open('finalIOChit.csv') as finalhit:
for hit in finalhit:
for line in watchfile:
emailed = alreadyemailed.findall(line)
for match in patn.findall(hit):
val = datetime.strptime(match, '%Y-%m-%d')
if val == today and emailed != '#':
hit = re.sub('query: ','query: # ',hit)
watchfile.write(hit)
message = """From:server <server#comapny.com>
To: user <user#company.com>
Subject: Passive DNS hit
"""
subject = ' ' + str(hit)
messagefull = message + subject
try:
smtpObj = smtplib.SMTP('emailserver')
smtpObj.sendmail(sender, receivers, messagefull)
except SMTPException:
print "Error: unable to send email"

Categories