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

# Customer-Managed Keys (BYOK)

> Register, activate, rotate, and revoke a customer-managed encryption key held in your own KMS (AWS KMS, Google Cloud KMS, Azure Key Vault, HashiCorp Vault).

# Customer-Managed Keys (BYOK)

**Bring Your Own Key (BYOK)** is Orbit's control plane for recording which
encryption key — held in **your** external key-management system — governs
your organization's key-management posture. You register a **reference** to
the key (an ARN, resource name, or vault path), then activate, rotate, and
revoke it through the full lifecycle below.

<Note>
  **No key material ever leaves your KMS.** Orbit stores only the key
  reference and echoes back a truncated fingerprint — never the reference
  itself — so a lower-privileged viewer can't see the exact ARN or vault
  path. Writes to this surface are restricted to organization owners and
  admins.
</Note>

All endpoints below are rooted at
`https://api.orbit.devotel.io/api/v1/compliance/byok`. The same lifecycle is
available in the dashboard at **Settings → Compliance → Customer-Managed
Keys**, guarded to owner/admin roles.

***

## Lifecycle states

A registered key moves through this state machine:

| From                 | Action                        | Endpoint                         | To                               |
| -------------------- | ----------------------------- | -------------------------------- | -------------------------------- |
| none / revoked       | register                      | `PUT /compliance/byok`           | `pending`                        |
| `pending`            | activate (optional `enforce`) | `POST /compliance/byok/activate` | `active`                         |
| `pending` / `active` | rotate                        | `POST /compliance/byok/rotate`   | same state, `rotation_count` + 1 |
| `pending` / `active` | revoke                        | `POST /compliance/byok/revoke`   | `revoked`                        |

| State     | Meaning                                                                                 |
| --------- | --------------------------------------------------------------------------------------- |
| `pending` | Registered and validated; not yet activated. Only a `pending` key can be activated.     |
| `active`  | You have granted Orbit's service identity decrypt access and confirmed the key is live. |
| `revoked` | Key is withdrawn. Re-register afresh to re-enable BYOK.                                 |

