ops0ops0

Migrate ClickOps to IaC

Transform manually-created AWS resources into version-controlled Terraform code without recreating them.


Scenario

Your team has been creating AWS resources through the console for months or years. You now need to:

  • Bring everything under version control
  • Enable reproducible deployments
  • Meet compliance requirements
  • Stop "who changed what?" mysteries

This guide shows how to use ops0's Discovery feature to scan, import, and manage existing resources.


Prerequisites

AWS integration configured with read permissions (Setup guide)
At least one IaC project created (for importing resources)

Step 1: Run a Discovery Scan

1Click Discovery in the left sidebar
2Click New Scan
3Select your AWS integration
4Choose regions to scan (or select "All Regions")
5Click Start Scan

What Gets Scanned

ops0 discovers resources across these categories:

CategoryResources
ComputeEC2 instances, Auto Scaling groups, Lambda functions
NetworkingVPCs, subnets, security groups, NAT gateways, load balancers
StorageS3 buckets, EBS volumes, EFS file systems
DatabaseRDS instances, DynamoDB tables, ElastiCache clusters
SecurityIAM roles, policies, KMS keys
ContainersECS clusters, EKS clusters, ECR repositories

Step 2: Review Discovered Resources

After the scan completes, you'll see a list of all discovered resources.

Understanding the Status

StatusMeaning
UnmanagedResource exists in AWS but not in any Terraform state
ManagedResource is already tracked by an ops0 project
DriftedResource differs from Terraform state (manual change detected)

Filtering Results

Use filters to focus on what matters:

By Type
Show only EC2, S3, RDS, etc.
By Region
Focus on specific regions
By Status
Show unmanaged only

Step 3: Select Resources to Import

Not all resources need to be imported immediately. Start with a logical group:

1Networking first - VPCs, subnets, route tables (other resources depend on these)
2Security next - Security groups, IAM roles
3Storage - S3 buckets, EBS volumes
4Compute last - EC2, Lambda, containers

Select resources by clicking the checkbox next to each one, or use Select All for the filtered view.


Step 4: Create Terraform Code

With resources selected, click Create Terraform.

ops0 will:

  1. Analyze each resource's current configuration
  2. Produce Terraform code that matches the live state
  3. Organize code into logical files (vpc.tf, ec2.tf, etc.)

Example Code

For an EC2 instance:

resource "aws_instance" "web_server" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.medium"
  subnet_id     = aws_subnet.private_1a.id

  vpc_security_group_ids = [
    aws_security_group.web.id
  ]

  root_block_device {
    volume_size = 50
    volume_type = "gp3"
    encrypted   = true
  }

  tags = {
    Name        = "web-server"
    Environment = "production"
  }
}

Review the Code

ops0 highlights potential issues:

Warnings to Address

• Hardcoded AMI IDs (consider using data sources)
• Missing lifecycle rules (prevent accidental destruction)
• Secrets in environment variables (move to Secrets Manager)


Step 5: Import into Terraform State

This is the critical step - importing resources into Terraform state without recreating them.

1Click Import to Project
2Select the destination IaC project (or create a new one)
3ops0 runs terraform import for each resource
4View the import log for each resource

Import Log Example

Importing aws_vpc.main...
  terraform import aws_vpc.main vpc-0123456789abcdef
  Import successful!

Importing aws_subnet.private_1a...
  terraform import aws_subnet.private_1a subnet-0123456789abcdef
  Import successful!

Importing aws_instance.web_server...
  terraform import aws_instance.web_server i-0123456789abcdef
  Import successful!

Import complete: 3 resources imported

Step 6: Verify No Changes

After import, run a Terraform plan to confirm the code matches reality:

1Open your IaC project
2Click Plan
3Verify the output shows No changes

Expected Output

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration
and found no differences, so no changes are needed.

If there are differences, ops0's AI can help you fix the Terraform code to match the live resource exactly.


Step 7: Set Up Ongoing Drift Detection

Now that resources are managed, detect future manual changes:

1Go to your IaC project settings
2Enable Drift Detection
3Set schedule (e.g., daily at 6 AM)
4Configure notifications (Slack, email)

When drift is detected, you can:

  • View what changed
  • Update Terraform to match (accept the manual change)
  • Revert to Terraform state (undo the manual change)

Troubleshooting

Import Fails with "Resource already managed"

The resource is already in another Terraform state. Check:

  • Other ops0 projects
  • External Terraform workspaces
  • Terraform Cloud/Enterprise

Plan Shows Unexpected Changes

Common causes:

IssueSolution
Default valuesAWS adds defaults that weren't in original config. Add them explicitly to Terraform.
Computed attributesSome attributes are computed. Add lifecycle { ignore_changes = [...] }.
Order differencesLists may be in different order. Sort them in Terraform.

Large Number of Resources

For 100+ resources:

  • Import in batches by resource type
  • Start with one environment (dev) before production
  • Use Discovery filters to focus on specific VPCs or regions

Best Practices

Start with Non-Production
Test the import process on dev/staging before production resources.
Review Produced Code
Don't blindly accept. Review for hardcoded values, missing tags, security issues.
Add Lifecycle Rules
For critical resources, add prevent_destroy = true to avoid accidents.
Document the Migration
Keep a log of what was imported and any manual adjustments made.

Next Steps