Cloudformation Lambda function, environment variables not available, input is not available - amazon-web-services

Not sure where I am doing wrong. Below is my lambda code and cloudformation template.
Below is my lambda function:
import os
import boto3
def quickstart_lambda_handler(event, context):
print("event={}".format(event)) # nothing shows as k1:v1
print(os.environ) # nothing show in output as var1
print("environment variable var1: " + os.environ['var1'])
json_str = "{\"a1\":\"b1\"}"
bucket_name = "my-s3-bucket"
file_name = "qs.json"
s3_path = "cf-quickstart/" + file_name
s3 = boto3.resource("s3")
s3.Bucket(bucket_name).put_object(Key=s3_path, Body=json_str)
print("object stored in s3")
return s3_path
My cloud formation template is as below for lambda function and associated rule.
"QSLERole": {
"Description" : "Quick Start Lambda Execution Role",
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName" : "QSLERole",
"AssumeRolePolicyDocument": {
"Version" : "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [ "lambda.amazonaws.com" ]
},
"Action": [ "sts:AssumeRole" ]
}]
},
"Path": "/",
"Policies": [
{
"PolicyName": "root",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["logs:*"],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "*"
}
]
}
}]
}
},
"QSLambdaF": {
"Description" : "Quick Start Lambda Function",
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": "my-s3-bucket",
"S3Key": "generate-quickstartjson.zip"
},
"Handler": "generate-quickstartjson.quickstart_lambda_handler",
"Runtime": "python2.7",
"Timeout": "30",
"Environment" : {
"Variables" : {
"var1" : "var1 value"
}
},
"Role": {
"Fn::GetAtt": [
"QSLERole",
"Arn"
]
}
}
},
"ScheduledRule": {
"Description" :"Cloud Watch Quick Start Event Rule",
"DependsOn" : [
"QSLambdaF","EC2Instance"],
"Type": "AWS::Events::Rule",
"Properties" : {
"Description" : "CloudWatch Event for generating output",
"ScheduleExpression" : "rate(1 minute)",
"State": "ENABLED",
"Targets" : [
{
"Arn": { "Fn::GetAtt": [
"QSLambdaF", "Arn"] },
"Detail" : {
"test" : "value"
},
"Input": "{\"k1\":\"v1\"}",
"Id" : "QSScheduledRuleV1"
}
]
}
},
"PEILambda": {
"Description" : "Permission For Events To Invoke Lambda Function",
"Type": "AWS::Lambda::Permission",
"Properties" : {
"FunctionName": { "Ref": "QSLambdaF"},
"Action": "lambda:InvokeFunction",
"Principal": "events.amazonaws.com",
"SourceArn": { "Fn::GetAtt": [
"ScheduledRule", "Arn"] }
}
},
--- ec2 instance creation below with security group
Niether environment variables are available nor Input fields are available in lambda lambda.
"Input": "{\"k1\":\"v1\"}",
Please let me know where I am wrong. Thanks for the help.

works well as is. I was using wrong template file :))

Related

AWS Firehose DynamicPartitioningConfiguration/Prefix simply won't work

