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

# Tenant KMS: Azure Key Vault setup

> Configure Azure Key Vault as your tenant wrapping key provider using a client secret env var or Managed Identity. Client secret values are never stored in the database.

This guide walks you through creating an Azure Key Vault and key, granting KnoxCall access, and onboarding it as your tenant's wrapping key.

Two authentication paths are available:

| Option                                       | When to use                                              |
| -------------------------------------------- | -------------------------------------------------------- |
| **App Registration + client secret env var** | Cloud-hosted KnoxCall (recommended for most tenants)     |
| **Managed Identity**                         | Self-hosted KnoxCall on an Azure VM, App Service, or AKS |

## Prerequisites

* Azure subscription with permission to create Key Vaults, App registrations, and RBAC role assignments
* KnoxCall **Owner** or **Admin** role

<Warning>
  The `client_secret_env_var` field accepts the **name** of an environment variable set on the KnoxCall server — the actual secret value is read at runtime and is **never stored in the database**. This is enforced server-side. Passing a raw client secret value as the field value is rejected.
</Warning>

***

## Step 1: Create an Azure Key Vault and key

```bash theme={"dark"}
az keyvault create \
  --name my-knoxcall-kv \
  --resource-group my-rg \
  --location eastus \
  --sku premium \
  --enable-rbac-authorization true

az keyvault key create \
  --vault-name my-knoxcall-kv \
  --name tenant-wrapping-key \
  --kty RSA \
  --size 2048 \
  --ops wrapKey unwrapKey
```

Note the vault key URL — you'll use it as `kms_key_ref`:

```text theme={"dark"}
https://my-knoxcall-kv.vault.azure.net/keys/tenant-wrapping-key
```

<Info>
  Use the RBAC authorization model (`--enable-rbac-authorization true`), not access policies. This is required for the Key Vault Crypto User role to work.
</Info>

***

## Option A: App Registration + client secret env var

This option works for any deployment. The App Registration acts as KnoxCall's identity in your Azure AD tenant.

### Step 2: Create an App Registration

In the Azure portal, go to **Azure Active Directory → App registrations → New registration**:

* **Name**: `KnoxCall Tenant KMS`
* **Supported account types**: Single tenant
* No redirect URI needed

Note the **Application (client) ID** and **Directory (tenant) ID**.

### Step 3: Create a client secret

In the App Registration, go to **Certificates & secrets → Client secrets → New client secret**:

* **Description**: `KnoxCall BYOK`
* **Expires**: 24 months (or per your policy)

Note the secret **value** immediately — you'll set it as a server-side environment variable. It won't be shown again.

Set the secret on the KnoxCall server environment:

```bash theme={"dark"}
# On the KnoxCall server / container
export AZURE_KC_CLIENT_SECRET="<secret-value-from-portal>"
```

The value of `client_secret_env_var` you pass to the API is the **variable name** (`AZURE_KC_CLIENT_SECRET`), not the secret itself.

### Step 4: Grant access to the key

Assign the **Key Vault Crypto User** role to the App Registration on the key vault:

```bash theme={"dark"}
az role assignment create \
  --role "Key Vault Crypto User" \
  --assignee <APPLICATION_CLIENT_ID> \
  --scope /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/my-rg/providers/Microsoft.KeyVault/vaults/my-knoxcall-kv
```

### Step 5: Onboard via admin UI

1. Go to **Settings → Security**, find the **Tenant Master Key** card, click **Customer KMS**, then **Set up BYOK**
2. Select **Azure Key Vault** and click **Next**
3. Fill in:
   * **Key Vault key URL** — `https://my-knoxcall-kv.vault.azure.net/keys/tenant-wrapping-key`
   * **Vault URL** — `https://my-knoxcall-kv.vault.azure.net`
   * **Entra tenant ID** — your Directory (tenant) ID
   * **Client ID** — the Application (client) ID
4. Click **Next** to review, then **Confirm + activate**

### Step 6: Onboard via API

```bash theme={"dark"}
curl -X POST https://api.knoxcall.com/admin/tenant-kms \
  -H "Authorization: Bearer $KC_ADMIN_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "azure",
    "kms_key_ref": "https://my-knoxcall-kv.vault.azure.net/keys/tenant-wrapping-key",
    "config": {
      "vault_url": "https://my-knoxcall-kv.vault.azure.net",
      "azure_tenant_id": "aaaabbbb-cccc-dddd-eeee-ffffgggghhhh",
      "client_id": "11112222-3333-4444-5555-666677778888",
      "client_secret_env_var": "AZURE_KC_CLIENT_SECRET"
    }
  }'
```

