Deploy AWS SAM functions using already created roles - amazon-web-services

When trying to deploy to AWS using AWS SAM CLI my Lambda functions using the following script:
aws cloudformation deploy --template-file /Users/ndelvalle/Projects/foo/functions/packaged-template.yaml --stack-name foo --region sa-east-1 --capabilities CAPABILITY_IAM --no-fail-on-empty-changeset
I got the following error in the stack events:
API: iam:CreateRole User: arn:aws:iam::user/nico is not authorized to perform: iam:CreateRole on resource
This is because I don't have role creation permissions on my account. That is why I wonder if there is a way to define pre-created roles to my lambdas, so the script does not need to create the role.

There is more information needed to answer this for you. Many different permissions come into play when deploying with SAM. I implemented SAM template for my company to manage our lambda stacks. We needed to give our Java Developers working on the stacks the same permissions that the SAM template implicitly and explicitly creates, beyond just creating roles. For this we created several special groups in IAM that we attached our Serverless Devs too. It is possible to assign specific predefined roles to Lambdas, https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction. If you define a role in the template, it does not automatically create a role. However, if you are declaring other resources like Api Gateway and DynamoDB, you will still run into problems.
So long story short, if you are working with SAM its better you have your Sys admin give you permissions to Create role, and you will need other permissions as well, or have the deployment of the SAM template done by a Job runner like Jenkins (that has the permissions). It it is too permissive for your team/company, maybe SAM is not a good solution... Best to switch to something like pure CloudFormation and abandon a developer oriented workflow. Somethings to think about, hope its helpful.

You can use the Role property as mentioned in the docs for AWS::Serverless::Function
A sample template which creates a new lambda without creating a new role,
Transform: AWS::Serverless-2016-10-31
Description: >
sam-app
Sample SAM Template for sam-app
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
Tracing: Active
Api:
TracingEnabled: True
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello-world/
Handler: app.lambdaHandler
Runtime: nodejs18.x
Role: <ARN of ROLE>
Architectures:
- x86_64
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello
Method: get
Metadata: # Manage esbuild properties
BuildMethod: esbuild
BuildProperties:
Minify: true
Target: "es2020"
Sourcemap: true
EntryPoints:
- app.ts
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: "API Gateway endpoint URL for Prod stage for Hello World function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldFunction:
Description: "Hello World Lambda Function ARN"
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: "Implicit IAM Role created for Hello World function"
Value: !GetAtt HelloWorldFunctionRole.Arn

Related

How to add a resource based policy to a lambda using AWS SAM

I want to create a deployment script for some lambda functions using AWS SAM. Two of those functions will be deployed into one account(account A) but will be triggered by an s3 bucket object creation event in a second account(account B). From what I know the only way to do this is by using adding a resource based policy to my lambda. But I don't know how to do that in AWS SAM. My current yaml file looks like this.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
deploy-test-s3-triggered-lambda
Parameters:
AppBucketName:
Type: String
Description: "REQUIRED: Unique S3 bucket name to use for the app."
Resources:
S3TriggeredLambda:
Type: AWS::Serverless::Function
Properties:
Role: arn:aws:iam::************:role/lambda-s3-role
Handler: src/handlers/s3-triggered-lambda.invokeAPI
CodeUri: src/handlers/s3-triggered-lambda.js.zip
Runtime: nodejs10.x
MemorySize: 128
Timeout: 60
Policies:
S3ReadPolicy:
BucketName: !Ref AppBucketName
Events:
S3NewObjectEvent:
Type: S3
Properties:
Bucket: !Ref AppBucket
Events: s3:ObjectCreated:*
AppBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref AppBucketName
What do I need to add to this yaml file in order to tie a resource based policy that allows for cross account access to my lambda function?
This can be done achieved with the help of AWS::Lambda::Permission using aws_cdk.aws_lambda.CfnPermission.
For example, to allow your lambda to be called from a role in another account, add the following to your CDK:
from aws_cdk import aws_lambda
aws_lambda.CfnPermission(
scope,
"CrossAccountInvocationPermission",
action="lambda:InvokeFunction",
function_name="FunctionName",
principal="arn:aws:iam::111111111111:role/rolename",
)
If your bucket and your Lambda function exist in separate accounts I don't know if it's possible to modify both of them from SAM / a single CloudFormation template.
Don't think cross account s3 event is possible with SAM, may need to go back to CFN.

AWS SAM Template: Issue mapping S3 events to Lambda

