top of page

OpenTofu and Terraform: A Tale of Two Infrastructure as Code Tools


IBM Acquisition: A New Chapter for HashiCorp and Terraform


In a significant move, IBM has acquired HashiCorp, the company behind the popular infrastructure as code tool Terraform. This acquisition has sent ripples through the DevOps and cloud computing communities, leaving many to wonder about the future of Terraform and its implications for cloud infrastructure management. As the dust settles, it's essential to examine the potential consequences of this deal and how it may impact your cloud strategy on platforms like Azure and AWS.


A Brief History of Terraform and HashiCorp


Terraform, created by Mitchell Hashimoto and Armon Dadgar in 2014, revolutionized the way organizations manage their cloud infrastructure. Its infrastructure as code approach enabled DevOps teams to version, manage, and deploy infrastructure configurations across various cloud providers. HashiCorp, founded by the same duo, expanded its product portfolio to include tools like Vault, Nomad, and Consul, cementing its position as a leader in the cloud automation space.


A brief History of Opentofu


The OpenTofu Manifesto advocates for Terraform's return to an open-source license, following HashiCorp's switch to the non-open-source Business Source License (BUSL). This change threatens the community and ecosystem built around Terraform over nine years, causing uncertainty and potential legal risks for users. The BUSL license is seen as a "poison pill" that will dwindle the ecosystem and harm similar open-source projects. To ensure Terraform remains truly open source, a fork, OpenTofu, has been created and will be maintained by the Linux Foundation, guaranteeing a community-driven, impartial, and modular project that remains open source and backwards compatible


Implications for Terraform Users and the Community


The acquisition raises questions about Terraform's future development, support, and pricing. IBM's involvement may bring increased investment, but it also risks altering the product's direction and community-driven ethos. Terraform users and the open-source community may face changes in:


  • Pricing and licensing: IBM might modify HashiCorp's pricing models or licensing terms, potentially affecting users' costs or access to products.

  • Product roadmap: IBM's influence may shift Terraform's development focus, prioritizing its interests over community-driven features.

  • Support and documentation: IBM's support and documentation standards may differ from HashiCorp's, potentially impacting users' experience.



The Rise of OpenTofu and Alternative Solutions


In response to the acquisition, the open-source community has already begun exploring alternatives, including OpenTF (Open ToFu ). This community-driven project aims to maintain Terraform's open-source spirit, ensuring users' investments in Terraform configurations and skills remain valuable. Other alternatives, like AWS CloudFormation and Azure Bicep, may also gain traction as users seek flexibility and freedom from vendor lock-in.


Migrating to OpenTofu: A Step-by-Step Guide


Step 0: Prepare for a Smooth Transition

Before embarking on the migration journey, make sure you have a reliable disaster recovery plan in place. This will ensure that you're well-prepared for any unexpected situations.


Step 1: Upgrade to Terraform 1.8.2 and newer


This guide is specifically designed for Terraform 1.8.2. If you're running an earlier version, please upgrade to 1.8.2 before proceeding. If you're on a later version, wait for a compatible migration guide.


Step 2: Finalize Pending Changes


Run terraform apply to ensure all changes are applied. Verify that terraform plan shows no pending changes. This step is crucial to avoid any potential issues during the migration process.

terraform plan

Step 3: Install OpenTofu 1.7.0

Follow the installation instructions for the OpenTofu CLI tool. Test the installation by running tofu --version to confirm the successful installation.

# Download the installer script:
curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
chmod +x install-opentofu.sh
./install-opentofu.sh --install-method deb
rm install-opentofu.sh

Step 4: Backup Your State File and Code

Backup your state file and code to prevent any data loss during the migration process. If using a local state file, simply copy the terraform.tfstate file. For remote backends like S3, follow the recommended backup procedures.


Step 5: Update Your Code

Perform the necessary code changes to ensure a seamless migration:

  • For S3 backend users, remove the skip_s3_checksum option and verify that your code works as intended.

  • Update the removed block according to OpenTofu's documentation.

  • Restructure your tests to work without mock_provider and override features.


Step 6: Initialize OpenTofu

Run tofu init in your Terraform code directory. OpenTofu will download the necessary providers and modules from the registry.

tofu init

Step 7: Review the Plan

Run tofu plan to ensure no unexpected changes. If issues arise, roll back to Terraform and troubleshoot the migration.

tofu plan

Step 8: Apply the Changes

Run tofu apply to update the state file, even if no changes are expected.


tofu apply



Side by side example of Terraform and OpenTofu


Terraform Example deploying MySQL Flexible server on Azure

This Terraform script provisions an Azure Database for MySQL Flexible Server, setting up basic configurations such as server version, storage, and compute capacity:


provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "example" {
  name     = "example-resources"
  location = "East US"
}

resource "azurerm_mysql_flexible_server" "example" {
  name                   = "example-mysqlserver"
  resource_group_name    = azurerm_resource_group.example.name
  location               = azurerm_resource_group.example.location
  version                = "5.7"
  delegated_subnet_id    = azurerm_subnet.example.id

  administrator_login          = "mysqladmin"
  administrator_password       = "H@Sh1CoR3!"

  storage_mb                   = 32768
  sku_name                     = "Standard_D2s_v3"

  backup_retention_days        = 7
  geo_redundant_backup_enabled = true
}

resource "azurerm_subnet" "example" {
  name                 = "example-subnet"
  resource_group_name  = azurerm_resource_group.example.name
  virtual_network_name = azurerm_virtual_network.example.name
  address_prefixes     = ["10.0.0.0/24"]
  service_endpoints    = ["Microsoft.Storage", "Microsoft.Sql"]
}

resource "azurerm_virtual_network" "example" {
  name                = "example-vnet"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
}

output "mysql_server_id" {
  value = azurerm_mysql_flexible_server.example.id
}
OpenToFu Example of deploying MySQL Flexible server on Azure

Here's how you might configure the same Azure MySQL Flexible Server using OpenTofu. Note that the syntax and structure are quite similar to Terraform, reflecting its roots and compatibility with Terraform's approach:


provider "azure" {
  features {}
}

resource "azure_resource_group" "example" {
  name     = "example-resources"
  location = "East US"
}

resource "azure_mysql_flexible_server" "example" {
  name                   = "example-mysqlserver"
  resource_group_name    = azure_resource_group.example.name
  location               = azure_resource_group.example.location
  version                = "5.7"
  delegated_subnet_id    = azure_subnet.example.id

  administrator_login          = "mysqladmin"
  administrator_password       = "H@Sh1CoR3!"

  storage_mb                   = 32768
  sku_name                     = "Standard_D2s_v3"

  backup_retention_days        = 7
  geo_redundant_backup_enabled = true
}

resource "azure_subnet" "example" {
  name                 = "example-subnet"
  resource_group_name  = azure_resource_group.example.name
  virtual_network_name = azure_virtual_network.example.name
  address_prefixes     = ["10.0.0.0/24"]
  service_endpoints    = ["Microsoft.Storage", "Microsoft.Sql"]
}

resource "azure_virtual_network" "example" {
  name                = "example-vnet"
  address_space       = ["10.0.0.0/16"]
  location            = azure_resource_group.example.location
  resource_group_name = azure_resource_group.example.name
}

output "mysql_server_id" {
  value = azure_mysql_flexible_server.example.id
}


12 views0 comments
bottom of page