> ## 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: AWS KMS setup

> Configure AWS KMS as your tenant's wrapping key provider using cross-account IAM role assumption. No static credentials accepted.

This guide walks you through creating an AWS KMS key, granting KnoxCall cross-account access via an IAM role, and onboarding it as your tenant's wrapping key.

## Prerequisites

* AWS account with permission to create KMS keys and IAM roles
* KnoxCall **Owner** or **Admin** role

<Warning>
  Static credentials (`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`) are **rejected at the API level** — not just discouraged. Cross-account role assumption via `role_arn` + `external_id` is the only accepted authentication method.
</Warning>

## Step 1: Create a symmetric KMS key

In your AWS account, create a new symmetric KMS key:

```bash theme={"dark"}
aws kms create-key \
  --description "KnoxCall tenant master key wrapping" \
  --key-usage ENCRYPT_DECRYPT \
  --key-spec SYMMETRIC_DEFAULT \
  --region us-east-1
# Note the KeyId and Arn in the response
```

Optionally add an alias:

```bash theme={"dark"}
aws kms create-alias \
  --alias-name alias/knoxcall-tenant-wrapping \
  --target-key-id <KeyId>
```

## Step 2: Create a cross-account IAM role

KnoxCall assumes a role in your account using STS. Create an IAM role with the following trust policy — replace `<KNOXCALL_AWS_ACCOUNT_ID>` with KnoxCall's AWS account ID, shown in the BYOK setup wizard (**Settings → Security → Tenant Master Key → Customer KMS → Set up BYOK**, AWS step). The wizard also renders this exact trust policy ready to paste, with the account ID and your external ID already substituted.

If you prefer the API, the same value is available at:

```bash theme={"dark"}
curl https://admin.knoxcall.com/admin/tenant-kms/provider-identity \
  -H "Authorization: Bearer $KC_ADMIN_JWT" \
  -H "X-Tenant-ID: $KC_TENANT_ID"
# → { "aws": { "configured": true, "account_id": "...", "principal_arn": "..." }, "gcp": { ... } }
```

```json theme={"dark"}
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "AWS": "arn:aws:iam::<KNOXCALL_AWS_ACCOUNT_ID>:root"
    },
    "Action": "sts:AssumeRole",
    "Condition": {
      "StringEquals": {
        "sts:ExternalId": "<your-chosen-external-id>"
      }
    }
  }]
}
```

Generate a random UUID for `<your-chosen-external-id>` — you'll enter it in KnoxCall. Using an external ID prevents confused-deputy attacks.

Attach this inline permission policy to the role, scoped to only the one KMS key:

```json theme={"dark"}
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["kms:Encrypt", "kms:Decrypt"],
    "Resource": "<the-kms-key-arn>"
  }]
}
```

Note the role's ARN — you'll need it in the next step.

## Step 3: Onboard via admin UI

1. Go to **Settings → Security**, find the **Tenant Master Key** card, click **Customer KMS**, then **Set up BYOK**
2. Select **AWS KMS** and click **Next**
3. Fill in:
   * **KMS key ARN** — the full `arn:aws:kms:...` ARN (or alias ARN)
   * **Region** — the AWS region where your KMS key lives
   * **Cross-account role ARN** — the role you created in Step 2
   * **External ID** — the UUID from Step 2
4. Click **Next** to review, then **Confirm + activate**

KnoxCall performs a probe encrypt + decrypt round-trip before committing. If verification fails, the change is not applied.

## Step 4: Onboard via API

No step-up verification is required for onboarding. KnoxCall runs a probe (wrap + unwrap on 32 test bytes) before writing anything — if the IAM grant isn't working, the request fails immediately with `400` and a plain message like `KMS access denied. Check that the IAM/RBAC grant gives KnoxCall both Encrypt and Decrypt on this key.` (or `KMS probe failed.` for other probe errors). If KMS itself is unreachable, you get `502` with `KMS provider unreachable during probe.` instead.

```bash theme={"dark"}
curl -X POST https://admin.knoxcall.com/admin/tenant-kms \
  -H "Authorization: Bearer $KC_ADMIN_JWT" \
  -H "X-Tenant-ID: $KC_TENANT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "aws",
    "kms_key_ref": "arn:aws:kms:us-east-1:111122223333:key/abcd-1234-5678-efgh",
    "config": {
      "region": "us-east-1",
      "role_arn": "arn:aws:iam::111122223333:role/KnoxCallKMSAccess",
      "external_id": "550e8400-e29b-41d4-a716-446655440000"
    }
  }'
```

Note: `provider` is `"aws"` (not `"aws_kms"`). A successful response:

```json theme={"dark"}
{
  "ok": true,
  "provider": "aws",
  "kms_key_ref": "arn:aws:kms:us-east-1:111122223333:key/abcd-1234-5678-efgh",
  "new_key_version": 1,
  "new_key_id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
  "rewrap_status": "enqueued",
  "note": "A background rewrap pass will re-encrypt existing tenant data under the new key. Existing in-flight agent sessions remain valid for up to 5 minutes (BYOK session TTL)."
}
```

`rewrap_status` is always `"enqueued"` — KnoxCall unconditionally issues a background rewrap lease after onboarding.

## Step 5: Verify the configuration

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

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

## Session duration impact

<Note>
  Once BYOK is active, all agent sessions for this tenant have a **5-minute TTL** instead of the default 1 hour. Self-hosted proxy agents will renew sessions more frequently — this is intentional to bound plaintext exposure if you later revoke KMS access. Ensure your agents are not configured with session renewal intervals longer than 4 minutes.
</Note>

## Revoking access (the kill switch)

To lock KnoxCall out of your tenant data:

1. Remove (or deny) the `kms:Decrypt` permission from the IAM role — or detach the inline policy entirely.
2. On the next unwrap cache miss — within one cache TTL (1 hour) — KnoxCall will fail to unwrap and the tenant will enter the [sealed state](/essentials/tenant-kms/sealed-state). New agent sessions stop being issued sooner: because BYOK caps session TTL at 5 minutes, no fresh plaintext exposure can be granted beyond that window.

This is reversible — restore the IAM permission and KnoxCall will unseal automatically on the next successful unwrap.

To **permanently destroy** the data, revoke the tenant master key in KnoxCall itself (cryptographic erasure). The KMS key in your account becomes irrelevant — the wrapped key material is gone.

## Troubleshooting

**`AccessDenied` during onboarding verify:**

* Check the trust policy includes the correct KnoxCall AWS account ID (shown in the BYOK setup wizard's AWS step)
* Verify `sts:ExternalId` in the trust policy matches what you entered exactly
* Confirm the inline policy ARN matches the KMS key ARN (no typos)

**`NoCredentialProviders` error:**

* The KnoxCall principal ARN must appear in the trust policy's `Principal.AWS` field
* Ensure you saved the role after adding the trust policy

**Role ARN mismatch:**

* Copy the role ARN directly from the IAM console — avoid hand-typing the account ID

**Verification times out:**

* Check KMS key is not in a pending-deletion state: `aws kms describe-key --key-id <arn>`
* Verify the KMS key is in the correct region

<CardGroup cols={2}>
  <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 KMS becomes unreachable
  </Card>

  <Card title="Key rotation" icon="refresh-cw" href="/essentials/tenant-kms/key-rotation">
    Rotate to a new master key version
  </Card>

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