<?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: Guillaume LANNEBERE</title>
    <description>The latest articles on DEV Community by Guillaume LANNEBERE (@guillan40).</description>
    <link>https://dev.to/guillan40</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%2F503307%2F0c2905bb-f184-46fe-aa66-1b72e4b152bd.jpg</url>
      <title>DEV Community: Guillaume LANNEBERE</title>
      <link>https://dev.to/guillan40</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/guillan40"/>
    <language>en</language>
    <item>
      <title>Should we consider migrating to Amazon EventBridge from Amazon SNS + SQS?</title>
      <dc:creator>Guillaume LANNEBERE</dc:creator>
      <pubDate>Sat, 05 Feb 2022 08:22:08 +0000</pubDate>
      <link>https://dev.to/aws-builders/should-we-consider-migrate-to-amazon-eventbridge-from-amazon-sns-sqs--4dgi</link>
      <guid>https://dev.to/aws-builders/should-we-consider-migrate-to-amazon-eventbridge-from-amazon-sns-sqs--4dgi</guid>
      <description>&lt;p&gt;In early 2019, Betclic was in a corner, and we decided to migrate to microservices approach and migrate to the cloud.&lt;/p&gt;

&lt;p&gt;The first step of this change was the implementation of an Event Driven Architecture (EDA).&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Betclic presentation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before speaking of architecture and EDA, it’s essential to know what Betclic is doing to understand our choice quickly.&lt;/p&gt;

&lt;p&gt;Betclic is a French online gambling company. Betclic operates in Sports betting, horse race betting, and online poker.&lt;/p&gt;

&lt;p&gt;The specificity of gambling is that we don’t have predictive traffic. We have high traffic peaks during significant events and weekends. We can see an example of traffic on a soccer event:&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%2Fcdn-images-1.medium.com%2Fmax%2F2112%2F1%2Az9f5RHRSBqy5iFEc5te3zg.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F2112%2F1%2Az9f5RHRSBqy5iFEc5te3zg.png" alt="Example of traffic"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;EDA wishlist&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When beginning 2019, we did a workshop to identify the key features of our ideal EDA; we would like something:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;allowing &lt;strong&gt;multiple reads&lt;/strong&gt;: the same message can be read by various services&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;with &lt;strong&gt;error recovery&lt;/strong&gt;: in case of error, we would like to replay events&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;easy to monitor&lt;/strong&gt;: particularly with &lt;strong&gt;Datadog&lt;/strong&gt;, our centralized monitoring solution&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;with &lt;strong&gt;schema registry&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;language-agnostic&lt;/strong&gt;: we use 3 main languages &lt;strong&gt;.net&lt;/strong&gt;, *&lt;em&gt;Kotlin, **and **Typescript *&lt;/em&gt;(for Lambda), and the chosen solution must work with all languages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;with &lt;strong&gt;analytics capabilities&lt;/strong&gt;: we would like to integrate all our events of EDA in our data lake&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;fully managed&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;with &lt;strong&gt;auto scaling&lt;/strong&gt;: essential feature for us; we have unpredictable traffic with big spikes at the end of matches, so we need to have an EDA to be able to absorb our spikes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;with &lt;strong&gt;low latency and high availability&lt;/strong&gt;: also an essential feature, we would like our EDA to serve critical use cases for our final users, so we want something the most real-time and the most available possible&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;well-integrated with AWS services&lt;/strong&gt;: EDA is one of our first bricks in the cloud, but we want something to help us to migrate to AWS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;easy to use&lt;/strong&gt;: we want all the time something easy to use :) but here it’s particularly true because EDA is a centralized solution, and the majority of our developers will use it (and back in 2019 majority of our developers wasn’t Cloud developer)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;cost-effective&lt;/strong&gt;: what is the cost-effectiveness?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;2019: Amazon SNS + Amazon SQS: The best solution&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Remember here; we were beginning 2019: Amazon EventBridge (&lt;a href="https://aws.amazon.com/about-aws/whats-new/2019/07/introducing-amazon-eventbridge/" rel="noopener noreferrer"&gt;announced in July 2019&lt;/a&gt;) or Amazon MQ for RabbitMq (&lt;a href="https://aws.amazon.com/about-aws/whats-new/2020/11/announcing-amazon-mq-rabbitmq/" rel="noopener noreferrer"&gt;announced in November 20&lt;/a&gt;20) weren’t out.&lt;/p&gt;

&lt;p&gt;Following our needs, we decided to combine Amazon SNS with Amazon SQS.&lt;/p&gt;

