AWS VPC and EC2 Hands-on Lab: Building a Secure Network

Poonam VetalPoonam Vetal
15 min read

In the world of cloud computing, Amazon Web Services (AWS) offers unparalleled flexibility and power. At the heart of building a robust and secure infrastructure on AWS lie two fundamental services: Amazon Virtual Private Cloud (VPC) ๐ŸŒ and Amazon Elastic Compute Cloud (EC2) ๐Ÿ’ป.

Understanding the Core Components ๐Ÿงฉ

Before diving into the practical steps, let's briefly understand what VPC and EC2 are and why they're crucial:

1. Amazon Virtual Private Cloud (VPC) ๐Ÿ›ก๏ธ

Imagine having your own private data center, but in the cloud. That's essentially what a VPC provides. It's a logically isolated section of the AWS cloud where you can launch AWS resources into a virtual network that you define. You get complete control over:

  • IP Address Ranges (CIDR Blocks): You specify the private IP address space for your VPC. ๐Ÿ”ข

  • Subnets: You divide your VPC into smaller segments called subnets. These can be:

    • Public Subnets: For resources that need direct internet access (e.g., web servers, bastion hosts). ๐ŸŒ

    • Private Subnets: For resources that should not be directly accessible from the internet (e.g., databases, application servers). ๐Ÿ”’

  • Route Tables: These act like traffic cops, defining rules for how network traffic flows within your VPC and to/from the internet. ๐Ÿšฆ

  • Internet Gateway (IGW): A horizontally scaled, redundant, and highly available VPC component that allows communication between instances in your VPC and the internet. ๐Ÿ“ก

  • NAT Gateway (Network Address Translation Gateway): Enables instances in a private subnet to initiate outbound connections to the internet (e.g., for software updates) while preventing inbound connections from the internet. It resides in a public subnet. ๐Ÿ“ค

  • Security Groups: Instance-level virtual firewalls that control inbound and outbound traffic for your EC2 instances. ๐Ÿ”ฅ

  • Network Access Control Lists (NACLs): Subnet-level stateless firewalls that provide an additional layer of security. ๐Ÿ”

2. Amazon Elastic Compute Cloud (EC2) โ˜๏ธ

EC2 provides resizable compute capacity in the cloud in the form of virtual servers, known as instances. You can launch instances with various operating systems (like Amazon Linux, Ubuntu, Windows) and configure them to run your applications. EC2 instances are always launched within a VPC. ๐Ÿ–ฅ๏ธ

Our Hands-on Journey: Building a Secure Web Environment ๐Ÿ› ๏ธ

Our lab focused on setting up a common and secure architecture: a public-facing web server and a private internal web server, with access to the private server secured via a bastion host.

Step 1: Laying the Network Foundation (VPC and Subnets) ๐Ÿ—๏ธ

We started by creating a custom VPC named MyCustomVPC with an IP range of 10.0.0.0/16. This large block was then segmented into:

  • MyPublicSubnet (10.0.1.0/24): Where public-facing resources reside. ๐ŸŒ

  • MyPrivateSubnet (10.0.2.0/24): For internal, protected resources. ๐Ÿคซ

Both subnets were placed in the same Availability Zone for simplicity in this demo.

Step 2: Enabling Connectivity (Gateways and Route Tables) ๐Ÿ”—

Connectivity is key!

  • An Internet Gateway (MyVPC-IGW) was created and attached to MyCustomVPC. This is the bridge to the internet. ๐ŸŒ‰

  • A Public Route Table (MyPublicRT) was configured to send all internet-bound traffic (0.0.0.0/0) from MyPublicSubnet to MyVPC-IGW. โžก๏ธ

  • A NAT Gateway (MyVPC-NATGateway) was provisioned within MyPublicSubnet and assigned an Elastic IP. This allows our private instances to get out to the internet for updates without being directly exposed. ๐Ÿšช

  • A Private Route Table (MyPrivateRT) was set up to direct all internet-bound traffic from MyPrivateSubnet through MyVPC-NATGateway. โ†ฉ๏ธ

Step 3: Securing Your Servers (Security Groups and Key Pair) ๐Ÿ”’๐Ÿ”‘

Security is paramount in the cloud. We defined two Security Groups:

  • WebServerSG: Allowed inbound HTTP (port 80) and HTTPS (port 443) traffic from anywhere (0.0.0.0/0), and SSH (port 22) from within our VPC's CIDR block (10.0.0.0/16). This was attached to both our public and private web servers. ๐ŸŒ๐Ÿ›ก๏ธ

  • BastionHostSG: A more restrictive group, allowing inbound SSH (port 22) only from our specific local public IP address. This was attached to our public instance. ๐Ÿ’ปโžก๏ธ๐Ÿ”’