Every register, activate, rotate, and revoke writes an audit-log entry — see
[Auditing](#auditing).

***

## What `enforce` does — and does not do

The `enforce` flag (set at activation, or toggled later) **records your
organization's key-management policy for compliance evidence.** It is a
control-plane assertion, and it matters that you understand its exact scope:

* It does **not** re-encrypt tenant data. Platform-managed field encryption
  (the encrypt-everything envelope Orbit applies to tenant data at rest)
  stays authoritative regardless of your BYOK config's state.
* You cannot point it back off casually once on: revocation clears it, and
  subsequent BYOK-gated operations behave as below.

When `enforce` is on, platform field-encryption calls that consult BYOK fail
**closed** — they refuse to proceed with a
`409 BYOK_KEY_UNAVAILABLE` — if the key is revoked, unprovisioned (no wrapped
data-encryption key yet), or its wrapped key cannot be recovered. They never
fall back silently to the platform key when your policy says a customer key
must govern.

Do not interpret an active, enforced BYOK config as "tenant data is encrypted
under my key" — today, tenant data at rest is protected by platform-managed
encryption, and BYOK records your policy and gates the field-encryption seam.

***

## Provider setup

Pick your KMS provider, copy its canonical key reference, and register it
either in the dashboard (**Settings → Compliance → Customer-Managed Keys**)
or via the API. The provider catalog (`GET /compliance/byok`) returns the
exact expected format for each provider.

### AWS KMS

Register a **key or alias ARN**:

```text theme={null}
arn:aws:kms:<region>:<account>:key/<uuid>
```

Example: `arn:aws:kms:us-east-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab`

```bash theme={null}
curl -X PUT https://api.orbit.devotel.io/api/v1/compliance/byok \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "aws_kms",
    "key_reference": "arn:aws:kms:us-east-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab",
    "key_alias": "Tenant data key",
    "justification": "SOC 2 evidence"
  }'
```

### Google Cloud KMS

Register the **CryptoKey resource name**:

```text theme={null}
projects/<project>/locations/<location>/keyRings/<ring>/cryptoKeys/<key>
```

Example: `projects/acme/locations/europe-west1/keyRings/orbit/cryptoKeys/tenant-data`

```bash theme={null}
curl -X PUT https://api.orbit.devotel.io/api/v1/compliance/byok \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "gcp_kms",
    "key_reference": "projects/acme/locations/europe-west1/keyRings/orbit/cryptoKeys/tenant-data"
  }'
```

### Azure Key Vault

Register the **key identifier URL**:

```text theme={null}
https://<vault>.vault.azure.net/keys/<name>/<version>
```

Example: `https://acme-kv.vault.azure.net/keys/orbit-tenant-data`

```bash theme={null}
curl -X PUT https://api.orbit.devotel.io/api/v1/compliance/byok \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "azure_keyvault",
    "key_reference": "https://acme-kv.vault.azure.net/keys/orbit-tenant-data"
  }'
```

### HashiCorp Vault (Transit)

Register the **transit key path** (optionally fully qualified):

```text theme={null}
https://<vault-host>/v1/transit/keys/<name>
```

Example: `https://vault.acme.internal/v1/transit/keys/orbit-tenant-data`

```bash theme={null}
curl -X PUT https://api.orbit.devotel.io/api/v1/compliance/byok \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "hashicorp_vault",
    "key_reference": "https://vault.acme.internal/v1/transit/keys/orbit-tenant-data"
  }'
```

The API validates the reference against the provider's canonical grammar and
rejects a malformed one with `409 BYOK_INVALID_KEY_REFERENCE`.

***

## Read the current config

`GET /compliance/byok` returns the registered config (or `null` when unset),
the provider catalog, and the resolved posture. Available to any
authenticated user; never echoes the raw reference.

```bash theme={null}
curl https://api.orbit.devotel.io/api/v1/compliance/byok \
  -H "X-API-Key: $ORBIT_API_KEY"
```

```json theme={null}
{
  "data": {
    "config": {
      "provider": "aws_kms",
      "key_alias": "Tenant data key",
      "fingerprint": "kf_9f2a…",
      "state": "active",
      "enforced": true,
      "rotation_count": 1,
      "created_at": "2026-06-01T00:00:00.000Z",
      "activated_at": "2026-06-01T01:00:00.000Z",
      "rotated_at": "2026-08-01T00:00:00.000Z"
    },
    "providers": [ /* the provider catalog above */ ],
    "posture": {
      "enabled": true,
      "enforced": true,
      "state": "active",
      "provider": "aws_kms",
      "fingerprint": "kf_9f2a…"
    }
  },
  "meta": { "request_id": "…", "timestamp": "…" }
}
```

***

## Activate

Mark a `pending` key active once you have granted Orbit's service identity
decrypt access. Pass `enforce: true` to record it as your organization's
governing key-management policy.

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/byok/activate \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enforce": true }'
```

If no key is registered the endpoint returns `404 BYOK_NOT_FOUND`; if the
key is not `pending` it returns `409 BYOK_NOT_PENDING`.

***

## Rotate

Replace the registered key reference with a new one. The new reference is
validated and re-fingerprinted; an `active` key stays `active` and the
rotation count bumps. Rotation is refused on a revoked key — register anew
instead.

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/byok/rotate \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "aws_kms",
    "key_reference": "arn:aws:kms:us-east-1:111122223333:key/5678efgh-56ef-78gh-90ij-5678901234ab"
  }'
```

Rotation increments the `rotation_count` for provenance. For an enforced
key it also re-wraps the internal data-encryption key under the new
reference; if the existing wrapped key can't be recovered the rotation is
refused with `409 BYOK_REWRAP_FAILED` rather than silently dropping
enforcement.

***

## Revoke

Withdraw the customer key. Revocation clears enforcement from your recorded
policy and destroys the wrapped data-encryption key, so it can never be
recovered again. It does **not** re-encrypt or otherwise affect stored
tenant data — platform-managed encryption stays authoritative throughout.

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/byok/revoke \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "justification": "Key retired after annual rotation policy" }'
```

Revoking an already-revoked key returns `409 BYOK_ALREADY_REVOKED`. To
re-enable BYOK after revocation, register a key afresh with `PUT`.

***

## Auditing

Every register, activate, rotate, and revoke writes an audit-log entry
recording the provider, fingerprint, enforcement state, and (for revokes)
your justification. Read it in the dashboard at **Settings → Audit Log**.

For SOC 2 / ISO 27001 evidence, point auditors at the audit trail and cite
the resolved BYOK posture in your [Compliance Evidence Binder](/compliance/evidence-binder).

***

## Related

* [Posture Overview](/compliance/posture-overview) — the compliance toggle
  map, including where BYOK shows up.
* [Error Codes reference](/reference/error-codes) — the
  `BYOK_KEY_UNAVAILABLE` row and every BYOK-specific conflict code.
* [HIPAA posture](/compliance/hipaa) — how PHI encryption is handled
  alongside your key-management policy.