&lt;p&gt;Amazon SNS is essential in our solution because it helps us to do &lt;strong&gt;multiple reads&lt;/strong&gt; and also helps us to &lt;strong&gt;centralize the solution.&lt;/strong&gt;&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%2Fcdn-images-1.medium.com%2Fmax%2F2782%2F1%2Ae2DoSQSXWLkHezghh75zWw.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F2782%2F1%2Ae2DoSQSXWLkHezghh75zWw.png" alt="Amazon SNS — Publisher"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;All events are published in a centralized Amazon SNS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each functional domain has its own topic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each functional domain can publish only on its own topic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lambda/Fargate/On-Premise publish in the same manner&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F3062%2F1%2AeFrIFYlUBAKV3IdY0kKfAQ.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F3062%2F1%2AeFrIFYlUBAKV3IdY0kKfAQ.png" alt="Amazon SNS + Amazon SQS — Consumer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A service consume only events of another functional domain&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each service has its own queue with its own filter&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A filter is based on an &lt;a href="https://docs.aws.amazon.com/sns/latest/dg/sns-message-attributes.html" rel="noopener noreferrer"&gt;Amazon SNS message attributes, &lt;/a&gt;and it’s limited to 10 attributes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fargate/On-Premise service consume in the same manner&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For Lambda, we prefer to create an Amazon SNS subscription of type Lambda with a filter and consume directly from Amazon SNS&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Custom features&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Following the wish list features listed above, the majority of features are taken into account in this architecture excepted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;schema registry&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;error recovery&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;analytics capabilities&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We decided to make a custom implementation for these features.&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%2Fcdn-images-1.medium.com%2Fmax%2F3100%2F1%2A0QtGR7RA9-tF76GcCXY0lg.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F3100%2F1%2A0QtGR7RA9-tF76GcCXY0lg.png" alt="Error recovery and analytics capabilities"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Error recovery and analytics capabilities are implemented in the same architecture&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;All events are stored in our Data Lake with the help of Kinesis Data Firehose and Amazon S3&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In case of an issue, we can replay events by extracting events from our data lake to Amazon S3. An object S3 triggers a Lambda and Lambda push events to correct topic in Amazon SNS.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We store events in a file in case of connectivity failure between our on-premise and AWS. Once connectivity comes back, events of the files are pushed to Amazon SNS on the correct topic with the help of FluentD&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One feature that is missing for now on error recovery it’s the ability to replay events on a specific SQS queue. All the events are replayed to an SNS topic, so all events consumers service receive events again. &lt;a href="https://en.wikipedia.org/wiki/Idempotence" rel="noopener noreferrer"&gt;**Idempotence&lt;/a&gt;** is necessary for consumer services.&lt;/p&gt;

&lt;p&gt;Concerning schema registry, nothing is in production for now. We have just developed a portal with all the available events and a debug console to validate the event format in Stage environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cost
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;550 million events are published by month&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The average size of an event is 630 B / event&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;1.1 billion events are transferred for domain (average of 2 services consume an event)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;1.5 billion Amazon SQS requests are made to consume and delete events&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Publication cost in Amazon SNS&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;550 million events published = &lt;strong&gt;$ 275.50&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Consumption cost in Amazon SNS + Amazon SQS&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Amazon SNS: Data transfer = 1.1 billion events x 630 B = 693 Gb transferred ==&amp;gt; 693 x 0.09 (price by Gb out)= &lt;strong&gt;$ 63.78&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Amazon SQS: Events sent = 1.1 billion events = &lt;strong&gt;$ 440&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Amazon SQS: Receive + Delete = 1.5 billion requests = &lt;strong&gt;$ 600&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consumption cost = $ 1103.78&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error recovery + analytics capabilities&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;550 million events published to Kinesis Data Firehose = &lt;strong&gt;$ 104.50&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;346.5 Gb of data transferred from Amazon SNS to Kinesis Data Firehose = &lt;strong&gt;$ 31.09&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kinesis Data Firehose cost = &lt;strong&gt;$ 81.30&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;S3 cost with 1 month retention = 346.5 Gb of data = &lt;strong&gt;$ 7.97&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total cost = &lt;strong&gt;$ 1603.14&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lambda for replay isn’t estimated because we don’t know how many replays we do monthly.&lt;/p&gt;

&lt;p&gt;Detail of the price is available in AWS calculator &lt;a href="https://calculator.aws/#/estimate?id=361d64ff4ebc02695480c818b205cafcfe1df0c7" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2021: Amazon EventBridge ?
&lt;/h2&gt;

&lt;p&gt;As we saw in 2019, our best choice for EDA was Amazon SNS + Amazon SQS. Is it still right in 2021?&lt;/p&gt;

&lt;p&gt;A lot of interesting features have been out on Amazon EventBridge for 2 years:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/about-aws/whats-new/2020/02/introducing-content-filtering-amazon-eventbridge/" rel="noopener noreferrer"&gt;Content filtering &lt;/a&gt;(02/2020)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/about-aws/whats-new/2020/04/amazon-eventbridge-schema-registry-now-generally-available/" rel="noopener noreferrer"&gt;Schema registry&lt;/a&gt; (04/2020)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/about-aws/whats-new/2020/10/amazon-eventbridge-announces-support-dead-letter-queues/" rel="noopener noreferrer"&gt;Dead letter queues&lt;/a&gt; (10/2020)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/about-aws/whats-new/2020/11/amazon-eventbridge-introduces-support-for-event-replay/" rel="noopener noreferrer"&gt;Event replay&lt;/a&gt; (11/2020)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/about-aws/whats-new/2020/11/amazon-eventbridge-adds-server-side-encryption-sse-and-increases-default-quotas/" rel="noopener noreferrer"&gt;Increase quotas&lt;/a&gt; (11/2020)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/about-aws/whats-new/2021/04/amazon-eventbridge-introduces-support-cross-region-event-bus-targets/" rel="noopener noreferrer"&gt;Cross account&lt;/a&gt; (04/2021)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;According to this, all the features of our wishlist are natively supported.&lt;/p&gt;

