> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tensor9.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart: Azure to AWS

> Send Azure Blob Storage requests through Cloud Adapter to Amazon S3.

Keep the Azure Blob Storage API in your application while Cloud Adapter stores block blobs as objects in Amazon S3.

<Frame>
  <img className="block dark:hidden" src="https://mintcdn.com/tensor9/3qwgIru3kCfHriJC/images/diagrams/cloud-adapter-quickstart-azure-to-aws-dark.svg?fit=max&auto=format&n=3qwgIru3kCfHriJC&q=85&s=be5d8683c6b823ccc89da9e260e37670" alt="Azure API requests pass through Tensor9 Cloud Adapter to AWS services." width="1100" height="360" data-path="images/diagrams/cloud-adapter-quickstart-azure-to-aws-dark.svg" />

  <img className="hidden dark:block" src="https://mintcdn.com/tensor9/3qwgIru3kCfHriJC/images/diagrams/cloud-adapter-quickstart-azure-to-aws-light.svg?fit=max&auto=format&n=3qwgIru3kCfHriJC&q=85&s=1d0e9622c0a33950aae010c5fdb904d1" alt="Azure API requests pass through Tensor9 Cloud Adapter to AWS services." width="1100" height="360" data-path="images/diagrams/cloud-adapter-quickstart-azure-to-aws-light.svg" />
</Frame>

## What this route preserves

The [Blob Storage to AWS profile](/cloud-adapter/service-catalog/azure/databases-storage/blob-storage#on-aws) supports the block-blob lifecycle. Cloud Adapter retains origin account and container identity and keeps lease state so Azure callers see coherent lease behavior.

Append blobs, page blobs, and index-tag queries are rejected. Every lease-dependent writer must use Cloud Adapter because a direct S3 writer bypasses adapter-held lease state. Existing objects, metadata, and leases are not copied automatically.

## Prerequisites

* an installed Azure-origin endpoint with a Blob Storage to S3 service adapter;
* an origin-side Azure Storage credential accepted by the endpoint;
* an AWS runtime identity with access to one test bucket;
* a separate read-only AWS profile for native verification;
* Python 3 with `azure-storage-blob` and AWS CLI v2.

## Set values

```bash theme={null}
export ADAPTER_BLOB_ENDPOINT="https://adapter.example.test/origin-account"
export ORIGIN_ACCOUNT_NAME="origin-account"
export ORIGIN_ACCOUNT_KEY="use-your-test-secret-source"
export ORIGIN_CONTAINER="adapter-smoke-test"
export TARGET_BUCKET="adapter-smoke-test-aws"
export AWS_VERIFY_PROFILE="aws-target-verify"
export AWS_TARGET_REGION="us-east-1"
export TEST_BLOB="quickstart/azure-aws-$(date +%s).txt"
```

Keep the account key in a secret store or ephemeral test environment. Do not commit it or include it in diagnostics.

The endpoint shape and origin authentication in this sample are deployment-specific placeholders. Use the exact account URL and caller credential mode supplied by your Cloud Adapter deployment. Target AWS credentials remain adapter-owned.

## Upload and read through the Azure API

```python theme={null}
import os
from azure.core.credentials import AzureNamedKeyCredential
from azure.storage.blob import BlobServiceClient, ContentSettings

service = BlobServiceClient(
    account_url=os.environ["ADAPTER_BLOB_ENDPOINT"],
    credential=AzureNamedKeyCredential(
        os.environ["ORIGIN_ACCOUNT_NAME"],
        os.environ["ORIGIN_ACCOUNT_KEY"],
    ),
)
container = service.get_container_client(os.environ["ORIGIN_CONTAINER"])
blob = container.get_blob_client(os.environ["TEST_BLOB"])
expected = b"hello from Blob Storage to S3\n"

blob.upload_blob(
    expected,
    overwrite=True,
    content_settings=ContentSettings(content_type="text/plain"),
)
properties = blob.get_blob_properties()
actual = blob.download_blob().readall()
assert actual == expected
print({"etag": properties.etag, "size": properties.size})
```

Use a unique blob name. `overwrite=True` is safe here only because the test owns that exact key.

## Verify the S3 object

```bash theme={null}
aws s3api head-object \
  --bucket "$TARGET_BUCKET" \
  --key "$TEST_BLOB" \
  --profile "$AWS_VERIFY_PROFILE" \
  --region "$AWS_TARGET_REGION"

aws s3api get-object \
  --bucket "$TARGET_BUCKET" \
  --key "$TEST_BLOB" \
  --profile "$AWS_VERIFY_PROFILE" \
  --region "$AWS_TARGET_REGION" \
  /tmp/cloud-adapter-target.txt

printf 'hello from Blob Storage to S3\n' | cmp - /tmp/cloud-adapter-target.txt
```

Compare content type and bytes. Azure ETags and S3 object identifiers are adapted representations, not portable IDs to store interchangeably.

## Exercise a missing blob and a lease

Request a missing blob through the Azure client and retain the `RequestId`, HTTP status, Azure error code, and diagnostic headers. Then, if your workload uses leases, acquire and release a short lease through Cloud Adapter. Do not modify the leased object directly through S3 during the test; that path bypasses adapter lease enforcement.

## Clean up

Delete the test blob through the Azure API:

```python theme={null}
blob.delete_blob()
```

Confirm that the current target object is no longer readable. Versioned or soft-delete-enabled targets can retain prior versions or recovery state; use an unversioned disposable target for this quickstart or remove the created version explicitly. Container and bucket cleanup are separate decisions.

## Before production

Inventory block types, conditions, ranges, metadata, leases, pagination, retries, and concurrency. Ensure every writer uses the same adapter boundary when leases matter. Plan object and metadata migration separately, and test uncertain writes before enabling retries.

Use [Testing Your Adapters](/cloud-adapter/local-testing/testing-your-adapters) to preserve this lifecycle as a regression test.
