Skip to main content
Cloud DevOps Solutions
Get a quote Talk to an engineer

ClickOps & Cloud Setup

ClickOps Inventory and Migration Plan: Moving Hand-Built Cloud Resources to Infrastructure as Code

A ClickOps inventory is a complete list of cloud resources created by hand, with their owners, dependencies and risk. The migration plan then orders them into stages, importing or rebuilding each into Terraform so that console changes stop being the way infrastructure is managed. We deliver both, in your repository, without requiring downtime.

Key takeaways

  • You cannot migrate what you have not listed, so the inventory comes first and is kept as a living document.
  • Not everything should be imported: some resources are cheaper to rebuild, and some should simply be deleted.
  • Staging by risk and blast radius lets the team learn on low-stakes resources before touching databases and networks.
  • A plan with no drift around the edges only works if console write access is restricted once resources are managed.
  • The goal is a clean `terraform plan` with no unexplained changes, not a repository that merely exists.

Why an inventory comes before any Terraform

Most teams that decide to adopt infrastructure as code start by writing Terraform for the first resource they can think of. A few weeks later they have a repository covering a fraction of the account and an uneasy feeling that nobody knows what the rest is. The missing step is a map.

An inventory answers four questions for every resource: what is it, who owns it, what depends on it, and what happens if it breaks. Without that, ordering the work is guesswork, and the riskiest items tend to be left until last, then avoided indefinitely. This deliverable is the discipline behind the ClickOps and cloud setup service, and it sits alongside the practical walkthrough in our blog post on moving from ClickOps to Terraform on AWS.

What a good inventory contains

A spreadsheet is enough if it is complete and maintained. We record:

  • Identity: account, region, service, name, ARN or ID.
  • Ownership: a person or team, and the environment (production, staging, sandbox, unknown).
  • Cost: what it adds to the bill, taken from billing data rather than estimated.
  • Dependencies: what talks to it and what it talks to.
  • Risk: customer impact if it fails, and whether it holds data.
  • Disposition: import, rebuild, replace, or delete.
  • State of documentation: whether anyone can explain why it exists.

The last column matters more than it looks. Resources nobody can explain are often the most valuable to understand, because they were built during an incident or a deadline and then became load-bearing.

Finding what is really there

No single source is reliable. We cross-check several:

SourceGood atBlind spot
AWS Config or Resource ExplorerListing resources across regionsContext, intent, ownership
Cost Explorer and billing dataRevealing forgotten, expensive itemsFree or cheap resources
CloudTrail historyWho created what, and whenAnything older than retained logs
Interviews with the teamWhy things existMemory is imperfect
Existing scripts and wikisPartial intentOften out of date

Regions deserve special attention. Resources are often created in a region nobody uses by accident, and a security review is incomplete without them. Our organisation guardrails later prevent this by denying unused regions.

Deciding what happens to each resource

Not everything should be imported. The disposition decision is where judgement matters.

Import

Best for stateful or hard-to-replace resources that are well understood: VPCs, databases, buckets, IAM roles. Importing leaves the real resource untouched and attaches it to code.

Rebuild

Best for stateless or simple resources, or those whose current configuration is wrong. It is often cleaner to define a new load balancer properly and move traffic than to import a badly configured one and carry its mistakes forward.

Replace

Sometimes the right answer is not to codify a hand-built thing at all. A self-managed server running a queue might be replaced by a managed queue service. That belongs in a separate project, but the inventory should flag it.

Delete

Orphaned snapshots, unattached volumes, idle test environments and old load balancers can usually go, after a quiet period. Stop or isolate first, wait, then remove.

Importing safely

Terraform supports import blocks, which let you review an import as part of a normal plan:

import {
  to = aws_s3_bucket.assets
  id = "example-company-assets"
}

resource "aws_s3_bucket" "assets" {
  bucket = "example-company-assets"
}
terraform plan -generate-config-out=generated.tf
terraform plan

The first command can draft configuration, which we then clean up. The aim is a plan that reports no changes. If a plan wants to replace a database or recreate a subnet, we stop and investigate before applying anything. Setting prevent_destroy on stateful resources gives a safety net while the code is still being corrected.

State should live remotely with locking from the start, as described in our Terraform landing zone code work, and imports should happen through pull requests so that a colleague sees what is being brought under management.