&lt;p&gt;We can imagine doing something like this for publishing events with Amazon EventBridge:&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%2Fcdn-images-1.medium.com%2Fmax%2F2782%2F1%2AKKHft7ooAygd6hFYEksy0Q.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F2782%2F1%2AKKHft7ooAygd6hFYEksy0Q.png" alt="Amazon EventBridge — Publisher"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;All events are published in a centralized Amazon EventBridge&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each functional domain has its own Event Bus&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each functional domain can publish only in its own Event Bus&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lambda/Fargate/On-Premise publish in the same manner&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Schema Registry is natively supported, Events are defined in Schema Registry, and developers generate code based on these events (&lt;a href="https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-schema-code-bindings.html" rel="noopener noreferrer"&gt;Code bindings&lt;/a&gt; isn’t supported in the language that we use in Betclic)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Schema Discovery allows knowing which events are published to Amazon EventBridge and allows to identify events that don’t respect the contract&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Schema Discovery and Schema Registry are fully managed&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Schema Discovery is generally activated on-demand in Production.&lt;/p&gt;

&lt;p&gt;For consuming events, something like that:&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%2Fcdn-images-1.medium.com%2Fmax%2F3422%2F1%2AZ4Gq526eIxDYG4MbhLyBbA.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F3422%2F1%2AZ4Gq526eIxDYG4MbhLyBbA.png" alt="Amazon EventBridge — Consumer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A service consume only events of another functional domain&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/blogs/compute/simplifying-cross-account-access-with-amazon-eventbridge-resource-policies/" rel="noopener noreferrer"&gt;To send events to other accounts&lt;/a&gt;, we need to publish on a new Amazon EventBridge Event Bus&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Events can be filtered on all the data of the events&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Amazon EventBridge can’t publish directly to Fargate or On-Premise; we need to pass by an Amazon SQS queue to consume in this case&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each service has its own EventBridge Rule, its own queue with its own filter&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fargate/On-Premise service consume in the same manner&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For Lambda, we consume directly from Amazon EventBridge through a rule&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Error recovery and analytics capabilities&lt;/strong&gt;
&lt;/h3&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%2Fcdn-images-1.medium.com%2Fmax%2F2196%2F1%2Aluyx5a5ymPa5n39CKE4ebA.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F2196%2F1%2Aluyx5a5ymPa5n39CKE4ebA.png" alt="Amazon EventBridge — Error recovery and analytics capabilities"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Error recovery and analytics capabilities are fully managed with Amazon EventBridge&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;All events are stored in our Data Lake with the help of Kinesis Data Firehose and Amazon S3&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In case of issue, we can replay events directly from Amazon EventBridge&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Possibility to replay data on a specific rule or all the rules&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Cost&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We have the following based on the same elements as Amazon SNS + SQS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Publication cost in Amazon EventBridge&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;550 million events published = &lt;strong&gt;$ 550&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Consumption cost in Amazon EventBridge&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Amazon EventBridge: Events transferred to others Event Bus= 1.1 billion events = &lt;strong&gt;$ 1100&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Amazon SQS: Events sent = 1.1 billion events = &lt;strong&gt;$ 440&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Amazon SQS: Receive + Delete = 1.5 billion requests = &lt;strong&gt;$ 600&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consumption cost = &lt;strong&gt;$ 2140&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error recovery + analytics capabilities&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Kinesis Data Firehose cost = &lt;strong&gt;$ 81.30&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;S3 cost with 1 month retention = 346.5 Gb of data = &lt;strong&gt;$ 7.97&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;EventBridge archive for 3 months: = 346.5 Gb x 3 months = 1039 Gb x $ 0.11 = &lt;strong&gt;$ 114.29&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total cost = &lt;strong&gt;$ 2893.56&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;EventBridge replay and Schema Registry aren’t estimated because we don’t know how many replays/discoveries we will do monthly.&lt;/p&gt;

&lt;p&gt;Detail of the price (without EventBridge archive) is available in AWS calculator &lt;a href="https://calculator.aws/#/estimate?id=79965fd07e79cf32088d8451951a3dfe3b1723bc" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Amazon EventBridge has all the features that we want natively supported. No need to implement custom features with EventBridge.&lt;/p&gt;

&lt;p&gt;However, cross-account EventBridge is more complicated than Amazon SNS because 2 rules need to be updated to consume a new event in a domain. In contrast, SNS need only the creation of 1 subscription with the correct filter.&lt;/p&gt;

&lt;p&gt;It would have been nice to allow EventBridge to publish Events directly with Fargate and even better with On-Premise server. This feature is missing because we need to consume from Amazon SQS.&lt;/p&gt;

&lt;p&gt;So in terms of features, Amazon EventBridge wins over Amazon SNS + SQS.&lt;/p&gt;

&lt;p&gt;Concerning the price, it’s a little bit different.&lt;/p&gt;

&lt;p&gt;The cost of the architecture with Amazon SNS + SQS, in our case, is &lt;strong&gt;$ 1603.14.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While with EventBridge, the cost of the same architecture is &lt;strong&gt;$ 2893.56.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;80%&lt;/strong&gt; of cost difference is huge. Is it the price of the missing features of Amazon SNS compared to EventBridge ?&lt;/p&gt;

