Skip to content

feat: add Azure Blob Storage channel support - #2615

Open
tenzinplatter wants to merge 104 commits into
conda:mainfrom
greenroom-robotics:feat/azure-blob-channel
Open

feat: add Azure Blob Storage channel support#2615
tenzinplatter wants to merge 104 commits into
conda:mainfrom
greenroom-robotics:feat/azure-blob-channel

Conversation

@tenzinplatter

@tenzinplatter tenzinplatter commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Description

Adds Azure Blob Storage as a first-class conda channel backend across rattler,
addressed through az:// URLs — the Azure counterpart to the existing S3 (s3://)
and GCS support. Channels hosted in a blob container can be fetched, solved,
indexed, and uploaded to
with no separate endpoint/config block.

Closes #2285.

URL model

A channel is addressed by its full blob host:

az://<account>.blob.core.windows.net/<container>/<prefix>

The account, endpoint, container and root prefix are all derived from the URL, so
the channel is spelled the same way it appears on the wire. Sovereign clouds and
the Azurite emulator work automatically because the endpoint lives in the host —
no allow-list of accounts or endpoints is baked in.

What's included

  • rattler_azure (new crate): az:// URL parsing into typed
    AzureCoordinates { account, container }, AzureCredentials
    (account key / SAS token), and optional az login → short-lived
    user-delegation SAS minting for write paths (behind the clap feature).
  • rattler_networking: AzureMiddleware — rewrites az://https://
    (a plain scheme swap) and signs via reqsign's DefaultCredentialProvider
    chain (env vars → workload/managed identity → az login). Public/anonymous
    containers work with zero credentials; a configured-but-broken credential is
    a hard error rather than a silent anonymous downgrade.
  • rattler_repodata_gateway: accepts the az:// channel scheme for
    (sharded) repodata fetch.
  • rattler_index: azblob indexing backend (opendal), CLI subcommand.
  • rattler_upload: az:// upload path with concurrent block upload.
  • rattler-bin: registers AzureMiddleware behind an azure feature.
  • py-rattler: AzureMiddleware binding, included in the default client stack.

Authentication

Source How
Account key --account-key / AZURE_STORAGE_KEY
SAS token --sas-token / AZURE_STORAGE_SAS_TOKEN
az login --azure-cli mints a short-lived user-delegation SAS (write paths)
Ambient (read) reqsign chain: env → managed/workload identity → az login

Security / trust model

The URL host is trusted verbatim and becomes the request target, so az://
userinfo is rejected. This is a pure safety gate that removes no
functionality: Azure Blob has no user:pass@ auth mode — credentials come from
Shared Key headers, SAS query strings, or AAD bearer tokens, and the storage
account is the host's first label (account.blob.core.windows.net), never
userinfo. So userinfo in an az:// URL can do exactly one thing: hide the real
host — az://trusted.blob.core.windows.net@attacker.example/… targets
attacker.example. Rejecting it closes that host-spoofing vector while leaving
every legitimate URL untouched. (Scoped to az://; https:// channels that
legitimately use Basic-auth userinfo are unaffected.)

On Windows the Azure CLI is resolved via which and invoked directly rather than
through cmd /C, avoiding a metacharacter-injection surface.

Known limitations (documented in-code)

  • opendal 0.57's azblob backend honours if_not_exists only on the single-shot
    Put Blob path (≤ 10 MiB), not the multi-block path used for larger packages,
    so the upload overwrite guard does an explicit pre-write stat to cover all
    sizes (with a small, documented stat→write TOCTOU window).
  • A user-delegation SAS minted against a flat container is container-scoped,
    not prefix-scoped; a short TTL bounds the blast radius.

How Has This Been Tested?

  • Unit tests across rattler_azure, rattler_networking (URL rewrite, userinfo
    rejection, credential-source detection, unsigned fallback, SAS pass-through),
    and rattler_upload.
  • Azurite-backed integration tests for the index path.
  • Live-Azure gated tests (az login AAD fetch) against a real account.
  • py-rattler: unit test asserting AzureMiddleware is in the default client stack.
  • Full workspace cargo build, cargo clippy -D warnings, cargo fmt, and
    cargo nextest all green.
  • Running in production on our internal build farm, where it indexes and
    serves conda packages from an Azure Blob-hosted channel.

Platform caveat: all testing has been on Linux only — I have no access
to Windows or macOS machines. In particular the Windows Azure CLI handling (the
which-based az/az.cmd resolution) is written but has not been exercised on
a real Windows host; a review pass or CI on those platforms would be welcome.

AI Disclosure

  • This PR contains AI-generated content.
    • I have tested any AI-generated content in my PR.
    • I take responsibility for any AI-generated content in my PR.

Tools: Claude Code (Claude Opus 4.8)

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added sufficient tests to cover my changes.

tenzinplatter and others added 30 commits June 12, 2026 09:35
* feat(rattler_index): add Azure Blob backend

* fix(rattler_index): disable preconditions on azure (opendal azblob lacks conditional writes)

* fix(rattler_index): re-index packages whose blob size changed
* fix(rattler_index): re-index packages whose blob size changed

* fix: move to md5 checks instead of size

* feat(rattler_index): add Azure Blob backend

* fix(rattler_index): disable preconditions on azure (opendal azblob lacks conditional writes)

* fix(rattler_index): base64-decode backend md5 before comparing

* test(rattler_index): probe azure content_md5 on list

* chore: lint
@tenzinplatter

Copy link
Copy Markdown
Contributor Author

apache/opendal#7990
^azure changes in opendal

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Azure Blob Middleware to rattler_networking

2 participants