A MyVPCKeyPair.pem was generated to securely SSH into our instances. ๐Ÿ”‘

Step 4: Launching Your Virtual Servers (EC2 Instances) ๐Ÿš€

With the network and security in place, we launched our EC2 instances:

  • PublicWebServer-Bastion: Launched in MyPublicSubnet with "Auto-assign public IP" enabled (later replaced with a static Elastic IP for persistence). This instance serves as our public web server and our secure jump box (bastion host). User data scripts installed Apache and a simple "Hello from Public Web Server!" page. ๐Ÿ‘‹๐ŸŒ

  • PrivateWebServer: Launched in MyPrivateSubnet with "Auto-assign public IP" disabled. This instance hosts our private web server, accessible only from within our VPC. User data scripts also installed Apache and a "Hello from Private Web Server!" page. ๐Ÿคซ๐Ÿ’ป

An Elastic IP was then allocated and associated with PublicWebServer-Bastion to ensure its public IP address remained constant, even after stopping and starting the instance. ๐Ÿ”„

Step 5: Accessing Your Cloud Resources ๐Ÿšช

Finally, we demonstrated access:

  • Public Web Server Access: By navigating to the Elastic IP of PublicWebServer-Bastion in a web browser, we could see its "Hello" page, confirming public internet accessibility. โœ…

  • Bastion Host SSH Access: We securely SSH'd into PublicWebServer-Bastion from our local machine using our private key and the instance's Elastic IP, leveraging the BastionHostSG rules. ๐Ÿ”โžก๏ธ๐Ÿ’ป

  • Private Web Server Access (via Bastion Host): The crucial step for security. We used SSH tunneling (or connected from the bastion host itself) to reach PrivateWebServer using its private IP address. A curl command from the bastion host to the private web server's private IP successfully retrieved its "Hello" page. This proved that the private instance was isolated from the internet but reachable from authorized internal resources. ๐Ÿ•ต๏ธโ€โ™‚๏ธโžก๏ธ๐Ÿคซ

Prerequisites

  • An active AWS account.

  • Basic understanding of networking concepts (IP addresses, subnets, routing).

  • A terminal or SSH client on your local machine.

Part 1: Create the VPC and Subnets

First, we'll create our custom VPC and divide it into a public and a private subnet.

Step 1.1: Create Your Custom VPC

  1. Log in to the AWS Management Console.

  2. Navigate to the VPC service (you can search for "VPC" in the search bar).

  3. In the left navigation pane, click on Your VPCs.

  4. Click the Create VPC button.

  5. Choose VPC only.

  6. Configure the VPC:

    • Name tag: MyCustomVPC

    • IPv4 CIDR block: 10.0.0.0/16 (This gives you 65,536 private IP addresses for your VPC).

    • IPv6 CIDR block: No IPv6 CIDR block.

    • Tenancy: Default

  7. Click Create VPC.

Step 1.2: Create a Public Subnet

This subnet will host resources that need direct internet access, like your web server or a bastion host.

  1. In the left navigation pane, click on Subnets.

  2. Click the Create subnet button.

  3. Configure the public subnet:

    • VPC ID: Select MyCustomVPC (the VPC you just created).

    • Subnet name: MyPublicSubnet

    • Availability Zone: Choose any Availability Zone (e.g., us-east-1a). It's good practice to spread resources across AZs for high availability, but for this demo, one is sufficient.

    • IPv4 CIDR block: 10.0.1.0/24 (This allocates 256 IPs within your VPC for this subnet).

  4. Click Create subnet.

Step 1.3: Create a Private Subnet

This subnet will host resources that should not have direct internet access, such as databases or internal application servers.

  1. Click the Create subnet button again.

  2. Configure the private subnet:

    • VPC ID: Select MyCustomVPC.

    • Subnet name: MyPrivateSubnet

    • Availability Zone: Choose the same Availability Zone as your public subnet for simplicity in this demo (e.g., us-east-1a).

    • IPv4 CIDR block: 10.0.2.0/24 (Another 256 IPs for this subnet).

  3. Click Create subnet.

Part 2: Configure Network Components

Now, we'll set up the components that enable internet connectivity for our public subnet and outbound internet access for our private subnet.

Step 2.1: Create an Internet Gateway (IGW)

The Internet Gateway allows communication between your VPC and the internet.

  1. In the left navigation pane, click on Internet gateways.

  2. Click the Create internet gateway button.

  3. Name tag: MyVPC-IGW

  4. Click Create internet gateway.

  5. Once created, select MyVPC-IGW and click Actions > Attach to VPC.

  6. Select MyCustomVPC from the dropdown and click Attach internet gateway.

