Migrating Off Terraform Cloud/Enterprise: Part 2
Step-by-step guide to safely leave Terraform Cloud/Enterprise: move state, refactor pipelines and handle secrets without downtime. (Part 2 of 4)
Part 2: The "How": Core Migration Steps for Decoupling
With a clear understanding of why a migration is necessary and a thorough inventory of your current setup (as detailed in Part 1), it's time to delve into the how. This second part focuses on the core technical procedures for decoupling your Infrastructure as Code (IaC) workflows from Terraform Cloud (TFC) or Terraform Enterprise (TFE). The primary objective is to regain control over your Terraform state and execution environment, paving the way for your chosen alternative.
1. The Primary Goal: Decoupling from TFC/TFE
The essence of this phase is to carefully extract two critical components from TFC/TFE:
- Terraform State Files: These files are the definitive record of your managed infrastructure. Migrating them correctly is paramount to avoid disruptions or accidental resource modifications.
- Terraform Configurations & Workflow Logic: While your HCL code likely resides in VCS, TFC/TFE might hold specific workspace settings, variable configurations, and run trigger logic that needs to be replicated or re-evaluated in your new setup.
Successfully decoupling means your local Terraform CLI (or your new automation platform) can manage your infrastructure without relying on TFC/TFE for state storage or run execution.
2. Key Migration Steps and Considerations
The exact steps can vary slightly based on your current TFC/TFE configuration (e.g., whether you're using the cloud {}
block or a standard remote
backend configuration for TFE).
- Step 1: Final State Backup and Freeze Changes (If Possible)
- Before initiating the active migration of any workspace, perform one last backup of its state file (as covered in Part 1).
- Ideally, implement a temporary freeze on infrastructure changes for the specific workspace(s) being migrated. This minimizes the risk of state drift during the transition. Communicate this clearly to the relevant teams.
- Step 2: Prepare Your New Backend
- You should have already decided on your new backend type (e.g., AWS S3 with DynamoDB, Azure Blob Storage, Google Cloud Storage, or a TACO-managed backend).
- Set up the storage:
- AWS S3: Create an S3 bucket. Enable versioning (critical for rollback capability) and server-side encryption. Create a DynamoDB table for state locking. Ensure appropriate IAM permissions for access.
- Azure Blob Storage: Create an Azure Storage Account and a Blob Container. Enable versioning and configure access controls. Azure Blob Storage provides native state locking.
- Google Cloud Storage (GCS): Create a GCS bucket. Enable versioning and encryption. GCS also offers native state locking.
- Note down the necessary configuration details for your chosen backend (bucket names, table names, keys, regions, etc.).
- Step 3: Update Terraform Backend Configuration in Your Code
- This is where you tell your Terraform code where its state will now live.
- In your Terraform configuration files (typically
backend.tf
ormain.tf
), modify theterraform {}
block. - If migrating from TFC using the
cloud {}
block:- You will remove the
cloud {}
block entirely. - You will add a new
backend "<your_chosen_backend_type>"
block.
- You will remove the
- If migrating from TFE or TFC using a
remote
backend:- You will modify the existing
backend "remote"
block tobackend "<your_chosen_backend_type>"
.
- You will modify the existing
- Important: The
key
(for S3/Azure) orprefix
(for GCS) determines the path within the bucket where the state file for this specific configuration will be stored. Plan your naming convention carefully to organize state files logically (e.g., by project, environment, component).
- Step 4: Initialize the New Backend and Migrate State
- Navigate to the directory containing your Terraform configuration with the updated backend block.
- Run
terraform init
. - Terraform will detect that you're changing the backend configuration.
- If you were previously using TFC/TFE as a remote backend and have local credentials configured for it, Terraform might offer to automatically migrate the state. It will prompt: "Do you want to copy the existing state to the new backend?"
- Carefully review the prompt. If you are confident in your downloaded backup and the new backend configuration, you can type
yes
. Terraform will then attempt to pull the latest state from TFC/TFE and push it to your newly configured backend.
- Carefully review the prompt. If you are confident in your downloaded backup and the new backend configuration, you can type
- If automatic migration is not offered or if you prefer manual control (recommended for critical workloads):
- Ensure you have the state file you backed up in Part 1 (e.g.,
downloaded_workspace.tfstate
). - Run
terraform init -migrate-state
. Terraform will initialize the new backend. - Then, push your backed-up state file to the new backend:
terraform state push downloaded_workspace.tfstate
(Ensuredownloaded_workspace.tfstate
is the correct, most recent state file for this configuration.)
- Ensure you have the state file you backed up in Part 1 (e.g.,
- Verification: After
terraform init
(and potentiallystate push
), runterraform plan
. If the backend migration was successful and the state is correctly recognized, the plan should show "No changes. Your infrastructure matches the configuration." or only reflect intentional changes you've made. Any unexpected proposed changes (especially destructions) indicate a potential issue with the state migration that needs immediate investigation.
- Step 5: Manage Variables and Environment Configuration
- Variables previously managed within the TFC/TFE workspace UI (Terraform variables, environment variables) now need to be managed according to your new setup.
- Options include:
.tfvars
files (for non-sensitive variables, committed to VCS or managed securely).- Environment variables in your CI/CD system.
- Secrets management solutions (e.g., HashiCorp Vault, AWS Secrets Manager, Azure Key Vault) for sensitive data.
- Replicate the necessary variable configurations for your new execution environment.
- Step 6: Test Thoroughly
- Perform a
terraform plan
to ensure Terraform can read the state from the new backend and correctly interprets your infrastructure. - If possible, apply a small, non-critical change to confirm the
terraform apply
process works as expected with the new backend and variable setup.
- Perform a
- Step 7: Update CI/CD Pipelines
- If you have CI/CD pipelines that interacted with TFC/TFE (e.g., triggering runs via API), these will need to be updated.
- They should now execute Terraform CLI commands directly, configured to use your new backend and variable management strategy.
- Step 8: Decommission Old TFC/TFE Workspaces (Cautiously)
- Once you are fully confident that a workspace is successfully migrated and operating correctly with the new backend, you can consider decommissioning the old workspace in TFC/TFE.
- Proceed with caution. It's often wise to leave the old workspace in a read-only or non-operational state for a period before full deletion, just in case a rollback is unexpectedly needed. Ensure all state data is securely and redundantly backed up from TFC/TFE before deletion.
Example: Migrating to Google Cloud Storage
terraform {
backend "gcs" {
bucket = "your-new-gcs-bucket-name" # Replace
prefix = "path/to/your/terraform.tfstate" # e.g., networking/prod
}
}
Example: Migrating to Azure Blob Storage
terraform {
backend "azurerm" {
resource_group_name = "your-resource-group" # Replace
storage_account_name = "yourstorageaccountname" # Replace
container_name = "your-container-name" # Replace
key = "path/to/your/terraform.tfstate" # e.g., networking/prod/terraform.tfstate
}
}
Example: Migrating to AWS S3
# Remove this if it exists:
# terraform {
# cloud {
# organization = "your-tfc-org"
# workspaces {
# name = "your-workspace-name"
# }
# }
# }
# Add or modify to this:
terraform {
backend "s3" {
bucket = "your-new-s3-bucket-name" # Replace
key = "path/to/your/terraform.tfstate" # e.g., networking/prod/terraform.tfstate
region = "your-aws-region" # Replace
dynamodb_table = "your-dynamodb-lock-table-name" # Replace
encrypt = true
}
}
Choosing Your Target Backend: Key Considerations Revisited
As mentioned in Part 1, the choice of your new backend is crucial.
- Cloud Object Storage (AWS S3, Azure Blob, GCS):
- Pros: Highly available, durable, cost-effective, native versioning and encryption, often integrates well with other cloud services and CI/CD tools. State locking is well-supported.
- Cons: Requires you to manage access permissions (IAM roles/policies) and potentially the setup of locking mechanisms (though often native now).
- TACO-Managed Backend: If you're moving to a Terraform Automation and Collaboration Software (TACO), it will typically provide its own managed state backend.
- Pros: Simplifies backend setup and management as it's handled by the TACO platform. Often comes with integrated UI, RBAC, and other collaboration features.
- Cons: You are reliant on the TACO vendor for state management; less direct control than managing your own object storage.
Successfully navigating these core migration steps will free your IaC workflows from TFC/TFE. This newfound independence allows you to select an operational model—be it a full open-source stack, a TACO, or a GitHub Actions-centric approach—that best aligns with your team's needs and strategic goals.
Next in the Series (Part 3): Exploring Alternative Paths: The Open-Source Stack vs. TACOs.