8.1 Infrastructure as Code with Terraform and the OCI Provider

Key Takeaways

  • Terraform describes infrastructure declaratively in HCL (.tf) or JSON (.tf.json) files, and the OCI provider translates those files into OCI API calls.

  • The core Terraform workflow is terraform init, terraform plan, terraform apply, and terraform destroy.

  • Terraform records what it created in a state file, so the state must be stored safely and protected from concurrent changes.

  • Modules package reusable configurations, such as a standard VCN, so teams build environments from tested components.

  • The OCI provider can authenticate with an API signing key, an instance principal, a resource principal, or a security token.

Last updated: October 2026

Why Infrastructure as Code

Clicking through the Console works for a lab but not for an enterprise. Infrastructure as Code (IaC) describes infrastructure in text files that are versioned, reviewed, and executed by automation. Architects care about IaC because it delivers:

  • Repeatability: the same configuration builds development, test, production, and disaster recovery environments.
  • Consistency: fewer configuration differences between regions and environments.
  • Reviewability: changes go through pull requests, so security and network teams can approve them before they happen.
  • Speed of recovery: a destroyed environment can be rebuilt from code, which complements backups and replication.
  • Auditability: the repository history shows who changed what and why.

OCI's IaC tooling is built on Terraform, an open-source tool from HashiCorp, together with the OCI Terraform provider. OCI Resource Manager (next section) runs Terraform as a managed service.

Terraform Building Blocks

Terraform configurations are written in HashiCorp Configuration Language (HCL) files ending in .tf, or in JSON files ending in .tf.json. Terraform reads all files in the working directory together.

BlockPurposeExample
providerConfigures the plugin that talks to a platform's APIprovider "oci" { region = var.region }
resourceSomething Terraform creates and managesresource "oci_core_vcn" "main" { ... }
dataReads information that already existsdata "oci_identity_availability_domains" "ads" { ... }
variableAn input valuevariable "compartment_ocid" {}
outputA value shown after apply or passed to other configurationsoutput "vcn_id" { value = oci_core_vcn.main.id }
moduleA reusable package of configurationmodule "network" { source = "./modules/vcn" }

Example: A VCN and a Subnet

variable "compartment_ocid" {}
variable "region" { default = "us-ashburn-1" }

provider "oci" {
  region = var.region
}

resource "oci_core_vcn" "main" {
  compartment_id = var.compartment_ocid
  cidr_blocks    = ["10.0.0.0/16"]
  display_name   = "app-vcn"
}

resource "oci_core_subnet" "private_app" {
  compartment_id             = var.compartment_ocid
  vcn_id                     = oci_core_vcn.main.id
  cidr_block                 = "10.0.1.0/24"
  prohibit_public_ip_on_vnic = true
  display_name               = "private-app"
}

output "subnet_id" {
  value = oci_core_subnet.private_app.id
}

The subnet refers to oci_core_vcn.main.id, so Terraform knows to create the VCN first. Terraform builds a dependency graph from these references and creates independent resources in parallel.

Variables

Variables make one configuration usable in several environments. Values can come from defaults, .tfvars files, command-line flags, or environment variables named TF_VAR_<name>. Mark sensitive values, such as passwords, as sensitive = true so Terraform hides them in output, and prefer pulling secrets from OCI Vault at run time.

Modules

A module is any directory of Terraform files. A root configuration calls child modules and passes variables to them. Platform teams publish standard modules, such as a hub VCN with a Network Firewall or a hardened compute instance, so application teams compose environments from approved building blocks. Oracle also publishes OCI landing zone and reference architecture configurations that follow the same idea.

State

Terraform stores a state file (terraform.tfstate, in JSON) that maps each resource in the configuration to the real resource OCID. Terraform compares the configuration, the state, and the real infrastructure to decide what to change. Important practices:

  • Store state remotely and securely, because it can contain sensitive values.
  • Lock state during runs so two people cannot apply changes at the same time.
  • Never edit state by hand. Use terraform state commands or terraform import to bring existing resources under management.

The Terraform Workflow

CommandWhat it does
terraform initInitializes the working directory and downloads providers and modules
terraform validateChecks the configuration for syntax and internal consistency
terraform fmtFormats files in the canonical style
terraform planShows the actions Terraform would take, without changing anything
terraform applyExecutes the actions in the plan
terraform destroyDeletes the resources managed by the configuration
terraform outputShows output values

Changing Infrastructure

To change infrastructure, you edit the configuration and run plan again. The plan marks each resource as create, update in place, destroy, or destroy and then create (replace). Reviewing the plan is critical: some attribute changes, such as a subnet CIDR block, force replacement, which would delete resources that depend on it. Lifecycle settings such as prevent_destroy protect critical resources, and create_before_destroy reduces downtime when a replacement is unavoidable.

Scaling a Configuration: count, for_each, and Environments

Two meta-arguments create several similar resources from one block:

  • count = 3 creates three copies addressed as resource_type.name[0], [1], and [2]. It suits identical resources.
  • for_each iterates over a map or set, addressing each copy by key, such as oci_core_subnet.tier["web"]. Removing one key deletes only that resource, so for_each is safer when items are added and removed over time.

For separate environments, most teams keep one set of modules and a small root configuration per environment (development, test, production, and DR), each with its own variables and its own state. This keeps a mistake in development from touching production and makes the DR region a second instance of the same code rather than a hand-built copy.

Authenticating the OCI Provider

When you run Terraform yourself, the OCI provider supports several authentication methods:

MethodTypical use
API signing key (user OCID, fingerprint, private key, tenancy OCID)A developer's workstation
Instance principalTerraform running on a compute instance in a dynamic group
Resource principalTerraform running inside an OCI service that has its own identity
Security token (session authentication)Short-lived interactive sessions created with oci session authenticate

When Terraform runs inside Resource Manager, the service handles authentication for you, and the provider "oci" block only needs the region.

Loading diagram...
Terraform Workflow
Test Your Knowledge

A platform team wants application teams to see exactly which OCI resources a change will create, modify, or delete before anything is changed, so the network team can approve it. Which Terraform command produces this output?

A

terraform init

B

terraform plan

C

terraform apply with the -auto-approve flag

D

terraform fmt

Test Your Knowledge

Two engineers run terraform apply against the same environment at the same time from their laptops, and the second run corrupts the record of which OCIDs belong to the configuration. Which practice prevents this?

A

Copy terraform.tfstate into each engineer's working directory before every run

B

Delete the state file after every apply so Terraform rebuilds it each time

C

Store all OCIDs as hard-coded variables instead of keeping a state file

D

Keep state in a shared, secured location with locking for each run

Sections you finish are checked off in the contents.