CloudFormation template - Using existing IAM role in for Lambda functions - amazon-web-services

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.

Related

Pass email address list to SNS subscription endpoint

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.

Does AWS CloudFormation support Tags Property Attribute for AWS::EC2::VPCEndpoint

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

Optional parameters when using AWS CLI to launch CloudFormation template

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" : ""
}
}

How does one add an iam:PermissionsBoundary to a role created via CloudFormation template

I have a user who can create roles iff there is an attached permission boundary. The user can execute this function via the AWS console and via API calls from the API. However, there does not seem to be a way to automate the process in CloudFormation. Is it possible to create a role in a CFT and attach a permissions boundary to it?
Permissions Boundary is now supported by the CloudFormation's schema https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html.
{
"Type" : "AWS::IAM::Role",
"Properties" : {
"AssumeRolePolicyDocument" : Json,
"ManagedPolicyArns" : [ String, ... ],
"MaxSessionDuration" : Integer,
"Path" : String,
"PermissionsBoundary" : String,
"Policies" : [ Policy, ... ],
"RoleName" : String
}
}
YAML
Type: AWS::IAM::Role
Properties :
AssumeRolePolicyDocument : Json
ManagedPolicyArns :
- String
MaxSessionDuration : Integer
Path : String
PermissionsBoundary : String
Policies :
- Policy
RoleName : String
As an aside, the support for it was available in Terraform before it was in CFT.

Cloudformation to automatically pick up the default instance profile

I use a CloudFormation template to deploy an instance to the environment. I want the template to pick up the default EC2 instance profile for the instance which is something like "arn:aws:iam::12345678910:role/EC2InstanceProfile-InstanceRole-14F2A0ATJNUO1"
I would like to use the same template for every AWS accounts I have. However, the problem is that the instance profile name is different in every account. A randomly generated suffix is attached to the name (in this example 14F2A0ATJNUO1). How can I workaround this problem to make the template reusable in every account. Please provide the code if possible.
"EC2InstanceProfile" : {
"Description" : "The default instance profile",
"Type": "String",
"ConstraintDescription" : "must be the name of an existing defualt EC2 instance profile."
},
"IamInstanceProfile": { "Ref": "EC2InstanceProfile" }
Get your instance profile from the role name using the below cloudformation.
"InstanceProfile" : {
"Type" : "AWS::IAM::InstanceProfile",
"Properties" : {
"Path" : "/",
"Roles" : ["your-role-name"]
}
}
"IamInstanceProfile": {"Fn::GetAtt" : ["InstanceProfile", "Arn"] },