I've been slamming my head against the wall for the past 2 days trying to get dynamic partitioning to work in the delivery stream I'm creating using a serverless application model template. I've tried multiple configurations, but it seems as soon as I fill in a prefix, enable dynamic partitioning and add a metadata extraction processor to get myself a field I can use as the prefix my stack stops working, I can generate alerts in aws and see the logs from the lambda processor I also added, but no files reach the bucket, I also can't seem to configure cloudwatch logs for the stream as well, since I've tried creating them through the script and manually and neither at least have logs pertaining to any error....
I'll leave my script here, hopefully I'm doing something wrong:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Transform": "AWS::Serverless-2016-10-31",
"Description": "An AWS Serverless Application.",
"Parameters": {
"BucketArn": {
"Type": "String"
}
},
"Resources": {
"DeliveryPolicy": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "K-POLICY",
"Roles": [
{
"Ref": "DeliveryRole"
}
],
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
{
"Ref": "BucketArn"
}
]
},
{
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction",
"lambda:GetFunctionConfiguration"
],
"Resource": [
{
"Fn::GetAtt": [
"Processor",
"Arn"
]
}
]
}
]
}
}
},
"DeliveryRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"firehose.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
}
}
},
"DeliveryStream": {
"Type": "AWS::KinesisFirehose::DeliveryStream",
"Properties": {
"DeliveryStreamName": "K-STREAM",
"DeliveryStreamType": "DirectPut",
"ExtendedS3DestinationConfiguration": {
"BucketARN": {
"Ref": "BucketArn"
},
"Prefix": "!{partitionKeyFromQuery:symb}",
"ErrorOutputPrefix": "errors/!{firehose:random-string}/!{firehose:error-output-type}/!{timestamp:yyyy/MM/dd}",
"RoleARN": {
"Fn::GetAtt": [
"DeliveryRole",
"Arn"
]
},
"DynamicPartitioningConfiguration": {
"Enabled": true
},
"ProcessingConfiguration": {
"Enabled": true,
"Processors": [
{
"Type": "MetadataExtraction",
"Parameters": [
{
"ParameterName": "MetadataExtractionQuery",
"ParameterValue": "{symb: .TICKER_SYMBOL}"
},
{
"ParameterName": "JsonParsingEngine",
"ParameterValue": "JQ-1.6"
}
]
},
{
"Type": "Lambda",
"Parameters": [
{
"ParameterName": "LambdaArn",
"ParameterValue": {
"Fn::GetAtt": [
"Processor",
"Arn"
]
}
}
]
}
]
}
}
}
},
"Processor": {
"Type": "AWS::Serverless::Function",
"Properties": {
"Handler": "K-PROCESSOR::KRATOS_PROCESSOR.Functions::FunctionHandler",
"FunctionName": "K-PROCESSOR",
"Runtime": "dotnetcore3.1",
"CodeUri": "./staging/app/3cs-int-k",
"MemorySize": 256,
"Timeout": 60,
"Role": null,
"Policies": [
"AWSLambdaBasicExecutionRole"
]
}
}
}
}

Need help on CloudFormation template and AWS lambda for pulling events from SQS to S3 via lambda

