Converting Existing Terraform HCL to CDKTF Python

Migrating legacy HCL to programmatic infrastructure requires strict state preservation. Converting existing Terraform HCL to CDKTF Python eliminates configuration drift. It also enables deterministic CI/CD validation pipelines.

This guide details the exact workflow for safe translation. We prioritize state integrity and secure credential handling. Every step includes testable Python IaC patterns.

Pre-Migration State Audit & Backend Locking

Before modifying infrastructure code, verify remote state integrity. Enforce backend locking immediately. Immutable state snapshots prevent catastrophic resource recreation during translation.

Always export a full state backup before executing synthesis commands. Cross-reference provider configurations against your target environment.

CLI: State Audit & Backup

terraform state list
terraform state pull > state-backup.json
terraform force-unlock -force <LOCK_ID> # Use only if backend is stuck

Validate the backend lock status. Confirm all resource addresses resolve correctly. For comprehensive backend compatibility and lock mechanisms, review CDKTF Workflows & Terraform Synthesis.

Validation Steps:

  • Run terraform state list to verify resource inventory
  • Export terraform state pull > state-backup.json for immutable rollback
  • Confirm backend lock status via provider dashboard or CLI output

Automated Translation via cdktf convert

The cdktf convert utility generates baseline Python constructs from legacy HCL files. It does not produce production-ready code out of the box. You must explicitly pin provider versions to prevent silent breaking changes.

CLI: Automated HCL Translation

cdktf init --template="python" --local
cdktf convert --language python --provider-hashicorp/aws --provider-version "~> 5.0" < main.tf > main.py

After generation, verify cdktf.json provider constraints match your requirements.txt. Replace dynamic HCL blocks with native Python iteration patterns. Run cdktf synth --no-color to validate the initial JSON payload.

Validation Steps:

  • Execute cdktf convert --language python --provider-hashicorp/aws
  • Audit cdktf.json for exact provider version constraints
  • Run cdktf synth --no-color and inspect the output directory

Python 3.9+ Type Enforcement & Construct Refactoring

Automated translation strips type safety. You must apply strict typing annotations to all construct parameters. Replace HCL count and for_each directives with Python list comprehensions or dictionary mappings.

from typing import Dict, List, Optional, Any
import os
from constructs import Construct
from cdktf import TerraformStack
from cdktf_cdktf_provider_aws import AwsProvider, s3

class MigratedStack(TerraformStack):
 def __init__(
 self,
 scope: Construct,
 ns: str,
 config: Dict[str, Optional[Any]]
 ) -> None:
 super().__init__(scope, ns)

 # Secure credential handling via environment variables
 access_key = os.environ.get("AWS_ACCESS_KEY_ID")
 secret_key = os.environ.get("AWS_SECRET_ACCESS_KEY")

 AwsProvider(
 self, 
 "aws", 
 region=config.get("region", "us-east-1"),
 access_key=access_key,
 secret_key=secret_key
 )

 bucket_name = config.get("bucket_name")
 if not bucket_name:
 raise ValueError("bucket_name is required for S3 provisioning")

 s3.Bucket(
 self,
 "data",
 bucket=bucket_name,
 tags=config.get("tags", {}),
 )

Enforce mypy --strict or pyright checks before synthesis. This catches AttributeError exceptions caused by untyped nested configurations. Validate construct boundaries to prevent environment variable leakage.

Validation Steps:

  • Add explicit type hints to all __init__ parameters
  • Replace HCL loops with Python comprehensions
  • Execute mypy --strict main.py and resolve all warnings

State Reconciliation & Drift Detection

Legacy resource addresses rarely match CDKTF-generated identifiers. You must map legacy IDs to the new construct tree safely. Use cdktf import to reconcile state files without triggering destructive replacements.

CLI: State Address Mapping & Import

terraform state list
cdktf synth
cdktf import aws_s3_bucket.data <state-file.json> --state=terraform.tfstate

When addressing provider-specific state mapping and ID translation, consult Terraform Provider Bridging. Execute cdktf diff --json to verify zero unexpected changes before deployment.

Validation Steps:

  • Run cdktf synth to generate updated JSON payloads
  • Execute cdktf import <resource-id> <state-file> for each legacy resource
  • Validate cdktf diff --json output for zero drift
  • Confirm no destructive actions appear in the execution plan

Production Rollback & CI/CD Pipeline Handoff

Safe deployment requires automated rollback triggers. Configure your CI/CD runner to execute cdktf test before any production deployment. Implement state snapshot restoration on failure to maintain infrastructure consistency.

import subprocess
import sys
from typing import Tuple

def validate_drift() -> int:
 """Programmatic drift validation for CI/CD integration."""
 result = subprocess.run(
 ["cdktf", "diff", "--json"],
 capture_output=True,
 text=True,
 check=False
 )
 if result.returncode != 0:
 print("Drift detected or synth failed.", file=sys.stderr)
 return 1
 print("State matches synthetic output.")
 return 0

if __name__ == "__main__":
 sys.exit(validate_drift())

Establish pre-deploy validation hooks. Schedule post-deploy drift monitoring via cron jobs. Define explicit failure boundaries to prevent partial deployments.

Validation Steps:

  • Configure pipeline to run cdktf test before cdktf deploy
  • Implement automated state snapshot restore on pipeline failure
  • Schedule drift detection jobs for continuous compliance monitoring

Common Mistakes

  • Assuming cdktf convert yields production-ready code without manual type annotation.
  • Failing to pin provider versions in cdktf.json, causing silent synthesis drift.
  • Overwriting remote state by deploying before executing cdktf import.
  • Ignoring Python typing boundaries, leading to runtime AttributeError on nested configs.
  • Skipping cdktf synth validation in CI/CD, resulting in undetected JSON payload errors.

FAQ

How do I preserve existing Terraform state during CDKTF conversion? Lock the remote backend. Export a state snapshot. Run cdktf synth. Use cdktf import or terraform state mv to map legacy addresses before deploying.

Does cdktf convert handle dynamic blocks and for_each correctly? It generates baseline equivalents. Complex loops require manual refactoring into native Python comprehensions with strict type hints.

How do I enforce Python 3.9+ typing for complex infrastructure variables? Use typing.Dict[str, Any], typing.Optional, and typing.List for all inputs. Validate at instantiation with pydantic or isinstance checks to prevent runtime synthesis failures.

What is the safest rollback procedure if cdktf deploy fails? Halt the pipeline immediately. Restore the pre-migration state snapshot. Run terraform state replace-provider if aliases changed. Revert to the legacy branch until drift is reconciled.