Ordering the waves

We usually sequence by risk and learning value:

  1. Low-risk, high-learning: buckets, DNS records, tags, IAM roles. The team gets used to the workflow.
  2. Foundations: networking, accounts and baseline security. See the landing zone work.
  3. Shared services: logging, monitoring, container registries.
  4. Stateful workloads: databases and queues, with backups verified first.
  5. Application compute: instances, clusters, autoscaling groups, last because they change most often.

Production data stores are not first, even though they are the scariest, because mistakes there are the most expensive.

Common failure modes

  • Boil the ocean. Trying to import everything at once stalls the project. Waves keep momentum.
  • Drift returns. If people can still click in the console, they will, and the code goes stale. Reducing write access is part of the plan.
  • Imported mistakes. Faithfully codifying an insecure configuration just makes it permanent.
  • One giant state file. It slows every plan and makes every change risky. We split state by environment and domain.
  • No owner. An inventory with no one responsible for keeping it current is out of date within months.

When not to migrate

A throwaway prototype, a short-lived proof of concept or an environment about to be decommissioned is not worth codifying. And if your biggest risk is not infrastructure drift but missing backups, fix that first. The plan states this honestly.

Delivery and handover

You receive the inventory, the disposition decisions with reasoning, the wave plan, and the Terraform for completed waves in your repository. We document how to import a new resource, how to detect drift, and who approves changes. For ongoing support afterwards, see managed DevOps, or talk to us about scoping the first wave.

How to tell it is working

  • terraform plan on managed stacks shows no unexpected changes.
  • New infrastructure is only ever created through pull requests.
  • The inventory shrinks as items are imported, rebuilt or deleted.
  • Nobody is afraid to touch a resource because they cannot tell what depends on it.

References

How we deliver it

  1. 01

    Discover everything

    We combine the Resource Explorer or Config inventory, billing data, CloudTrail history and talking to the people who built things, because tools alone miss context.

  2. 02

    Classify each resource

    Every item is marked keep and import, rebuild, replace with a managed service, or delete, with an owner and an environment recorded.

  3. 03

    Map dependencies and risk

    We note what depends on what, and what would hurt customers if a change went wrong, so ordering follows blast radius.

  4. 04

    Write the staged plan

    Waves are agreed with you, each with scope, method, rollback and a definition of done.

  5. 05

    Execute wave by wave

    Resources are imported or recreated, plans are reviewed until they show no unexpected change, and results are merged through pull requests.

  6. 06

    Lock the door

    Console write access to managed resources is reduced and a drift check is scheduled, so the work does not decay.

Tools and technologies

Terraformterraform import and import blocksAWS Resource ExplorerAWS ConfigCloudTrailCost ExplorerTerraformerCheckovtflintGitHub Actions

Frequently asked questions

How do you find resources that were created by hand?
We use several sources together: AWS Config or Resource Explorer for what exists, Cost Explorer for what is billing, CloudTrail for who created what and when, and interviews for intent. Tags help when they exist, but untagged resources are exactly where the surprises hide, so we do not rely on tagging.
Can existing resources be brought into Terraform without recreating them?
Usually yes. Terraform can import an existing resource into state, and import blocks make this reviewable in a plan. You then write configuration that matches reality until the plan shows no changes. Some resources are awkward to import or poorly modelled, and we rebuild those instead.
Do we need downtime for the migration?
Importing does not touch the running resource, so most of the work needs no downtime. Replacing resources, such as moving a database into a new subnet group, may. We identify those in the plan, schedule them in agreed windows and prepare rollback before starting.
Should we auto-generate Terraform from our account?
Generation tools are useful for a first draft, but the output is rarely something a team wants to maintain: flat, repetitive and full of defaults. We use them to save typing, then refactor into modules with sensible variables before merging.
What happens to resources nobody can explain?
They go on a quarantine list. We check usage, traffic and billing, tag them with an intended removal date, tell likely owners, and only delete once nothing objects. Stopping or isolating a resource first is safer than deleting it outright.

Talk to an engineer about clickops to infrastructure as code migration

Book a free 30-minute call. We review your current setup and tell you honestly whether and how we can help.

Written by Saddique Khan, DevOps / SRE / Cloud Consultant Engineer. Last updated 2026-10-08.