I am new to AWS CloudFormation, and I am trying to capture events from SQS Queue and place them in S3 bucket via AWS lambda. Flow of events is
SNS --> SQS <-- Lambda ---> S3 bucket.
I am trying to achieve above flow using cloudFormation template.I am getting below error message after deploying my CloudFormation template. Any help you can provide would be greatly appreciated. Thank you
11:51:56 2022-01-13 17:51:47,930 - INFO - ...
11:52:53 2022-01-13 17:52:48,511 - ERROR - Stack myDemoApp shows a rollback status ROLLBACK_IN_PROGRESS.
11:52:53 2022-01-13 17:52:48,674 - INFO - The following root cause failure event was found in the myDemoApp stack for resource EventStreamLambda:
11:52:53 2022-01-13 17:52:48,674 - INFO - Resource handler returned message: "Error occurred while GetObject. S3 Error Code: NoSuchKey.
S3 Error Message: The specified key does not exist. (Service: Lambda, Status Code: 400, Request
ID: 5f2f9882-a863-4a58-90bd-7e0d0dfdf4d5, Extended Request ID: null)" (RequestToken: 0a95acb4-a677-0a2d-d0bc-8b7487a858ad, HandlerErrorCode: InvalidRequest)
11:52:53 2022-01-13 17:52:48,674 - INFO - ..
MY lambda function is :
import json
import logging
import boto3
logger = logging.getLogger()
logger.setLevel(logging.INFO)
logging.basicConfig(level=logging.INFO,
format='%(asctime)s: %(levelname)s: %(message)s')
def lambda_handler(event, context):
logger.info(f"lambda_handler -- event: {json.dumps(event)}")
s3_bucket = boto3.resource("3")
event_message = json.loads(event["Records"][0]["body"])
s3_bucket.put_object(Bucket="S3DeployBucket", key="data.json", Body=json.dumps(event_message))
My complete CloudFormation template is :
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "myDemoApp Resource Stack",
"Mappings": {
},
"Parameters": {
"S3DeployBucket": {
"Default": "myDemoApp-deploy-bucket",
"Description": "Bucket for deployment configs and artifacts for myDemoApp",
"Type": "String"
},
"EnvName": {
"Description": "Platform environment name for myDemoApp",
"Type": "String"
},
"AuditRecordKeyArn": {
"Description": "ARN for audit record key encryption for myDemoApp",
"Type": "String"
},
"ParentVPCStack": {
"Description": "The name of the stack containing the parent VPC for myDemoApp",
"Type": "String"
},
"StackVersion": {
"Description": "The version of this stack of myDemoApp",
"Type": "String"
},
"EventLogFolderName": {
"Type": "String",
"Description": "folder name for the logs for the event stream of myDemoApp",
"Default": "event_log_stream"
},
"EventLogPartitionKeys": {
"Type": "String",
"Description": "The partition keys that audit logs will write to S3. Use Hive-style naming conventions for automatic Athena/Glue comprehension.",
"Default": "year=!{timestamp:yyyy}/month=!{timestamp:MM}/day=!{timestamp:dd}/hour=!{timestamp:HH}"
},
"AppEventSNSTopicArn": {
"Description": "Events SNS Topic of myDemoApp",
"Type": "String"
},
"ReportingEventsRetentionDays": {
"Default": "2192",
"Description": "The number of days to retain a record used for reporting.",
"Type": "String"
}
},
"Resources": {
"AppEventSQSQueue": {
"Type": "AWS::SQS::Queue"
},
"AppEventSnsSubscription": {
"Type": "AWS::SNS::Subscription",
"Properties": {
"TopicArn": {
"Ref": "AppEventSNSTopicArn"
},
"Endpoint": {
"Fn::GetAtt": [
"AppEventSQSQueue",
"Arn"
]
},
"Protocol": "sqs"
}
},
"S3DeployBucket": {
"Type": "AWS::S3::Bucket",
"DeletionPolicy": "Retain",
"UpdateReplacePolicy": "Retain",
"Properties": {
"BucketEncryption": {
"ServerSideEncryptionConfiguration": [
{
"ServerSideEncryptionByDefault": {
"KMSMasterKeyID": {
"Ref": "AuditRecordKeyArn"
},
"SSEAlgorithm": "aws:kms"
}
}
]
},
"VersioningConfiguration": {
"Status": "Enabled"
},
"LifecycleConfiguration": {
"Rules": [
{
"ExpirationInDays": {
"Ref": "ReportingEventsRetentionDays"
},
"Status": "Enabled"
}
]
}
}
},
"EventStreamLogGroup": {
"Type": "AWS::Logs::LogGroup"
},
"EventLogStream": {
"Type": "AWS::Logs::LogStream",
"Properties": {
"LogGroupName": {
"Ref": "EventStreamLogGroup"
}
}
},
"EventStreamSubscriptionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "sns.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"Policies": [
{
"PolicyName": "SNSSQSAccessPolicy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": {
"Action": [
"sqs:*"
],
"Effect": "Allow",
"Resource": "*"
}
}
}
]
}
},
"EventDeliveryRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "sqs.amazonaws.com"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": {
"Ref": "AWS::AccountId"
}
}
}
}
]
}
}
},
"EventSqsQueuePolicy": {
"Type": "AWS::SQS::QueuePolicy",
"Properties": {
"PolicyDocument": {
"Version": "2012-10-17",
"Id": "SqsQueuePolicy",
"Statement": [
{
"Sid": "Allow-SNS-SendMessage",
"Effect": "Allow",
"Principal": "*",
"Action": [
"sqs:SendMessage",
"sqs:ReceiveMessage"
],
"Resource": {
"Fn::GetAtt": [
"EventStreamLambda",
"Arn"
]
},
"Condition": {
"ArnEquals": {
"aws:SourceArn": {
"Ref": "EventSNSTopicArn"
}
}
}
}
]
},
"Queues": [
{
"Ref": "EventSNSTopicArn"
}
]
}
},
"EventDeliveryPolicy": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "sqs_delivery_policy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": [
{
"Fn::GetAtt": [
"S3DeployBucket",
"Arn"
]
},
{
"Fn::Join": [
"",
[
{
"Fn::GetAtt": [
"S3DeployBucket",
"Arn"
]
},
"/*"
]
]
}
]
},
{
"Effect": "Allow",
"Action": [
"logs:PutLogEvents"
],
"Resource": {
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:${EventStreamLogGroup}:log-stream:${EventLogStreamLogStream}"
}
},
{
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey"
],
"Resource": [
{
"Ref": "AuditRecordKeyArn"
}
],
"Condition": {
"StringEquals": {
"kms:ViaService": {
"Fn::Join": [
"",
[
"s3.",
{
"Ref": "AWS::Region"
},
".amazonaws.com"
]
]
}
},
"StringLike": {
"kms:EncryptionContext:aws:s3:arn": {
"Fn::Join": [
"",
[
{
"Fn::GetAtt": [
"S3DeployBucket",
"Arn"
]
},
"/*"
]
]
}
}
}
}
]
},
"Roles": [
{
"Ref": "EventDeliveryRole"
}
]
}
},
"EventStreamLambda": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Handler": "lambda_function.lambda_handler",
"MemorySize": 128,
"Runtime": "python3.8",
"Timeout": 30,
"FunctionName": "sqs_s3_pipeline_job",
"Role": {
"Fn::GetAtt": [
"SQSLambdaExecutionRole",
"Arn"
]
},
"Code": {
"S3Bucket": {
"Ref": "S3DeployBucket"
},
"S3Key": {
"Ref": "S3DeployBucket"
}
},
"TracingConfig": {
"Mode": "Active"
}
}
},
"SQSLambdaExecutionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Policies": [
{
"PolicyName": "StreamLambdaLogs",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:*"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
}
},
{
"PolicyName": "SQSLambdaPolicy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sqs:ReceiveMessage",
"sqs:DeleteMessage",
"sqs:GetQueueAttributes",
"sqs:ChangeMessageVisibility"
],
"Resource":"*"
}
]
}
}
]
}
}
},
"Outputs": {
"VpcSubnet3ExportKey": {
"Value": {
"Fn::Sub": "${ParentVPCStack}-privateSubnet3"
}
}
}
}
SubscriptionRoleArn is only for kinesis:
This property applies only to Amazon Kinesis Data Firehose delivery stream subscriptions.

