-
Notifications
You must be signed in to change notification settings - Fork 24
Description
Enhance Key Access Server Table
Context and Problem Statement
Currently, the Key Access Server (KAS) stores a jsonb representation of the public_key. This design presents a limitation, as it implies that a Key Access Server can have only a single public key associated with it. However, this is not the case.
In our proto definitions, we define the PublicKey field within the KeyAccessServer proto message:
platform/service/policy/objects.proto
Line 269 in 069f939
| PublicKey public_key = 3; |
The PublicKey message can take on one of the following forms:
platform/service/policy/objects.proto
Lines 302 to 318 in 069f939
| message PublicKey { | |
| // Deprecated | |
| reserved "local"; | |
| reserved 2; | |
| oneof public_key { | |
| // kas public key url - optional since can also be retrieved via public key | |
| string remote = 1 [(buf.validate.field).cel = { | |
| id: "uri_format" | |
| message: "URI must be a valid URL (e.g., 'https://demo.com/') followed by additional segments. Each segment must start and end with an alphanumeric character, can contain hyphens, alphanumeric characters, and slashes." | |
| expression: "this.matches('^https://[a-zA-Z0-9]([a-zA-Z0-9\\\\-]{0,61}[a-zA-Z0-9])?(\\\\.[a-zA-Z0-9]([a-zA-Z0-9\\\\-]{0,61}[a-zA-Z0-9])?)*(/.*)?$')" | |
| }]; | |
| // public key with additional information. Current preferred version | |
| KasPublicKeySet cached = 3; | |
| } | |
| } |
This allows for either storing a reference to a remote public key or defining a public key via a KasPublicKeySet, which is essentially a repeated list of KasPublicKey entries:
platform/service/policy/objects.proto
Lines 284 to 295 in 069f939
| message KasPublicKey { | |
| // x509 ASN.1 content in PEM envelope, usually | |
| string pem = 1; | |
| // A unique string identifier for this key | |
| string kid = 2; | |
| // A known algorithm type with any additional parameters encoded. | |
| // To start, these may be `rsa:2048` for encrypting ZTDF files and | |
| // `ec:secp256r1` for nanoTDF, but more formats may be added as needed. | |
| KasPublicKeyAlgEnum alg = 3; | |
| } |
Potential Issues:
- Key Rotation Confusion: As an admin, I could list multiple RSA keys, including old rotated keys, which might create confusion about which key is active.
- Lack of Key Selection Mechanism: There is currently no way for our SDK to identify which key should be used as the correct or active key.
Additionally, there is a mismatch between how we assign the KAS to a namespace, attribute, or attribute value. This assignment would work if the KAS were intended to operate with only a single key at a time. However, this does not align with how KAS was originally designed.
Proposed Solution:
Instead of associating a KAS directly with a namespace, attribute, or attribute value, we should use Grants to map a specific Key to the policy resources. This would better reflect the original design intent and allow for more flexible future key management.
Decision Drivers
- Support key rotations
- Ensure strict values
- Allow Key to
namespace,attribute, orvaluemapping
Considered Options
- Store multiple keys within the
public_keyjsonb typed column - Create an auxiliary table to store the keys with a many:1 relationship with the KeyAccessServer table
Decision Outcome
Chosen option: "{title of option}"
Store multiple keys within the public_key jsonb typed column
- 🟢 Existing table structure and no migration needed
- 🔴 With JSONB the data does not have a schema to conform to and data structure migrations are hard
- 🔴 No indication from a high-level which key is primary without decoding the JSONB
- 🔴 Row needs to be updated "frequently" to capture key rotations and identify the current key
- 🔴 After many key rotations the resulting data is quite large and filtering needs to be added to the service code
Create an auxiliary table to store the keys
erDiagram
%% KeyAccessServer ||--|| PublicKey: "has current key"
PublicKey }|--|| KeyAccessServer: "belongs to"
XPublicKeyMap }|--|| PublicKey: "has many"
X ||--|| XPublicKeyMap: "has one"
X {
uuid id PK
}
XPublicKeyMap {
uuid X_id FK
uuid key_access_server_id FK
}
%% moving public_key out
KeyAccessServer {
uuid id PK
text name
text uri UK
jsonb metadata
date created_on
date updated_on
}
PublicKey {
uuid id PK
boolean is_active
boolean was_mapped
uuid key_access_server_id FK
varchar(36) key_id
varchar(50) alg "algorithm"
constraint unique_key UK "enforces unique key_id and algorithm per KAS (key_access_server_id, key_id, alg)"
constraint unique_active_key UK "enforce only one active key per KAS per algorithm"
text public_key
jsonb metadata
}
Updated from #1485 (comment)
- 🟢 Schema enforced solution to multiple keys
- 🟢 Ensure future migrations are simpler (not-NoSQL)
- 🟡 Requires an auto migration to move public keys
- 🔴 If public key json has many keys, a manual migration is required