DEV Community

Cover image for Building a Secure Alibaba Cloud VPC: From Public Internet to Private Architecture
Raphael Gab-Momoh
Raphael Gab-Momoh

Posted on Originally published at raphaelgmomoh.pages.dev

Building a Secure Alibaba Cloud VPC: From Public Internet to Private Architecture

Part 5 of the Alibaba Cloud Engineering Lab Series.

Architecture

Most VPC tutorials explain terminology. This one builds a real three-tier network and deliberately breaks a route so the troubleshooting is genuine, not scripted.

Internet
   │
   ▼
 SLB (public VSwitch, 10.0.1.0/24)
   │
   ▼
 App Tier (private VSwitch, 10.0.2.0/24) ── NAT Gateway ── Internet (outbound only)
   │
   ▼
 Data Tier (private VSwitch, 10.0.3.0/24, no internet route at all)

 Bastion Host (public VSwitch, restricted security group) ──▶ App/Data tiers via SSH
Enter fullscreen mode Exit fullscreen mode

Before the how, the what — three terms this build leans on:

  • VPC (Virtual Private Cloud) / VSwitch — a VPC is an isolated network you control inside Alibaba Cloud; a VSwitch is a subdivision of it (Alibaba's equivalent of an Azure subnet or AWS subnet) bound to a single availability zone. Splitting one VPC into multiple VSwitches by tier (public, app, data) is what makes it possible to apply different network rules to each tier.
  • NAT Gateway — lets resources with no public IP of their own still reach the internet outbound (for package installs, calling an external API), without ever being reachable inbound from the internet. It's the standard way to give a private-tier resource internet access without making it internet-facing.
  • Bastion host — a single, tightly locked-down server that's the only path allowed in for administrative access (SSH/RDP) to everything else in the private tiers. Rather than exposing every server's management port to the internet, you expose exactly one, monitor it closely, and route all admin access through it.

Problem

The naive version of this architecture puts everything in one VSwitch with one permissive security group — a frontend, backend, and database all mutually reachable, and the database directly internet-facing "temporarily" during setup, which in practice means indefinitely.


Implementation

VPC and tiered VSwitches:

resource "alicloud_vpc" "main" {
  vpc_name   = "vpc-secure-lab"
  cidr_block = "10.0.0.0/16"
}

resource "alicloud_vswitch" "public" {
  cidr_block = "10.0.1.0/24"
  vpc_id     = alicloud_vpc.main.id
  zone_id    = "ap-southeast-1a"
}

resource "alicloud_vswitch" "app_private" {
  cidr_block = "10.0.2.0/24"
  vpc_id     = alicloud_vpc.main.id
  zone_id    = "ap-southeast-1a"
}

resource "alicloud_vswitch" "data_private" {
  cidr_block = "10.0.3.0/24"
  vpc_id     = alicloud_vpc.main.id
  zone_id    = "ap-southeast-1b"
}
Enter fullscreen mode Exit fullscreen mode

NAT Gateway for the app tier's outbound-only path (package updates, external API calls) without any inbound route from the internet:

resource "alicloud_nat_gateway" "app_nat" {
  vpc_id      = alicloud_vpc.main.id
  vswitch_id  = alicloud_vswitch.public.id
  nat_type    = "Enhanced"
}
Enter fullscreen mode Exit fullscreen mode

Security groups, least privilege. Four groups — one per tier — declared first, then the rules between them:

resource "alicloud_security_group" "slb_sg" {
  security_group_name = "sg-slb-tier"
  vpc_id = alicloud_vpc.main.id
}

resource "alicloud_security_group" "app_sg" {
  security_group_name = "sg-app-tier"
  vpc_id = alicloud_vpc.main.id
}

resource "alicloud_security_group" "data_sg" {
  security_group_name = "sg-data-tier"
  vpc_id = alicloud_vpc.main.id
}

resource "alicloud_security_group" "bastion_sg" {
  security_group_name = "sg-bastion"
  vpc_id = alicloud_vpc.main.id
}
Enter fullscreen mode Exit fullscreen mode
resource "alicloud_security_group_rule" "app_from_slb_only" {
  type              = "ingress"
  security_group_id = alicloud_security_group.app_sg.id
  ip_protocol       = "tcp"
  port_range        = "8080/8080"
  source_security_group_id = alicloud_security_group.slb_sg.id
}

resource "alicloud_security_group_rule" "data_from_app_only" {
  type              = "ingress"
  security_group_id = alicloud_security_group.data_sg.id
  ip_protocol       = "tcp"
  port_range        = "3306/3306"
  source_security_group_id = alicloud_security_group.app_sg.id
}
Enter fullscreen mode Exit fullscreen mode

The data tier's security group accepts traffic only from the app tier's security group — not a CIDR range, a security-group reference. That distinction matters: CIDR-based rules break the moment IPs shift; security-group references stay correct as instances scale.

Bastion access:

resource "alicloud_security_group_rule" "bastion_ssh" {
  type              = "ingress"
  security_group_id = alicloud_security_group.bastion_sg.id
  ip_protocol       = "tcp"
  port_range        = "22/22"
  cidr_ip           = var.admin_office_cidr # not 0.0.0.0/0
}
Enter fullscreen mode Exit fullscreen mode

Failure / Challenge

After deploying, the app-tier instances couldn't reach the internet for package installation — apt-get update hung and timed out. The NAT Gateway was provisioned, but the app-tier VSwitch's route table still had its default route pointing nowhere (the implicit local-only route), because Terraform's alicloud_route_entry resource for the NAT default route hadn't been declared — the NAT Gateway existing isn't enough; the route table has to actually point traffic at it.


Solution

resource "alicloud_route_entry" "app_default_route" {
  route_table_id        = alicloud_vpc.main.route_table_id
  destination_cidrblock = "0.0.0.0/0"
  nexthop_type           = "NatGateway"
  nexthop_id              = alicloud_nat_gateway.app_nat.id
}
Enter fullscreen mode Exit fullscreen mode

This is the Alibaba Cloud equivalent of forgetting a Route Table association on an Azure UDR, or an AWS route table missing its NAT Gateway target — the same class of "the component exists, but nothing points traffic at it" mistake shows up on every cloud's networking stack.


Cost / Performance

Component Monthly Cost (approx.)
NAT Gateway (Enhanced) ~$45
SLB (s2.small) ~$18
Bastion ECS (t6.small) ~$8
Total network overhead ~$71/mo

That's the fixed cost of a properly segmented network, independent of the compute it protects — worth budgeting explicitly rather than discovering it as an unexplained line item later.


Lessons Learned

  • A NAT Gateway provisioned but not routed-to is a silent no-op — verify the route table, not just the resource's existence.
  • Security-group-to-security-group references are more resilient than CIDR rules in any environment where instances scale or get replaced.
  • "Temporarily" public database access has a way of becoming permanent — build the private path first, never as a follow-up task.

GitHub Repository: secure-alibaba-cloud-vpc-lab — the three-tier VPC, NAT gateway, and security-group tier isolation, ready to run.

VPC · Alibaba Cloud · Networking · Security Groups · NAT Gateway · Route Tables


Originally published on my portfolio.

Top comments (0)