0
votes

Using AWS Amplify CLI, I've created a Lambda function for my project. It created a Cloudformation template as part of that process. I'm editing the template, adding an IoT rule to trigger the lambda function. The function name itself changes per environment, along with the Lambda function ARN I'm attempting to target in my IoT rule section.

Here's the section I'm working on now:

"IoTRuleS3RequestSignedUrl": {
    "Type": "AWS::IoT::TopicRule",
    "Properties": {
        "RuleName": "twinTigerSecurityS3SignedUrlRequests",
        "TopicRulePayload": {
            "Actions": [
                {
                    "Lambda": {
                        "FunctionArn": "HOW DO I REFERENCE THIS DYNAMIC ARN?"
                    }
                }
            ],
            "Description": "Get S3 bucket signed URL to upload image directly to S3.",
            "RuleDisabled": false,
            "Sql": "SELECT operation, bucket, key, replyTo FROM 'iot/topic'"
        }
    }
} 

Here's the full template in progress:

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "Lambda resource stack creation using Amplify CLI",
    "Parameters": {
        "CloudWatchRule": {
            "Type": "String",
            "Default" : "NONE",
            "Description" : " Schedule Expression"
        },
        "env": {
            "Type": "String"
        }

    },
    "Conditions": {
        "ShouldNotCreateEnvResources": {
            "Fn::Equals": [
                {
                    "Ref": "env"
                },
                "NONE"
            ]
        }
    },
    "Resources": {
        "LambdaFunction": {
        "Type": "AWS::Lambda::Function",
        "Metadata": {
            "aws:asset:path": "./src",
            "aws:asset:property": "Code"
        },
        "Properties": {
            "Handler": "index.handler",
            "FunctionName": {
                "Fn::If": [
                    "ShouldNotCreateEnvResources",
                    "twinTigerSecurityRequestS3SignedUrl", 
                    {

                        "Fn::Join": [
                            "",
                            [
                                "twinTigerSecurityRequestS3SignedUrl",
                                "-",
                                {
                                    "Ref": "env"
                                }
                            ]
                        ]
                    }      
                ]
            },
            "Environment": {
                "Variables" : {
                    "ENV": {
                        "Ref": "env"
                    },
                    "REGION": { 
                        "Ref": "AWS::Region"
                    }

                }
            },
            "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] },
            "Runtime": "nodejs12.x",
            "Timeout": "25"
        }
        },
        "LambdaExecutionRole": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "RoleName": {
                    "Fn::If": [
                        "ShouldNotCreateEnvResources",
                        "twintigersecurityLambdaRolebf1a383b", 
                        {

                            "Fn::Join": [
                                "",
                                [
                                    "twintigersecurityLambdaRolebf1a383b",
                                    "-",
                                    {
                                        "Ref": "env"
                                    }
                                ]
                            ]
                        } 
                    ]
                },
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": {
                                "Service": [
                                    "lambda.amazonaws.com"
                                ]
                            },
                            "Action": [
                                "sts:AssumeRole"
                            ]
                        }
                    ]
                }
            }
        }
        ,"lambdaexecutionpolicy": {
            "DependsOn": ["LambdaExecutionRole"],
            "Type": "AWS::IAM::Policy",
            "Properties": {
                "PolicyName": "lambda-execution-policy",
                "Roles": [{ "Ref": "LambdaExecutionRole" }],
                "PolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Action":["logs:CreateLogGroup",
                            "logs:CreateLogStream",
                            "logs:PutLogEvents"],
                            "Resource": { "Fn::Sub" : [ "arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*", { "region": {"Ref": "AWS::Region"},  "account": {"Ref": "AWS::AccountId"}, "lambda": {"Ref": "LambdaFunction"}} ]}
                        }
                    ]
                }
            }
        },
        "IoTRuleS3RequestSignedUrl": {
            "Type": "AWS::IoT::TopicRule",
            "Properties": {
                "RuleName": "twinTigerSecurityS3SignedUrlRequests",
                "TopicRulePayload": {
                    "Actions": [
                        {
                            "Lambda": {
                                "FunctionArn": "HOW DO I REFERENCE THIS DYNAMIC ARN?"
                            }
                        }
                    ],
                    "Description": "Get S3 bucket signed URL to upload image directly to S3.",
                    "RuleDisabled": false,
                    "Sql": "SELECT operation, bucket, key, replyTo FROM 'iot/topic'"
                }
            }
        }              
    },
    "Outputs": {
        "Name": {
            "Value": {
                "Ref": "LambdaFunction"
            }
        },
        "Arn": {
            "Value": {"Fn::GetAtt": ["LambdaFunction", "Arn"]}
        },
        "Region": {
            "Value": {
                "Ref": "AWS::Region"
            }
        },
        "LambdaExecutionRole": {
            "Value": {
                "Ref": "LambdaExecutionRole"
            }
        }

    }
}

I could do this in the UI, however that's not ideal long-term nor the intent of configuration by code provided by Amplify/Cloudformation. What's the best way to proceed in referencing the Lambda function from the IoT rule?

1
Did you try using "Fn::GetAtt": ["LambdaFunction", "Arn"]? - Oleksii Donoha
I had not! After a shot, I'm getting this error: CREATE_FAILED functiontwinTigerSecurityRequestS3SignedUrl AWS::CloudFormation::Stack Sun Apr 19 2020 07:07:42 GMT-0600 (Mountain Daylight Time) Embedded stack arn:aws:cloudformation:us-east-1:444444444444:stack/amplify-twintigersecurity-dev-44444-functiontwinTigerSecurityRequestS3SignedUrl-ABCDEFGHIJKL/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa was not successfully created: The following resource(s) failed to create: [lambdaexecutionpolicy, IoTRuleS3RequestSignedUrl]. Note that all works when taking out IoTRuleS3RequestSignedUrl. - Christopher Stevens
Unable to unmarshall exception response with the unmarshallers provided (Service: AWSIot; Status Code: 400; Error Code: null; Request ID: - Christopher Stevens
I have gut feeling that JSON is borked for some reason, maybe try converting it to YAML? - Oleksii Donoha
I suppose I could try. It's not really in the normal Amplify CLI workflow where all is generated as JSON. I personally like YAML better, however using it here would be a ding against argument to use Amplify on the test project I'm working. Do you feel it's worth the effort? (maybe there's a CLI config option for this...). I updated my question with sample JSON update. It looks like YAML config is a requested feature: github.com/aws-amplify/amplify-cli/issues/2915 - Christopher Stevens

1 Answers

3
votes

You can use intrinsic function Fn::GetAtt to get ARN of the resource like follows:

"Fn::GetAtt": ["LambdaFunction", "Arn"]