For AI agents: the documentation index is at /docs/interbox/llms.txt. A Markdown version of this page is available at /docs/interbox/concepts/reading-files/azure-blob-storage.md or by requesting it with the Accept: text/markdown header.
Interbox Docs

Azure Blob Storage

Use an Azure feed when the sending system puts files into an Azure Blob Storage container.

When Interbox reads a file

On an account with a hierarchical namespace (Data Lake Storage Gen2), a file is visible while the sending system is still writing it. Interbox treats every account the same way: it reads a file once its size and modification time match across two polls and it is at least minFileAge old; an empty file waits at least five minutes. A delivery's marker file follows the same rule. After a restart every file waits one poll, since Interbox has no earlier listing to compare.

Set minFileAge when a sending system can pause mid-file for longer than pollInterval.

Setup

Interbox needs the Storage Blob Data Reader role on the container or the account, and no other grant.

credentialsInterbox usesDefault
"ambient"the identity Interbox itself runs as: a workload identity on AKS, else a managed identity (AZURE_CLIENT_ID names a user-assigned one). Interbox tries nothing else: no client secret in the environment and no developer loginyes
"key"the account key in AZURE_STORAGE_KEY

Prefer "ambient": no key is stored anywhere.

Interbox refuses credentials: "ambient" together with endpoint, so Azure identity tokens never go to a host named in the configuration.

Workload identity on AKS
  1. Enable the OIDC issuer and workload identity on the cluster:

    az aks update --resource-group example-rg --name example-aks \
      --enable-oidc-issuer --enable-workload-identity
    
  2. Create a user-assigned managed identity and let Interbox's service account use it:

    az identity create --resource-group example-rg --name interbox-reader
    az identity federated-credential create --resource-group example-rg \
      --identity-name interbox-reader --name interbox \
      --issuer "$(az aks show -g example-rg -n example-aks --query oidcIssuerProfile.issuerUrl -o tsv)" \
      --subject system:serviceaccount:interbox:interbox
    
  3. Give the identity read access to the container:

    az role assignment create --role "Storage Blob Data Reader" \
      --assignee "$(az identity show -g example-rg -n interbox-reader --query clientId -o tsv)" \
      --scope "/subscriptions/<subscription-id>/resourceGroups/example-rg/providers/Microsoft.Storage/storageAccounts/examplestorage/blobServices/default/containers/inbound"
    
  4. Annotate the service account with the identity's client ID, and label the pod:

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: interbox
      namespace: interbox
      annotations:
        azure.workload.identity/client-id: "<client-id>"
    
    metadata:
      labels:
        azure.workload.identity/use: "true"
    spec:
      serviceAccountName: interbox
    

A missing identity or permission fails each poll with an error that says what is missing. Interbox skips no file over it, and reads as soon as the access is fixed.

Configuration

import { env } from "@health-samurai/interbox";
import { aidbox, fhirItems, skipUnchanged } from "@health-samurai/interbox/aidbox";
import { pipeline, postgresStore } from "@health-samurai/interbox/chain";
import type { Bundle, Resource } from "@health-samurai/interbox/fhir/4.0.1";
import { deliveryEnd, fileDropSource, ndjson, records, azure, unpack, type NdjsonRecord } from "@health-samurai/interbox/files";

const toAidbox = aidbox({
  url: env("AIDBOX_URL"),
  auth: { kind: "basic", user: env("AIDBOX_CLIENT_ID", "root"), password: env("AIDBOX_CLIENT_SECRET") },
});

function bundleToResources(row: NdjsonRecord): Resource[] {
  const bundle = row as unknown as Bundle;
  return (bundle.entry ?? []).flatMap((entry) => (entry.resource === undefined ? [] : [entry.resource]));
}

pipeline("clinical")
  .source(
    fileDropSource({
      transport: azure({ account: "examplestorage", container: "inbound", prefix: "clinical" }),
    }),
  )
  .step(unpack())
  .step(ndjson())
  .store(postgresStore({ codec: "json" }))
  .step(deliveryEnd())
  .step(records(bundleToResources))
  .step(fhirItems())
  .step(skipUnchanged())
  .sender(toAidbox);
FieldRequiredDefaultSets
accountyesthe storage account name
containeryes
prefixyesthe feed; "" for the whole container
endpointanother URL, such as an emulator's; unset means https://<account>.blob.core.windows.net
credentials"ambient"see Setup
timeout30sthe longest Interbox waits for any one answer
minFileAge0show old a file must be before Interbox reads it

To try a feed locally, run Azurite, point endpoint at its blob service, and set credentials: "key" with Azurite's account key in AZURE_STORAGE_KEY.

Files Interbox cannot read

  • Archived files. A blob in the Archive tier cannot be read until someone moves it back to the Hot or Cool tier. Interbox skips it and logs why.
  • Append and page blobs. Interbox reads block blobs, which every upload tool writes. An append or page blob can still be growing when it is listed, so Interbox skips it and logs its type. A marker file that is an append or page blob rejects its folder.
  • Blobs encrypted with your own key. Interbox never has a customer-provided key, so it skips a blob encrypted with one and logs why.

Network

HTTPS 443 to <account>.blob.core.windows.net or to endpoint. With "ambient", also to the Azure identity endpoint: instance metadata or Microsoft Entra ID. See Network Access for egress rules.

Deliveries, file formats and pipeline settings shared by every storage are on Reading Files from Storage.

Last updated: