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.

Input: storage account and containermain.tf
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"
}
Input: azurerm_storage_management_policy.mediamain.tf
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
      }
    }
  }
}
STACKIT Terraform by StackToITterraform/storage.tf
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.

Commandterminal
stacktoit assess . ./out --offline --no-validate
Console summaryconsole
Source        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 demoWhat the run decidedYour action
account_replication_type = GRSNot 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 = trueNot 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_policyNot 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 = StandardNot generated; the account kind and tiers have no counterpart.None, but note it in the architecture record.
Account name and container namesCarried 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. 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. 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. 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. 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. 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.

Enable versioning (STACKIT documentation)terminal
aws --endpoint-url https://object.storage.eu01.onstackit.cloud s3api put-bucket-versioning \
  --bucket $BUCKET_NAME \
  --versioning-configuration Status=Enabled
Copy and compare (example)terminal
# 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-only

Decide 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.