Step 2.2: Create a Public Route Table

This route table will direct internet-bound traffic from MyPublicSubnet to the Internet Gateway.

  1. In the left navigation pane, click on Route tables.

  2. Click the Create route table button.

  3. Configure the public route table:

    • Name tag: MyPublicRT

    • VPC: Select MyCustomVPC.

  4. Click Create route table.

  5. Select MyPublicRT.

  6. Click on the Routes tab, then click Edit routes.

  7. Click Add route.

    • Destination: 0.0.0.0/0 (This means "all internet traffic").

    • Target: Select Internet Gateway and then choose MyVPC-IGW.

  8. Click Save changes.

  9. Now, associate this route table with your public subnet. Click on the Subnet associations tab, then click Edit subnet associations.

  10. Select the checkbox next to MyPublicSubnet.

  11. Click Save associations.

Step 2.3: Create a NAT Gateway

A NAT Gateway allows instances in your private subnet to initiate outbound connections to the internet (e.g., for software updates) without being directly accessible from the internet.

  1. In the left navigation pane, click on NAT gateways.

  2. Click the Create NAT gateway button.

  3. Configure the NAT Gateway:

    • Name tag: MyVPC-NATGateway

    • Subnet: Select MyPublicSubnet (the NAT Gateway must reside in a public subnet).

    • Connectivity type: Public

    • Elastic IP allocation ID: Click Allocate Elastic IP to create a new Elastic IP address for the NAT Gateway.

  4. Click Create NAT gateway.

    • Note: It takes a few minutes for the NAT Gateway to become available. Wait for its status to change from "Pending" to "Available".

Step 2.4: Create a Private Route Table

This route table will direct internet-bound traffic from MyPrivateSubnet through the NAT Gateway.

  1. In the left navigation pane, click on Route tables.

  2. Click the Create route table button.

  3. Configure the private route table:

    • Name tag: MyPrivateRT

    • VPC: Select MyCustomVPC.

  4. Click Create route table.

  5. Select MyPrivateRT.

  6. Click on the Routes tab, then click Edit routes.

  7. Click Add route.

    • Destination: 0.0.0.0/0

    • Target: Select NAT Gateway and then choose MyVPC-NATGateway.

  8. Click Save changes.

  9. Associate this route table with your private subnet. Click on the Subnet associations tab, then click Edit subnet associations.

  10. Select the checkbox next to MyPrivateSubnet.

  11. Click Save associations.

Part 3: Launch EC2 Instances

Now we'll launch our EC2 instances: one in the public subnet (which will act as our bastion host and public web server) and one in the private subnet (our private web server).

Step 3.1: Create Security Groups