&lt;p&gt;In Betclic, the choice is quickly seen; we have already developed the missing features that we want, so we are not interested in migrating to Amazon EventBridge. But we follow the news of Amazon EventBridge carefully because it’s a constantly evolving service.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>architecture</category>
      <category>cloud</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>Serverless Proxy with AWS API Gateway and AWS Lambda</title>
      <dc:creator>Guillaume LANNEBERE</dc:creator>
      <pubDate>Mon, 11 Jan 2021 16:33:11 +0000</pubDate>
      <link>https://dev.to/aws-builders/serverless-proxy-with-aws-api-gateway-and-aws-lambda-3bd2</link>
      <guid>https://dev.to/aws-builders/serverless-proxy-with-aws-api-gateway-and-aws-lambda-3bd2</guid>
      <description>&lt;p&gt;It's sometimes difficult to communicate between public and private subnet in AWS.&lt;br&gt;
We will see how we can easily do that with the help of API Gateway and AWS Lambda.  &lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Use case example&lt;/strong&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Example 1&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It's sometimes necessary to have a Github repository communicating with a private EC2 instance.&lt;br&gt;&lt;br&gt;
But when an instance is private, it can be really complicated without impacting the security of the instance.  &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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhunix4fbomsybaxo1k73.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhunix4fbomsybaxo1k73.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe9ekaa7igw73gl5raaau.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe9ekaa7igw73gl5raaau.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Github Webhook calls a Public API Gateway, API Gateway triggers a Lambda attached to VPC. The role of this Lambda is to forward the content of the Github Webhook to the EC2 instance.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Remark&lt;/strong&gt;: An AWS Lambda attached to a VPC isn't deployed inside the VPC, an Elastic Network Interface (ENI) is created to link the Lambda function and the different subnets inside the VPC.  &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Example 2&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Other example, we may need to communicate between a public instance inside a public subnet and a private instance inside a private subnet inside a  VPC. &lt;br&gt;
For security reason, direct routing between Public subnet and private Subnet is not possible. So, to facilitate this, it's possible to use this solution of Serverless Proxy.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fspjtgmfdjvrmjfer6k71.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fspjtgmfdjvrmjfer6k71.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fz9fu2qjzvx1m15z9vi2h.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fz9fu2qjzvx1m15z9vi2h.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
On the same way as Solution 1, we can communicate between Public and Private instance via a Serverless Proxy thanks to AWS Api Gateway and AWS Lambda.&lt;br&gt;
This solution is easy to implement, highly scalable, secure and not expensive.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Implementation&lt;/strong&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;AWS Lambda&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Lambda function is quite simple. The goal of this lambda is just to forward the information received from API Gateway to the destination inside VPC. &lt;br&gt;
Here we use python and Lambda function is as simple as that:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urllib3&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;URL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Two way to have http method following if lambda proxy is enabled or not
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;httpMethod&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;http_method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;httpMethod&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;http_method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;requestContext&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;method&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;headers&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;headers&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Important to remove the Host header before forwarding the request
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Host&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Host&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;host&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;host&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PoolManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;http_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;urllib3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exceptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewConnectionError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Connection failed.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Connection failed.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To redirect requests I use the python lib urllib3, for more information or if you want to update the code check &lt;a href="https://urllib3.readthedocs.io/en/latest/user-guide.html" rel="noopener noreferrer"&gt;the official documentation&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
To facilitate the deployment, backend url is passed in environment variable.&lt;br&gt;&lt;br&gt;
This lambda need to be attached to a VPC.&lt;br&gt;&lt;br&gt;
To know how to optimize Lambda for cost and/or performance, 2 tools exists:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the well know &lt;a href="https://github.com/alexcasalboni/aws-lambda-power-tuning" rel="noopener noreferrer"&gt;AWS Lambda Power Tuning&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/about-aws/whats-new/2020/12/aws-compute-optimizer-delivers-recommendations-aws-lambda-functions/" rel="noopener noreferrer"&gt;AWS Compute Optimizer&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By executing the Forwarder Lambda with 50 parallel executions thanks to Lambda Power Tuning tool, I have the following result:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5wq5h6bg8ycvo4vnsgaz.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5wq5h6bg8ycvo4vnsgaz.png" alt="Forward Lambda - Lambda Power Tuning"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that &lt;strong&gt;512 mb&lt;/strong&gt; of memory is the best for this Lambda with 9 ms execution time on average.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;AWS Api Gateway&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here AWS Api Gateway need to be public and have an AWS Lambda integration. So 2 types of Api Gateway can be used:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;REST Api&lt;/li&gt;
&lt;li&gt;HTTP Api&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vs-rest.html" rel="noopener noreferrer"&gt;Let's see how to choose between both types of Api Gateway.&lt;/a&gt;&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fitxzru2sooqg34lm7k6u.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fitxzru2sooqg34lm7k6u.png" alt="REST Api / HTTP Api comparison"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So here, we can see that REST Api have really more feature than HTTP Api, especially concerning security and optimization.&lt;br&gt;&lt;br&gt;
Concerning pricing, it's also really important to know that:&lt;br&gt;
Requests are not charged for authorization and authentication failures.&lt;br&gt;&lt;br&gt;
Calls to methods that require API keys are not charged when API keys are missing or invalid.&lt;br&gt;&lt;br&gt;
API Gateway-throttled requests are not charged when the request rate or burst rate exceeds the preconfigured limits.&lt;br&gt;
Usage plan-throttled requests are not charged when rate limits or quota exceed the preconfigured limits.  &lt;/p&gt;