cloudwatchevent_rule default to latest version of lambda function

I am trying to automate the creation of a lambda function and cloudwatch rule for it. However it seems that the cloudwatchevent_rule ansible task requires a version id to attach itself to my lambda function. This is causing an error:
No target to arn:aws:lambda:us-east-
1:MYACCOUNTID:function:MYFUNCTIONNAME could be found on the rule
MYFUNCTIONNAME.
How can I change this so that the cloudwatch rule will always attach itself to the latest version of my lambda function:
- name: create cloudwatch rule
cloudwatchevent_rule:
name: 'name_for_rule'
region: "{{region}}"
description: 'trigger on new instance creation'
state: present
event_pattern: |-
{
"detail-type": [
"AWS API Call via CloudTrail"
],
"detail": {
"eventSource": [
"ec2.amazonaws.com"
],
"eventName": [
"RunInstances"
]
}
}
targets:
- id: "{{ lambda.configuration.version }}"
arn: "{{ lambda.configuration.function_arn }}"
I've configured a Lambda Function with CloudWatch rule triggering it. The following SAM Template also contains permission, policy and roles I require. Please ignore those if not required.
{
"AWSTemplateFormatVersion": "2010-09-09",
"Transform": "AWS::Serverless-2016-10-31",
"Description": "AWS SAM template configuring lambda functions written in test package.",
"Resources": {
"OrchestratorTestLambdaFunction": {
"DependsOn": [
"LambdaPolicy"
],
"Type": "AWS::Lambda::Function",
"Properties": {
"Handler": "com.test.TestClass::orchestrateTestLambda",
"FunctionName": "OrchestratorTestLambda",
"Runtime": "java8",
"MemorySize": 256,
"Timeout": 60,
"Code": {
"S3Bucket": "BATS::SAM::CodeS3Bucket",
"S3Key": "BATS::SAM::CodeS3Key"
},
"Role": {
"Fn::GetAtt": [
"LambdaRole",
"Arn"
]
},
"Description": "Lambda reads from SQS provided in the cloud watch."
}
},
"LambdaRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "LambdaRole",
"AssumeRolePolicyDocument": {
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
}
},
"LambdaPolicy": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "lambda_policy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Action": [
"sqs:DeleteMessage",
"sqs:ReceiveMessage"
],
"Resource": [
{
"Fn::Sub": "arn:aws:sqs:eu-west-1:${AWS::AccountId}:TestUpdates"
}
]
},
{
"Sid": "",
"Action": [
"lambda:InvokeAsync"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Sid": "",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
},
"Roles": [
{
"Ref": "LambdaRole"
}
]
}
},
"PermissionForEventsToInvokeLambda": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Ref": "OrchestratorTestLambdaFunction"
},
"Action": "lambda:InvokeFunction",
"Principal": "events.amazonaws.com",
"SourceArn": {
"Fn::GetAtt": [
"TestRule",
"Arn"
]
}
}
},
"TestRule": {
"Type": "AWS::Events::Rule",
"Properties": {
"Name": "TestRule",
"Description": "Rule to Trigger OrchestratorTestLambdaFunction",
"ScheduleExpression": "rate(1 minute)",
"State": "ENABLED",
"Targets": [
{
"Arn": {
"Fn::GetAtt": [
"OrchestratorTestLambdaFunction",
"Arn"
]
},
"Id": "TestRuleV1",
"Input": {
"Fn::Sub": "{\"queueUrl\":\"https://sqs.eu-west-1.amazonaws.com/${AWS::AccountId}/TestUpdates\"}"
}
}
]
}
}
},
"Outputs": {
"StackArn": {
"Value": {
"Ref": "AWS::StackId"
},
"Description": "Use this as the stack_arn in your cloud_formation_deployment_stack override."
}
}
}
I've noticied that function_arn registered from lambda ansible module output is not consistent.
Some times is
"function_arn": "arn:aws:lambda:zone:account:function:name"
other time is:
"function_arn": "arn:aws:lambda:zone:account:function:name:version"
So I've construct the arn appending always the $LATEST version:
- cloudwatchevent_rule:
profile: "{{ aws_profile }}"
name: StartStop
schedule_expression: cron(* * * * ? *)
description: trigger my lambda
targets:
- id: StartStop
arn: "arn:aws:lambda:{{aws_zone}}:{{aws_account_id}}:function:{{lambdadeploy.configuration.function_name}}:$LATEST"

