Encryption keys
The Encryption keys screen lets you create the envelope keys that encrypt the data of the tenant, rotate them, and read the public metadata of the keys that sign the execution contexts (with their revocation by a platform administrator). Portal path: /security/encryption-keys, menu Security and governance > Encryption keys. It is used by tenant administrators and security officers, and by platform administrators for the signing keys.
What the screen shows
The screen (EncryptionKeys in portal/src/screens/encryption.tsx) holds two tables.
Encryption keys, read from GET /v1/encryption/keys (no paging), sorted by name:
| Column | Content |
|---|---|
| Name | Name of the key, for example customer-data. |
| Purpose | Use of the key, data by default. |
| Algorithm | Encryption algorithm. |
| Backend | openbao-transit when OpenBao is configured, else local. |
| Version | Current version; each rotation adds one. |
| Status | Status of the key, for example active. |
| Rotated | Date of the last rotation. |
| Created | Creation date. |
Empty table: "No encryption key", "Create a key to encrypt tenant data; rotation adds a new version."
Context signing keys, read from GET /v1/context/keys: public metadata only, never key material.
| Column | Content |
|---|---|
| Key id | kid of the signing key. |
| Algorithm | Signature algorithm. |
| Status | For example active or revoked. |
| First used, Last used | First and last use of the key. |
| Retire after | Date after which the key is retired. |
| Revoked at, Revoked by | Revocation date and author. |
A click on a row of either table shows the row in a side panel.
Actions
| Button or action | What it does | API call | Roles |
|---|---|---|---|
| New key (then Create) | Creates a key with Name (required, placeholder customer-data) and Purpose (default data); version 1 is generated. Audited as encryption.key.create. | POST /v1/encryption/keys | tenant_admin, security_officer (button hidden for others) |
Rotation (row menu, shown when the key is active) | After a confirmation, adds a new version of the key; data encrypted with older versions stays readable. Audited as encryption.key.rotate. | POST /v1/encryption/keys/{key_id}/rotate | tenant_admin, security_officer (hidden for others) |
| Revoke (row menu of a signing key not yet revoked) | Opens a form with Reason (required), then Revoke: the execution contexts signed by this key are no longer accepted. Audited as context.key.revoke. | POST /v1/context/keys/{kid}/revoke | platform_admin (hidden for others) |
| Row click or View details | Shows the row. | None | Readers of the table |
| Refresh icon of a table | Reads the list again. | GET /v1/encryption/keys or GET /v1/context/keys | Readers of the table |
Revoking a signing key refuses at once every execution context it signed: running agents and applications holding such a context must obtain a new one.
Roles
The portal shows the creation and the rotation to ROLES.encryptionAdmins (tenant_admin, security_officer) and the revocation to ROLES.platformAdmins (platform_admin), from portal/src/lib/kit.ts. The Control Plane enforces the same roles: the list of the encryption keys needs a tenant only, create and rotate need tenant_admin or security_officer (services/control-plane/src/eai/domains/privacy/__init__.py); the list of the signing keys needs security_officer or auditor, the revocation platform_admin (services/control-plane/src/eai/domains/context/routes.py). platform_admin passes every role check.
Typical tasks
Create a key for a data domain
- Open the form. One key per data domain limits the impact of a rotation. Click New key. Expected result: a side panel with Name and Purpose. If it fails: no button means you are neither
tenant_adminnorsecurity_officer. - Name it. Enter a Name in lowercase, for example
customer-data, keep Purposedata. Expected result: the form accepts the name. If it fails: nothing to retry at this step. - Create. Click Create. Expected result: the message Created and a row with Version
1and the statusactive. If it fails:invalid_request(HTTP 400) withnamemeans a name outside[a-z0-9][a-z0-9._-]{0,62};conflict(HTTP 409) means the name exists.
Rotate a key
- Find the key. Only an
activekey can be rotated. Locate its row and note Version. Expected result: the current version. If it fails: no Rotation in the menu means the key is notactiveor you lack the role. - Rotate. Row menu > Rotation, then accept the confirmation. Expected result: the message Done, Version increased by one and a new Rotated date. If it fails:
key_not_found(HTTP 404) means the key was removed; refresh the table.
Revoke a compromised signing key
- Find the key. The revocation applies to one
kid. Locate the row by its Key id in Context signing keys. Expected result: the key with its status and last use. If it fails:forbiddenon this table means you are neithersecurity_officer,auditornorplatform_admin. - Revoke. Row menu > Revoke, enter the Reason, then Revoke. Expected result: the message Done and the status
revokedwith Revoked at and Revoked by. If it fails:signing_key_not_found(HTTP 404) means the key is unknown or already revoked;validation_errormeans a reason shorter than 3 characters.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Context signing keys shows forbidden (HTTP 403) | The list needs security_officer or auditor (or platform_admin); a tenant_admin alone cannot read it. | Ask for one of these roles. |
invalid_request (HTTP 400) with name | The name does not match [a-z0-9][a-z0-9._-]{0,62}. | Use lowercase letters, digits, ., _ and -. |
conflict (HTTP 409) | A key with this name already exists. | Choose another name, or rotate the existing key. |
key_not_found (HTTP 404) | The key does not exist for this tenant. | Refresh the table. |
signing_key_not_found (HTTP 404) | Signing key not found or already revoked. | Refresh the table. |
tenant_required (HTTP 403) | The account acts without a tenant. | Sign in with an account of the tenant. |