&lt;p&gt;More information &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-pricing.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
Another important things to know before choosing between REST Api or HTTP Api is to take care about security and particularly about the most common attacks in the cloud:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Denial-of-service (DoS) and distributed denial-of-service (DDoS) attacks&lt;/li&gt;
&lt;li&gt;Denial-of-wallet (DoW) attacks&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://portswigger.net/daily-swig/denial-of-wallet-attacks-how-to-protect-against-costly-exploits-targeting-serverless-setups" rel="noopener noreferrer"&gt;Denial-of-Wallet (DoW)&lt;/a&gt; exploits are similar to traditional denial-of-service (DoS) attacks in the sense that both are carried with the intent to cause disruption.&lt;br&gt;&lt;br&gt;
However, while DoS assaults aim to force a targeted service offline, DoW seeks to cause the victim financial loss.&lt;br&gt;&lt;br&gt;
And also we can see that everybody is concerned by DoW or generally costs out of control in the Cloud and not only big companies: multiple examples exist for example &lt;a href="https://chrisshort.net/the-aws-bill-heard-around-the-world/" rel="noopener noreferrer"&gt;this one&lt;/a&gt; or &lt;a href="https://www.theregister.com/2020/12/10/google_cloud_over_run/" rel="noopener noreferrer"&gt;lately this one&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommendation&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Following all the information above, my recommendation is to use REST Api when APIs calls can't be authenticated.&lt;br&gt;&lt;br&gt;
If it's possible to authenticate APIs calls and if pricing concern is an important consideration, HTTP api can be used.&lt;br&gt;
So here in example 1, REST api should be used because it's not possible to authenticate calls from Github. In example 2, HTTP Api can be used if front APIs calls are authenticated else REST Api should be used.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Remarks&lt;/strong&gt;: HTTP Api is quite new compared to REST Api. Some features are possible but complicate to deploy. Example, with Serverless Framework throttle isn't yet supported.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Deployment&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;To deploy the stack, I've decided to use Serverless Framework.&lt;br&gt;
If you don't know Serverless Framework, I let you see the &lt;a href="https://www.serverless.com/framework/docs/getting-started/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;br&gt;
My serverless.yml looks like this:&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;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;serverless-proxy&lt;/span&gt;

&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-python-requirements&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-prune-plugin&lt;/span&gt;

&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://myurl:80&lt;/span&gt; &lt;span class="c1"&gt;#to be replaced by backend url&lt;/span&gt;
  &lt;span class="na"&gt;vpcId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vpc-123456&lt;/span&gt; &lt;span class="c1"&gt;#to be replaced by vpc id&lt;/span&gt;
  &lt;span class="na"&gt;subnetIds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;subnet-123&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;subnet-456&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;subnet-789&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;#to be replaced by subnet ids&lt;/span&gt;
  &lt;span class="na"&gt;pythonRequirements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;#serverless-python-requirements configuration&lt;/span&gt;
    &lt;span class="na"&gt;dockerizePip&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;prune&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;#serverless-prune-plugin configuration: 3 versions are kept&lt;/span&gt;
    &lt;span class="na"&gt;automatic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;

&lt;span class="c1"&gt;#Create security group&lt;/span&gt;
&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;SecurityGroup&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::EC2::SecurityGroup&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;GroupDescription&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SG for Serverless Proxy forwarder&lt;/span&gt;
        &lt;span class="na"&gt;VpcId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.vpcId}&lt;/span&gt;
        &lt;span class="na"&gt;SecurityGroupEgress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;IpProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tcp&lt;/span&gt;
            &lt;span class="na"&gt;FromPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
            &lt;span class="na"&gt;ToPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
            &lt;span class="na"&gt;CidrIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;IpProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tcp&lt;/span&gt;
            &lt;span class="na"&gt;FromPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;
            &lt;span class="na"&gt;ToPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;
            &lt;span class="na"&gt;CidrIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;
        &lt;span class="na"&gt;Tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name&lt;/span&gt;
            &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;serverless-proxy-sg&lt;/span&gt;

&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&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;python3.8&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eu-west-1&lt;/span&gt; &lt;span class="c1"&gt;#to be changed by your AWS function&lt;/span&gt;

&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;serverless-proxy&lt;/span&gt;&lt;span class="pi"&gt;:&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;handler.main&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;serverless-proxy&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lambda Forwarder function&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;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.url}&lt;/span&gt;
    &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;securityGroupIds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SecurityGroup&lt;/span&gt;
      &lt;span class="na"&gt;subnetIds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.subnetIds}&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&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;forward&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="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&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;forward&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;head&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&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;forward&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;post&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&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;forward&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;put&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;2 Serverless plugins are used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/UnitedIncome/serverless-python-requirements" rel="noopener noreferrer"&gt;serverless-python-requirements&lt;/a&gt;: to automatically bundle Python dependencies from requirements.txt&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/UnitedIncome/serverless-python-requirements" rel="noopener noreferrer"&gt;serverless-prune-plugin&lt;/a&gt;: to purge previous versions of AWS Lambda automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;"requirements.txt" looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

