AWS Lambda, SNS and Python - "Missing final '#domain'" - amazon-web-services

I am trying to send SNS messages for old AWS access keys, but am getting the below error:
Response
null
Function Logs
START RequestId: a266bda6-2d17-4c24-a6d3-a0a05180025b Version: $LATEST
[ERROR] 2021-03-17T15:48:33.592Z a266bda6-2d17-4c24-a6d3-a0a05180025b Missing final '#domain'
I have tried Googling a bit, and the IAM user accounts are NOT email addresses - just people's first names. The SNS subscriber is already setup, so I'm not sure why it would care to know a user's email address.
Any ideas?
Python Script below:
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 >= 1:
sns_client.publish(
TopicArn='<redacted SNS topic>',
Subject='User with Old Access Key Detected',
Message="The access key for " + str(message) + " days old. This user access key should be replaced ASAP.",

if active_days >= 1:
sns_client.publish(
TopicArn='<redacted SNS topic>',
Subject='User with Old Access Key Detected',
For Publishing the message you don't need Subject. You can send message as described as here
SNS Publish API Call
Subject
Optional parameter to be used as the "Subject" line when the message is delivered to email endpoints. This field will also be included, if present, in the standard JSON messages delivered to other endpoints.
To publish a message to a topic, we simply call the publish() function, passing the topic’s ARN, the desired message, and optionally a subject (it will only be used in email messages).
aws examples for sns operations using boto3

Related

How to send all the results from a lambda function in one email using aws sns

I have a lambda script that extract all the filenames in a bucket that were uploaded more than one hour before and send an email via sns. My lambda function works well. However instead of receiving one mail containing all the files, I receive one email for each file. This means that when I have 100 files found by the lambda, I receive 100 emails.
Is there a way to group all the files and just receive one email from sns ?
Here is my lambda sample script:
import boto3
import json
from datetime import datetime, timedelta, timezone
def lambda_handler(event, context):
AWS_REGION = "aws-region"
sns_resource = boto3.resource('sns', region_name=AWS_REGION)
TOPIC_ARN = 'sns_topic_arn'
sns_topic = sns_resource.Topic(TOPIC_ARN)
s3_client = boto3.client('s3')
paginator = s3_client.get_paginator('list_objects_v2')
page_iterator = paginator.paginate(
Bucket = 'bucket',
Prefix = 'data/raw/mdf/'
)
for page in page_iterator:
for object in page['Contents']:
if object['LastModified'] < datetime.now(tz=timezone.utc) - timedelta(hours=2):
message = object['Key']
sns_topic.publish(Message=message)
any help is welcome
Best regards
If you do not want to get a message for every file found, you should not publish a message for every iteration in your for loop.
So the following line should be outside of the for loop:
sns_topic.publish(Message=message)
Within the for loop you only create the message. After the for loop you publish it.
Example:
keys = []
for page in page_iterator:
for object in page['Contents']:
if object['LastModified'] < datetime.now(tz=timezone.utc) - timedelta(hours=2):
keys.append(object['Key'])
message = ",".join(keys)
sns_topic.publish(Message=message)
This will create a list of keys and then create a message that is just those keys separated by a comma (,).
You could create a message where every key is on a new line. This is up to you.
Beware: this does not scale. If you have thousands of files that have been created, the email won't help much.
You might be better off using AWS SES and sending an email with a file as attachment. The file contains a list of new keys.

Send emails by reading email address from S3

I am trying the following -
Read the email address from a csv file in S3, first column has email address, second column has the subject, third column has the body of the email.
Send email with the subject and body to the email address read from S3.
I was able to read the file in S3 into a DF using Lambda, but unable to send the email. Any ideas on how to do this using AWS services
you can use same lambda function to create smtp server of your own to send emails. e.g. while parsing data from the S3 csv file, for each entry in csv send email.
#!/usr/bin/env python
import smtplib
from email.mime.text import MIMEText
sender = 'xx#xx.com' # parsed data
receivers = ['yy#yy.com'] # parsed data
port = 1025
msg = MIMEText('email text') # parsed data
msg['Subject'] = 'Test mail'
msg['From'] = sender
msg['To'] = receivers
with smtplib.SMTP('localhost', port) as server:
server.sendmail(sender, receivers, msg.as_string())
print("email sent")
You can send emails from within a Lambda function by invoking the SES service. There is an example of creating a Lambda function (implemented in Java) that shows how to send an email message as part of a larger workflow created using AWS Step Functions. See this example:
Create AWS serverless workflows by using the AWS SDK for Java

SNS publish to topic with phone number is not working

I have boto3 code that creates a topic and creates a subscription to that topic and publishes the message to the topic.
The code was working fine. I tried to add a US number to the mix of Indian phone number subscribed group and everything went south. I don't get any errors all the responses are successful but I don't receive any messages.
Then I tried with normal console publish a message, even the console publish is not working.
TO cross-verify it the issue was with the region I tried publishing in us-east-1 and all worked fine.
Here is my code:
def lambda_handler(event, context):
sns = boto3.client("sns")
number = ['+91xxxxxxxx','+1xxxxxxxxxxxx','+91xxxxxxxxxx']
response = sns.create_topic(
Name='loadeo-demo',
Attributes={
}
)
arn = response['TopicArn']
print ("arn: " + arn)
for phno in number:
response = sns.subscribe(
TopicArn=arn,
Protocol='sms',
Endpoint=phno,
Attributes={
},
ReturnSubscriptionArn=False
)
# print(response)
response = sns.list_subscriptions_by_topic(
TopicArn=arn
)
print (response)
response = sns.publish(
topicArn=arn,
Message="A Load of your interest has been placed.\n" + "Please visit the web for more details.\n" + "Thank you",
)

Cleanup older SNS subscriptions

As a team we inherited an project that is using Amazon SNS to publish mobile notifications to mobile apps, this system is already active for multiple years.
The system works as following
We create a customer specific Topic
We register a new endpoint with the GCM or APN token
We noticed in older setups we had some stale endpoint data e.g. of apps that where reinstalled, uninstalled, ...
We would like to do 2 things
Cleanup that older endpoints that are not active anymore (Can we do this purely on the "status" of the endpoint?)
Actively react on when a device comes inactive - I read on how you can subscribe on "EndpointUpdated" events with an http endpoint - but it's not clear to me how can we determine that the "EndpointUpdated" is an uninstall, ... so we could clean this up?
Thanks
Python 3.6
Boto3
Need to Configure AWS Profile Account in your Local.
import boto3
def start_process(aws_profile_name):
session = boto3.Session(profile_name=aws_profile_name)
sns_client = session.client('sns')
print("Started Process")
list_of_sns = sns_client.list_topics()
list_of_topics = [x.get("TopicArn") for x in list_of_sns.get('Topics')]
for topic in list_of_topics:
try:
subscriptions = sns_client.list_subscriptions_by_topic(TopicArn=topic)
list_of_subscription = [s.get("SubscriptionArn") for s in subscriptions.get('Subscriptions')]
unsubscribe(list_of_subscription, sns_client)
sns_client.delete_topic(TopicArn=topic)
print(f"Successfully Deleted Topic - {topic}")
except Exception:
print(f"Failed to delete the sns - {topic}")
subscriptions = sns_client.list_subscriptions()
print(subscriptions)
list_of_subscription = [s.get("SubscriptionArn") for s in subscriptions.get('Subscriptions')]
unsubscribe(list_of_subscription, sns_client)
def unsubscribe(subscription_arn: list, sns_client):
for arn in subscription_arn:
try:
sns_client.unsubscribe(SubscriptionArn=arn)
print(f"Successfully unsubscribe - {arn}")
except Exception:
print(f"Failed to unsubscribe - {arn}")
print("""
Here Profile name like where access key
and secret key you stored Locally
To See
--------------------------
cat ~/.aws/creddential
To Add new One:
--------------------------
aws configure --profile <your custom profile name>
""")
profile_name = input(f"Enter the profile name (i;e 'archive'): ")
start_process(profile_name)

boto3 - aws sns - specify Sender ID

The following code works to send a message but when it arrives, it displays the text 'VERIFY' for a sender id. How do I specific a sender ID? I think it's done with the message attributes but I cannot figure out the syntax.
session = boto3.session.Session(profile_name='Credentials',region_name='us-east-1')
theMessage='Now is the time for all good people to come to the aid of their party'
senderID='Godzilla'
snsclient = session.client('sns')
response = snsclient.publish(PhoneNumber='+84932575571', Message=theMessage)
pp = pprint.PrettyPrinter(indent=4)
print(pp.pprint(response))
Add a third parameter MessageAttributes to the publish method.
snsclient.publish(PhoneNumber='+84932575571', Message=theMessage,MessageAttributes={
'AWS.SNS.SMS.SenderID': {
'DataType': 'String',
'StringValue': 'Godzilla'
}})
The sender id is not supported in many countries. see AWS SNS SMS SenderId Supported Countries