Creating an Oracle Cloud VCN with Terraform

I’m Pratik Borkar, a Technical Architecture specializing in Oracle Cloud Infrastructure (OCI) and Kubernetes. I have extensive experience designing, automating, and optimizing cloud environments using Terraform, CI/CD pipelines, and container orchestration tools. I enjoy sharing hands-on guides and real-world implementations that help engineers simplify cloud operations, improve scalability, and adopt Infrastructure as Code best practices. When I’m not automating infrastructure, I explore new DevOps tools, contribute to open-source projects, and write about cloud-native technologies.
A Virtual Cloud Network (VCN) in Oracle Cloud Infrastructure (OCI) is a customizable, software-defined network that hosts your cloud resources such as compute instances, databases, and load balancers.
Using Terraform, you can automate the creation and management of VCNs, ensuring repeatable and consistent infrastructure deployments.
Prerequisites
Before you begin, make sure you have:
OCI Account with permissions to create networking resources.
Terraform installed (v1.10.0 or higher recommended).
OCI Terraform Provider configured.
Your OCI credentials:
Tenancy OCID
User OCID
Compartment OCID
Fingerprint
Private key path
Region
Project Structure
Create a working directory, for example:
oci-vcn-terraform/
│
├── main.tf
├── variables.tf
└── terraform.tfvars
Step 1: Define Provider and Resources (main.tf)
# -------------------------------
# Provider
# -------------------------------
provider "oci" {
tenancy_ocid = var.tenancy_ocid
user_ocid = var.user_ocid
fingerprint = var.fingerprint
private_key_path = var.private_key_path
region = var.region
}
# -------------------------------
# VCN
# -------------------------------
resource "oci_core_vcn" "oke_vcn" {
cidr_block = var.vcn_cidr
compartment_id = var.compartment_ocid
display_name = "OKE-VCN-Sydney"
dns_label = "okevcn"
}
# -------------------------------
# Gateways
# -------------------------------
resource "oci_core_internet_gateway" "igw" {
display_name = "Internet-Gateway"
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.oke_vcn.id
enabled = true
}
resource "oci_core_nat_gateway" "nat_gw" {
display_name = "NAT-Gateway"
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.oke_vcn.id
block_traffic = false
}
# -------------------------------
# Subnet Definitions
# -------------------------------
locals {
subnets = {
jump_host = { name = "Jump-Host-Subnet", cidr = var.jump_host_cidr, public = true }
master = { name = "Master-Subnet", cidr = var.master_cidr, public = false }
node = { name = "Node-Subnet", cidr = var.node_cidr, public = false }
lb = { name = "LB-Subnet", cidr = var.lb_cidr, public = true }
pod = { name = "POD-Subnet", cidr = var.pod_cidr, public = false }
}
}
# -------------------------------
# Security Lists
# -------------------------------
resource "oci_core_security_list" "sl" {
for_each = local.subnets
display_name = "Security List for ${each.value.name}"
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.oke_vcn.id
egress_security_rules {
destination = "0.0.0.0/0"
protocol = "all"
}
ingress_security_rules {
source = "0.0.0.0/0"
protocol = "all"
}
}
# -------------------------------
# Route Tables
# -------------------------------
resource "oci_core_route_table" "rt" {
for_each = local.subnets
display_name = "Route Table for ${each.value.name}"
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.oke_vcn.id
# Attach Internet Gateway for public subnets
# Attach NAT Gateway for private subnets
route_rules {
description = each.value.public ? "Route to Internet via IGW" : "Route to Internet via NAT"
destination = "0.0.0.0/0"
destination_type = "CIDR_BLOCK"
network_entity_id = each.value.public ? oci_core_internet_gateway.igw.id : oci_core_nat_gateway.nat_gw.id
}
}
# -------------------------------
# Subnets
# -------------------------------
resource "oci_core_subnet" "subnet" {
for_each = local.subnets
cidr_block = each.value.cidr
display_name = each.value.name
dns_label = replace(lower(each.key), "_", "")
prohibit_public_ip_on_vnic = each.value.public ? false : true
vcn_id = oci_core_vcn.oke_vcn.id
route_table_id = oci_core_route_table.rt[each.key].id
security_list_ids = [oci_core_security_list.sl[each.key].id]
compartment_id = var.compartment_ocid
}
Step 2: Define Variables (variables.tf)
variable "tenancy_ocid" {
type = string
description = "Tenancy OCID"
}
variable "user_ocid" {
type = string
description = "User OCID"
}
variable "fingerprint" {
type = string
description = "API Key Fingerprint"
}
variable "private_key_path" {
type = string
description = "Path to private key"
}
variable "region" {
type = string
description = "OCI region"
}
variable "compartment_ocid" {
type = string
description = "Compartment OCID"
}
variable "existing_vcn_id" {
type = string
description = "Existing VCN OCID"
}
variable "endpoint_subnet_id" {
type = string
description = "Subnet OCID for cluster endpoints"
}
variable "lb_subnet_id" {
type = string
description = "Subnet OCID for load balancer"
}
variable "node_pool_subnet_id" {
type = string
description = "Subnet OCID for node pool"
}
variable "node_pool_ssh_public_key" {
type = string
description = "SSH public key for node pool"
}
variable "nodepool_image_id" {
type = string
description = "OCID of the image for node pool"
}
variable "nodepool_cloud_init" {
type = string
description = "Cloud-init script for node pool"
default = ""
}
Step 3: Provide Variable Values (terraform.tfvars)
# -------------------------------
# Provider Authentication
# -------------------------------
tenancy_ocid = "ocid1.tenancy.oc1.xxx"
user_ocid = "ocid1.user.oc1..axxx"
fingerprint = "3a:ds.xx.xx"
private_key_path = "path of key"
region = "ap-sydney-1"
# -------------------------------
# Networking Details
# -------------------------------
compartment_ocid = "ocid1.compartment.oc1.."
Step 4: Initialize and Apply
terraform init
terraform plan
terraform apply
TerraformConfirm with yes when prompted.
Terraform will provision
| Resource Type | Count | Purpose |
| ---------------- | ----- | -------------------------------- |
| VCN | 1 | Core network |
| Internet Gateway | 1 | Public internet access |
| NAT Gateway | 1 | Private outbound internet access |
| Security Lists | 5 | One per subnet |
| Route Tables | 5 | One per subnet |
| Subnets | 5 | Logical network segments |
Verification
After the deployment:
Log in to the OCI Console.
Navigate to Networking → Virtual Cloud Networks.
You’ll see the newly created OKE-VCN-Sydney and related resources.
You can also verify via CLI:
oci network vcn list --compartment-id <compartment_ocid>
Clean Up
To remove all resources:
terraform destroy