I've followed the AWS SAM documentation for hands-on learning experience and have reached this particular section: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-s3.html
Above page in the documentation explains how to map the S3 events to any resource and I've done something similar on my local machine. My local template below.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
CreateThumbnail:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.6
Timeout: 60
Policies: AWSLambdaExecute
Events:
CreateThumbnailEvent:
Type: S3
Properties:
Bucket: !Ref testBucket
Events: s3:ObjectCreated:*
testBucket:
Type: AWS::S3::Bucket
Now, when I build and deploy above SAM template, while a new S3 bucket is getting created, the 'object creation' event is not mapped to the Lambda function created. PSB screenshot.
I haven't found any articles or blogs on this error (probably, I'm doing a silly mistake here)
Please help.
Thanks.
I realized that for some reason, the AWS Lambda console is not showing the trigger event but the mapping is successful. I've also validated by uploading sample image to the bucket which triggered the lambda.
The event mapping can be seen in the properties section of the S3 bucket created.
S3 test bucket created -> Properties -> Events
You can add a AWS::Lambda::Permission to your Resources as described in this AWS SAM Github issue
LambdaInvokePermission:
Type: 'AWS::Lambda::Permission'
Properties:
FunctionName: !GetAtt MyFunction.Arn
Action: 'lambda:InvokeFunction'
Principal: 's3.amazonaws.com'
SourceAccount: !Sub ${AWS::AccountId}
SourceArn: !GetAtt MyBucket.Arn
First create bucket where you plan to save packaged code
aws s3 mb s3://youtbucketname
After sam build
go for
sam package --template-file template.yaml --s3-bucket <yourbucketname>

Attach a preexisting role in template.yml file while creating sam application through console

I am trying to create a sam application with a pre existing role through sam-cli.By default the sam clil creates new user roles with basic lambda exuection policies ,but as i want to run x-ray on my sam application i would want application to be created with existing user role.
Here is my template.yml
AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
POCLambdaExecutionRole:
Type: 'AWS::IAM::Role'
SAMLocal:
Type: AWS::Serverless::Function
Properties:
Handler: SAMLocal.lambda_handler
Runtime: python2.7
TracingConfig:
Mode: Active
Environment:
Variables:
dev_table: "MessageQueue"
Events:
SAMLocal:
Type: Api
Properties:
Path: /
Method: GET
SAMLocal1:
Type: AWS::Serverless::Function
Properties:
Handler: SAMLocal.lambda_handler
Runtime: python2.7
How can i achieve the same .
found this article on stack overflow but does not really helps my casue Associate existing IAM role with EC2 instance in CloudFormation
you need to put existing role in your yaml file in ARN format
role: arn:aws:iam::XXXXXX:role/role
you can either set role or permission. If you do not define role for your funcition, SAM will create one role for every function. by default, it will scope for each funcition individually.
Declare Role outside your function in the fashion i have described in my solution role: arn:aws:iam::XXXXXX:role/role
Check THIS

Difference between SAM template and Cloudformation template