Security Groups act as virtual firewalls for your instances.

  1. Navigate to the EC2 service.

  2. In the left navigation pane, under Network & Security, click on Security Groups.

  3. Click Create security group.

    • Security Group 1: Web Server SG

      • Security group name: WebServerSG

      • Description: Allow HTTP/HTTPS traffic

      • VPC: Select MyCustomVPC.

      • Inbound rules:

        • Click Add rule.

          • Type: HTTP, Source: 0.0.0.0/0 (Allow HTTP from anywhere)
        • Click Add rule.

          • Type: HTTPS, Source: 0.0.0.0/0 (Allow HTTPS from anywhere)
        • Click Add rule.

          • Type: SSH, Source: 10.0.0.0/16 (Allow SSH from within your VPC for internal communication)
      • Outbound rules: All traffic (default)

      • Click Create security group.

    • Security Group 2: Bastion Host SG

      • Security group name: BastionHostSG

      • Description: Allow SSH from your IP only

      • VPC: Select MyCustomVPC.

      • Inbound rules:

        • Click Add rule.

          • Type: SSH, Source: My IP (This automatically detects your public IP address. If it doesn't, you can find your public IP by searching "what is my ip" on Google and entering it manually with /32 at the end, e.g., X.X.X.X/32).
      • Outbound rules: All traffic (default)

      • Click Create security group.

Step 3.2: Create a Key Pair

You'll need a key pair to SSH into your EC2 instances.

  1. In the EC2 dashboard, under Network & Security, click on Key Pairs.

  2. Click Create key pair.

  3. Key pair name: MyVPCKeyPair

  4. Key pair type: RSA

  5. Private key file format: .pem (for OpenSSH)

  6. Click Create key pair.

  7. Important: Your private key file (MyVPCKeyPair.pem) will be downloaded automatically. Keep it secure and do not share it. You'll need it to connect to your instances.

Step 3.3: Launch Public EC2 Instance (Bastion Host & Public Web Server)

This instance will be in your public subnet and will have a public IP address. It will serve as both your public web server and a "bastion host" to access your private instance.

  1. In the EC2 dashboard, click on Instances in the left navigation pane.

  2. Click Launch instances.

  3. Name: PublicWebServer-Bastion

  4. Application and OS Images (Amazon Machine Image - AMI): Select Amazon Linux 2023 AMI (or Amazon Linux 2 AMI).

  5. Instance type: t2.micro (Free tier eligible).

  6. Key pair (login): Choose MyVPCKeyPair.

  7. Network settings:

    • Click Edit.

    • VPC: Select MyCustomVPC.

    • Subnet: Select MyPublicSubnet.

    • Auto-assign public IP: Enable (This is crucial for public access).

    • Firewall (security groups): Select Select existing security group(s).

      • Choose BastionHostSG (for SSH access from your IP)

      • Choose WebServerSG (for HTTP/HTTPS access)

  8. Configure storage: Leave as default (8 GiB gp2).

  9. Advanced details (User data): This script will install Apache and start a simple web server when the instance launches.

    ```plaintext #!/bin/bash sudo yum update -y sudo yum install -y httpd sudo systemctl start httpd sudo systemctl enable httpd echo "

    Hello from Public Web Server in MyCustomVPC!

    " | sudo tee /var/www/html/index.html


10. Click **Launch instance**.


### Step 3.4: Launch Private EC2 Instance (Private Web Server)

This instance will be in your private subnet and will *not* have a public IP address.

1. In the EC2 dashboard, click **Launch instances** again.

2. **Name:** `PrivateWebServer`

3. **Application and OS Images (Amazon Machine Image - AMI):** Select `Amazon Linux 2023 AMI` (or Amazon Linux 2 AMI).

4. **Instance type:** `t2.micro` (Free tier eligible).

5. **Key pair (login):** Choose `MyVPCKeyPair`.

6. **Network settings:**

    * Click **Edit**.

    * **VPC:** Select `MyCustomVPC`.

    * **Subnet:** Select `MyPrivateSubnet`.

    * **Auto-assign public IP:** **Disable** (Crucial for a private instance).

    * **Firewall (security groups):** Select **Select existing security group(s)**.

        * Choose `WebServerSG` (to allow internal HTTP/HTTPS traffic from other instances in the VPC).

7. **Configure storage:** Leave as default.

8. **Advanced details (User data):** This script will install Apache and start a simple web server.

    ```plaintext
    #!/bin/bash
    sudo yum update -y
    sudo yum install -y httpd
    sudo systemctl start httpd
    sudo systemctl enable httpd
    echo "<h1>Hello from Private Web Server in MyCustomVPC!</h1>" | sudo tee /var/www/html/index.html
  1. Click Launch instance.

An Elastic IP (EIP) is a static public IP address that you can associate with your EC2 instance. Unlike a regular public IP, an EIP doesn't change when you stop and start your instance, making it ideal for public-facing servers.

  1. In the EC2 dashboard, under Network & Security, click on Elastic IPs.

  2. Click Allocate Elastic IP address.

  3. Click Allocate.

  4. Select the newly allocated Elastic IP.

  5. Click Actions > Associate Elastic IP address.

  6. Resource type: Instance

  7. Instance: Select PublicWebServer-Bastion.

  8. Private IP address: Select the private IP address of your PublicWebServer-Bastion instance (it should be pre-selected).

  9. Click Associate.

Part 4: Accessing EC2 Instances

Now that everything is set up, let's test access to our instances.

Step 4.1: Access the Public Web Server

  1. In the EC2 dashboard, go to Instances.

  2. Select PublicWebServer-Bastion.

  3. Copy its Elastic IP address (or Public IPv4 address if you skipped the EIP step).

  4. Paste this IP address into your web browser. You should see: Hello from Public Web Server in MyCustomVPC!

Step 4.2: Access the Public EC2 Instance (Bastion Host) via SSH

  1. Open your terminal or SSH client on your local machine.

  2. Navigate to the directory where you saved MyVPCKeyPair.pem.

  3. Change the permissions of your private key file:

    ```plaintext chmod 400 MyVPCKeyPair.pem


4. Connect to your `PublicWebServer-Bastion` instance using its Elastic IP:

    ```plaintext
    ssh -i MyVPCKeyPair.pem ec2-user@<Public_EC2_Elastic_IP>
  • Replace <Public_EC2_Elastic_IP> with the actual Elastic IP of your PublicWebServer-Bastion instance.

  • Type yes if prompted to confirm the host's authenticity.

  • You should now be logged into your public EC2 instance. This instance is now acting as your bastion host.

Step 4.3: Access the Private EC2 Instance via the Bastion Host (SSH Tunneling)

You cannot directly SSH into your private EC2 instance from the internet because it has no public IP. You must first connect to your bastion host, and then from the bastion host, connect to your private instance.

  1. From your local machine, you can use SSH Agent Forwarding or a single SSH command to tunnel through the bastion. Let's use a single command for simplicity:

    ```plaintext ssh -i MyVPCKeyPair.pem -o ProxyCommand="ssh -W %h:%p -i MyVPCKeyPair.pem ec2-user@" ec2-user@


    * Replace `<Public_EC2_Elastic_IP>` with the Elastic IP of your `PublicWebServer-Bastion` instance.

    * Replace `<Private_EC2_Private_IP>` with the **private IP address** of your `PrivateWebServer` instance. You can find this in the EC2 console under the instance details.

    * **Explanation of the command:**

        * `ssh -i MyVPCKeyPair.pem`: Uses your local key to authenticate.

        * `-o ProxyCommand="ssh -W %h:%p -i MyVPCKeyPair.pem ec2-user@<Public_EC2_Elastic_IP>"`: This is the magic part. It tells your local SSH client to first establish an SSH connection to the bastion host (`ec2-user@<Public_EC2_Elastic_IP>`) using your key. Then, it forwards the traffic (`-W %h:%p`) from your local machine through this established connection to the target private IP (`%h`) and port (`%p`).

        * `ec2-user@<Private_EC2_Private_IP>`: This is the final target for your SSH connection, the private EC2 instance.

2. You should now be logged into your `PrivateWebServer` instance. This demonstrates that you can securely access private resources within your VPC using a bastion host.


### Step 4.4: Access the Private Web Server (from Bastion Host)

While connected to your `PublicWebServer-Bastion` instance via SSH, you can now access the web server running on your `PrivateWebServer` instance.

1. From the SSH session on your `PublicWebServer-Bastion` (your bastion host), use `curl` to access the private web server:

    ```plaintext
    curl http://<Private_EC2_Private_IP>
  • Replace <Private_EC2_Private_IP> with the actual private IP address of your PrivateWebServer instance.
  1. You should see the output: <h1>Hello from Private Web Server in MyCustomVPC!</h1>

This confirms that:

  • Your private EC2 instance is running a web server.

  • The WebServerSG on the private instance is allowing HTTP traffic from the bastion host (which is within the 10.0.0.0/16 CIDR block allowed by WebServerSG's SSH rule, and HTTP is explicitly allowed from anywhere, which includes internal VPC traffic).

  • The private subnet's route table is correctly configured to allow internal communication.

Cleanup (Important!)

To avoid incurring charges, remember to terminate your EC2 instances, release your Elastic IP, and delete your NAT Gateway, Internet Gateway, route tables, security groups, subnets, and VPC.

  1. Terminate EC2 Instances:

    • Go to EC2 > Instances.

    • Select both PublicWebServer-Bastion and PrivateWebServer.

    • Click Instance state > Terminate instance.

  2. Release Elastic IP:

    • Go to EC2 > Elastic IPs.

    • Select the Elastic IP you allocated.

    • Click Actions > Release Elastic IP addresses.

  3. Delete NAT Gateway:

    • Go to VPC > NAT gateways.

    • Select MyVPC-NATGateway.

    • Click Actions > Delete NAT gateway. (Wait for it to be deleted).

  4. Delete Internet Gateway:

    • Go to VPC > Internet gateways.

    • Select MyVPC-IGW.

    • Click Actions > Detach from VPC.

    • Once detached, click Actions > Delete internet gateway.

  5. Delete Route Tables:

    • Go to VPC > Route tables.

    • Select MyPublicRT and MyPrivateRT.

    • Click Actions > Delete route table. (You cannot delete the default route table).

  6. Delete Security Groups:

    • Go to EC2 > Security Groups.

    • Select WebServerSG and BastionHostSG.

    • Click Actions > Delete security groups.

  7. Delete Subnets:

    • Go to VPC > Subnets.

    • Select MyPublicSubnet and MyPrivateSubnet.

    • Click Actions > Delete subnet.

  8. Delete VPC:

    • Go to VPC > Your VPCs.

    • Select MyCustomVPC.

    • Click Actions > Delete VPC.

0
Subscribe to my newsletter

Read articles from Poonam Vetal directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Poonam Vetal
Poonam Vetal

I am student from Pune institute of computer technology !๐ŸŽ“