Article · part of a guide
Building an IDP with Terraform & OpenTofu
Step-by-step guide to building a scalable Internal Developer Platform with Terraform & OpenTofu: automate infra, boost velocity and stay cloud-agnostic.

Key takeaways
- An Internal Developer Platform (IDP) is a self-service layer that lets developers provision infrastructure autonomously within defined guardrails.
- A Terraform or OpenTofu IDP centers on four components: a self-service developer portal, a component catalog, an IaC automation engine, and reusable versioned modules.
- Terraform uses the BSL 1.1 license while OpenTofu uses MPL 2.0; both share HCL and the same provider ecosystem, so the choice hinges on licensing and governance preferences.
- Best practices for an IDP include private versioned module registries, remote state with locking and encryption, CI/CD with GitOps, and Policy as Code guardrails via tools like OPA.
- Embed security throughout by injecting secrets at runtime, enforcing RBAC and least privilege, and scanning IaC with tools like tfsec, checkov, or Trivy.
An Internal Developer Platform (IDP) is a self-service layer that lets developers provision their own resources within guardrails the platform team sets. Build it on a mature Infrastructure as Code (IaC) tool like Terraform or its open-source fork OpenTofu, and developers stop filing tickets for infrastructure. They get standard, repeatable setups instead, and ship faster because of it.
This guide assumes you have already decided to build. For the upstream decision of whether you need a custom IDP or a Terraform management platform, and how a platform team scales self-service across many developers, see our platform-engineering guide.
Terraform vs. OpenTofu: Which IaC Foundation Should You Build On?
Terraform and OpenTofu let you define infrastructure in human-readable configuration files. Both follow the same core workflow: Write (define infrastructure in HCL), Plan (preview changes), and Apply (provision or modify infrastructure).
A basic HCL example looks similar for both:
# main.tf - Example for AWS EC2 instance
provider "aws" {
region = "us-west-2"
}
resource "aws_instance" "example" {
ami = "ami-0c55b31ad29f52381" # Example AMI
instance_type = "t2.micro"
tags = {
Name = "ExampleInstance"
}
}The key difference lies in licensing and governance:
| Aspect | Terraform | OpenTofu |
|---|---|---|
| Licensing Model | Business Source License (BSL 1.1) | Mozilla Public License 2.0 (MPL 2.0) |
| Core IaC Functionality | Mature, extensive provider ecosystem, HCL | Compatible with HCL, uses the same provider ecosystem |
| Community & Governance | HashiCorp-led | Linux Foundation, community-governed |
| Enterprise Offerings | HCP Terraform, Terraform Enterprise | Relies on 3rd-party platforms (Scalr, Spacelift, etc.) |
| Key Feature Divergences | Ephemeral resources (example) | Client-side state encryption (example) |
OpenTofu started as a fork of Terraform, meant to keep the tool open source for the long haul. Its MPL 2.0 license gives teams more flexibility down the road, which matters most if you plan to build services on top of the IaC tooling. If procurement asks whether Terraform itself is still open source, the license file answers it: as of July 2026, releases from 1.6.0 on ship under BUSL 1.1, and 1.5.7 was the last MPL release.
What Are the Core Components of a Terraform/OpenTofu IDP?
A Terraform/OpenTofu IDP rests on four parts: a self-service interface or developer portal (Backstage, Port, or custom-built), a component catalog of modules and their metadata, an IaC automation engine that runs init/plan/apply, and a set of reusable versioned modules. The platform-engineering guide covers how those layers divide up and where a Terraform management platform fits versus a portal. The rest of this post is about building the engine and the guardrails around it.
What Technical Considerations and Best Practices Matter Most?
1. Module Management
Reusable modules are the building blocks of a scalable IaC practice. They ensure consistency and embed best practices.
Referencing a module:
# Consuming a VPC module
module "vpc" {
source = "terraform-aws-modules/vpc/aws" # Public registry example
version = "3.14.2"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["us-west-2a", "us-west-2b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
enable_nat_gateway = true
enable_vpn_gateway = false
}- Best Practice: Use private registries for internal modules, version them (Semantic Versioning), and document them thoroughly.
2. State Management
The state file tracks your managed infrastructure. Protecting it is crucial.
Backend configuration (e.g., AWS S3 with DynamoDB for locking):
# backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state-bucket-unique-name"
key = "global/s3/terraform.tfstate"
region = "us-west-2"
dynamodb_table = "terraform-state-lock-table"
encrypt = true
}
}- Best Practices: Always use remote backends. Enable state locking, encryption at rest, and versioning. Isolate state files per environment/component to minimize blast radius. OpenTofu also offers client-side state encryption.
3. CI/CD Integration
Automate your IaC workflows for consistency and speed.
Conceptual CI/CD pipeline step (e.g., GitHub Actions):
# .github/workflows/terraform.yml (snippet)
name: 'Terraform CI/CD'
on:
push:
branches:
- main
pull_request:
jobs:
terraform:
name: 'Terraform'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Terraform/OpenTofu
uses: hashicorp/setup-terraform@v2 # or opentofu/setup-opentofu
with:
# terraform_version: 1.5.0 # Specify version
# tofu_version: 1.6.0 # For OpenTofu
- name: Terraform Init
run: terraform init # or tofu init
- name: Terraform Validate
run: terraform validate # or tofu validate
- name: Terraform Plan
if: github.event_name == 'pull_request'
run: terraform plan -no-color -input=false # or tofu plan
continue-on-error: true
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve -input=false # or tofu apply- Best Practice: Integrate
init,validate,plan, andapplystages. Use GitOps principles: store IaC in Git, use Pull/Merge Requests for changes, and automate plan reviews.
4. Policy Enforcement
Implement guardrails using Policy as Code (PaC).
Conceptual Rego policy snippet (for Open Policy Agent - OPA):
package terraform.aws.security
# Deny if an S3 bucket does not have versioning enabled
deny[msg] {
input.resource_changes[_].type == "aws_s3_bucket"
not input.resource_changes[_].change.after.versioning[_].enabled
msg = "S3 buckets must have versioning enabled."
}
# Deny overly permissive security group ingress rule
deny[msg] {
sg_rule = input.resource_changes[_]
sg_rule.type == "aws_security_group_rule"
sg_rule.change.after.type == "ingress"
contains(sg_rule.change.after.cidr_blocks[_], "0.0.0.0/0")
sg_rule.change.after.protocol == "-1" # All protocols
msg = "Security group rule allows all traffic from any source. Please restrict."
}- Best Practice: Integrate PaC tools like OPA into CI/CD pipelines to validate plans against organizational policies for security, compliance, and cost.
5. Security
Embed security throughout the IDP.
- Secrets Management: Never hardcode secrets. Integrate with tools like HashiCorp Vault, AWS Secrets Manager, etc., to inject secrets at runtime.
- RBAC: Implement Role-Based Access Control for the IDP and ensure IaC tools operate with least privilege. Scalr, a drop-in Terraform Cloud alternative, lets you compose custom roles from individual permissions across account, environment, and workspace scopes. That granularity buys you two things. It enforces least privilege, so every role gets only the access it needs. And it lets you onboard more personas safely for self-service: a junior engineer who can plan but not apply, an app team scoped to its own environment, an auditor with read plus audit access, or a contractor limited to a single workspace.
- Vulnerability Scanning: Use tools like
tfsec,checkov, orTrivyto scan IaC code for misconfigurations.
Is an IDP Built on Terraform or OpenTofu Worth It?
An IDP built on Terraform or OpenTofu gives developers a faster path to infrastructure and gives the platform team consistent, governed setups to maintain. Most of the work is in the parts covered above: reusable modules, protected state, automated pipelines, policy checks, and security baked into each step. Get those right and you have a platform people actually use instead of working around. The choice between Terraform and OpenTofu mostly comes down to licensing, and OpenTofu is the open-source option if that is what your team needs.
Frequently asked questions
What is an Internal Developer Platform (IDP)?
An Internal Developer Platform is a self-service layer that lets developers provision their own infrastructure within guardrails set by the platform team. Instead of filing tickets, developers get standard, repeatable setups and ship faster. Building one on Terraform or OpenTofu gives it a mature Infrastructure as Code foundation.
Should I build an IDP on Terraform or OpenTofu?
Both share HCL syntax, the same provider ecosystem, and the same write-plan-apply workflow, so the choice mostly comes down to licensing and governance. Terraform uses the Business Source License (BSL 1.1) and is HashiCorp-led, while OpenTofu uses MPL 2.0 and is community-governed under the Linux Foundation. OpenTofu's open-source license gives more flexibility if you plan to build services on top of the tooling.
What are the core components of a Terraform or OpenTofu IDP?
Four parts: a self-service developer portal (such as Backstage, Port, or something custom), a component catalog of modules and their metadata, an IaC automation engine that runs init, plan, and apply, and a set of reusable versioned modules. The engine plus guardrails like policy checks and RBAC are where most of the build effort goes.
How do you secure a Terraform-based Internal Developer Platform?
Never hardcode secrets; inject them at runtime from a tool like HashiCorp Vault or AWS Secrets Manager. Enforce role-based access control and least privilege so each persona gets only the access it needs. Scan IaC code for misconfigurations with tools like tfsec, checkov, or Trivy, and validate plans with Policy as Code tools like OPA in CI/CD.
About the author

CEO at Scalr
Sebastian Stadil is the CEO of Scalr with 15+ years of DevOps experience. He started with AWS in 2004 and advised early Microsoft Azure and Google Cloud.
Part of this guide
8 sheets
What Are Terraform TACOs?
- Terraform vs GitOps for Kubernetes: Where the Line Should Fall
- Choosing Your Engine: Top Continuous Delivery Tools and Trends
- Cloud Orchestration Tools and Platforms
- New Finding: Companies Without Platform Engineering Teams Suffer Lower Developer Velocity and Operational Stability
- Streamlining Terraform and OpenTofu with an Internal Developer Platform
- The Fallacy of