{"id":15710648,"url":"https://github.com/pchol22/sls-natgateway","last_synced_at":"2025-05-12T21:10:36.450Z","repository":{"id":181327642,"uuid":"666590157","full_name":"PChol22/sls-natgateway","owner":"PChol22","description":"A \"free\" serverless alternative to AWS NAT Gateways. Still WIP ⚙️, help welcome!","archived":false,"fork":false,"pushed_at":"2023-07-14T23:40:02.000Z","size":327,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-28T12:56:38.551Z","etag":null,"topics":["aws","cdk","free","nat-gateway","serverless","typescript"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PChol22.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-07-14T23:37:27.000Z","updated_at":"2024-08-30T01:40:18.000Z","dependencies_parsed_at":"2023-07-15T00:46:51.326Z","dependency_job_id":null,"html_url":"https://github.com/PChol22/sls-natgateway","commit_stats":null,"previous_names":["pchol22/sls-natgateway"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PChol22%2Fsls-natgateway","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PChol22%2Fsls-natgateway/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PChol22%2Fsls-natgateway/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PChol22%2Fsls-natgateway/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PChol22","download_url":"https://codeload.github.com/PChol22/sls-natgateway/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253823453,"owners_count":21969848,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","cdk","free","nat-gateway","serverless","typescript"],"created_at":"2024-10-03T21:09:13.746Z","updated_at":"2025-05-12T21:10:36.393Z","avatar_url":"https://github.com/PChol22.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sls-natgateway\n\n## Why and what?\n\n### The problem with NAT Gateways\n\nI am software engineer and I love doing serverless on AWS 🌸.\n\nOne day I had to access a resource residing inside a private VPC subnet from a Lambda function. The plan was simple: place the Lambda function inside the same subnet. 💪\n\n_PROBLEM:_ the subnet was private, so the Lambda function could not access the internet anymore. 😭\n\n_SOLUTION:_ I placed a NAT Gateway inside the subnet. 💪\n\n**BIG PROBLEM:** NAT gateways are f\\*cking expensive, and are not serverless at all. 💀\n\nAt this point, I started thinking, and found a loophole: VPC Gateway Endpoints! These are FREE and SERVERLESS endpoints that allow resources inside private VPCs to access S3 and DynamoDB without going through a NAT Gateway. 🎉\n\nThis only solves issues when trying to access S3 or DynamoDB, but you see me coming, with a little tweaking, you can use execute any HTTP request from the private subnet. 🧠\n\n### The serverless alternative\n\nMeet my \"genius solution\": sls-natgateway. 🤪\n\n![sls-natgateway schema](./docs/schema.png 'sls-natgateway schema')\n\nsls-natgateway is a set of 2 npm packages:\n\n- 1️⃣ `@sls-natgateway/construct`: a CDK construct that provisions a S3 Bucket and a Lambda function able to execute HTTP requests. Everytime an object `{id}/request.json` is created in the bucket, the Lambda function will execute the HTTP request described in the JSON file and store the response in `{id}/response.json`.\n\n- 2️⃣ `@sls-natgateway/sdk`: a single TS function that replaces `fetch`. It's simple: it creates a `{id}/request.json` file in the S3 bucket, waits for the `{id}/response.json` file to be created, and returns the response.\n\n## How to use?\n\n### 1️⃣ Add a S3 Gateway Endpoint to your VPC\n\nFirst, you need to add a S3 Gateway Endpoint to your VPC. This lib does not do it for you. Here is a code example using AWS CDK:\n\n```typescript\nconst SUBNET_GROUP_NAME = 'private-subnet-group';\n\nconst vpc = new cdk.aws_ec2.Vpc(this, 'Vpc', {\n  subnetConfiguration: [\n    {\n      name: SUBNET_GROUP_NAME,\n      subnetType: cdk.aws_ec2.SubnetType.PRIVATE_ISOLATED,\n    },\n  ],\n  gatewayEndpoints: {\n    S3: {\n      service: cdk.aws_ec2.GatewayVpcEndpointAwsService.S3,\n      subnets: [\n        {\n          subnetGroupName: SUBNET_GROUP_NAME,\n        },\n      ],\n    },\n  },\n});\n```\n\n### 2️⃣ Add the sls-natgateway construct to your CDK stack\n\nVery simple:\n\n```typescript\nimport { SlsNatGatewayConstruct } from '@sls-natgateway/construct';\n\nconst { bucket } = new SlsNatGatewayConstruct(this, 'SlsNatConstruct');\n```\n\nDo not forget to grant access to the bucket to the Lambda living in your private subnet, and to pass it the bucket name as an environment variable.\n\n```typescript\nconst privateLambda = new cdk.aws_lambda_nodejs.NodejsFunction(\n  this,\n  'PrivateLambda',\n  {\n    entry: path.join(__dirname, 'private-lambda', 'handler.ts'),\n    handler: 'handler',\n    vpc,\n    vpcSubnets: {\n      subnetGroupName: SUBNET_GROUP_NAME,\n    },\n    securityGroups: [\n      new cdk.aws_ec2.SecurityGroup(this, 'PrivateLambdaSecurityGroup', {\n        vpc,\n        allowAllOutbound: true,\n      }),\n    ],\n    environment: {\n      BUCKET_NAME: bucket.bucketName,\n    },\n    timeout: cdk.Duration.seconds(15),\n  },\n);\n\nbucket.grantReadWrite(privateLambda);\n```\n\n### 3️⃣ Use the sls-natgateway SDK in your private Lambda\n\nThe code speaks for itself:\n\n```typescript\nimport { S3Client } from '@aws-sdk/client-s3';\nimport { getNatFetchRequest } from '@sls-natgateway/sdk';\n\nconst client = new S3Client({});\nconst bucketName = process.env.BUCKET_NAME;\n\nif (bucketName === undefined) {\n  throw new Error('BUCKET_NAME is not defined');\n}\n\nconst natFetch = getNatFetchRequest(bucketName, client);\n\nexport const handler = async (event: { pokemon: string }): Promise\u003cvoid\u003e =\u003e {\n  const { body, status } = await natFetch(\n    `https://pokeapi.co/api/v2/pokemon/${event.pokemon}`,\n    {\n      method: 'GET',\n    },\n  );\n\n  console.log(status, body);\n};\n```\n\n## Caveats\n\n- This library only supports requests to HTTP endpoints.\n- This library only supports JSON payloads for now (contributions welcome!)\n- Usual response delay is increased by around 2 seconds, which can increase compute costs.\n\n_I am not sure this is a good idea, but I had fun doing it. 🤷‍♂️ **It's 100% not production ready**, but I would love to hear your feedback, and get your help to make it better!_\n\n## Thanks\n\nThe project template was generated using [Swarmion](https://github.com/swarmion/swarmion). Go check them out they are great!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpchol22%2Fsls-natgateway","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpchol22%2Fsls-natgateway","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpchol22%2Fsls-natgateway/lists"}