Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example request: Create NAT Instance #1350

Open
sarink opened this issue Feb 16, 2023 · 4 comments
Open

Example request: Create NAT Instance #1350

sarink opened this issue Feb 16, 2023 · 4 comments
Labels
area/examples kind/enhancement Improvements or new features size/S Estimated effort to complete (1-2 days).

Comments

@sarink
Copy link

sarink commented Feb 16, 2023

Hello!

  • Vote on this issue by adding a 馃憤 reaction
  • If you want to implement this feature, comment to let us know (we'll work with you on design, scheduling, etc.)

Issue details

NAT Gateways are expensive. There are a lot of posts on this topic across the internet, so I won't get into that here. A few good solutions have cropped up and become very popular (namely https://github.com/1debit/alternat and https://github.com/int128/terraform-aws-nat-instance), but one thing every solution I've come across has in common, is that they're written using tf files.

Given the scale of this problem, I think it would be really helpful for pulumi to have an example of implementing a NAT Instance on EC2. This could be a blog post, a plugin, or something in crosswalk.

@sarink sarink added kind/enhancement Improvements or new features needs-triage Needs attention from the triage team labels Feb 16, 2023
@Frassle Frassle transferred this issue from pulumi/pulumi Feb 17, 2023
@cnunciato
Copy link
Member

Thanks for suggesting this, @sarink! We'll see what we can do about getting it covered.

@mikhailshilkov mikhailshilkov removed the needs-triage Needs attention from the triage team label Mar 2, 2023
@scottslowe scottslowe self-assigned this Feb 16, 2024
@scottslowe scottslowe added the size/S Estimated effort to complete (1-2 days). label Feb 26, 2024
@scottslowe scottslowe removed their assignment Feb 26, 2024
@productTechnologies
Copy link

I am looking for an example of NAT using pulumi was anyone able to find any

@zdk
Copy link

zdk commented Jul 3, 2024

For non-HA NAT instance, feel free to use the following quick TS example as AWS NAT Instance to experiment and adjust further on:

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

// Create a new VPC
const vpc = new aws.ec2.Vpc("my-vpc", {
  cidrBlock: "10.0.0.0/16",
  enableDnsSupport: true,
  enableDnsHostnames: true,
});

// Create an Internet Gateway
const internetGateway = new aws.ec2.InternetGateway("internet-gateway", {
  vpcId: vpc.id,
});

// Create a public subnet
const publicSubnet = new aws.ec2.Subnet("public-subnet", {
  vpcId: vpc.id,
  cidrBlock: "10.0.1.0/24",
  availabilityZone: "ap-southeast-1a",  // Replace with your preferred AZ
  mapPublicIpOnLaunch: true,
});

// Create a private subnet
const privateSubnet = new aws.ec2.Subnet("private-subnet", {
  vpcId: vpc.id,
  cidrBlock: "10.0.2.0/24",
  availabilityZone: "ap-southeast-1b",  // Replace with your preferred AZ
});

// Create a route table for the public subnet
const publicRouteTable = new aws.ec2.RouteTable("public-route-table", {
  vpcId: vpc.id,
  routes: [{
    cidrBlock: "0.0.0.0/0",
    gatewayId: internetGateway.id,
  }],
});

// Associate the public subnet with the public route table
const publicRouteTableAssociation = new aws.ec2.RouteTableAssociation("public-route-table-association", {
  subnetId: publicSubnet.id,
  routeTableId: publicRouteTable.id,
});

// Create a route table for the private subnet
const privateRouteTable = new aws.ec2.RouteTable("private-route-table", {
  vpcId: vpc.id,
});

// Associate the private subnet with the private route table
const privateRouteTableAssociation = new aws.ec2.RouteTableAssociation("private-route-table-association", {
  subnetId: privateSubnet.id,
  routeTableId: privateRouteTable.id,
});

// Create a security group for the NAT instance
const natSecurityGroup = new aws.ec2.SecurityGroup("nat-security-group", {
  vpcId: vpc.id,
  ingress: [{
    protocol: "tcp",
    fromPort: 0,
    toPort: 65535,
    cidrBlocks: ["0.0.0.0/0"],
  }],
  egress: [{
    protocol: "tcp",
    fromPort: 0,
    toPort: 65535,
    cidrBlocks: ["0.0.0.0/0"],
  }],
});


// Create a network interface for the NAT instance
const natNetworkInterface = new aws.ec2.NetworkInterface("nat-network-interface", {
  subnetId: publicSubnet.id,
  privateIp: "10.0.1.100",  // Static private 'IP' for the NAT instance
  sourceDestCheck: false, // disable src&dst check
  securityGroups: [natSecurityGroup.id],
});


// Look up for ubuntu-jammy-22 ami
const ubuntu = aws.ec2.getAmi({
  mostRecent: true,
  filters: [
    {
      name: "name",
      values: ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"],
    },
    {
      name: "virtualization-type",
      values: ["hvm"],
    },
  ],
  owners: ["099720109477"],
});

// Launch a NAT instance
const natInstance = new aws.ec2.Instance("nat-instance", {
  networkInterfaces: [{
    deviceIndex: 0,
    networkInterfaceId: natNetworkInterface.id,
  }],
  instanceType: "t2.micro",  // Replace with your preferred instance type
  ami: ubuntu.then(ubuntu => ubuntu.id),
  keyName: "my-test",  // Replace with your SSH key pair name
  userData: pulumi.interpolate`#!/bin/bash
        echo 1 > /proc/sys/net/ipv4/ip_forward
        echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
        iptables -t nat -A POSTROUTING -o eth0 -s ${privateSubnet.cidrBlock} -j MASQUERADE
        sysctl -p /etc/sysctl.conf
    `,
  tags: {
    Name: "nat-instance"
  }
});

// Create a route in the private route table to route traffic through the NAT instance
const privateRoute = new aws.ec2.Route("private-route", {
  routeTableId: privateRouteTable.id,
  destinationCidrBlock: "0.0.0.0/0",
  networkInterfaceId: natNetworkInterface.id
});

export const vpcId = vpc.id;
export const publicSubnetId = publicSubnet.id;
export const privateSubnetId = privateSubnet.id;
export const privateRouteId = privateRoute.id;
export const publicRouteTableAssociationId = publicRouteTableAssociation.id;
export const natSecurityGroupId = natSecurityGroup.id;
export const natInstanceId = natInstance.id;
export const publicDns = natInstance.publicDns
export const publicIP = natInstance.publicIp

@cnunciato Should this be fine if I open PR with the above code in this examples repo ? Please suggest, thanks.

@cnunciato
Copy link
Member

cnunciato commented Jul 11, 2024

@zdk Sorry for the delayed response. Absolutely, that'd be amazing! Feel free to use the other examples in the repo as a guide. Thank you for offering!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/examples kind/enhancement Improvements or new features size/S Estimated effort to complete (1-2 days).
Projects
None yet
Development

No branches or pull requests

6 participants