urllib3==1.25.8


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;3 parameters need to be updated before deploy the stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;url: with the correct url of your backend service&lt;/li&gt;
&lt;li&gt;vpcId: vpc id of where is deployed your backend service&lt;/li&gt;
&lt;li&gt;subnetIds: subnet ids of where is deployed your backend service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;"resources" part is used to create a new security group, we will see this in detail in the security part.&lt;br&gt;&lt;br&gt;
Concerning "functions" part:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;memorySize is 512mb according to AWS Lambda Power Tuning&lt;/li&gt;
&lt;li&gt;url is passed in environment variable in "environment" part&lt;/li&gt;
&lt;li&gt;Lambda is attached to vpc in "vpc" part&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In "event", we have here a &lt;strong&gt;REST Api&lt;/strong&gt; with 4 routes /forward: GET, HEAD, POST and PUT. If you want another HTTP verb simply add a new route here.&lt;/p&gt;

&lt;p&gt;If you want to replace &lt;strong&gt;REST Api&lt;/strong&gt; by &lt;strong&gt;HTTP Api&lt;/strong&gt;, you have just to replace:&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;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&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;forward&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="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&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;forward&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;head&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&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;forward&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;post&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&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;forward&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;put&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;By:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;httpApi&lt;/span&gt;&lt;span class="pi"&gt;:&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;/forward&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="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;httpApi&lt;/span&gt;&lt;span class="pi"&gt;:&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;/forward&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;head&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;httpApi&lt;/span&gt;&lt;span class="pi"&gt;:&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;/forward&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;post&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;httpApi&lt;/span&gt;&lt;span class="pi"&gt;:&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;/forward&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;put&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once everything is good, simply execute the following command to deploy the stack:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

sls deploy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  &lt;strong&gt;Security&lt;/strong&gt;
&lt;/h1&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Lambda&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To protect Lambda against security attacks like Denial-of-Service or Denial-of-Wallet, it's important to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;protect security group&lt;/li&gt;
&lt;li&gt;set a good timeout for the function&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Security Group&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
For Security Group, only the Egress port of your backend route need to be open. And only the specific IP (or CIDR block) need to be opened. &lt;strong&gt;No Ingress rule need to be opened.&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Example: if your backend route is on port 80 and IP: 172.0.0.10, Security Group need to be as following:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fi0r8zyc58kslm9vdk13b.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fi0r8zyc58kslm9vdk13b.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This gives in "serverless.yml"&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;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;SecurityGroup&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::EC2::SecurityGroup&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;GroupDescription&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SG for Serverless Proxy forwarder&lt;/span&gt;
        &lt;span class="na"&gt;VpcId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.vpcId}&lt;/span&gt;
        &lt;span class="na"&gt;SecurityGroupEgress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;IpProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tcp&lt;/span&gt;
            &lt;span class="na"&gt;FromPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
            &lt;span class="na"&gt;ToPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
            &lt;span class="na"&gt;CidrIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;172.0.0.10/32&lt;/span&gt;
        &lt;span class="na"&gt;Tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name&lt;/span&gt;
            &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;serverless-proxy-sg&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Timeout&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Concerning timeout, it's important to set a good timeout to protect cost. As a reminder, a Lambda function is priced in function of the memory and the execution time. Minimum timeout is 1 second and maximum 900 seconds.&lt;br&gt;&lt;br&gt;
My suggestion is to set a timeout to 3 times the average execution time, average execution time is 9ms so here, we need to set the timeout to the minimum of 1 second.&lt;br&gt;&lt;br&gt;
It gives in "serverless.yml"&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;memorySize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&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;1&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Api Gateway&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In the same way as Lambda, Api Gateway need to be protected against security attacks. And it's even more important because Api Gateway here is public.&lt;br&gt;&lt;br&gt;
So we need to ensure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;throttling is enabled and set at a correct value by endpoint&lt;/li&gt;
&lt;li&gt;authentication is enabled when it's possible&lt;/li&gt;
&lt;li&gt;usage plan and api key is enabled&lt;/li&gt;
&lt;li&gt;resource policy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Throttling&lt;/strong&gt;&lt;br&gt;
To understand more precisely how throttling works, check this &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
To enable throttling on REST Api with Serverless Framework, we need to install a new plugin:&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;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-api-gateway-throttling&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After this, 2 ways, first you set a throttling at the stage level and it will be applied for all endpoint:  &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;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;apiGatewayThrottling&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;maxRequestsPerSecond&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
    &lt;span class="na"&gt;maxConcurrentRequests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Else, you set a throttling directly at an endpoint level:&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;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&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;forward&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;throttling&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;maxRequestsPerSecond&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
        &lt;span class="na"&gt;maxConcurrentRequests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;For HTTP Api, it's possible to have throttle but it's not possible to do it with Serverless Framework.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Remark&lt;/strong&gt;: It's important to set throttling that fit your use case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authentication&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Authentication is a good way to secure HTTP Api or REST Api and it's possible to do it with different manners. I won't detail in this article how we can manage authentication but it can be a really good article for later. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage plan and Api Key&lt;/strong&gt;&lt;br&gt;
