> ## 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: AWS to Azure

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

This quickstart keeps the AWS S3 API at the application boundary while Cloud Adapter stores object data in Azure Blob Storage.

![AWS API requests pass through Tensor9 Cloud Adapter to Azure services.](https://mintcdn.com/tensor9/ufP2gYsEkScmc1Bt/images/cloud-adapter-early-access/diagrams/cloud-adapter-quickstart-aws-to-azure-dark.svg?fit=max\&auto=format\&n=ufP2gYsEkScmc1Bt\&q=85\&s=f09e3e2636948d792204d1fa90196495)

## Start this route locally

Use the directed S3 to Blob Storage mapping in the shared startup steps:

```bash theme={null}
export T9_ORIGIN_SERVICE="aws::1.0.0::s3"
export T9_BACKEND_SERVICE="azure::1.0.0::blob-storage"
```

**1. Install or update the Tensor9 CLI**

Install the customer CLI with Homebrew, then confirm the binary is available:

```bash theme={null}
brew tap tensor9ine/tensor9
brew trust tensor9ine/tensor9
brew install tensor9
tensor9 --version
```

If `tensor9` is already installed, run `brew upgrade tensor9` instead of the install command.

**2. Authenticate with Tensor9**

To create a Tensor9 account and download an API key yourself, follow [Get a Tensor9 API key](https://docs.tensor9.com/byoc/getting-started/api-key.md).

A Tensor9 API key is required. Use the key issued during onboarding, or email [hello@tensor9.com](mailto:hello@tensor9.com) to request one for your organization. Do not share your account or key with another customer or organization.

If your secret manager has already supplied `T9_API_KEY`, skip the prompt. Otherwise, enter your key at a hidden prompt in the terminal where you will run `tensor9`:

> [tab] Bash
>
> ```bash theme={null}
> set +x
> IFS= read -r -s -p 'Tensor9 API key: ' T9_API_KEY
> printf '\n'
> export T9_API_KEY
> ```

> [tab] Zsh
>
> ```zsh theme={null}
> set +x
> IFS= read -r -s 'T9_API_KEY?Tensor9 API key: '
> printf '\n'
> export T9_API_KEY
> ```

Check that the variable is set without printing it, then verify your Tensor9 identity:

```bash theme={null}
: "${T9_API_KEY:?Set T9_API_KEY before continuing}"
tensor9 whoami
```

Confirm that the reported identity belongs to the intended customer account. Do not continue if authentication fails or the account is wrong. While `T9_API_KEY` is set, `tensor9` commands in this terminal use the key instead of any controller profile, so use a separate terminal for this work and run `unset T9_API_KEY` when you finish. Keep shell tracing disabled while using the key. Do not paste the key into commands, shell profiles, source files, screenshots or support messages.

See [Install and Authenticate](https://docs.tensor9.com/cloud-adapter-early-access/getting-started/install-and-authenticate.md) for the planned license lifecycle, entitlements and credential boundaries.

**3. Confirm the directed service mapping**

Confirm that you exported the canonical origin and backend service names supplied by this quickstart:

```bash theme={null}
: "${T9_ORIGIN_SERVICE:?set the origin service name shown above}"
: "${T9_BACKEND_SERVICE:?set the backend service name shown above}"
printf 'Origin:  %s\nBackend: %s\n' \
  "$T9_ORIGIN_SERVICE" "$T9_BACKEND_SERVICE"
```

Then inspect the mapping before starting a process:

```bash theme={null}
tensor9 explain \
  -origin "$T9_ORIGIN_SERVICE" \
  -target "$T9_BACKEND_SERVICE" \
  -fmt Human
```

Read the supported operations and limitations for that direction. A similarly named service in the target cloud is not enough. If no directed profile exists, choose another mapping before continuing.

**4. Prepare target-cloud access**

Authenticate with the target cloud using its standard credential chain. The adapter uses that target identity when it calls the backend service.

Keep credentials in your shell, workload identity, or local credential store. Do not put secrets in the command line, source code, or screenshots.

**5. Start the service adapter**

Run one service adapter as a foreground process:

```bash theme={null}
tensor9 adapt svc run \
  --origin "$T9_ORIGIN_SERVICE" \
  --backend "$T9_BACKEND_SERVICE"
```

Leave this terminal open. This is the current foreground launcher, not the pending Docker launcher for [local development mode](https://docs.tensor9.com/cloud-adapter-early-access/deployment/single-binary.md). It calls your actual target-cloud services; it is separate from the in-memory emulator. Acquisition and license renewal require Tensor9 authentication. Keep the endpoint local to your test.

**6. Copy the listening endpoint**

When the command reports its listening endpoint, copy that exact value into a second terminal:

```bash theme={null}
export T9_CLOUD_ADAPTER_ENDPOINT="<endpoint printed by tensor9>"
```

Keep the endpoint local to the test unless you have deliberately configured network access and authentication for another machine.

**7. Run one bounded request**

Continue with this page's client or tool instructions. Point only the service under test at `T9_CLOUD_ADAPTER_ENDPOINT`, then perform one operation whose target effect you can verify independently.

Check both sides: read the origin-shaped response and inspect the native target resource. A successful client response alone does not prove that the target state is correct.

**8. Stop the local adapter**

Return to the first terminal and press **Control-C**. Confirm the process exits before deleting the test resource with the target cloud's native client.

If the request failed, preserve the request ID, adapter endpoint, operation name, target request ID, and any `x-t9-explain-*` receipt headers before stopping the process.

## Outcome

You will upload one S3 object through Cloud Adapter, read it back through S3, verify the corresponding Azure blob, test a missing-object response, and delete the object.

Review [S3 on Azure](https://docs.tensor9.com/cloud-adapter-early-access/service-catalog/aws/databases-storage/s3.md#on-azure) first. Common object CRUD is supported. Azure's flat listing does not reproduce every S3 delimiter and `CommonPrefixes` behavior. Copy downloads and re-uploads the object, multi-delete becomes multiple backend calls, and one `PutObject` is limited to 5,000 MiB in this profile. Bucket policy, ACL, retention, and legal-hold behavior remain outside the object endpoint.

## Prerequisites

* an installed AWS-origin Cloud Adapter endpoint;
* an S3 to Blob Storage service adapter;
* an origin-side AWS test identity;
* an Azure runtime identity for the adapter and a separate read-only verification identity;
* an existing test storage account and container;
* AWS CLI v2 and Azure CLI.

## Set test values

```bash theme={null}
: "${T9_CLOUD_ADAPTER_ENDPOINT:?start the local adapter and copy its endpoint first}"
export AWS_PROFILE="adapter-test"
export AWS_REGION="us-east-1"
export AWS_REQUEST_CHECKSUM_CALCULATION="WHEN_REQUIRED"
export ORIGIN_BUCKET="adapter-smoke-test"
export AZURE_STORAGE_ACCOUNT="adaptedsmoke"
export AZURE_CONTAINER="adapter-smoke-test"
export TEST_KEY="quickstart/aws-azure-$(date +%s).txt"
printf 'hello from S3 to Blob Storage\n' > /tmp/cloud-adapter-smoke.txt
```

`AWS_REQUEST_CHECKSUM_CALCULATION=WHEN_REQUIRED` keeps this smoke test on the required S3 checksum path. Validate optional flexible-checksum behavior separately if your application enables it.

The commands below use an explicit `--endpoint-url`. To route every S3 client in the process instead, set `AWS_ENDPOINT_URL_S3="$T9_CLOUD_ADAPTER_ENDPOINT"` and omit the command-level override.

## Verify the native target

```bash theme={null}
az storage container show \
  --account-name "$AZURE_STORAGE_ACCOUNT" \
  --name "$AZURE_CONTAINER" \
  --auth-mode login
```

If this fails, repair the verification identity or target selection before testing adaptation.

## Write through S3

```bash theme={null}
aws s3api put-object \
  --bucket "$ORIGIN_BUCKET" \
  --key "$TEST_KEY" \
  --body /tmp/cloud-adapter-smoke.txt \
  --content-type text/plain \
  --metadata quickstart=aws-to-azure \
  --endpoint-url "$T9_CLOUD_ADAPTER_ENDPOINT" \
  --profile "$AWS_PROFILE" \
  --region "$AWS_REGION"
```

Read it back through the origin API:

```bash theme={null}
aws s3api head-object \
  --bucket "$ORIGIN_BUCKET" --key "$TEST_KEY" \
  --endpoint-url "$T9_CLOUD_ADAPTER_ENDPOINT" --profile "$AWS_PROFILE" --region "$AWS_REGION"

aws s3api get-object \
  --bucket "$ORIGIN_BUCKET" --key "$TEST_KEY" \
  --endpoint-url "$T9_CLOUD_ADAPTER_ENDPOINT" --profile "$AWS_PROFILE" --region "$AWS_REGION" \
  /tmp/cloud-adapter-origin.txt
```

## Verify the Azure blob

```bash theme={null}
az storage blob show \
  --account-name "$AZURE_STORAGE_ACCOUNT" \
  --container-name "$AZURE_CONTAINER" \
  --name "$TEST_KEY" \
  --auth-mode login

az storage blob download \
  --account-name "$AZURE_STORAGE_ACCOUNT" \
  --container-name "$AZURE_CONTAINER" \
  --name "$TEST_KEY" \
  --file /tmp/cloud-adapter-target.txt \
  --auth-mode login \
  --overwrite

cmp /tmp/cloud-adapter-smoke.txt /tmp/cloud-adapter-origin.txt
cmp /tmp/cloud-adapter-smoke.txt /tmp/cloud-adapter-target.txt
```

Check the content type and metadata in both views. Do not assume S3 version IDs, delete markers, ETags, or account-level settings have identical Azure representations.

## Verify the error path

Request a missing key through S3 and retain the command timestamp, AWS error code, and message. The normal AWS CLI output does not expose arbitrary response headers; use an SDK with structured, redacted response metadata when a support workflow requires them. A target-side authorization failure should not be mistaken for not found.

```bash theme={null}
aws s3api get-object \
  --bucket "$ORIGIN_BUCKET" --key "quickstart/missing-object" \
  --endpoint-url "$T9_CLOUD_ADAPTER_ENDPOINT" --profile "$AWS_PROFILE" --region "$AWS_REGION" \
  /tmp/cloud-adapter-missing.txt
```

S3 can return permission denied instead of not found when the caller lacks permission to establish that the object is missing.

## Inspect an explanation

Confirm the operation in the [S3 to Azure service profile](https://docs.tensor9.com/cloud-adapter-early-access/service-catalog/aws/databases-storage/s3.md#on-azure), then use [Understanding Behavior with Explain](https://docs.tensor9.com/cloud-adapter-early-access/debugging/explain.md) to inspect the selected mapping or a covered request. Start with a hypothetical explanation when you do not intend to change the blob. The shorthand `x-t9-explain: true` is an executing mode, so adding it to a repeated upload can write the object again.

Compare the explanation with both the S3-shaped response and the native Azure blob state. The [worked adapter investigations](https://docs.tensor9.com/cloud-adapter-early-access/debugging/worked-examples.md) show the same evidence pattern. If the receipt is absent or the report is incomplete, that does not establish that no target action occurred.

## Clean up

```bash theme={null}
aws s3api delete-object \
  --bucket "$ORIGIN_BUCKET" --key "$TEST_KEY" \
  --endpoint-url "$T9_CLOUD_ADAPTER_ENDPOINT" --profile "$AWS_PROFILE" --region "$AWS_REGION"

az storage blob show \
  --account-name "$AZURE_STORAGE_ACCOUNT" \
  --container-name "$AZURE_CONTAINER" \
  --name "$TEST_KEY" \
  --auth-mode login
```

The native check should show that the current blob 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. Keep container deletion separate from object cleanup.

## Production readiness

Test listing prefixes and pagination, copy sizes, batch-delete failure handling, metadata, conditional requests, retries, and any versioning behavior the application depends on. Plan existing-object migration separately. Record which Azure account settings are shared across adapted buckets, and establish an uncertain-write check before enabling automatic retries.

Use [Debugging Your Adapters](https://docs.tensor9.com/cloud-adapter-early-access/debugging/overview.md) when the S3 response and Azure state disagree.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.