SNS topic not triggering Lambda

I am attempting to set up a email-sending lambda function that is triggered by an SNS topic in cloudformation, but for some reason it is not working. I went in and checked all of the dependencies/permissions after the lambda & sns went up and everything seems to be in order, but when I publish to the topic nothing happens. When I manually test the lambda in the Lambda console, it works perfectly.
Cloudformation
"Resources": {
"CloudformationEventHandlerLambdaExecutionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"Path": "/",
"Policies": [
{
"PolicyName": "CloudformationTrigger",
"PolicyDocument": {
"Statement": [
{
"Effect": "Allow",
"Action": [
"ses:*"
],
"Resource": [
"arn:aws:ses:*"
]
}
]
}
}
],
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
}
}
]
}
}
},
"CloudformationEventHandlerLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Handler": "lambda_function.lambda_handler",
"Role": {
"Fn::GetAtt": [
"CloudformationEventHandlerLambdaExecutionRole",
"Arn"
]
},
"Code": {
"S3Bucket": {
"Ref": "Bucket"
},
"S3Key": "CloudformationEventHandler.zip"
},
"Runtime": "python2.7",
"Timeout": "30"
},
"DependsOn": [
"CloudformationEventHandlerLambdaExecutionRole"
]
},
"CloudformationEventHandlerLambdaInvokePermission": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"Action": "lambda:InvokeFunction",
"SourceAccount": {
"Ref": "AWS::AccountId"
},
"Principal": "sns.amazonaws.com",
"SourceArn": {
"Ref": "CloudformationTopic"
},
"FunctionName": {
"Fn::GetAtt": [
"CloudformationEventHandlerLambdaFunction",
"Arn"
]
}
}
},
"CloudformationTopic": {
"Type": "AWS::SNS::Topic",
"Properties": {
"DisplayName": "CloudformationIngestTopic",
"Subscription": [
{
"Endpoint": {
"Fn::GetAtt": [
"CloudformationEventHandlerLambdaFunction",
"Arn"
]
},
"Protocol": "lambda"
}
]
},
"DependsOn": [ "CloudformationEventHandlerLambdaFunction" ]
}
}
Python SES Lambda
import boto3
client = boto3.client('ses')
def lambda_handler(event, context):
message = """
Event:
{}
Context:
{}
""".format(event, context)
response = client.send_email(
Source='***censored***',
Destination={ 'ToAddresses': [ ***censored***' ] },
Message={
'Subject': {
'Data': 'CFMTest'
},
'Body': {
'Text': {
'Data': message
}
}
}
)
The SourceAccount for the AWS::Lambda::Permission resource type is only meant to be used with Cloudwatch logs, CloudWatch rules, S3 and SES.
After removing this field from the CloudformationEventHandlerLambdaInvokePermission resource on your template, I am able to invoke the lambda function by publishing to the SNS topic.
Refer to this documentation for more information regarding lambda permissions

"Fn::Join" with delimiter from a parameter?

I'm trying to parametise the delimiter used by an Fn::Join, e.g. at first I had:
"Name" : { "Fn::Join" : [ ".", [
{ "Ref":"serviceName"}, { "Ref": "environment" } ] ] },
Which works well, but then I changed it to:
"Name" : { "Fn::Join" : [ {"Ref":"HostNameSeparator"}, [
{ "Ref":"serviceName"}, { "Ref": "environment" } ] ] },
I get the following error from the validation phase:
A client error (ValidationError) occurred when calling the
ValidateTemplate operation: Template error: every Fn::Join object
requires two parameters, (1) a string delimiter and (2) a list of
strings to be joined or a function that returns a list of strings
(such as Fn::GetAZs) to be joined.
Is it possible to do what I want, i.e. pass the Join delimiter as a template parameter?
(I've shortened the examples above for clarity sake, please ignore typos)
You can achieve this by using a CustomResource.
This CloudFormation Template is ready to run and illustrates how it could work. Delimiter is passed as a parameter and you'll find the joined string in the Outputs of the stack.
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Example Join",
"Parameters": {
"Delimiter": {
"Type": "String"
}
},
"Resources": {
"LambdaExecutionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": ["lambda.amazonaws.com"]
},
"Action": ["sts:AssumeRole"]
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": "root",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"cloudformation:DescribeStacks"
],
"Resource": "*"
}
]
}
}
]
}
},
"LambdaJoin": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"ZipFile": { "Fn::Join": ["\n", [
"var response = require('cfn-response');\n",
"exports.handler = function (event, context) {\n",
"if (event.RequestType === 'Delete') {\n",
"return response.send(event, context, response.SUCCESS, {}, event.PhysicalResourceId);\n",
"}\n",
"var delimiter = event.ResourceProperties.delimiter || '';\n",
"var strings = event.ResourceProperties.strings || [];\n",
"return response.send(event, context, response.SUCCESS, { string: strings.join(delimiter) }, event.PhysicalResourceId);\n",
"};\n"
]]}
},
"Handler": "index.handler",
"Runtime": "nodejs",
"Timeout": "10",
"Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }
}
},
"CustomJoin": {
"Type": "Custom::Join",
"Version": "1.0",
"Properties": {
"ServiceToken": { "Fn::GetAtt": ["LambdaJoin", "Arn"] },
"delimiter": { "Ref": "Delimiter" },
"strings": ["first", "second", "third"]
},
"DependsOn": ["LambdaJoin"]
}
},
"Outputs": {
"JoinedString": {
"Value": { "Fn::GetAtt": ["CustomJoin", "string"] }
}
}
}