Note: `provider` is `"azure"` (not `"azure_key_vault"`). There is no `key_name` in `config` — the key name is part of `kms_key_ref`.

***

## Option B: Managed Identity (for self-hosted KnoxCall on Azure)

If you run a [self-hosted KnoxCall](/infrastructure/self-hosted-proxy) on an Azure VM, App Service, AKS, or Container App with a system-assigned or user-assigned Managed Identity, you can grant that identity direct access to the vault.

### Step 2 (Option B): Grant Managed Identity access

Find your Managed Identity's object ID and assign **Key Vault Crypto User**:

```bash theme={"dark"}
az role assignment create \
  --role "Key Vault Crypto User" \
  --assignee-object-id <MANAGED_IDENTITY_OBJECT_ID> \
  --assignee-principal-type ServicePrincipal \
  --scope /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/my-rg/providers/Microsoft.KeyVault/vaults/my-knoxcall-kv
```

### Step 3 (Option B): Onboard via API

When `client_secret_env_var` is omitted and no explicit client credentials are provided, KnoxCall uses `DefaultAzureCredential` which picks up the Managed Identity automatically via the Azure IMDS endpoint:

```bash theme={"dark"}
curl -X POST https://api.knoxcall.com/admin/tenant-kms \
  -H "Authorization: Bearer $KC_ADMIN_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "azure",
    "kms_key_ref": "https://my-knoxcall-kv.vault.azure.net/keys/tenant-wrapping-key",
    "config": {
      "vault_url": "https://my-knoxcall-kv.vault.azure.net"
    }
  }'
```

`azure_tenant_id`, `client_id`, and `client_secret_env_var` are all omitted — the Managed Identity is detected at runtime.

***

## Verify the configuration

```bash theme={"dark"}
curl https://api.knoxcall.com/admin/tenant-kms \
  -H "Authorization: Bearer $KC_ADMIN_JWT"
```

Confirm `config.sealed_since` is `null` and the `keys` array contains one active version.

## Session duration impact

<Note>
  BYOK tenants have a **5-minute session TTL** (vs 1 hour for standard tenants). Self-hosted proxy agents renew sessions every 4 minutes. Ensure your infrastructure does not block frequent outbound HTTPS to `api.knoxcall.com`.
</Note>

## Revoking access

To lock KnoxCall out within one cache TTL (5 minutes):

1. Remove the **Key Vault Crypto User** role assignment from the App Registration or Managed Identity, **or**
2. Disable or delete the key in Key Vault

Within 5 minutes, the tenant enters the [sealed state](/essentials/tenant-kms/sealed-state). No data is lost — you can unseal at any time by restoring the role assignment.

## Troubleshooting

**`Forbidden` / `Authorization failed` during verify:**

* Confirm the App Registration or Managed Identity has `Key Vault Crypto User` on the **vault** (not just a key-level grant)
* Check the vault has RBAC authorization enabled: `az keyvault show --name my-kv --query properties.enableRbacAuthorization`

**`client_secret_env_var` not found:**

* The environment variable is not set on the KnoxCall server process
* The env var name is case-sensitive — `AZURE_KC_CLIENT_SECRET` ≠ `azure_kc_client_secret`

**Managed Identity not detected:**

* Managed Identity must be enabled on the Azure resource running KnoxCall (VM → Identity → On, or `--assign-identity` flag)
* `DefaultAzureCredential` queries the IMDS endpoint at `http://169.254.169.254` — ensure no firewall blocks it

**`InvalidKeySize` or key operation error:**

* Key Vault requires RSA 2048+ for wrap/unwrap operations
* Ensure the key was created with `--ops wrapKey unwrapKey` (not `encrypt decrypt` — Azure uses different operations for RSA keys)

<CardGroup cols={2}>
  <Card title="AWS KMS setup" icon="aws" href="/essentials/tenant-kms/setup-aws">
    Cross-account IAM role setup for AWS
  </Card>

  <Card title="GCP Cloud KMS setup" icon="google" href="/essentials/tenant-kms/setup-gcp">
    Service account impersonation for GCP
  </Card>

  <Card title="Sealed state and unseal" icon="lock-open" href="/essentials/tenant-kms/sealed-state">
    What to do when Key Vault becomes unreachable
  </Card>

  <Card title="Tenant KMS API reference" icon="square-terminal" href="/api-reference/tenant-kms">
    Full endpoint reference
  </Card>
</CardGroup>
