<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Harprit Singh</title>
    <description>The latest articles on DEV Community by Harprit Singh (@harprit).</description>
    <link>https://dev.to/harprit</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F309358%2F01a4e1ad-80cb-476e-b9e7-2fc1bf980bdc.jpg</url>
      <title>DEV Community: Harprit Singh</title>
      <link>https://dev.to/harprit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harprit"/>
    <language>en</language>
    <item>
      <title>A Serverless App with AWS SAM to Rediscover Liked Tweets</title>
      <dc:creator>Harprit Singh</dc:creator>
      <pubDate>Sat, 23 Jan 2021 15:05:16 +0000</pubDate>
      <link>https://dev.to/aws-builders/a-serverless-app-with-aws-sam-to-rediscover-liked-tweets-4ln2</link>
      <guid>https://dev.to/aws-builders/a-serverless-app-with-aws-sam-to-rediscover-liked-tweets-4ln2</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Following the tradition of  &lt;a href="https://www.lastweekinaws.com/blog/counting-twitter-followers-over-time-the-corey-quinn-way/"&gt;solving our little Twitter problems with serverless&lt;/a&gt;, this post describes an app that would help you rediscover tweets that you have liked in the past. Of course, with the goal of learning how to do serverless along the way. We will be building this simple yet interesting app using &lt;a href="https://aws.amazon.com/lambda/"&gt;AWS Lambda&lt;/a&gt; and related services. For configuring and gluing together all the components we will be making use of &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html"&gt;AWS SAM&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On Twitter, you may be following a bunch of smart folks and often tap the like icon for interesting thoughts they share. However, once you have liked a tweet, it's quite hard to rediscover that after a while. Twitter's native option for that is a chronological display of all liked Tweets with an endless scroll. That, let's just say, isn't that cool.&lt;/p&gt;

