1. Answers
  2. How to set up an Internet-facing ALB for EC2 in a private subnet?

How do I set up an Internet-facing ALB for EC2 in a private subnet?

To set up an Internet-facing Application Load Balancer (ALB) for EC2 instances in a private subnet on AWS, we need to create a few key resources:

  1. VPC: A Virtual Private Cloud to host all our resources.
  2. Subnets: Public and private subnets. Public subnets will host the ALB, and private subnets will host the EC2 instances.
  3. Internet Gateway: To allow the ALB to communicate with the internet.
  4. Route Tables: To route traffic from the public subnet to the Internet Gateway.
  5. Security Groups: To control the inbound and outbound traffic to the ALB and EC2 instances.
  6. ALB: The Application Load Balancer to distribute traffic.
  7. EC2 Instances: The backend instances that will receive traffic from the ALB.

Below is a detailed Pulumi program written in TypeScript to accomplish this setup:

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

// Create a VPC
const vpc = new awsx.ec2.Vpc("my-vpc", {
    subnetSpecs: [
        {
            type: awsx.ec2.SubnetType.Public,
            cidrBlocks: ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"],
        },
        {
            type: awsx.ec2.SubnetType.Private,
            cidrBlocks: ["10.0.3.0/24", "10.0.4.0/24", "10.0.5.0/24"],
        }
    ],
});

// Create an Internet Gateway
const igw = new aws.ec2.InternetGateway("my-igw", {
    vpcId: vpc.vpcId,
});

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

// Associate the public subnet with the route table
const publicSubnetRouteTableAssociation = new aws.ec2.RouteTableAssociation("public-subnet-rta", {
    subnetId: vpc.publicSubnetIds[0],
    routeTableId: publicRouteTable.id,
});

// Create a Security Group for the ALB
const albSecurityGroup = new aws.ec2.SecurityGroup("alb-sg", {
    vpcId: vpc.vpcId,
    ingress: [
        {
            protocol: "tcp",
            fromPort: 80,
            toPort: 80,
            cidrBlocks: ["0.0.0.0/0"],
        },
    ],
    egress: [
        {
            protocol: "-1",
            fromPort: 0,
            toPort: 0,
            cidrBlocks: ["0.0.0.0/0"],
        },
    ],
});

// Create a Security Group for the EC2 instances
const ec2SecurityGroup = new aws.ec2.SecurityGroup("ec2-sg", {
    vpcId: vpc.vpcId,
    ingress: [
        {
            protocol: "tcp",
            fromPort: 80,
            toPort: 80,
            securityGroups: [albSecurityGroup.id],
        },
    ],
    egress: [
        {
            protocol: "-1",
            fromPort: 0,
            toPort: 0,
            cidrBlocks: ["0.0.0.0/0"],
        },
    ],
});

// Create an ALB
const alb = new aws.lb.LoadBalancer("my-alb", {
    securityGroups: [albSecurityGroup.id],
    subnets: vpc.publicSubnetIds,
    loadBalancerType: "application",
});

// Create a Target Group for the ALB
const targetGroup = new aws.lb.TargetGroup("my-target-group", {
    port: 80,
    protocol: "HTTP",
    vpcId: vpc.vpcId,
    targetType: "instance",
});

// Create a Listener for the ALB
const listener = new aws.lb.Listener("my-listener", {
    loadBalancerArn: alb.arn,
    port: 80,
    defaultActions: [
        {
            type: "forward",
            targetGroupArn: targetGroup.arn,
        },
    ],
});

// Launch EC2 instances in the private subnet
const ec2Instances = [];
for (let i = 0; i < 2; i++) {
    ec2Instances.push(new aws.ec2.Instance(`my-instance-${i}`, {
        instanceType: "t2.micro",
        ami: "ami-0c55b159cbfafe1f0",  // This is a public Amazon Linux 2 AMI in us-west-2
        subnetId: vpc.privateSubnetIds[0],
        securityGroups: [ec2SecurityGroup.name],
        userData: `#!/bin/bash
echo "Hello, World!" > index.html
nohup python -m SimpleHTTPServer 80 &`,
    }));
}

// Register EC2 instances with the ALB Target Group
for (let i = 0; i < ec2Instances.length; i++) {
    const instance = ec2Instances[i];
    new aws.lb.TargetGroupAttachment(`tg-attachment-${i}`, {
        targetGroupArn: targetGroup.arn,
        targetId: instance.id,
        port: 80,
    });
}

// Export the ALB DNS name
export const albDnsName = alb.dnsName;

Explanation

  1. VPC and Subnets: We create a VPC with public and private subnets using awsx.ec2.Vpc.
  2. Internet Gateway: An Internet Gateway is created and associated with the VPC.
  3. Route Table: A route table is created for the public subnet to route traffic to the Internet Gateway.
  4. Security Groups: Two security groups are created, one for the ALB allowing HTTP traffic from the internet, and another for the EC2 instances allowing traffic from the ALB.
  5. ALB: An Application Load Balancer is created in the public subnet.
  6. Target Group and Listener: A Target Group and a Listener are created for the ALB to forward traffic to the EC2 instances.
  7. EC2 Instances: Two EC2 instances are launched in the private subnet and registered with the ALB Target Group.
  8. Export: The DNS name of the ALB is exported for easy access.

This setup ensures that the ALB is internet-facing and can distribute traffic to EC2 instances in a private subnet.

Deploy this code

Want to deploy this code? Sign up for a free Pulumi account to deploy in a few clicks.

Sign up

New to Pulumi?

Want to deploy this code? Sign up with Pulumi to deploy in a few clicks.

Sign up