A good way to secure an Api is to provide an Api Key.&lt;br&gt;&lt;br&gt;
To do this, an Api Key need to be provided to the Api and after each call need to have a header name "x-api-key", more information &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-key-source.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Once it's done, it's possible to specify usage plan by endpoint to limit the number of calls allowed.&lt;br&gt;&lt;br&gt;
In Serverless Framework it's possible with the help of the plugin &lt;a href="https://www.serverless.com/plugins/serverless-add-api-key" rel="noopener noreferrer"&gt;serverless-add-api-key&lt;/a&gt; on this way:&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;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-add-api-key&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To specify a key, let AWS auto set the value and specify Usage Plan at the stage level:&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;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;apiKeys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret&lt;/span&gt;
    &lt;span class="na"&gt;usagePlan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;global-plan"&lt;/span&gt;
      &lt;span class="na"&gt;quota&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
        &lt;span class="na"&gt;period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DAY&lt;/span&gt;
      &lt;span class="na"&gt;throttle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;burstLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
        &lt;span class="na"&gt;rateLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To finish, it's important to required Api Key on all the endpoints in the following way:&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;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&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;forward&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;private&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&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;forward&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;head&lt;/span&gt;
      &lt;span class="na"&gt;private&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&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;forward&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;post&lt;/span&gt;
      &lt;span class="na"&gt;private&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&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;forward&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;put&lt;/span&gt;
      &lt;span class="na"&gt;private&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once it's done, to call api, you need to do:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

curl -X GET https://ep.execute-api.eu-west-1.amazonaws.com/stage/forward -H "x-api-key: my-generate-key"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Remark&lt;/strong&gt;: This feature is available only with REST Api, not with HTTP Api. It's not possible to do that easily with Github example 1, because with Github Webhook it's not possible to add a key "x-api-key"… Something is possible with a Lambda authorizer but it's much more complicated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource Policy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Resource Policy is a good way to secure REST Api, for example by limiting invocation to specific IPs or CIDR blocks.&lt;br&gt;&lt;br&gt;
In example 1 with Github Webhook, is a good way to limit invocation only to Github hooks CIDR blocks. Github hooks CIDR blocks are publicly available &lt;a href="https://api.github.com/meta" rel="noopener noreferrer"&gt;here&lt;/a&gt;. So with the help of the following policy, only Github IPs are able to call my REST Api.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"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;"Deny"&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="s2"&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;"execute-api:Invoke"&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;"execute-api:/*"&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;"NotIpAddress"&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:SourceIp"&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;"192.30.252.0/22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"185.199.108.0/22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"140.82.112.0/20"&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;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="s2"&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;"execute-api:Invoke"&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;"execute-api:/*"&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;"IpAddress"&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:SourceIp"&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;"192.30.252.0/22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"185.199.108.0/22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"140.82.112.0/20"&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;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;If we do exactly the same thing with Serverless Framework:&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;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&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;python3.8&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eu-west-1&lt;/span&gt;
  &lt;span class="na"&gt;resourcePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deny&lt;/span&gt;
      &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
      &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;execute-api:Invoke&lt;/span&gt;
      &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;execute-api:/*/*/forward&lt;/span&gt;
      &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;NotIpAddress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;aws:SourceIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;192.30.252.0/22&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;185.199.108.0/22&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;140.82.112.0/20&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
      &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
      &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;execute-api:Invoke&lt;/span&gt;
      &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;execute-api:/*/*/forward&lt;/span&gt;
      &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;IpAddress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;aws:SourceIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;192.30.252.0/22&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;185.199.108.0/22&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;140.82.112.0/20&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Remarks&lt;/strong&gt;: This feature is available only with REST Api, not with HTTP Api.&lt;/p&gt;




