Is it possible to pass a list of email addresses as the endpoint for an SNS subscription?
I've got something like this
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources" : {
"EmailSNSTopic": {
"Type" : "AWS::SNS::Topic",
"Properties" : {
"DisplayName" : "${display_name}"
}
},
"MySubscription": {
"Type": "AWS::SNS::Subscription",
"Properties": {
"TopicArn" : { "Ref" : "EmailSNSTopic" },
"Endpoint" : "foo#foo.com"
"Protocol" : "email"
}
}
},
"Outputs" : {
"ARN" : {
"Description" : "Email SNS Topic ARN",
"Value" : { "Ref" : "EmailSNSTopic" }
}
}
}
But what I'd like to do is pass a number of email addresses instead of just one.
As per the documentation
Endpoint should be a string
Cloudformation doesn't allow you to pass a list.
You dont want to have a custom resource as well.
There is one more way Running bash commands in AWS CloudFormation templates
You just run awscli command like below
Resources:
Command:
Type: 'AWSUtility::CloudFormation::CommandRunner'
Properties:
Command: aws s3 ls > /command-output.txt
Role: String
LogGroup: String #Optional
SubnetId: String #Optional
SecurityGroupId: String #Optional
KeyId: String #Optional
I don’t thing it is possible using native syntax.
You might want to try aws cloud formation custom resource and pass list to lambda for execution one by one.
Related
I'm trying to use an existing role (present in the AWS account) in a cloudformation template to setup a lambda function, i plan to be use this across multiple AWS accounts.
In the CF template, I'm using Parameters to set the name of the Role and then using Ref in the Role property for the Lambda function. This is what my template looks like,
"Parameters" : {
"ExistingRoleName" : {
"Type" : "String",
"Default" : "MyCustomRole"
}
"Resources" : {
"CustomLambdaFunction" : {
"Type" : "AWS::Lambda::Function",
"Properties" : {
"MemorySize" : "128",
"Role" : { "Ref" : "ExistingRoleName" },
}
},
...
However, the CF template fails with the following error :
Properties validation failed for resource CustomLambdaFunction with message: #/Role: failed validation constraint for keyword [pattern]
Is this because Lambda resource in Cloudformation needs the role arn instead of RoleName as i seen in this docaws-resource-lambda-function
Based on which i updated the CF like so,
"Resources" : {
"CustomLambdaFunction" : {
"Type" : "AWS::Lambda::Function",
"Properties" : {
"MemorySize" : "128",
"Role" : "arn:aws:iam::AccountID:role/MyCustomRole",
}
},
However, i still see the same error.
Properties validation failed for resource CustomLambdaFunction with message: #/Role: failed validation constraint for keyword [pattern]
I was wondering if i'm missing something here ?
The Ref of an IAM Role “returns the resource name”, not its ARN. But you can use GetAtt on the Arn attribute of the role instead.
In JSON:
{"Fn::GetAtt": ["MyRole", "Arn"]}
In YAML:
!GetAtt MyRole.Arn
Format to reference the iam role arn
"Role" : { "Fn::Sub" : "arn:aws:iam::${AWS::AccountId}:role/MyCustomRole" }
In yaml if you are pointing to an already existing role the syntax is:
function:
...
role: !Sub arn:aws:iam::${AWS::AccountId}:role/MyRoleName
Somehow I have forgotten the !Sub in the beginning
This is what worked for me,
"Role": { "Fn::Join" : [ "", [ "arn:aws:iam::", { "Ref" : "AWS::AccountId" }, ":role/MyCustomRole" ] ] }
I was getting the same problem with below syntax -
"Resources" : {
"CustomLambdaFunction" : {
"Type" : "AWS::Lambda::Function",
"Properties" : {
"Role" : "arn:aws:iam::<account-id>:role/MyCustomRole",
}
},
I solved it like this -
The issue was that when inserting my AWS account ID in place of "account-id", I was keeping it in the same format as is given on the AWS console i.e. xxxx-xxxx-xxxx. However, the "account-id" space expects "\d{12}" format, i.e. 12 digits only. Removing the '-' in between digits solved the problem for me.
I have been trying to create endpoints for my two vpc's, it is creating the vpc's, but it is not working with the Tags property which i require to name the vpc endpoint created.
Error: "Encountered unsupported property Tags"
{
"Resources": {
"VPCEndpoint1": {
"Type" : "AWS::EC2::VPCEndpoint",
"Properties" : {
"PrivateDnsEnabled" : "True",
"RouteTableIds" : ["rtb-1"],
"ServiceName" : "com.amazonaws.eu-west-1.s3",
"VpcEndpointType" : "Gateway",
"VpcId" : "vpc-id1",
"Tags": [
{
"Key": "Name",
"Value": "name1"
}
]
}
},
"VPCEndpoint2": {
"Type" : "AWS::EC2::VPCEndpoint",
"Properties" : {
"PrivateDnsEnabled" : "True",
"RouteTableIds" : ["rtb-2"],
"ServiceName" : "com.amazonaws.eu-west-1.s3",
"VpcEndpointType" : "Gateway",
"VpcId" : "vpc-id2",
"Tags": [
{
"Key": "Name",
"Value": "name2"
}
]
}
}
}
}
Cloudformation do not support Tags property.
Refer cloudformation document => https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpcendpoint.html
Tags are supported for AWS::EC2::VPC, But not for AWS::EC2::VPCEndpoint.
If, you need tags, create tags on vpc level, not on endpoints.
VPC Level Tags - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpc.html
CloudFormation does not support tagging VPC Endpoints yet.
See https://github.com/aws-cloudformation/cloudformation-coverage-roadmap/issues/196
Here is a workaround to tag your VPCE in CloudFormation:
You can setup the custom resource and macro from https://github.com/awslabs/aws-cloudformation-templates/tree/55ebf9f7129e87530e68c242d7e46167e6a798b8/aws/services/CloudFormation/MacrosExamples/Boto3
The code is 4 years old, so it needs to be updated:
Use python3.9
Move lambda code to InlineCode in template to replace urllib2 with cfnresponse
Remove calls to json.dumps
Remove property case lowering
Then you should be able to add a tag using CloudFormation like this:
VpceTagName:
Type: Boto3::ec2.create_tags
Properties:
Resources:
- !Ref VpcEndpoint
Tags:
- Key: Name
Value: My VPCE
I'm trying to create a CloudFormation template that'll deploy a Lambda function, And I need the security options to be optional parameters.
I was able to partially accomplish this using the question here:
How to make a whole object in CloudFormation templates optional?
Interestingly, that method worked great to make the VpcConfig property optional in the AWS GUI Console, but it did NOT work to make it optional for the CLI. And unfortunately, I need it to work in the CLI, since I'll be using CodeBuild to call and deploy this template's resources.
Here are the relevant parameters:
"SecurityGroupIds" : {
"Type" : "CommaDelimitedList",
"Description" : "A list of one or more security groups IDs in the VPC that includes the resources to which your Lambda function requires access."
},
"SubnetIds" : {
"Type" : "CommaDelimitedList",
"Description" : "A list of one or more subnet IDs in the VPC that includes the resources to which your Lambda function requires access."
}
And conditions:
"HasVPC": {"Fn::And": [{"Fn::Not": [{"Fn::Equals": [{"Fn::Join": ["", {"Ref": "SubnetIds"}]}, ""]}]}, {"Fn::Not": [{"Fn::Equals": [{"Fn::Join": ["", {"Ref": "SecurityGroupIds"}]}, ""]}]}]}
And here's where that condition is used in the Lambda resource being defined in the Resources section of the template:
"VpcConfig": {
"Fn::If": [
"HasVPC",
{
"SecurityGroupIds" : {"Ref": "SecurityGroupIds"},
"SubnetIds" : {"Ref": "SubnetIds"}
},
{ "Ref":"AWS::NoValue" }
]
},
When I issue the command to deploy this stack in the CLI, I get the following error:
An error occurred (ValidationError) when calling the CreateChangeSet
operation: Parameters: [SecurityGroupIds, SubnetIds] must have values
Here's the AWS CLI command I'm issuing, from the same directory in which the template is located. Note: the ARN values have all been heavily modified to not be real values from my account, but I kept them in the right format so you can see the real format of the command:
aws cloudformation deploy --template-file lambda-template.json --stack-name "CLI-lambda-stack" --parameter-overrides S3BucketName="myBucket" S3FileLocation="lambda_function.zip" S3ObjectVersion="ZuB0iueEghOyh5q00.DiykLNudujdsc5" DeadLetterArn="arn:aws:sns:us-west-2:577898337216:CloudFormationTests" EnvironmentVariable="testing" KmsKeyArn="arn:aws:kms:us-west-2:504398934246:key/b24e7b72-a94d-6a3e-b848-165115c86212" HandlerFunctionName="lambda_function.lambda_handler" MemorySize="128" Role="arn:aws:iam::102893937243:role/serverless-test-default-us-east-1-lambdaRole" FuncName="myCLILambda"
You are not providing SecurityGroupIds neither SubnetIds default values and your are not providing them on your --parameter-overrides. Therefore, CloudFormation doesn't know how to process them if no values are provided.
Adding the Default statement should do the trick:
{
"Parameters" : {
"SecurityGroupIds" : {
"Type" : "CommaDelimitedList",
"Description" : "A list of one or more security groups IDs in the VPC that includes the resources to which your Lambda function requires access.",
"Default" : ""
},
"SubnetIds" : {
"Type" : "CommaDelimitedList",
"Description" : "A list of one or more subnet IDs in the VPC that includes the resources to which your Lambda function requires access.",
"Default" : ""
}
}
I´m using AWS cloud formation, and I could not find in any documentation information about this. When I use cloudformation with AWS CLI the information sent to AWS it´s encrypted?.
Regards.
The information is sent over HTTPS, so the communication between your client and AWS servers is secure. On the other hand, if you are providing sensitive information with parameters you can enable NoEcho parameter to prevent them from being displayed on AWS Console. The NoEcho property is set to true to prevent describe stack calls, such as the aws cloudformation describe-stacks AWS CLI command, from returning the parameter value
"Parameters" : {
"DBPort" : {
"Default" : "3306",
"Description" : "TCP/IP port for the database",
"Type" : "Number",
"MinValue" : "1150",
"MaxValue" : "65535"
},
"DBPwd" : {
"NoEcho" : "true",
"Description" : "The database admin account password",
"Type" : "String",
"MinLength" : "1",
"MaxLength" : "41",
"AllowedPattern" : "[a-zA-Z0-9]*"
}
}
I am creating some DNS entries in my cloudformation. There is a param passed into the cfn script, which results in the creation of a Route53 entry like hostname-test.example.com:
"Host" : {
"Type" : "AWS::Route53::RecordSetGroup",
"Properties" : {
"HostedZoneName" : "example.com.",
"RecordSets" : [
{
"Name" : {
"Fn::Join" : [ "-", [
{"Ref" : "Hostname" },
"test.example.com"
]]
},
"Type" : "A",
"AliasTarget" : {
"DNSName" : { "Fn::GetAtt" : [ "PublicWebLoadBalancer", "CanonicalHostedZoneName" ] },
"HostedZoneId" : { "Fn::GetAtt" : [ "PublicWebLoadBalancer", "CanonicalHostedZoneNameID" ] }
}
}
]
}
}
In my output, I would like to get the Name attribute from the RecordSet, but I don't know how to reference it. According to the Fn::GetAtt documentation, Route53 objects are not supported.
Is this possible?
This question is a bit old, but it I just ran into this same issue.
You need to output the entire RecordSet, ie:
"Outputs" : {
"MyDNSRecord" : {
"Description": "The DNS Record of ...",
"Value" : { "Ref": "MyRecordSet" }
}
}
Which (not intuitively) outputs the value of the record set name you are looking for.
I had the same question, and was looking for a clear answer in yaml.
Given the following AWS::Route53::RecordSet
rPublicReverseProxyNLBDnsRecord:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: !Ref pPublicHostedZoneName
Comment: !Sub 'DNS record for the ${AWS::StackName} ELB front door.'
Name: !Sub '${pDeploymentType}.${pPublicHostedZoneName}'
Type: CNAME
TTL: '30'
ResourceRecords:
- !GetAtt rPublicReverseProxyNLB.DNSName
I was able to output the Application URL I wanted with the following output section code:
Outputs:
ApplicationURL:
Description: 'The public URL for the application'
Value: !Sub 'https://${rPublicReverseProxyNLBDnsRecord}/'
Instead of embedding your RecordSet inside the RecordSetGroup, define it as a separate property, with the same HostedZoneName as your RecordSetGroup.
You can then use "Ref" to get the value of the Name attribute.
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset.html
I second the suggestion of trying RecordSet.
But your "Name" is deterministic. If the stack completes, outputting what you already have will never behave differently from what you want:
{
"Fn::Join" : [ "-", [
{"Ref" : "Hostname" },
"test.example.com"
]]
}
If this were OOP, I'd say it's decidedly wrong to kick back an argument without taking the opportunity to implicitly test the function.