AWS → STACKIT · CHECKLIST
AWS to STACKIT migration checklist
Use this list to carry an AWS estate to STACKIT without losing track. Every check names the file of the StackToIT output folder that holds the answer, so a reviewer can tick it against evidence instead of memory. Examples come from a demo estate of nine AWS units and from the published Retail Store run.
How the checklist is organised
Six phases, in the order the work happens. The file names are paths inside the output folder of an assessment.
Evidence, not opinion
A check is done when the file named beside it says so, or when a person has recorded the answer in the review files. StackToIT reads and writes files and changes nothing in any cloud.
Sized by a real run
The Retail Store run covers 282 Terraform resources and 44 migration units. Your estate gets its own numbers; the checks stay the same.
Decisions are part of the list
Open decisions block steps of the plan. A checklist that skips them ticks boxes the plan will not honour.
Phase 1 · Discovery
| Check | Where the answer is | Done when |
|---|---|---|
| The whole estate was read: every root module, child module and variable file | console.txt and assessment.json (resources scanned, migration units) | The unit count matches what your team expects; missing modules are explained |
| Variables that decide whether a resource exists are known | console.txt (visibility line), assessment.json (conditional units) | No unit is left conditional by a variable you can state; the Retail Store run records 41 units switched off and 8 conditional units that only a plan decides |
| The source passes its own checks | console.txt (source checks) | Validation ran, or you know why it did not (for example no dependency lock file) |
| Resources outside Terraform are listed | Your inventory; the optional discover command adds read-only collection | Console-created resources are added by hand, because an assessment only sees what is in the files |
Phase 2 · Design
| Check | Where the answer is | Done when |
|---|---|---|
| Every unit has a class and a target | assessment.json, migration/source-target.csv | No unit is unexplained; REDESIGN and MANUAL_REVIEW units have an owner |
| Open decisions are listed and owned | executive/decisions.md, decisions.json, review/decisions.yaml | Every decision that blocks a plan step has an answer or a date |
| Defaults the draft chose are confirmed or changed | executive/decisions.md (defaults to confirm) | Public endpoint, sizing and egress defaults each have a recorded answer |
| What the draft does not carry is understood | engineering/not-carried.csv, engineering/architect-report.md | Each not-carried property has a decision or an accepted loss |
| The landing zone is defined | migration/landing-zone-requirements.md | Organization, project, region and network ranges are agreed |
What "not carried" looks like
engineering/not-carried-summary.csv of the demo run: one row per unit with the number of properties the draft could not carry. A non-zero count is a design check, not an error.
unit,type,class,confidence,counted,properties_not_carried
aws_db_instance.orders,aws_db_instance,REPLATFORM,MEDIUM,yes,3
aws_instance.app,aws_instance,RECONFIGURE,MEDIUM,yes,2
aws_s3_bucket.uploads,aws_s3_bucket,RECONFIGURE,MEDIUM,yes,1
aws_secretsmanager_secret.api_key,aws_secretsmanager_secret,RECONFIGURE,MEDIUM,yes,1
aws_subnet.app_a,aws_subnet,RECONFIGURE,MEDIUM,yes,1
aws_subnet.app_b,aws_subnet,RECONFIGURE,MEDIUM,yes,1
aws_vpc.app,aws_vpc,RECONFIGURE,MEDIUM,no,Phase 3 · Build
| Check | Where the answer is | Done when |
|---|---|---|
| Required services are enabled in the target project and region | terraform/README.md (enable these services first) | The services the draft uses are enabled; the portal shows a disabled one as not enabled in your region |
| Variables without defaults have values | review/target-values.tfvars (the copy of target-values-template.tfvars), terraform/variables.tf | project_id, access scopes, client CIDRs, machine types and storage classes are set |
| The draft validates against a test project | terraform/README.md (init, validate, plan) | A plan runs clean in a test project; StackToIT never runs apply |
| The state is treated as a secret | terraform/README.md (secrets the provider writes into the state) | State storage and access are decided before the first apply |
| Apply order and pre-steps are followed | execution/terraform/apply.md | Manual steps and API calls that must come first are ticked |
| Opt-in API calls are decided | executive/decisions.md, execution/api/ | Each call to an API without a stated release status is allowed or refused on record |
Phase 4 · Data
| Check | Where the answer is | Done when |
|---|---|---|
| Every stateful unit has a chosen move method | migration/data-movement.md | No unit reads DECISION_REQUIRED |
| Size, change rate and downtime tolerance are stated | review/inputs.yaml (dataset size, downtime, RPO), migration/data-movement.md ("Not known" list) | The unknowns the report lists are replaced with your numbers |
| The method was rehearsed | Step "data rehearsal" in execution/manual/actions.md | The elapsed time of each part is recorded and the freeze window is agreed from it |
| Secrets are copied by a person | Secrets Manager steps in execution/manual/actions.md | Values are in STACKIT Secrets Manager; the draft never holds them |
| The comparison checks are agreed | migration/data-movement-plan.json (checks of each asset) | Counts, lists or checksums are named per store, with a GO or NO-GO owner |
The data table and the pre-step checks
Left: migration/data-movement.md. Every unit reads DECISION_REQUIRED and the data class, RPO and downtime are NOT_PROVIDED until you state them. Right: the first lines of execution/verify/checks.md, a tickable list generated from the plan.
| Unit | Source service | Target service | Application | Mechanism | State | Data class | RPO | Downtime tolerance |
|---|---|---|---|---|---|---|---|---|
| aws_db_instance.orders | aws_db_instance | STACKIT PostgreSQL Flex | | UNKNOWN | DECISION_REQUIRED | NOT_PROVIDED | NOT_PROVIDED | NOT_PROVIDED |
| aws_s3_bucket.uploads | aws_s3_bucket | STACKIT Object Storage | | UNKNOWN | DECISION_REQUIRED | NOT_PROVIDED | NOT_PROVIDED | NOT_PROVIDED |## Before each step
- [ ] `TF/stackit_network.app_a` · `variable-supplied` `variable=project_id` — The variable `project_id` has a value.
- [ ] `TF/stackit_network.app_b` · `variable-supplied` `variable=project_id` — The variable `project_id` has a value.
- [ ] `TF/stackit_secretsmanager_instance.migrated_secrets` · `variable-supplied` `variable=project_id` — The variable `project_id` has a value.
- [ ] `TF/stackit_secretsmanager_user.migration` · `variable-supplied` `variable=project_id` — The variable `project_id` has a value.Phase 5 · Cutover
| Check | Where the answer is | Done when |
|---|---|---|
| The applications that use each store are listed | Cutover steps in execution/manual/actions.md | The plan does not read which applications use a store; their owners list them |
| The window and the freeze are agreed | Write-freeze steps; the maintenance window input in review/inputs.yaml | A window is stated by the owner; the plan invents none |
| DNS has a lowered TTL and a rollback | migration/technical-sequencing.md (zone delegation steps) | TTL lowered and expired, answers verified at the target name servers |
| The rollback decision step has an owner | Rollback decision step in execution/manual/actions.md | A named owner will record GO or ROLLBACK |
| See the cutover and rollback runbook for the ordered steps | Cutover and rollback runbook | Every step has an owner, a check and a way back |
Phase 6 · After the cutover
| Check | Where the answer is | Done when |
|---|---|---|
| Progress is recorded | review/progress.yaml | Each step is DONE, FAILED or WAIVED with an owner and a date |
| Restore is proven | Restore check step for each database | A point-in-time clone was read and compared before the GO |
| The source is retired in order | Decommission steps in execution/manual/actions.md | Retirement started only after GO; final backups kept for the period you decided |
| The result is archived unchanged | Output folder and its manifest.json | The folder verifies with the verify command before it is shared or archived |
Where you record progress
review/progress.yaml starts from progress-template.yaml. Each entry ties to the step by a hash; if a later run changes the step, your entry is shown as stale rather than silently carried over.
entries:
# MANUAL critical-semantic - aws_subnet.app_a
- action_id: "MAN/semantic/aws_subnet.app_a/availability-zone"
contract_sha256: "sha256:466db94bafa1a6993c03688825aff955665d3be7fa1f3d4387e6c6a0c7d4ac72"
state: NOT_STARTED
# MANUAL critical-semantic - aws_subnet.app_a
- action_id: "MAN/semantic/aws_subnet.app_a/effective-route-table"Questions teams ask
Can the checklist be ticked from the report alone?
Only for the design phases. Build, data, cutover and after need work in your environment; the files tell you what to do and what counts as done, and you record the result in the review files.
Do I need a full AWS inventory first?
The assessment reads Terraform. For comparison with the live account the discover command collects read-only inventory with your local AWS credentials, and the assessment itself never connects to AWS.
Where do managed databases and buckets show their risks?
In the data movement files and the not-carried list: engine versions, public or private endpoints, bucket settings that go through an API instead of Terraform, and encryption statements that are unknown.
Is every box mandatory?
No. WAIVED exists in the progress journal for a reason, but a waiver needs a note, so the omission stays visible.
Sources
Your next move: STACKIT.
Tell us about your estate. We show you what StackToIT delivers for it: target architecture, Terraform artifacts and a structured migration plan.