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

# Azure Connector: Reader Role and ARM Credential Enforcement

> Configure Cynative's Azure connector: Azure credential chain, Reader role enforcement, subscription selection, cloud environment, and AKS cluster access.

The Azure connector authenticates to Azure Resource Manager control-plane APIs and enforces a per-operation RBAC check against the configured role definition before attaching any token. The AKS connector registers alongside it, sharing the same Azure credential chain.

**Connector id:** `azure`\
**AKS connector id:** `aks`

## Quick start

Run Cynative from an environment with a configured Azure CLI, environment, workload identity, or another source in Cynative's Azure credential chain:

```bash theme={null}
az login
cynative -p "review public Azure storage accounts"
```

## Credential discovery

Cynative uses its Azure credential chain, based on `DefaultAzureCredential` sources. CLI, environment, workload identity, and other non-managed-identity sources are preferred; managed identity is tried last and is non-fatal (so a metadata probe on a non-Azure host does not abort the chain). Cynative reads no `AZURE_*` variable to authenticate — the azidentity chain does.

### Credential sources

* `AZURE_TENANT_ID` / `AZURE_CLIENT_ID` / `AZURE_CLIENT_SECRET` — environment service-principal identity (secret auth).
* `AZURE_CLIENT_CERTIFICATE_PATH` (and `AZURE_CLIENT_CERTIFICATE_PASSWORD` for a password-protected certificate) — service-principal certificate auth.
* `AZURE_USERNAME` / `AZURE_PASSWORD` — username/password (ROPC) identity path.
* `AZURE_FEDERATED_TOKEN_FILE` — workload-identity federated token file.