&lt;p&gt;The serverless app we are going to build will show you back a liked tweet of yours with some serendipity added to the mix. Demo page is &lt;a href="https://random-likes.harprit.dev/"&gt;here&lt;/a&gt;. Though, once &lt;a href="https://developer.twitter.com/en/docs/twitter-api/v1/rate-limits"&gt;Twitter API rate limit&lt;/a&gt; is reached, it may not work :-( Below is a snapshot of how it should look though. Also, as we shall see, you may follow along the steps and deploy the same for yourself from the source &lt;a href="https://github.com/harprit/random-likes"&gt;here on Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U7YGqGOG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.harprit.dev/serverless-app-random-twitter-likes/Demo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U7YGqGOG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.harprit.dev/serverless-app-random-twitter-likes/Demo.jpg" alt="Random Twitter Likes Demo"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting out building this app, here's a list of things you need to have. You may find further details in the &lt;a href="https://github.com/harprit/random-likes/blob/master/README.md"&gt;readme&lt;/a&gt; as well.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AWS SAM CLI Installed&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check the introduction from &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html"&gt;these docs&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Twitter API Keys and Tokens&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Get yours using a &lt;a href="https://developer.twitter.com"&gt;Twitter Developer&lt;/a&gt; account. We shall be storing them in AWS SSM Parameter Store.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Java 8 with Maven&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lambda function is written in Java. You may skip this if you prefer to build a similar Lambda function in a different programming language.&lt;/p&gt;

&lt;h2&gt;
  
  
  Components
&lt;/h2&gt;

&lt;p&gt;Here's a view of different components of the app and how they interact:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--12BREcgU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.harprit.dev/serverless-app-random-twitter-likes/Flow.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--12BREcgU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.harprit.dev/serverless-app-random-twitter-likes/Flow.jpg" alt="Components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The flow gets triggered when a user, via the browser, invokes the API Gateway endpoint URL passing along their Twitter username. &lt;/li&gt;
&lt;li&gt;API Gateway, in turn in an event driven fashion, invokes the Lambda function with a request object containing the username.&lt;/li&gt;
&lt;li&gt;Lambda function on invocation fetches Twitter Authentication keys from AWS SSM Parameter Store. Followed by using these keys to invoke Twitter API to fetch a batch of tweets liked by the user. Finally, one random tweet out of this list is returned as response and eventually gets shown back to the user.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the upcoming sections of this post, let's look at each of these components one by one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parameter Store
&lt;/h3&gt;

&lt;p&gt;For invoking the Twitter APIs, we need to first obtain authentication keys using a &lt;a href="https://developer.twitter.com"&gt;Twitter Developer account&lt;/a&gt;. Once we have the keys, to be able to securely store and access them from Lambda function, we will make use of &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html"&gt;AWS SSM Parameter Store&lt;/a&gt;. To keep things simple and fetch all authentication related details in a single call to SSM, we shall be storing them as a comma separated StringList param as follows:&lt;/p&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--je9PM5Qh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.harprit.dev/serverless-app-random-twitter-likes/ParameterStore.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--je9PM5Qh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.harprit.dev/serverless-app-random-twitter-likes/ParameterStore.png" alt="Parameter Store"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Next, we need to define this &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html"&gt;parameter&lt;/a&gt; in the SAM template. This, as we shall see later in the SAM config, will be referred to as an environment variable by the Lambda function. This practice helps in achieving customization of stacks during &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-deploy.html"&gt;deployment using SAM CLI&lt;/a&gt;. We may &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html"&gt;pass along different parameter names&lt;/a&gt; at the time of deployment, that correspond to respective values for different environments.&lt;/p&gt;

&lt;p&gt;For example, let's say that, here we have defined a parameter resource TwitterAuthParam with default value as TWITTER_AUTH for all non prod environments. When we need to run this app on prod environment, we may override the same during deployment with value TWITTER_AUTH_PROD. Accordingly, the Lambda function with no change in code will be able to access the respective SSM param depending on the environment that it's running in.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;TwitterAuthParam&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TWITTER_AUTH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h3&gt;
  
  
  Lambda
&lt;/h3&gt;

&lt;p&gt;AWS Lambda function, defined for this app, contains the &lt;a href="https://github.com/harprit/random-likes/blob/master/functions/RandomLikesFunction/src/main/java/com/hs/randomlikes/App.java"&gt;code&lt;/a&gt; that for a given username invokes Twitter APIs to get a list of liked tweets for the user. This is followed by simple randomization to choose one liked tweet and return it back as a response. Lambda function is written in Java and makes use of the awesome &lt;a href="http://twitter4j.org"&gt;Twitter4J library&lt;/a&gt;. Of course, the same can be achieved in any language using a similar Twitter library.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/harprit/random-likes/blob/master/functions/RandomLikesFunction/src/main/java/com/hs/randomlikes/App.java"&gt;Lambda function code&lt;/a&gt; follows the best practice of performing initializations in the constructor code like fetching authentication keys from Parameter Store and creating Twitter connection instance. Keeping these initializations outside the handler function means that they get carried out only once during initial Cold Start for a given instance. This helps in making faster all subsequent handler function invocations on the same object.&lt;/p&gt;

&lt;p&gt;Here's the part of the SAM Template defining config for the Lambda function:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;RandomLikesFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Function&lt;/span&gt;
  &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;CodeUri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RandomLikesFunction&lt;/span&gt;
    &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.hs.randomlikes.App::handleRequest&lt;/span&gt;
    &lt;span class="na"&gt;Runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;java8&lt;/span&gt;
    &lt;span class="na"&gt;MemorySize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;512&lt;/span&gt;
    &lt;span class="na"&gt;Timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;TWITTER_AUTH_PARAM&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;TwitterAuthParam&lt;/span&gt;
    &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;SSMParameterReadPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;ParameterName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;TwitterAuthParam&lt;/span&gt;
    &lt;span class="na"&gt;Events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;GetResource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HttpApi&lt;/span&gt;
        &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get&lt;/span&gt;
          &lt;span class="na"&gt;Path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/u/{name}&lt;/span&gt;
          &lt;span class="na"&gt;ApiId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;RandomLikesHttpApi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h3&gt;
  
  
  API Gateway
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/harprit/random-likes/tree/master/public"&gt;Frontend&lt;/a&gt; for the app uses vanilla JS which invokes the API Gateway URL with user's Twitter username as a parameter. It's using &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html"&gt;HTTP flavor of API&lt;/a&gt; which is faster and simpler to use compared to &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html"&gt;REST&lt;/a&gt; (pun intended :-) &lt;/p&gt;

&lt;p&gt;Further, as we are using &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-integration-types.html"&gt;HTTP proxy integration&lt;/a&gt;, API Gateway converts the HTTP request into a JSON and passes this to the Lambda function. In Java world, this translates into an event of type &lt;code&gt;APIGatewayProxyRequestEvent&lt;/code&gt; as an input to the Lambda function. On the way back Lambda function returns &lt;code&gt;APIGatewayProxyResponseEvent&lt;/code&gt; as output, which eventually gets converted by API Gateway into an HTTP response eventually returned back to the caller.&lt;/p&gt;

&lt;p&gt;API Gateway, other than providing an interface to the Lambda function, also helps secure the app. This is required as the API endpoint is not authenticated and we need to define &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-throttling.html"&gt;throttling&lt;/a&gt; limits to avoid any abuse. Or, in other words, to avoid ending up with a big AWS bill due to numerous Lambda invocations.&lt;/p&gt;

&lt;p&gt;Finally, we need to enable CORS config to ensure that the browser allows our domain to invoke API Gateway endpoint and is able to access the response.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;RandomLikesHttpApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::HttpApi&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DefaultRouteSettings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ThrottlingBurstLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
        &lt;span class="na"&gt;ThrottlingRateLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
      &lt;span class="na"&gt;CorsConfiguration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;AllowMethods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GET&lt;/span&gt;
        &lt;span class="na"&gt;AllowOrigins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://random-likes.harprit.dev"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  SAM Template
&lt;/h2&gt;

&lt;p&gt;Finally, let's have a look at the complete AWS SAM configuration template for the app. Here's a visual of the same that describes different sections of the template and shows how SAM glues together all the components discussed above. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check &lt;a href="https://www.harprit.dev/serverless-app-random-twitter-likes/#sam-template"&gt;here&lt;/a&gt; for a better resolution version of this image.&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RU_CIijc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.harprit.dev/serverless-app-random-twitter-likes/Sam.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RU_CIijc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.harprit.dev/serverless-app-random-twitter-likes/Sam.jpg" alt="AWS SAM" width="500"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You may may find further details like how to build and deploy the app from the &lt;a href="https://github.com/harprit/random-likes"&gt;source code and README&lt;/a&gt;. As mentioned above, purpose behind this app was to build something fun and a bit useful while learning to build serverless apps with AWS SAM along the way. I hope it met that goal somewhat.&lt;/p&gt;



</description>
      <category>aws</category>
      <category>serverless</category>
      <category>lambda</category>
      <category>sam</category>
    </item>
    <item>
      <title>A visual introduction to AWS Lambda permissions</title>
      <dc:creator>Harprit Singh</dc:creator>
      <pubDate>Thu, 01 Oct 2020 04:53:45 +0000</pubDate>
      <link>https://dev.to/aws-builders/a-visual-introduction-to-aws-lambda-permissions-1k87</link>
      <guid>https://dev.to/aws-builders/a-visual-introduction-to-aws-lambda-permissions-1k87</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Big value in using AWS Lambda comes from its interplay with other AWS services. To achieve that, however, it's important to understand the role AWS IAM plays in both allowing and securing these interactions.&lt;/p&gt;

&lt;p&gt;When working with Lambda using AWS console or frameworks like Serverless or SAM, most of the connectivity details are sorted out for us behind the scenes. But when dealing with scenarios like cross account access and applying principle of least privilege, there's a need to have a better understanding of how Lambda's permissions work. In this post, we will go about looking at a general model for this followed by applying the same to a couple of scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Permissions Model
&lt;/h2&gt;

&lt;p&gt;At the heart of AWS IAM are the policy documents defining "who can do what" in the AWS world. Clearly, when trying to make sense of Lambda's interactions, it's best to look at things from relevant policies point of view. In this context, for a given Lambda function, following two questions come up which in turn get answered by two different kinds of policies:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Which service is allowed to invoke a Lambda function?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is decided by Resource Based Policy of a Lambda function. Such policies are called so as they are applied directly to a specific resource in an inline manner. In case of a Lambda function, the "Resource" element in the policy refers to the function's ARN. While the "Principal" config refers to other AWS resources to whom function invocation access is granted. Previously, Lambda's Resource Based Policies used to be referred to as Function Policies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Once invoked, which service is a Lambda function in turn allowed to invoke?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is controlled by policies attached to Execution Role of a Lambda function. Execution Role is the role that a Lambda function assumes during its execution. A "Principal" isn't defined in such policies as entities like Lambda function that assume the role themselves act as the principal. The "Resource" part of this policy refers to AWS resources to which the Lambda function is granted access to. We must also define a trust policy on the Execution Role so as to explicitly grant the function permission to assume the role as a principal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.harprit.dev%2Fvisual-aws-lambda-permissions%2Faws-lambda-permissions-model.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.harprit.dev%2Fvisual-aws-lambda-permissions%2Faws-lambda-permissions-model.jpg" alt="AWS Lambda Permissions Model"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An important difference to understand is that while policies attached to the Execution Role allow a set of permissions to Lambda function as a Principal. Resource Based Policies take care of the other side of things by stating what other Principals can do to a Lambda function as a resource. Put together, both the policies let us control complete access to and from a Lambda function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Invocation Modes
&lt;/h2&gt;

&lt;p&gt;Given the above general model, things change a bit based on the manner in which Lambda function gets invoked. Of which, there are following two modes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Push Mode&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this case, an external service pushes an event into Lambda and triggers the function. This event could originate due to some action in an another service or a user initiated web request and so on. In this scenario, from permissions perspective, the service that's the source of the event requires rights to invoke the Lambda function. As we saw above, for a Lambda function, the place to define such permissions is the Resource Based Policy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Pull Mode&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are some services like SQS and Kinesis that do not push events directly to invoke Lambda. For these event sources, Lambda as a service polls them for events and invokes the Lambda function i.e. the function doesn't gets invoked by an external service. From Lambda's permissions point of view, this implies that Resource Based Policies are not relevant here. Secondly, Lambda's Execution Role permissions need to be broadened so as to be able to poll and read messages from services like SQS and Kinesis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.harprit.dev%2Fvisual-aws-lambda-permissions%2Faws-lambda-invocation-modes.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.harprit.dev%2Fvisual-aws-lambda-permissions%2Faws-lambda-invocation-modes.jpg" alt="AWS Lambda Invocation Modes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we shall look at how things really look when applying Lambda's permissions model with examples on both types of invocation modes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Push Mode Permissions
&lt;/h2&gt;

&lt;p&gt;For this scenario, let's consider a simple design where a Lambda function subscribes to a SNS topic. When a message is published to the SNS topic, the subscribed Lambda function gets invoked by SNS with the message as payload. Upon invocation, the Lambda functions reads the message, extract some data of interest and inserts it into DynamoDB. While the logs go to CloudWatch. This flow is as visually shown below along with a summarized view of how policies applied to Lambda should look like to support the interactions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.harprit.dev%2Fvisual-aws-lambda-permissions%2Faws-lambda-push-mode-permissions.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.harprit.dev%2Fvisual-aws-lambda-permissions%2Faws-lambda-push-mode-permissions.jpg" alt="AWS Lambda Push Mode Permissions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example, we are assuming that both SNS and Lambda belong to the same account. We will look at the cross account scenario in the next section.&lt;/p&gt;

&lt;p&gt;Looking into more detailed look at the permissions, here's the Resource Based Policy allowing invocation of Lambda function by the subscribed SNS Topic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sns-to-lambda-same-account"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sns.amazonaws.com"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lambda:InvokeFunction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:us-east-1:ACCOUNT-A:function:MyLambda"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ArnLike"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"AWS:SourceArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:sns:us-east-1:ACCOUNT-A:MyTopic"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the Execution Role Policy as shown below grants access to the Lambda function to insert entries into DynamoDB table and write logs in CloudWatch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dynamodb:PutItem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:dynamodb:us-east-1:ACCOUNT-A:table/MyTable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:dynamodb:us-east-1:ACCOUNT-A:table/MyTable/index/*"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"logs:CreateLogGroup"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"logs:CreateLogStream"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"logs:PutLogEvents"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cross Account Scenario
&lt;/h3&gt;

&lt;p&gt;Next, let's see how things change in case the Lambda function and the subscribed SNS topic sit in different accounts. Say, Lambda function is defined in ACCOUNT-A while the subscribed SNS topic belongs to ACCOUNT-B.&lt;/p&gt;

&lt;p&gt;To allow this cross account invocation simply update SNS topic's ARN, belonging to ACCOUNT-B, in the Lambda function's Resource Based Policy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sns-to-lambda-cross-account"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sns.amazonaws.com"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lambda:InvokeFunction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:us-east-1:ACCOUNT-A:function:MyLambda"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ArnLike"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"AWS:SourceArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:sns:us-east-1:ACCOUNT-B:MyTopic"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While we are focusing here on Lambda, it's important to note that additional cross account permissions are required on SNS side of things as well. SNS Access Policy is counterpart of Lambda's Resource Based Policy on the SNS side. As the SNS Access Policy gets applied directly at the specific SNS topic level and let's us control who all can access the same.&lt;/p&gt;

&lt;p&gt;For the above scenario, SNS Access Policy needs to be updated with following statement allowing access to ACCOUNT-A to be able to subscribe to the SNS topic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::ACCOUNT-A:root"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"SNS:Subscribe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"SNS:ListSubscriptionsByTopic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"SNS:Receive"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:sns:us-east-1:ACCOUNT-B:MyTopic"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pull Mode Permissions
&lt;/h2&gt;

&lt;p&gt;For an example of pull mode scenario, let's consider a design where Lambda polls to read messages from a SNS Queue and invokes Lambda function. As in the push mode example, the function on invocation processes the messages and writes to DynamoDB table and CloudWatch. This is as shown below along with a summarized view of permissions that need to be defined in Lambda's execution role. As discussed above, in pull mode invocation there's no need for Resource Based Policies. This is because Lambda function is invoked by Lambda service itself and not any external entity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.harprit.dev%2Fvisual-aws-lambda-permissions%2Faws-lambda-pull-mode-permissions.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.harprit.dev%2Fvisual-aws-lambda-permissions%2Faws-lambda-pull-mode-permissions.jpg" alt="AWS Lambda Pull Mode Permissions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above visual shows a concise view of Lambda's Execution Role permissions required for this scenario. Check the following code snippet for more details on the same. To enable Lambda to continuously poll the SQS Queue for new messages, "GetQueueAttributes" and "ReceiveMessage" are required. "DeleteMessage" is required to remove the messages that get successfully processed by Lambda function. Remaining permissions are as discussed in above example for allowing updates to DynamoDB and CloudWatch Logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"sqs:GetQueueAttributes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"sqs:ReceiveMessage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"sqs:DeleteMessage"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:sqs:us-east-1:ACCOUNT-A:MyQueue"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dynamodb:PutItem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:dynamodb:us-east-1:ACCOUNT-A:table/MyTable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:dynamodb:us-east-1:ACCOUNT-A:table/MyTable/index/*"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"logs:CreateLogGroup"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"logs:CreateLogStream"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"logs:PutLogEvents"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cross Account Scenario
&lt;/h3&gt;

&lt;p&gt;For the cross account scenario, let's assume that the Lambda function is defined in ACCOUNT-A while the polled SQS Queue resides in ACCOUNT-B. In this case, Lambda's execution role needs to point to the ARN of the SQS Queue in ACCOUNT-B. This allows Lambda to pull messages from the queue in ACCOUNT-B. As rest of the services like DynamoDB are in the same account, no change is required for them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"sqs:DeleteMessage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"sqs:GetQueueAttributes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"sqs:ReceiveMessage"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:sqs:us-east-1:ACCOUNT-B:MyQueue"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dynamodb:PutItem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:dynamodb:us-east-1:ACCOUNT-A:table/MyTable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:dynamodb:us-east-1:ACCOUNT-A:table/MyTable/index/*"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"logs:CreateLogGroup"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"logs:CreateLogStream"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"logs:PutLogEvents"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As detailed in the push mode scenario, permissions in Lambda function's Resource Based Policy allow cross account invocation of the function. In case of SQS, similar resource level access control is achieved using SQS Access Policies. That's where we can define what all identities like users and roles can access a specific SQS queue and the actions they are allowed to perform.&lt;/p&gt;

&lt;p&gt;In this scenario, a statement needs to be added in the Access Policy of SQS queue as follows. Specifically, to allow access to Lambda function's role in ACCOUNT-A so that it's able to poll and read messages from the SQS queue in ACCOUNT-B.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::ACCOUNT-A:role/service-role/LambdaCrossAccountSQSRole"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"SQS:ChangeMessageVisibility"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"SQS:DeleteMessage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"SQS:ReceiveMessage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"SQS:GetQueueAttributes"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:sqs:us-east-1:ACCOUNT-B:MyQueue"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To summarize, as shown in the visual below, cross account access needs to be opened by both the parties. With updates required in Execution Role for the Lambda function and in the Access Policy for the SQS queue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.harprit.dev%2Fvisual-aws-lambda-permissions%2Faws-lambda-cross-account-pull-permissions.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.harprit.dev%2Fvisual-aws-lambda-permissions%2Faws-lambda-cross-account-pull-permissions.jpg" alt="AWS Lambda Cross Account Pull Mode Permissions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;AWS IAM is a vast yet profoundly important subject. It's vital for everyone who builds on AWS to take time to understand IAM well. As they say, security is job zero. Though this writeup only scratches the surface, I hope it helped you in some ways to have a basic model for working with AWS IAM and Lambda permissions.&lt;/p&gt;




&lt;p&gt;References:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/index.html" rel="noopener noreferrer"&gt;AWS Lambda Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/sns/latest/dg/sns-authentication-and-access-control.html" rel="noopener noreferrer"&gt;Identity and access management in Amazon SNS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-authentication-and-access-control.html" rel="noopener noreferrer"&gt;Identity and access management in Amazon SQS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/EBSdyoO3goc" rel="noopener noreferrer"&gt;Introduction to AWS Lambda &amp;amp; Serverless Applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/compute/easy-authorization-of-aws-lambda-functions/" rel="noopener noreferrer"&gt;Easy Authorization of AWS Lambda Functions&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>security</category>
      <category>lambda</category>
    </item>
  </channel>
</rss>