I'm finding it hard to understand the difference between SAM template and Cloudformation template. I know that SAM template can be used to define Serverless Applications like Lambda, but how does that make it different from Cloudformation template? Is the syntax different? I can still specify the Lambda definitions in cloudformation template. So, my question is why should I care about SAM? Won't knowing about just cloud formation template be sufficient?
From CloudFormation's perspective, SAM is a transform. Meaning: SAM templates are syntactically equivalent, but they allow you to define your serverless app with more brevity. The SAM template eventually gets expanded into full CFN behind the scenes. If you already know CFN, but want to write less YAML code, SAM may be beneficial to you. The idea is to reduce your effort.
SAM templates are a superset of Cloudformation. Any Cloudformation template can be run through SAM unchanged, and it will work. SAM supports all the types available in Cloudformation templates, so you can think of SAM as "CloudFormation++".
However, SAM also gives you additional "transforms" that allow you to define certain concepts succinctly, and SAM will figure out what you mean and fill in the the missing pieces to create a full, expanded, legal Cloudformation template.
Example: For SAM (and Serverless Framework) users, who deal mostly in Lambda functions, one of the more most useful transforms is the Events property on the Lambda function -- SAM will add all the objects needs to access that function through an API path in API Gateway.
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: HelloWorldFunction
Handler: app.lambdaHandler
Runtime: nodejs12.x
Events: # <--- "Events" property is not a real Cloudformation Lambda property
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get
The SAM template snippet shown above gets transformed/expanded into several API Gateway objects (a RestApi, a deployment, and a stage). The AWS::Serverless::Function type used in this snippet is not a real Cloudformation type -- you won't find it in the docs. SAM expands it into a Cloudformation template containing a AWS::Lambda::Function object and several different AWS::ApiGateway::* objects that Cloudformation understands.
To give you an idea of how much manual coding this saves you, here's what the expanded version of the above SAM template looks like as a full Cloudformation template:
Resources:
HelloWorldFunctionHelloWorldPermissionProd:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
Principal: apigateway.amazonaws.com
FunctionName:
Ref: HelloWorldFunction
SourceArn:
Fn::Sub:
- arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/hello
- __Stage__: "*"
__ApiId__:
Ref: ServerlessRestApi
HelloWorldFunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Tags:
- Value: SAM
Key: lambda:createdBy
ServerlessRestApiProdStage:
Type: AWS::ApiGateway::Stage
Properties:
DeploymentId:
Ref: ServerlessRestApiDeployment_NNN
RestApiId:
Ref: ServerlessRestApi
StageName: Prod
ServerlessRestApiDeployment_NNN:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId:
Ref: ServerlessRestApi
Description: 'RestApi deployment id: ???'
StageName: Stage
ServerlessRestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Body:
info:
version: '1.0'
title:
Ref: AWS::StackName
paths:
"/hello":
get:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloWorldFunction.Arn}/invocations
responses: {}
swagger: '2.0'
HelloWorldFunction:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: aws-sam-cli-managed-default-samclisourcebucket-???
S3Key: temp/???
Tags:
- Value: SAM
Key: lambda:createdBy
Handler: app.lambdaHandler
Role:
Fn::GetAtt:
- HelloWorldFunctionRole
- Arn
Timeout: 3
Runtime: nodejs12.x
Previously, if you were authoring pure Cloudformation, you would have had to code all this by hand, over and over, for each API Gateway endpoint that you wanted to create. Now, with a SAM template, you define the API as an "Event" property of the Lambda function, and SAM (or Serverless Framework) takes care of the drudgery.
In the old days, when we had to do all this by hand, it totally sucked. But now, everything is glorious again.
Like #Luis Colon said, SAM is a transform. What that means, is that at the top of a SAM Template there is a Transform statement that lets CloudFormation know to run an intrinsic function, Transform, on this SAM template to turn it into a CloudFormation template. So, all SAM Templates will eventually be converted into CF templates, but for the end-user in most cases it is easier to just use the SAM template. For instance, for a simple application with Lambdas triggered by a new API you're creating, the SAM template will let you accomplish this in fewer lines than CloudFormation.
To extend this, the Serverless Framework behaves similarly. Serverless is designed to work across platforms (AWS, Azure, etc.). It's syntax looks very similar to SAM, and it too converts the template into the target platform's (ie. AWS) fuller version of the template (ie. CloudFormation template).
You can imagine SAM as an extended form of CloudFormation. SAM makes Serverless/Lambda deployments easier.
Even CloudFormation can deploy lambda scripts using inline scripts but it has a limitation of 4096 characters and you cannot pack custom dependencies, python libraries.
So to make Lambda/Serverless deployments easy SAM is used. SAM is a CLI tool. You cannot find SAM in AWS Console.
In case of python deployment, sam will read the requirements.txt file build a package, and will deploy the package when you wish to sam deploy
So at the end of the day you can write as much lengthy Lambda Code, use as many libraries you want and even import your custom libraries i.e. complete flexibility.

How to attach an existing role to serverless.yml?

I want to attach an existing role to my serverless.yml file, I have created a role in aws console, my code works fine when I test it in aws console, but when I try to test it with the http endpoint it gives me the following:
{"message": "Internal server error"}
I think is because I did not specify any role in the serverless.yml file for the simple reason that I don't know how to do it.
Here is my serverless.yml file :
Resources:
ec2-dev-instance-status:
Properties:
Path: "arn:aws:iam::119906431229:role/lambda-ec2-describe-status"
RoleName: lambda-ec2-describe-status
Type: "AWS::IAM::Role"
functions:
instance-status:
description: "Status ec2 instances"
events:
-
http:
method: get
path: users/create
handler: handler.instance_status
role: "arn:aws:iam::119906431229:role/lambda-ec2-describe-status"
provider:
name: aws
region: us-east-1
runtime: python2.7
stage: dev
resources: ~
service: ec2
Please help.
Thank you.
According to the documentation, there's a few ways to attach existing roles to a function (or entire stack)
Role defined as a Serverless resource
resources:
Resources:
myCustRole0:
Type: AWS::IAM::Role
# etc etc
functions:
func0:
role: myCustRole0
Role defined outside of the Serverless stack
functions:
func0:
role: arn:aws:iam::0123456789:role//my/default/path/roleInMyAccount
Note that the role you use must have additional permissions to log to cloudwatch etc, otherwise you won't get logging.