(`AZURE_AUTHORITY_HOST` and `AZURE_CONFIG_DIR` are read to auto-detect the target cloud — see [Target selection](#target-selection).)

### Registration and validation

After constructing the chain, Cynative **eagerly validates it at startup** by minting a test ARM control-plane token. The `azure` and `aks` connectors register only if that probe succeeds (transient errors are retried once). A skip is shown loudly only when Azure is explicitly configured via the environment service-principal variables or under `--verbose`; an expired or not-logged-in `az login` is skipped quietly.

**References:**

* [Authenticate Go apps to Azure](https://learn.microsoft.com/en-us/azure/developer/go/sdk/authentication/authentication-overview) — the azidentity credential model Cynative mirrors.
* [EnvironmentCredential environment variables](https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential) — the authoritative `AZURE_*` variable spellings.

## Target selection

### Default target

The identity is whatever the credential chain resolves. The target subscription/resource is not a default — it is named per request inside the ARM URL path (for example `/subscriptions/<id>/...`). The Azure cloud defaults to auto-detected public (`AzureCloud`) unless overridden.

### Changing the target

Change the identity by re-pointing the credential chain: run `az login`, or set the environment service-principal variables. Target a subscription/resource per request by writing the subscription id into the ARM URL. Select the cloud with `connectors.azure.cloud` (or `CYNATIVE_CONNECTORS_AZURE_CLOUD`).

The vendor `AZURE_AUTHORITY_HOST` and `AZURE_CONFIG_DIR` variables are the cloud auto-detect signals under `cloud: auto`. Note: `connectors.azure.cloud` sets the ARM endpoint/audience Cynative targets and the cloud for environment, workload-identity, and managed-identity credentials, but the Azure CLI, Developer CLI, and PowerShell credentials mint tokens against their **own** active cloud — on a sovereign cloud, also run `az cloud set --name ...` so the CLI credential matches.

## Request usage

Use `auth_provider: "azure"` and include an `azure_auth` object:

```json theme={null}
{
  "azure_auth": {
    "service": "Microsoft.Compute",
    "cloud": "AzureCloud"
  }
}
```

`azure_auth.service` is required. `azure_auth.cloud` is optional and defaults from the request host when omitted. The `cloud` field is a **claim verified** against the cloud Cynative resolved at startup — it cannot switch clouds per request; a mismatch is rejected.

**Minimal example:**

```javascript theme={null}
const subscription = "00000000-0000-0000-0000-000000000000";
const resp = await http_request({
  method: "GET",
  url: `https://management.azure.com/subscriptions/${subscription}?api-version=2020-01-01`,
  headers: [],
  body: "",
  auth_provider: "azure",
  azure_auth: { service: "Microsoft.Resources", cloud: "AzureCloud" }
});
console.log(resp.body);
```

## Hardening

Azure has no credential-downscoping primitive, so the in-process action gate is the sole client-side control. Each request is host-pinned, classified, and authorized against the configured RBAC role definition before an ARM token is injected.

### Host pinning

Cynative pins ARM requests to the configured or resolved Azure cloud, so a model-authored request cannot claim one Azure cloud while sending the token to another.

### Action authorization

Cynative resolves the request to a service via a cached catalog, classifies the requested ARM operation, and authorizes it against the configured Azure RBAC role definition. The gate fails closed: if the operation or the role definition cannot be resolved, the request is denied.

### Model-supplied-credential rejection

Requests carrying an `Authorization`, `Proxy-Authorization`, or `X-Ms-Authorization-Auxiliary` header, or URL userinfo (`user:pass@`), fail closed. The Azure connector additionally rejects a SAS `sig=` query parameter.

### Response redaction

Cynative redacts secret-shaped content and credential-named fields from responses before the model sees them. Treat returned Azure data as sensitive regardless.

### Sovereign clouds

Cynative supports Azure public cloud and sovereign clouds — Azure US Government (`management.usgovcloudapi.net`) and Azure China / 21Vianet (`management.chinacloudapi.cn`). The ARM endpoint, token audience, and Microsoft Entra ID authority are selected per cloud.

By default (`connectors.azure.cloud: auto`), Cynative detects the cloud by reading `AZURE_AUTHORITY_HOST` first, then the Azure CLI config (`$AZURE_CONFIG_DIR/config`, default `~/.azure/config`, `[cloud] name`), falling back to the public cloud. Pin it explicitly where auto-detection is not reliable — for example managed identity on a sovereign host, where the cloud is not exposed without a network probe Cynative deliberately does not make.

### Reading the startup posture

```text theme={null}
✓ azure  access=default(read-only) · enforced=client · role definition=Reader (acdd72a7-3385-48ef-bd42-f606fba81ae7) · tenant#user · (+aks)
```

* `access=default(read-only)` when `connectors.azure.role_definition` is `Reader` (case-insensitive); `access=custom` for any other role.
* `enforced=client` — Azure has no credential-downscoping primitive; the in-process per-operation RBAC check is the sole client-side control.
* `role definition=<name> (<guid>)` — the configured role name and its resolved GUID.
* `(+aks)` — the AKS connector is folded in.

## Cynative configuration

### Cloud environment

The Azure cloud the connector targets (shared with the `aks` connector). Default `auto`.

```yaml theme={null}
connectors:
  azure:
    cloud: auto   # or AzureCloud / AzureUSGovernment / AzureChinaCloud
```

```bash theme={null}
export CYNATIVE_CONNECTORS_AZURE_CLOUD=auto
```

### Exposure and authorization

The Azure RBAC role definition the per-operation action gate authorizes against. Default `Reader`.

```yaml theme={null}
connectors:
  azure:
    role_definition: Reader
```

```bash theme={null}
export CYNATIVE_CONNECTORS_AZURE_ROLE_DEFINITION=Reader
```

You can also configure a role-definition GUID for a custom role:

```yaml theme={null}
connectors:
  azure:
    role_definition: acdd72a7-3385-48ef-bd42-f606fba81ae7
```

The role definition is **fetched live per run and validated at startup** — a role definition that cannot be resolved or fetched causes the `azure` and `aks` connectors to be skipped with a clear reason.

### Cache settings

The Azure service catalog is cached under `<cache.dir>/azure`. The role definition is fetched live per run and not cached.

```yaml theme={null}
cache:
  dir: ~/.cynative/cache
  ttl: 24h
```

***

## AKS connector

The AKS connector provides Kubernetes API access to Azure Kubernetes Service clusters. It registers alongside the `azure` connector, sharing the same Azure credential chain.

**Connector id:** `aks`

### How it works

For each request, Cynative lazily calls ARM `ListClusterUserCredentials` for the target cluster and parses the returned kubeconfig. A bearer token is used if present; client certificate and key data are supplied to the TLS transport if present; otherwise Cynative falls back to a Microsoft Entra ID token for the fixed AKS API server audience.

The per-cluster ARM `ListClusterUserCredentials` retrieval happens **lazily at request time** and can still fail there, even if connector registration succeeded. The calling identity needs the **Azure Kubernetes Service Cluster User Role** (`Microsoft.ContainerService/managedClusters/listClusterUserCredential/action`).

The connector then applies the shared Kubernetes hardening model (host pinning, `view` RBAC gate, dial-time IP authorization, response redaction).

### Request usage

Use `auth_provider: "aks"` and include an `aks_auth` object:

```json theme={null}
{
  "aks_auth": {
    "subscription_id": "00000000-0000-0000-0000-000000000000",
    "resource_group": "rg-prod",
    "cluster_name": "prod"
  }
}
```

All three fields are required. `subscription_id` is a GUID. `resource_group` is 1–90 letters, digits, underscores, parentheses, hyphens, or periods and does not end with a period. `cluster_name` is 1–63 letters, digits, hyphens, or underscores, starting and ending with a letter or digit.

```javascript theme={null}
const resp = await http_request({
  method: "GET",
  url: "https://prod-dns-00000000.hcp.eastus.azmk8s.io/api",
  headers: [],
  body: "",
  auth_provider: "aks",
  aks_auth: {
    subscription_id: "00000000-0000-0000-0000-000000000000",
    resource_group: "rg-prod",
    cluster_name: "prod"
  }
});
console.log(resp.body);
```

### Configuring the ClusterRole

The read-only ClusterRole the AKS connector authorizes against is configurable (default `view`). The Azure cloud is inherited from the shared `connectors.azure.cloud` setting.

```yaml theme={null}
connectors:
  aks:
    cluster_role: view
```

```bash theme={null}
export CYNATIVE_CONNECTORS_AKS_CLUSTER_ROLE=view
```

Widening the role past `view` widens Cynative's permitted verbs — including writes. See the shared [Kubernetes hardening model](/connectors/kubernetes) for full details.

## Defense at a glance (Azure + AKS)

| Control | Azure | AKS |
| - | - | - |
| Read-only by default | ✓ | ✓ |
| Enforcement model | per-operation RBAC check against configured role definition | live `view` ClusterRole (kube-apiserver-style classification) |
| Configurable exposure | ✓ any built-in role name or role-definition GUID (default `Reader`) | ✓ `connectors.aks.cluster_role` (default `view`) |
| Credential downscoping | — · no Entra ID RBAC-downscoping primitive | — · authn/authz decoupled in Kubernetes |
| Host pinning | ✓ (pinned to the configured/resolved Azure cloud) | ✓ (kubeconfig cluster `server` from ARM `ListClusterUserCredentials`) |
| Dial-time IP authorization | ✓ (default internal-range deny) | ✓ (dialed IP must be in the resolved endpoint IP set) |
| Model-supplied-credential rejection | ✓ (+ rejects a SAS `sig=` query parameter) | ✓ |
| Response redaction | ✓ | ✓ |

## Limitations

* **Data-plane operations** (Key Vault secrets, Blob/Queue/Table data, SQL/Cosmos data) are out of scope. Cynative is control-plane only and denies data-plane hosts at the network layer.
* **No per-session credential downscoping.** There is no primitive to reduce an existing Entra ID access token's effective RBAC at request time — Azure RBAC is evaluated server-side by Azure Resource Manager per request.
* **Sovereign cloud auto-detection is best-effort.** It covers the Azure CLI / environment-variable credential sources but not managed identity on a sovereign host — pin `connectors.azure.cloud` explicitly there. Custom / private / partner clouds are not modeled; an unrecognized signal falls back to the public cloud.
* **Action authorization fails closed** when operation or role-definition resolution fails.
* **AKS requires `ListClusterUserCredentials`** on the target cluster. When the returned kubeconfig carries no static bearer or certificate (for example a cluster with `disableLocalAccounts`), Cynative uses the Entra ID token.
* **There is no client-side credential downscoping for AKS.** The in-process `view` gate, host pinning, and dial-time IP authorization are the only client-side controls.
* The Azure connector is for ARM control-plane APIs. Use `aks` for Kubernetes API calls to AKS clusters.


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