>_STRYKE-AZURE
The cloud, one stryke pipe away. Azure client for stryke — Blob Storage, Storage Queues, Cosmos DB, Key Vault Secrets and Keys, Entra identity, plus an Azure Resource Manager management plane: Virtual Machines, Storage-account management, Service Bus, Monitor, Container Instances / AKS, Resource Groups, and Subscriptions. An opt-in package, kept out of the stryke core binary so the daily-driver install stays slim. The Azure SDK pulls in tokio, hyper, rustls, and reqwest — far too heavy to bake into stryke core.
It holds one shared tokio runtime and one Entra credential (DeveloperToolsCredential — the Azure CLI / azd chain), reused across every service client. No per-call fork, no per-call credential rebuild. The typed data-plane clients come from the GA Azure SDK for Rust; the management plane reaches Azure Resource Manager over REST using the same shared credential and the same azure_core HTTP stack — one auth path, one runtime, one HTTP client.
Install
# build the cdylib, install as a stryke package cd ~/projects/stryke-azure cargo build --release s pkg install -g . # one-liner make install # sign in first (DeveloperToolsCredential uses the az / azd chain) az login
The release build produces target/release/libstryke_azure.{dylib,so}; s pkg install -g . places it in ~/.stryke/store/azure@<ver>/. The cdylib is dlopened in-process on first use Azure.
Service map
stryke-azure mirrors the surface of stryke-aws, mapped onto Azure's GA Rust SDK.
| AWS service | Azure service / backing crate |
|---|---|
| S3 | Blob Storage — azure_storage_blob |
| SQS | Storage Queues — azure_storage_queue |
| DynamoDB | Cosmos DB (NoSQL) — azure_data_cosmos (preview) |
| Secrets Manager / SSM Parameter Store | Key Vault Secrets — azure_security_keyvault_secrets |
| KMS | Key Vault Keys — azure_security_keyvault_keys |
| STS | Entra identity token — azure_identity |
| EC2 | Virtual Machines — ARM REST |
| ECS / EKS | Container Instances / AKS — ARM REST |
| SNS / SQS (enterprise) | Service Bus — ARM + data-plane REST |
| CloudWatch | Azure Monitor metrics — ARM REST |
| (account mgmt) | Storage account management — ARM REST |
| (resource mgmt) | Resource Groups — ARM REST |
The typed data-plane services (Blob, Queue, Cosmos, Secrets, Keys, identity) come from the GA Azure SDK for Rust. The management plane has no GA typed Rust SDK crate, so those ops reach Azure Resource Manager over REST — using the same shared credential and the same azure_core HTTP client the typed clients use under the hood.
Usage — data plane
use Azure
use Azure::Blob
use Azure::Cosmos
use Azure::Queue
use Azure::Secrets
use Azure::Keys
# Connectivity probe (Entra token; the token value is never returned).
val $tok = Azure::identity_token()
p "expires: $tok->{expires_on}"
# Blob Storage — az://container/blob URIs.
Azure::Blob::create_container("data", account => "mystorage")
val @containers = Azure::Blob::containers(account => "mystorage")
Azure::Blob::put("az://data/hello.txt", data => "hi", account => "mystorage")
val $body = Azure::Blob::get("az://data/hello.txt", account => "mystorage")
Azure::Blob::delete_container("data", account => "mystorage")
# Storage Queues.
Azure::Queue::create("jobs", account => "mystorage")
Azure::Queue::send("jobs", "payload", account => "mystorage")
val @msgs = Azure::Queue::receive("jobs", max => 10, account => "mystorage")
Azure::Queue::drop("jobs", account => "mystorage") # delete the whole queue
# Cosmos DB (single-partition).
Azure::Cosmos::create_database("appdb", account => "mycosmos")
Azure::Cosmos::create_container("appdb", "users", "/tenant", account => "mycosmos")
Azure::Cosmos::put("appdb", "users", "acme",
{ id => "u1", name => "ada", tier => "gold" })
val $u = Azure::Cosmos::get("appdb", "users", "acme", "u1")
# Key Vault Secrets.
val $pw = Azure::Secrets::get("db-password", vault => "my-kv")
val @vers = Azure::Secrets::versions("db-password", vault => "my-kv")
# Key Vault Keys — RSA encrypt/decrypt (KMS analog) + list/get.
val $enc = Azure::Keys::encrypt("wrap-key", "secret data", vault => "my-kv")
val $clear = Azure::Keys::decrypt("wrap-key", $version, $enc->{ciphertext}, vault => "my-kv")
val @keys = Azure::Keys::ls(vault => "my-kv")
val $jwk = Azure::Keys::get("wrap-key", vault => "my-kv")->{jwk}
Usage — management plane (Azure Resource Manager)
These take a subscription from the subscription => opt or AZURE_SUBSCRIPTION_ID; scoped ops add resource_group => "<rg>". The management plane reaches ARM over REST on the shared credential and HTTP stack.
use Azure::ResourceGroups
use Azure::Compute
use Azure::Storage
use Azure::ServiceBus
use Azure::Monitor
use Azure::Containers
use Azure::Subscriptions
# Subscriptions + regions — tenant-scoped discovery (no subscription opt for ls).
val @subs = Azure::Subscriptions::ls()
val @regions = Azure::Subscriptions::locations(subscription => $sub)
# Resource Groups + provider-agnostic inventory.
val @rgs = Azure::ResourceGroups::ls(subscription => $sub)
Azure::ResourceGroups::create("app-rg", "eastus", subscription => $sub)
val @stores = Azure::ResourceGroups::resources(subscription => $sub,
filter => "resourceType eq 'Microsoft.Storage/storageAccounts'")
# Virtual Machines — list, get, power actions (long-running), live state + SKUs.
val @vms = Azure::Compute::ls(subscription => $sub, resource_group => "app-rg")
Azure::Compute::start("web1", subscription => $sub, resource_group => "app-rg")
val $st = Azure::Compute::status("web1", subscription => $sub, resource_group => "app-rg")
p "power: $st->{power_state}" # running / stopped / deallocated
val @sizes = Azure::Compute::skus(subscription => $sub, location => "eastus")
# Storage account management (distinct from data-plane Blob/Queue).
val @accts = Azure::Storage::ls(subscription => $sub)
val $keys = Azure::Storage::keys("mystorage", subscription => $sub, resource_group => "app-rg")
# Service Bus — queues/topics/namespaces listing (mgmt) + send/receive (data plane).
val @queues = Azure::ServiceBus::queues("myns", subscription => $sub, resource_group => "app-rg")
val @topics = Azure::ServiceBus::topics("myns", subscription => $sub, resource_group => "app-rg")
val @namespaces = Azure::ServiceBus::namespaces(subscription => $sub)
Azure::ServiceBus::send("myns", "orders", "payload")
val $msg = Azure::ServiceBus::receive("myns", "orders")
# Monitor — metrics for any resource by its ARM id.
val $m = Azure::Monitor::metrics($vm_resource_id, metrics => "Percentage CPU")
# Container Instances + AKS (incl. live node pools).
val @groups = Azure::Containers::groups(subscription => $sub)
val @clusters = Azure::Containers::clusters(subscription => $sub)
val @pools = Azure::Containers::node_pools("mycluster", subscription => $sub, resource_group => "app-rg")
Pure helpers (no Azure)
These open no client — credential-free string parsing, building, and validation usable from any pipeline:
Azure::parse_resource_id($id) # /subscriptions/.../providers/... → { subscription, resource_group, provider, types, resource_type, name }
Azure::resource_id_parent($id) # RBAC-scope "dirname" → { id, parent, has_parent }
Azure::build_resource_id(%opts) # inverse of parse_resource_id (canonical ARM casing)
Azure::parse_connection_string($cs) # Key=Value;... → { pairs => { Key => Value } }
Azure::build_connection_string(%pairs) # inverse of parse_connection_string (byte-identical round-trip)
Azure::redact_connection_string($cs) # mask AccountKey / SharedAccessSignature → { redacted, masked_count }
Azure::parse_blob_uri($uri) # https://<acct>.blob.core.windows.net/<container>/<blob> → { account, service, host, container, blob }
Azure::build_blob_uri(%opts) # inverse of parse_blob_uri
Azure::storage_endpoint(%opts) # account/service/cloud → { endpoint, url, suffix, … } (public/china/usgov)
Azure::parse_storage_endpoint($endpoint) # inverse: host/URL → { endpoint, account, service, cloud, suffix, url }
Azure::valid_storage_account_name($name) # 3-24 lowercase alphanumerics
Azure::valid_container_name($name) # Blob container rules
Azure::valid_blob_name($name) # 1-1024 chars, ≤254 path segments, no trailing dot/slash
Azure::valid_keyvault_secret_name($name) # 1-127 chars, alphanumeric + hyphens
Azure::valid_queue_name($name) # Queue DNS-label grammar
Azure::valid_table_name($name) # ^[A-Za-z][A-Za-z0-9]{2,62}$, "tables" reserved
Azure::valid_cosmos_id($id) # ≤255 chars, no / or \
Azure::valid_guid($guid) # 8-4-4-4-12 hex
Azure::normalize_guid($guid) # canonical lowercase 8-4-4-4-12
Azure::format_guid($guid, $format?) # .NET specifier: N / D / B {…} / P (…)
Each valid_* helper returns { name, valid, reason } so a pipeline can branch on the boolean and surface the reason.
Connection options
Each call takes a trailing %opts hash carrying the target account/vault. Authentication uses DeveloperToolsCredential — sign in with az login or azd auth login first.
| Service | Options |
|---|---|
| Blob / Queue | account => "<storageacct>" (or AZURE_STORAGE_ACCOUNT), or endpoint => "https://..." |
| Cosmos | account => "<cosmosacct>" (or AZURE_COSMOS_ACCOUNT), or endpoint, plus region => "East US" |
| Secrets / Keys | vault => "<kvname>" (or AZURE_KEYVAULT_NAME), or vault_url => "https://<kv>.vault.azure.net/" |
| Management plane (ARM) | subscription => "<id>" (or AZURE_SUBSCRIPTION_ID); scoped ops add resource_group => "<rg>"; sovereign clouds via arm_endpoint => "..." |
| Service Bus (data) | namespace => "<ns>", or sb_endpoint => "https://<ns>.servicebus.windows.net" |
Packages
The cdylib exports 89 FFI symbols, surfaced through the flat Azure namespace plus twelve typed sub-packages.
| Package | Surface |
|---|---|
| Azure | Flat API over every export (Azure::blob_*, Azure::queue_*, Azure::cosmos_*, Azure::secrets_*, Azure::keys_*, Azure::vm_*, Azure::servicebus_*, Azure::identity_token), plus all pure helpers, Azure::version, and Azure::ping. |
| Azure::Blob | az://container/blob URI helpers — ls, get, put, head, rm, containers, create_container, delete_container, set_metadata. |
| Azure::Queue | ls, send, receive, delete, clear, count, create, drop, and a pump receive→callback→delete loop. |
| Azure::Cosmos | Document helpers — databases, containers, put, get, delete, query, replace, create_database, create_container, delete_database, delete_container. |
| Azure::Secrets | Key Vault — get, set, ls, rm, versions, backup, plus param_get / param_put / param_delete aliases for parameter-store-style callers. |
| Azure::Keys | Key Vault keys (KMS analog) — encrypt, decrypt, ls, get. |
| Azure::Compute | Virtual Machines — ls, get, start, stop, deallocate, restart, status (live power state), skus (VM sizes). |
| Azure::Containers | Container Instances + AKS — groups, group, clusters, cluster, node_pools. |
| Azure::Storage | Storage-account management — ls, get, keys. |
| Azure::ResourceGroups | Resource-group management — ls, get, create, rm, resources (provider-agnostic inventory, ARM $filter). |
| Azure::ServiceBus | Service Bus messaging — queues, topics, namespaces, send, receive. |
| Azure::Subscriptions | Tenant/subscription discovery — ls (all subscriptions), locations (regions). |
| Azure::Monitor | Azure Monitor metrics (CloudWatch analog) — metrics. |
Why a package, not a builtin
The official Azure SDK for Rust crates pull in tokio, hyper, rustls, and reqwest, plus the typespec client-core and per-service generated models. That dependency tree ships once, on demand, as an opt-in package — stryke core is never linked against it.
The stryke side is a thin .stk wrapper; the heavy code lives in the libstryke_azure cdylib and is dlopened on first use Azure. The cdylib holds one shared tokio runtime and one Entra credential, reused across every service client — no per-call fork, no per-call credential rebuild.
FFI contract
Each export is a #[no_mangle] extern "C" fn azure__* taking a JSON request string and returning a JSON response string. stryke's FFI bridge resolves these symbols at load. Handler errors and panics are caught and surfaced as {"error": "..."} — a panic never crosses the C ABI into the host shell.
# the .stk wrapper decodes the JSON and dies on an {error} payload
fn Azure::_decode ($name, $json) {
val $o = from_json $json
if (ref $o eq "HASH" && exists $o->{error}) {
die "Azure::$name: $o->{error}"
}
$o
}
Build & test
make # release build (default) → target/release/libstryke_azure.{dylib,so}
make debug # cargo build
make test # cargo test, then `s test t/`
make install # cargo build --release && s pkg install -g .
cargo test # Rust unit tests (endpoint + FFI-safety pins; offline)
The Rust unit tests are offline endpoint-construction and FFI-safety pins. The t/ surface tests run under s test t/ and skip without Azure credentials. CI (.github/workflows/ci.yml) runs check, fmt, clippy -D warnings, test on ubuntu + macos, doc with -D warnings, and a release build on three targets.
Examples
Runnable .stk scripts under examples/:
examples/discover.stk— credential probe + read-only tour, CI-safe (an eval-guardedidentity_tokenreturns undef with no reachable credential, so the script runs end-to-end without Azure).examples/blob_browse.stk— list a container prefix.
Layout
stryke-azure/ ├── Cargo.toml # cdylib crate (publish = false) ├── src/ │ └── lib.rs # azure__* FFI exports + service ops ├── lib/ # stryke .stk wrappers (Azure + namespaces) ├── stryke.toml # stryke package manifest + ffi exports ├── t/ # offline surface tests ├── examples/ # runnable .stk examples ├── Makefile # `make install` builds + installs └── docs/ # this site (GitHub Pages)
Sibling packages
Part of the stryke package family. Browse the others via the MenkeTechnologiesMeta umbrella repo:
- stryke-arrow — Apache Arrow / Parquet / Feather
- stryke-aws — S3, DynamoDB, SQS, Lambda, STS
- stryke-clickhouse — ClickHouse
- stryke-demo — live demos for every connector
- stryke-docker — Docker daemon API
- stryke-duckdb — embedded DuckDB SQL engine
- stryke-email — email + campaign client
- stryke-fleet — parallel expect/PTY automation
- stryke-gcp — Cloud Storage, Pub/Sub, Secret Manager, BigQuery, Firestore
- stryke-grpc — reflection-based gRPC client
- stryke-gui — mouse / keyboard / screen / clipboard automation
- stryke-k8s — Kubernetes
- stryke-kafka — Apache Kafka
- stryke-mcpd — MCP servers without a runtime
- stryke-mongo — MongoDB
- stryke-mssql — Microsoft SQL Server
- stryke-mysql — MySQL / MariaDB
- stryke-neo4j — Neo4j graph (Bolt)
- stryke-office — Office docs / PDF / images
- stryke-parquet — Parquet file inspector
- stryke-polars — Polars + ndarray + linalg + FFT
- stryke-postgres — PostgreSQL
- stryke-redis — Redis / Valkey
- stryke-scrape — web scraping / crawling
- stryke-scylla — ScyllaDB / Cassandra
- stryke-search — Elasticsearch / OpenSearch
- stryke-selenium — browser automation (WebDriver)
- stryke-spark — Spark Connect (no JVM)
- stryke-utils — pure-stryke utility belt
- stryke-zmq — ZeroMQ messaging