# Rotating and revoking

How access ends: expiry, removing a grant, retiring key versions, and rotating the key itself.

Source: https://seal.zone/docs/revoking

There is no kill switch for one blob. Seal never stores blobs, and every copy opens the same way. You end access by changing what the enclave allows, or by killing the key at the provider.

## The ways access ends

| Mechanism | What it stops | Who does it |
| --- | --- | --- |
| An expiry sealed into the blob (`--expires`) | That blob, every copy of it | Whoever seals it, at seal time |
| Removing an app or identity from the grants (`seal revoke app`) | Every session that identity starts | Your admins |
| Removing a replica's deployment (`seal revoke enclave`) | Everything that replica serves | Your admins |
| Retiring old tenant key versions (`seal settings tenant-key bump --retire-older`) | Every blob sealed under an older version | Your admins |
| Revoking the key at the provider | The key itself, everywhere | Whoever owns the upstream account |
| Ending a session (`close()`) | One session | Your app, or the enclave on an integrity finding |
| An integrity suspension | Everything one identity does | Your tenant's integrity policy |

```shell
# Give a blob an end date when you seal it. It can't be changed later.
seal secret --to https://api.openai.com/v1 --app ci --expires 2026-12-31 < openai-key.txt > ci.blob
# Remove a whole app, or one of its identities
seal revoke app checkout
seal revoke app checkout azure --object-id 6f0c1a2e-0000-0000-0000-000000000000
# Remove a replica you run
seal revoke enclave azure --object-id <the replica's managed identity object id>
```

Remove the grant even if you disable the identity at your cloud. A disabled Azure managed identity can work for up to 24 hours on tokens it already has.

## How fast it takes effect

The admin mechanisms narrow access, so they apply once logged. Within about 30 seconds, every replica cuts the affected sessions and connections, even mid-transaction.

Seal's servers can't forge your state. They could serve an older one until its freshness statement runs out, 24 hours by default. Shorten it:

```shell
seal settings freshness window 1h
```

## Rotate a key

1. Create a new key at the provider, with the same permissions or fewer.
2. Seal it and replace the old blob.
3. Restart your apps, or let `reload_with` pick it up.
4. Revoke the old key at the provider.

`reload_with` rereads the blob. On `Expired`, the SDK calls it and restarts the session. Go has neither this nor `on_reseal` yet.

```python
with seal.session(current_blob(), kind="http", reload_with=current_blob) as s:
    ...
```

## Tenant key versions

`seal settings tenant-key bump` starts a new version and breaks nothing. A session on an older blob hands your `on_reseal` callback a copy under the new version. Store it. Once they've moved, `--retire-older` makes every older blob fail with `Expired`. It ends good blobs too, so reseal those first.

## After a suspected compromise

An attacker on your server couldn't read the key, only use it through the enclave.

1. Remove the server's grant with `seal revoke app`. If the identity is shared, remove it anyway and grant healthy servers a new one.
2. Read what it did on the Telemetry page, or with `seal telemetry --since <time>`.
3. Delete any keys, users or tokens at the provider you don't recognise.
4. Rotate the key if the logs are unclear.
5. Rebuild with a new identity. Tighten network rules, `--deny` paths and the key's permissions.

For a lost admin key, see [Admins and changes](https://seal.zone/docs/changes).
