AZURE BLOB → STACKIT OBJECT STORAGE · TUTORIAL
Azure Blob Storage to STACKIT Object Storage
A storage account with two containers becomes two STACKIT buckets. This tutorial runs StackToIT on a small demo estate, shows the Terraform it writes and lists what you set by hand afterwards: versioning, lifecycle rules, a second-region copy and the switch from the Azure Storage SDK to an S3 client.
The demo input and the draft
A storage account with versioning, soft delete, geo-redundant replication, two private containers and one lifecycle rule, written for this page and assessed by StackToIT on 4 November 2026. Left: the input. Right: the resource blocks of the STACKIT Terraform the engine wrote; the review comments above each block in the file are left out here. The input blocks are not adjacent in main.tf, so each has its own pane, verbatim.
resource "azurerm_storage_account" "media" {
name = "stmediagwc01"
resource_group_name = azurerm_resource_group.media.name
location = azurerm_resource_group.media.location
account_kind = "StorageV2"
account_tier = "Standard"
account_replication_type = "GRS"
access_tier = "Hot"
min_tls_version = "TLS1_2"
allow_nested_items_to_be_public = false
blob_properties {
versioning_enabled = true
delete_retention_policy {
days = 14
}
container_delete_retention_policy {
days = 7
}
}
}
resource "azurerm_storage_container" "invoices" {
name = "invoices"
storage_account_id = azurerm_storage_account.media.id
container_access_type = "private"
}resource "azurerm_storage_management_policy" "media" {
storage_account_id = azurerm_storage_account.media.id
rule {
name = "archive-old-exports"
enabled = true
filters {
prefix_match = ["exports/"]
blob_types = ["blockBlob"]
}
actions {
base_blob {
tier_to_cool_after_days_since_modification_greater_than = 30
delete_after_days_since_modification_greater_than = 365
}
}
}
}resource "stackit_objectstorage_bucket" "media" {
project_id = var.project_id
name = "stmediagwc01-exports"
}
resource "stackit_objectstorage_bucket" "media_2" {
project_id = var.project_id
name = "stmediagwc01-invoices"
}One account, one bucket per container
Azure groups containers under a storage account. STACKIT Object Storage has buckets, and buckets cannot be nested. The run writes one bucket for each container and names it after the account and the container, here stmediagwc01-exports and stmediagwc01-invoices.
Only name and project
The bucket resource of the pinned STACKIT provider carries a name and an object-lock setting. The account kind, performance tier, access tier, replication, versioning and lifecycle rule are therefore not generated, and the file says so in a NOT CARRIED comment for each of them.
The class is REPLATFORM
Azure Blob is not S3-compatible: the API, the authentication and the upload protocol differ. The run classifies the account as REPLATFORM with MEDIUM confidence and asks you to find every application that uses it.
Run it
The command reads the Terraform of the source and writes the report, the draft and the execution package into the output folder. It makes no network request and changes nothing in either cloud. The summary lines below are copied from the console of this run.
stacktoit assess . ./out --offline --no-validateSource 5 resources · 1 unit · visibility: Complete
Migration 1 drafted (of 1 units the draft considered)
Target STACKIT Terraform generated
Attention 1 unit to review · 5 open requests (1 block the draft, marked in inputs-template.yaml)Five resources, one unit
The storage account, its two containers and the lifecycle policy count as one unit, because they all move into the same service. The draft contains two resource blocks, one for each container.
One request blocks the draft
The run asks for the STACKIT region first (eu01 or eu02). Until it is answered in the inputs file, the draft is a proposal that cannot be planned as written.
Which file answers which question
- terraform/storage.tf
- The two buckets, with a comment for every Azure setting the draft does not carry
- migration/data-movement.md
- The data-movement table: the unit is listed with the mechanism UNKNOWN until a person chooses one
- execution/manual/actions.md
- The manual steps with an owner role and a done-when condition for each
- assurance/critical-semantics.json
- The critical settings of the account and why each is still open
- review/inputs.yaml
- Design answers, starting with the target region
- review/decisions.yaml
- Review records for the settings of the account, one per owner role
What the draft does with each Azure setting
| Azure setting in the demo | What the run decided | Your action |
|---|---|---|
| account_replication_type = GRS | Not generated. STACKIT Object Storage has no managed cross-region replication; the run records the setting as UNSUPPORTED. | Decide whether the second copy is needed. If it is, schedule a sync job to a bucket in the second region. |
| versioning_enabled = true | Not generated: the bucket resource has no versioning setting. | Enable versioning through the S3 API once the bucket exists. It can later be suspended but not switched off. |
| delete_retention_policy, container_delete_retention_policy | Not generated. The run found no soft delete or point-in-time restore for STACKIT Object Storage. | Use versioning, and Object Lock where deletion must be prevented. |
| storage_management_policy (cool after 30 days, delete after 365) | Not generated: the bucket resource of the pinned provider has no lifecycle attribute, and STACKIT documents no storage tiers, so the move to cool after 30 days has no counterpart. | Set the 365-day deletion as an S3 lifecycle Expiration rule on the bucket (put-bucket-lifecycle-configuration, see the STACKIT how-to). Drop the tiering step, and check that no rule protected data you now keep. |
| access_tier = Hot, account_tier = Standard | Not generated; the account kind and tiers have no counterpart. | None, but note it in the architecture record. |
| Account name and container names | Carried into the bucket name. Bucket names are unique within a region. | Confirm the names against everything that refers to the old account. |
Read from the comments in terraform/storage.tf and the findings in assessment.json of this run.
Move the data
StackToIT never moves data: its data-movement file lists the unit and leaves the mechanism to a person. This is the usual order.
1. Create the buckets and credentials
Apply the reviewed draft in a test project. The run names credential resources among the targets of the account but writes only the buckets, so create the access key and secret key for the project yourself; STACKIT manages credentials at project level.
2. Enable versioning before the first copy
Run the versioning command from the STACKIT documentation on each bucket that had it in Azure, so that every later overwrite keeps the older version.
3. Copy the data
Use a tool that speaks both protocols. The commands below are an example with rclone; the run itself points at rclone or an Azure-to-S3 copy tool. Size, change rate and tolerated downtime decide between one copy at cutover and repeated syncs before it.
4. Compare, then switch the applications
Compare object counts and sizes per bucket, then change the applications from the Azure Storage SDK to an S3 SDK and from account keys, SAS URLs or Entra tokens to S3 access keys.
5. Keep the source until the check is done
Leave the Azure account untouched until the new buckets have served real traffic. As long as no application has written only to STACKIT, rollback is a configuration switch; after that, copy the new objects back first.
Commands for the copy
Practice, not StackToIT output. The first pane is the versioning command from the STACKIT documentation for the eu01 endpoint; the second is one way to copy and compare with rclone, with the demo names.
aws --endpoint-url https://object.storage.eu01.onstackit.cloud s3api put-bucket-versioning \
--bucket $BUCKET_NAME \
--versioning-configuration Status=Enabled# for example, with rclone (not run by StackToIT)
rclone config create azblob azureblob account=stmediagwc01 key="$AZURE_STORAGE_KEY"
rclone config create stackit s3 provider=Other \
endpoint=https://object.storage.eu01.onstackit.cloud \
access_key_id="$STACKIT_ACCESS_KEY" secret_access_key="$STACKIT_SECRET_KEY"
rclone sync azblob:invoices stackit:stmediagwc01-invoices
rclone sync azblob:exports stackit:stmediagwc01-exports
rclone check azblob:invoices stackit:stmediagwc01-invoices --size-onlyDecide before you apply
Region and endpoint
Each region has its own endpoint, https://object.storage.eu01.onstackit.cloud for eu01, and a bucket in eu01 is independent of one with the same name in eu02. Answer the region request first.
Addressing style
STACKIT supports virtual-hosted and path-style addressing. Check which one your S3 client uses and whether it accepts a custom endpoint.
History
Decide whether old versions and soft-deleted blobs must move. A plain sync of the current content does not make STACKIT hold the history Azure held.
Public containers
The demo has none. If yours has containers with public read access, the bucket needs an explicit access design, because the draft does not carry the access level.
Questions storage teams ask
Is STACKIT Object Storage S3-compatible?
Yes. The STACKIT documentation describes an S3-compatible API over HTTPS, so standard S3 tools work against it. Azure Blob Storage is not S3-compatible, which is why applications change their client and their credentials.
Does the draft create the access keys?
No. For this demo it writes the two buckets only. Credentials are managed at project level on STACKIT, so create them after the apply and give them to the applications at cutover.
What happens to the lifecycle rule and to soft delete?
Neither is generated, because the bucket resource has no such setting, and the run lists both as open settings. STACKIT documents S3 lifecycle rules for expiring objects and old versions, so the 365-day deletion can be set on the bucket through the S3 API; the move to a cooler tier has no counterpart. For protection against deletion, use versioning, and Object Lock where it must be prevented.
Can I keep geo-redundant replication?
Not as a managed setting. STACKIT Object Storage has no managed cross-region replication in the sources the run checked. If a second copy is required, a sync job to a bucket in the second region provides it.
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.