23_1 ‐ OCI Hub‐and‐Spoke: Public Hub VCN Private Spoke VCN (with DRG, NGW, SGW, Bastion) - SanjeevOCI/Study GitHub Wiki

OCI Hub & Spoke (DRG): Public Hub + Private Spoke Goal: Centralize internet egress & admin in the Hub VCN, keep Spoke VCN private (no direct internet), while enabling:

Object Storage / OSMS privately (Service Gateway)

OS updates / public repos via Hub NAT Gateway

Admin via Bastion in Hub

  1. Quick Architecture

Tenancy └─ Compartments ├─ Network-Hub │ └─ VCN HUB 10.0.0.0/16 │ ├─ Subnet Hub-Public 10.0.1.0/24 [IGW] (Bastion, optional tools) │ ├─ Subnet Hub-Private 10.0.2.0/24 [NAT path/NVA optional] │ ├─ IGW, NAT GW, DRG, (SGW-HUB optional for hub workloads) └─ App-Spoke └─ VCN SPOKE 10.1.0.0/16 ├─ Subnet Spoke-Private 10.1.1.0/24 (VMs, no public IPs) ├─ SGW-SPOKE (required for private PaaS access) └─ DRG attachment (to Hub’s DRG)

Key change vs standalone labs:

NAT Gateway is in the Hub (not in Spoke).

Spoke sends 0.0.0.0/0 to DRG (centralized egress via Hub NAT).

Each VCN that needs private PaaS must have its own Service Gateway (SGW is not transitive).

  1. Addressing (example) HUB VCN: 10.0.0.0/16

Hub-Public: 10.0.1.0/24

Hub-Private: 10.0.2.0/24

SPOKE VCN: 10.1.0.0/16

Spoke-Private: 10.1.1.0/24

  1. Build Steps (High-Level) A) Create Hub VCN (Internet-enabled) VCN (10.0.0.0/16) with subnets:

Hub-Public (10.0.1.0/24) for Bastion

Hub-Private (10.0.2.0/24) for NAT path / future NVA

Gateways in Hub:

IGW (Internet Gateway)

NAT Gateway

DRG

(Optional) SGW-HUB if hub workloads need private PaaS

Route Tables (Hub)

Hub-Public RT: 0.0.0.0/0 → IGW

Hub-Private RT:

0.0.0.0/0 → NAT GW

(optional) all-oci-services-in-oracle-services-network → SGW-HUB

B) Deploy Bastion in Hub Place OCI Bastion in Hub-Public subnet (uses IGW).

Use Bastion session to reach Spoke VM (no public IP on Spoke VM).

C) Create Spoke VCN (No Internet) VCN (10.1.0.0/16) with Spoke-Private (10.1.1.0/24)

SGW-SPOKE (Service Gateway) — required for Object Storage/OSMS

Attach Spoke VCN to Hub’s DRG

D) DRG Transit Configuration Create DRG attachments: Hub VCN & Spoke VCN

DRG Route Tables & Distributions (simple, centralized egress):

Hub → Spoke: Export default route 0.0.0.0/0 to Spoke

Spoke → Hub: Export Spoke CIDR 10.1.0.0/16 to Hub

(Add on-prem later by attaching VPN/FC to the same DRG and importing/exporting on-prem prefixes)

E) Spoke Route Table (attach to Spoke-Private) all-oci-services-in-oracle-services-network → SGW-SPOKE (private PaaS)

0.0.0.0/0 → DRG (centralized egress via Hub NAT)

F) Security Lists / NSGs Spoke (subnet or NSG at VNIC):

Egress

all-oci-services-in-oracle-services-network, TCP 443 (SGW)

0.0.0.0/0, TCP 443 (NAT path via DRG → Hub)

Ingress

From Hub Bastion/VPN CIDR on admin ports (22/3389 as required)

No inbound from internet

Hub (Bastion + NAT path):

Bastion subnet: allow inbound from trusted admin IPs (SSH session establishment)

If using NVA (optional): allow spoke CIDR → NVA, and NVA → IGW as required

G) Spoke VM Create VM in Spoke-Private, no public IP

Connect via Bastion (Hub-Public)

  1. Verification (from Spoke VM via Bastion)

Object Storage / OSMS via SGW (private path) oci os ns get --region # should return namespace oci os bucket list --compartment-id <compartment_ocid> --region

Oracle Linux repos via OSMS (private):

sudo dnf check-update # or: sudo yum check-update

Outbound updates via Hub NAT (public repos) curl https://ifconfig.me # shows Hub NAT GW public IP sudo dnf install -y wget # or: sudo yum install -y wget

No broad internet (if you limited egress to 443) curl http://example.com:80 # should fail (NSG egress locked to 443)

Path sanity

Spoke VNIC → Effective Routes show:

all-oci-services... → SGW-SPOKE

0.0.0.0/0 → DRG

Hub NAT subnet RT → 0.0.0.0/0 → IGW

  1. Why NAT GW (when Hub has IGW)? NAT GW = outbound-only for private workloads; no unsolicited inbound possible.

Using IGW for Spoke traffic opens inbound paths unless heavily firewalled (breaks “no-internet Spoke” posture).

Best practice: Public subnets → IGW; Private subnets → NAT GW.

Interview soundbite:

“We centralize egress by moving NAT to the Hub and point the Spoke’s 0.0.0.0/0 to the DRG. This preserves the Spoke’s no-internet posture while enabling updates, and aligns with OCI’s gateway semantics.”

  1. Common Pitfalls (and fixes) Trying to use Hub SGW for Spoke: Not supported (SGW is not transitive). Create SGW in each VCN that needs private PaaS.

Missing DRG export/import: Spoke won’t see default route. Fix DRG RT + distributions to export 0.0.0.0/0 from Hub to Spoke.

Asymmetric routing with an NVA: Ensure return routes in Hub point back to DRG for Spoke CIDR and to IGW for internet.

Wrong route table attached to Spoke subnet: Double-check association.

Security rules too open: Keep Spoke egress TCP/443 only; prefer NSGs for per-VM control.

  1. Interview Nuggets (prove hands-on) Gateways are VCN-level (NAT/SGW): create gateway → reference in subnet RT.

DRG provides transit + policy (DRG RTs & distributions) across many VCNs and on-prem.

SGW is non-transitive: every VCN needs its own SGW.

Bastion in Hub Public for admin; Spoke VMs never get public IPs.

Effective routes & flow logs: I verify NIC routes and use VCN flow logs when troubleshooting.

Egress least privilege: 443 only; switch to NVA/OCI Network Firewall if I need FQDN/domain allow-listing.

  1. Quick Checklist Hub: IGW, NAT GW, DRG (+ optional SGW-HUB), Bastion in Hub-Public

Spoke: SGW-SPOKE, DRG attachment; no IGW

DRG: Export 0.0.0.0/0 (Hub → Spoke), import Spoke CIDR (Spoke → Hub)

Routes (Spoke): all-oci-services… → SGW-SPOKE, 0.0.0.0/0 → DRG

Routes (Hub): Hub-Public → IGW, Hub-Private → NAT GW (+ returns to Spoke CIDR)

Security: Spoke egress TCP/443 to SGW + 0.0.0.0/0; admin from Bastion/VPN only

Validate: oci os ns get, curl ifconfig.me, dnf/yum check-update

That’s the complete merged design: your original Public VCN becomes the Hub, your Private VCN becomes the Spoke, NAT moves to Hub, SGW stays local to each VCN, and Bastion lives in Hub to reach private instances in Spoke.

⚠️ **GitHub.com Fallback** ⚠️