AZURE → STACKIT · CUTOVER RUNBOOK
Azure to STACKIT cutover and rollback runbook
Cut over in the order the run computes from resource dependencies, give every step an owner and a check, and know the undo before you apply. This runbook ties the steps to the files a StackToIT run writes and marks what is general practice. The run never executes a cutover.
What the run gives you, and what it does not
A small portal estate (a VM, PostgreSQL, a storage account, a Key Vault and a network) was assessed on 4 November 2026. Six units, three waves.
Waves from dependencies
migration/technical-sequencing.md orders units by what they depend on. Units in one wave can move in parallel. It is a starting point, not a schedule.
Owners and checks
execution/README.md lists the steps in order with an owner role, and execution/verify/checks.md lists checks before and after each step.
Rollback per step
The execution plan says for each OpenTofu step whether it can be undone. For manual steps it says the person records how.
No cutover facts
The run found no DNS record, public address re-binding or certificate unit to cut over. That is not a statement that nothing has to move: names, addresses and certificates outside the scanned source are not seen.
Sequencing and the apply commands
Left: the three waves of the run. Right: the commands the execution package gives for the draft.
## Wave 1 — 4 unit(s)
| Unit | Class | Target |
|---|---|---|
| `azurerm_key_vault.portal` | RECONFIGURE / MEDIUM | STACKIT Secrets Manager (+ KMS for keys) |
| `azurerm_postgresql_flexible_server.portal` | REPLATFORM / MEDIUM | STACKIT PostgreSQL Flex |
| `azurerm_storage_account.docs` | REPLATFORM / MEDIUM | STACKIT Object Storage |
| `azurerm_virtual_network.app` | RECONFIGURE / MEDIUM | STACKIT project networking / Network Area (SNA) |
## Wave 2 — 1 unit(s)
| Unit | Class | Target |
|---|---|---|
| `azurerm_subnet.vm` | RECONFIGURE / MEDIUM | STACKIT network |
## Wave 3 — 1 unit(s)
| Unit | Class | Target |
|---|---|---|
| `azurerm_linux_virtual_machine.portal` | RECONFIGURE / MEDIUM | STACKIT Compute Engine |cd terraform
tofu init
tofu validate
tofu plan -out=stackit.tfplan
tofu apply stackit.tfplanDo not apply as written
All 7 OpenTofu steps of this run are marked not executable as the plan stands, and the package says to apply only when every OpenTofu step is executable. Treat the draft as a base for a test project, not for the production window.
Variables first
Six variables need a value before the steps run: the project id, the allowed CIDRs for the database, the storage class, the machine type, the image id and the boot volume size.
The runbook
Steps in order. Owner roles are the ones the run names. Steps marked practice are general working method, not output of the run.
| Step | Owner and check | Rollback |
|---|---|---|
| 1. Close the critical settings. Decide resource-group mapping, database login, network exposure, the boot image and the disk type. | Identity, Network, Platform and Security Architect. Check: assurance/critical-semantics.json says why each setting is open and what closes it. | Nothing is created yet; revert the decision record. |
| 2. Lay out projects and supply the variables. | Identity Architect. Check: the "variable supplied" rows of execution/verify/checks.md. | Nothing is created yet. |
| 3. Create the network (from the subnet, wave 2), the Secrets Manager instance and the bucket (wave 1 units). | Network, Identity, Storage Architect. Check: the resource exists in the state. | tofu destroy -target for the network and Secrets Manager instance; for the bucket, objects written since are lost. |
| 4. Create the PostgreSQL Flex instance and restrict its ACL. | Data Architect. Check: the instance exists in the state; test that only the listed CIDRs reach it (practice). | tofu destroy -target; data written since is lost. See the note on deletion below. |
| 5. Copy data (practice). The run chooses no mechanism. PostgreSQL moves with pg_dump and pg_restore or logical replication; objects with rclone. | Data and Storage Architect. Check: row counts and object counts match (practice). | The source stays untouched; discard the copy. |
| 6. Recreate secrets in the Secrets Manager instance and hand clients their credentials (practice). | Identity Architect. Check: each application can read its secret. | Delete the secrets you created; the Key Vault is still in place. |
| 7. Create the server with its key pair and network interface (wave 3). The plan names no owner role for the key pair and the interface; assign one. | Platform Architect. Check: the server exists in the state; a login with the new key works (practice). | tofu destroy -target; the boot volume is deleted with the server in the draft. |
| 8. Rehearse the cutover (practice). | Platform Architect. Check: an end-to-end test passes on STACKIT with no production traffic. | Discard the rehearsal copy. |
| 9. Cut over (practice). Freeze writes, run the last sync, switch clients, switch DNS if you own it. | All owners, one lead. Check: smoke tests, error rates and data counts. | Point clients back at Azure; the source was not changed. |
| 10. Hold, then retire the source (practice). | Platform Architect. Check: an agreed hold period passes without a rollback. | After retirement a rollback means a restore, so keep the hold long enough. |
Rows 1 to 4 and 7 follow the run. Rows 5, 6, 8, 9 and 10 are general practice and depend on your data size and tolerated downtime, which the source does not state. OpenTofu applies the whole draft in one run and orders the blocks by their references; to create rows 3, 4 and 7 one after another, target them yourself (practice).
Rollback and checks as the run writes them
Left: the rollback entries of two OpenTofu steps, an excerpt of execution-plan.json with the values as the run wrote them. Right: the checks the package lists for after the steps.
{
"actions": [
{
"id": "TF/stackit_network.vm",
"rollback": [
{
"capability": "AVAILABLE",
"how": "tofu destroy -target=stackit_network.vm, or remove the block and apply"
}
]
},
{
"id": "TF/stackit_postgresflex_instance.portal",
"rollback": [
{
"capability": "PARTIAL",
"how": "tofu destroy -target=stackit_postgresflex_instance.portal, or remove the block and apply; what was written to it since it was created is lost"
}
]
}
]
}## After each step
- [ ] `TF/stackit_network.vm` · `resource-exists` `address=stackit_network.vm` — `stackit_network.vm` exists in the STACKIT project (OpenTofu's state lists it).
- [ ] `TF/stackit_key_pair.portal` · `resource-exists` `address=stackit_key_pair.portal` — `stackit_key_pair.portal` exists in the STACKIT project (OpenTofu's state lists it).
- [ ] `TF/stackit_secretsmanager_instance.migrated_secrets` · `resource-exists` `address=stackit_secretsmanager_instance.migrated_secrets` — `stackit_secretsmanager_instance.migrated_secrets` exists in the STACKIT project (OpenTofu's state lists it).
- [ ] `TF/stackit_objectstorage_bucket.docs` · `resource-exists` `address=stackit_objectstorage_bucket.docs` — `stackit_objectstorage_bucket.docs` exists in the STACKIT project (OpenTofu's state lists it).
- [ ] `TF/stackit_postgresflex_instance.portal` · `resource-exists` `address=stackit_postgresflex_instance.portal` — `stackit_postgresflex_instance.portal` exists in the STACKIT project (OpenTofu's state lists it).
- [ ] `TF/stackit_network_interface.portal_1` · `resource-exists` `address=stackit_network_interface.portal_1` — `stackit_network_interface.portal_1` exists in the STACKIT project (OpenTofu's state lists it).
- [ ] `TF/stackit_server.portal` · `resource-exists` `address=stackit_server.portal` — `stackit_server.portal` exists in the STACKIT project (OpenTofu's state lists it).AVAILABLE and PARTIAL
AVAILABLE means destroying the block undoes the step (4 steps here). PARTIAL means the same, but what was written to it since is lost (3 steps: the bucket, the database and the server). The 14 manual steps are undone by the person who carries them out.
Checks are existence checks
The seven after-checks confirm that a resource exists in the OpenTofu state. They do not test data, logins or traffic, so add your own.
Rollback rules to agree before the window
Decide the point of no return
Before the final sync you can undo everything. After clients write to STACKIT, a rollback means copying data back (practice).
Guard the database instance
STACKIT states that deleting a PostgreSQL Flex instance without instance protection causes immediate, permanent data loss with API v3. Turn protection on before you rely on destroy.
No in-place restore
PostgreSQL Flex restores by cloning a backup into a new instance, so clients have to be pointed at it. Plan this into any recovery step.
Manual steps need a written undo
For manual steps the plan does not know how to undo. The person who carries it out records how.
Keep the source until the hold ends
Do not delete Azure resources in the same window as the cutover (practice).
Questions about cutover and rollback
Does StackToIT run the cutover?
No. It writes files only. Each step is carried out by a person, by OpenTofu or by a script that a person runs.
Can I apply the draft in the cutover window?
Not as the run stands. It marks every OpenTofu step as not executable yet and 14 manual steps wait for people. Apply on a test project first.
Which tool moves the data?
The run leaves the mechanism open. The STACKIT documentation has a tutorial that copies a bucket with rclone, and the engine names pg_dump and pg_restore or logical replication for PostgreSQL.
How long should the hold period be?
Your recovery needs decide it. STACKIT documents PostgreSQL Flex backups with point-in-time recovery, so compare their retention with the hold you want.
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.