&lt;p&gt;With all the security protection above, serverless.yml looks like:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;serverless-proxy&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-python-requirements&lt;/span&gt;&lt;br&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-prune-plugin&lt;/span&gt;&lt;br&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-api-gateway-throttling&lt;/span&gt;&lt;br&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-add-api-key&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&lt;a href="http://myurl:80" rel="noopener noreferrer"&gt;http://myurl:80&lt;/a&gt;&lt;/span&gt; &lt;span class="c1"&gt;#to be replaced by backend url&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;vpcId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vpc-123456&lt;/span&gt; &lt;span class="c1"&gt;#to be replaced by vpc id&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;subnetIds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;subnet-123&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;subnet-456&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;subnet-789&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;#to be replaced by subnet ids&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;pythonRequirements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;#serverless-python-requirements configuration&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;dockerizePip&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;prune&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;#serverless-prune-plugin configuration: 3 versions are kept&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;automatic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;apiGatewayThrottling&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;maxRequestsPerSecond&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;maxConcurrentRequests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;apiKeys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;usagePlan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;global-plan"&lt;/span&gt;&lt;br&gt;
        &lt;span class="na"&gt;quota&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DAY&lt;/span&gt;&lt;br&gt;
        &lt;span class="na"&gt;throttle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;burstLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;rateLimit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;SecurityGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::SecurityGroup&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
        &lt;span class="na"&gt;GroupDescription&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SG for Serverless Proxy forwarder&lt;/span&gt;&lt;br&gt;
        &lt;span class="na"&gt;VpcId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.vpcId}&lt;/span&gt;&lt;br&gt;
        &lt;span class="na"&gt;SecurityGroupEgress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;IpProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tcp&lt;/span&gt;&lt;br&gt;
            &lt;span class="na"&gt;FromPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;&lt;br&gt;
            &lt;span class="na"&gt;ToPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;&lt;br&gt;
            &lt;span class="na"&gt;CidrIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;&lt;br&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;IpProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tcp&lt;/span&gt;&lt;br&gt;
            &lt;span class="na"&gt;FromPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;&lt;br&gt;
            &lt;span class="na"&gt;ToPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;&lt;br&gt;
            &lt;span class="na"&gt;CidrIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;&lt;br&gt;
        &lt;span class="na"&gt;Tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name&lt;/span&gt;&lt;br&gt;
            &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;serverless-proxy-sg&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.8&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eu-west-1&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;resourcePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deny&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&lt;em&gt;"&lt;/em&gt;&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;execute-api:Invoke&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;execute-api://&lt;em&gt;/forward&lt;/em&gt;&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
        &lt;span class="na"&gt;NotIpAddress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;aws:SourceIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;192.30.252.0/22&lt;/span&gt;&lt;br&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;185.199.108.0/22&lt;/span&gt;&lt;br&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;140.82.112.0/20&lt;/span&gt;&lt;br&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;execute-api:Invoke&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;execute-api:/&lt;em&gt;/&lt;/em&gt;/forward&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
        &lt;span class="na"&gt;IpAddress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;aws:SourceIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;192.30.252.0/22&lt;/span&gt;&lt;br&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;185.199.108.0/22&lt;/span&gt;&lt;br&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;140.82.112.0/20&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;serverless-proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;handler.main&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;serverless-proxy&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lambda Forwarder function&lt;/span&gt;&lt;br&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;br&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.url}&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;securityGroupIds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SecurityGroup&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;subnetIds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.subnetIds}&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;forward&lt;/span&gt;&lt;br&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;br&gt;
          &lt;span class="na"&gt;private&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;br&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;forward&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;head&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;private&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;br&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;forward&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;post&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;private&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;br&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;forward&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;put&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;private&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;br&gt;
      &lt;span class="c1"&gt;#- httpApi:&lt;/span&gt;&lt;br&gt;
      &lt;span class="c1"&gt;#    path: /forward&lt;/span&gt;&lt;br&gt;
      &lt;span class="c1"&gt;#    method: get&lt;/span&gt;&lt;br&gt;
      &lt;span class="c1"&gt;#- httpApi:&lt;/span&gt;&lt;br&gt;
      &lt;span class="c1"&gt;#    path: /forward&lt;/span&gt;&lt;br&gt;
      &lt;span class="c1"&gt;#    method: head&lt;/span&gt;&lt;br&gt;
      &lt;span class="c1"&gt;#- httpApi:&lt;/span&gt;&lt;br&gt;
      &lt;span class="c1"&gt;#    path: /forward&lt;/span&gt;&lt;br&gt;
      &lt;span class="c1"&gt;#    method: post&lt;/span&gt;&lt;br&gt;
      &lt;span class="c1"&gt;#- httpApi:&lt;/span&gt;&lt;br&gt;
      &lt;span class="c1"&gt;#    path: /forward&lt;/span&gt;&lt;br&gt;
      &lt;span class="c1"&gt;#    method: put&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;strong&gt;To go further&lt;/strong&gt;&lt;br&gt;
&lt;/h1&gt;

&lt;p&gt;If in front of your EC2 instance, you have a Network Load balancer (NLB) or an Application Load Balancer (ALB), it can be possible to integrate it without Lambda.&lt;/p&gt;

&lt;p&gt;It's possible because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP Api can be integrated with private API through &lt;strong&gt;NLB and ALB&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;REST Api can be integrated with private API through &lt;strong&gt;NLB only&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, Example 1 with an NLB in front of EC2 instance gives:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9rj0clwuhs2evwwzyct1.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9rj0clwuhs2evwwzyct1.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To do that you should:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a VPC link in API Gateway&lt;/li&gt;
&lt;li&gt;Change method execution from Lambda to VPC Link&lt;/li&gt;
&lt;/ol&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1ltyaex004y1yc033odk.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1ltyaex004y1yc033odk.png" alt="Method Execution - VPC Link"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started-with-private-integration.html" rel="noopener noreferrer"&gt;More information here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remarks:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I have the same recommendation as above concerning choice between REST Api and HTTP Api&lt;/li&gt;
&lt;li&gt;All security stuffs listed above are applicable here for API Gateway&lt;/li&gt;
&lt;li&gt;This solution is more simple but also less customisable&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;This solution is relatively easy to implement, highly scalable, secure and not expensive. It can be deployed when we have communication issue between public and private zone.&lt;br&gt;&lt;br&gt;
You can find the implementation of the solution in &lt;a href="https://github.com/guillan/serverless-proxy" rel="noopener noreferrer"&gt;my github account&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>architecture</category>
      <category>github</category>
    </item>
  </channel>
</rss>
