Skip to main content

cmind/apikey/v2/api_key_service.proto

Package: cmind.apikey.v2

Enums

KeyType

ValueNumberDescription
KEY_TYPE_UNSPECIFIED0
KEY_TYPE_PERSONAL1
KEY_TYPE_SERVICE_ACCOUNT2

GrantTargetType

GrantTargetType is the kind of resource a KeyGrant targets. The set is intentionally closed: each target type has a fixed set of supported actions (see GrantAction) and a private mapping to the OpenFGA relation used for the check + the tuple write.

ValueNumberDescription
GRANT_TARGET_TYPE_UNSPECIFIED0
GRANT_TARGET_TYPE_MODEL_DEPLOYMENT1
GRANT_TARGET_TYPE_EXTERNAL_MODEL2
GRANT_TARGET_TYPE_RAG_DEPLOYMENT3
GRANT_TARGET_TYPE_GROUP4
GRANT_TARGET_TYPE_PRESET_AGENT5target_id is the PresetAgent CRD name. The agent must belong to the key's tenant.
GRANT_TARGET_TYPE_MODEL_ALIAS6

GrantAction

GrantAction names the kind of access a key gets on the target. Not every combination of (target_type, action) is valid — the service rejects unsupported pairs with InvalidArgument.

ValueNumberDescription
GRANT_ACTION_UNSPECIFIED0
GRANT_ACTION_MODEL_INVOKE1model_deployment, external_model, model_alias
GRANT_ACTION_RAG_READ2rag_deployment
GRANT_ACTION_RAG_WRITE3rag_deployment
GRANT_ACTION_GROUP_MEMBERSHIP5group
GRANT_ACTION_AGENT_INVOKE6preset agent

Messages

KeyGrant

KeyGrant describes one capability attached to a key. The service maps (target_type, action) to the underlying OpenFGA relation and verifies the caller has the corresponding permission before writing the tuple.

FieldTypeNumberDescription
targetTypeGrantTargetType1
targetIdstring2
actionGrantAction3

ApiKey

FieldTypeNumberDescription
idstring1
typeKeyType2
tenantIdstring3
userIdoptional string4
displayNamestring5
descriptionstring6
secretPrefixstring7
createdBystring8
createdAtgoogle.protobuf.Timestamp9
currentExpiresAtoptional google.protobuf.Timestamp10
revokedAtoptional google.protobuf.Timestamp11
revokedByoptional string12

CreateApiKeyRequest

FieldTypeNumberDescription
tenantIdstring1
displayNamestring2
grantsrepeated KeyGrant3
validForoptional google.protobuf.Duration4Must be positive. Mutually exclusive with permanent.
permanentbool5
descriptionstring6Free-form longer description. Optional.

GetApiKeyRequest

FieldTypeNumberDescription
tenantIdstring1
keyIdstring2

GetApiKeyResponse

FieldTypeNumberDescription
apiKeyApiKey1
grantsrepeated KeyGrant2

CreateApiKeyResponse

FieldTypeNumberDescription
apiKeyApiKey1
plaintextKeystring2
grantsrepeated KeyGrant3

RotateApiKeyRequest

FieldTypeNumberDescription
tenantIdstring1
keyIdstring2
overlapgoogle.protobuf.Duration3Overlap window during which the previous secret remains valid. The previous secret's expires_at is set to least(existing_expires_at, now() + overlap) so rotation never extends a near-expired secret.
validForoptional google.protobuf.Duration4Must be positive. Mutually exclusive with permanent.
permanentbool5

RotateApiKeyResponse

FieldTypeNumberDescription
apiKeyApiKey1
plaintextKeystring2

UpdateApiKeyMetadataRequest

FieldTypeNumberDescription
tenantIdstring1
keyIdstring2
displayNameoptional string3If set, replaces the key's display_name. Must be non-empty.
descriptionoptional string4If set, replaces the key's description. May be empty to clear.

UpdateApiKeyMetadataResponse

FieldTypeNumberDescription
apiKeyApiKey1

RevokeApiKeyRequest

FieldTypeNumberDescription
tenantIdstring1
keyIdstring2

RevokeApiKeyResponse

ListApiKeysRequest

FieldTypeNumberDescription
tenantIdstring1

ListApiKeysResponse

FieldTypeNumberDescription
apiKeysrepeated ApiKey1

ImportApiKeyRequest

ImportApiKeyRequest registers a pre-existing service-account API key in the new store. Temporary surface for the v1 → v2 migration — remove once migrations complete. The caller supplies the plaintext; the service hashes it and persists a key row identical in shape to a freshly created one, so ext_authz validation works without any code path for legacy material. The plaintext is not echoed back.

FieldTypeNumberDescription
tenantIdstring1
keyIdstring2Caller-supplied key id (legacy id, preserved for cross-system correlation). Must be a UUID. Collision => AlreadyExists.
displayNamestring3
descriptionstring4
grantsrepeated KeyGrant5
plaintextKeystring6Plaintext secret to register. Hashed server-side; collision on the hash => AlreadyExists.
expiresAtoptional google.protobuf.Timestamp7Absolute deadline preserved from the legacy key. Mutually exclusive with permanent. May be in the past — already-expired imports persist but never validate.
permanentbool8
createdAtoptional google.protobuf.Timestamp9Optional. Preserves the legacy key's creation timestamp. Defaults to now() when unset.

ImportApiKeyResponse

FieldTypeNumberDescription
apiKeyApiKey1
grantsrepeated KeyGrant2

Services

ApiKeyService

ApiKeyService manages the lifecycle of API keys. Validation does not live on this surface — it runs via the Envoy ext_authz contract at the Istio ingress (see RFC 2026-03-13-api-key-system.md). This service exposes only lifecycle operations. Every key is scoped to a tenant. The endpoints are split by key type so each RPC carries a single static authorization rule: - personal key creation check tenant membership (can_read). Rotate/Revoke enforce key ownership against the authenticated caller in the handler. - service-account endpoints check can_admin on the tenant.

CreatePersonalApiKey

POST /cmind.apikey.v2.ApiKeyService/CreatePersonalApiKey

Personal keys

Request: CreateApiKeyRequest

Response: CreateApiKeyResponse

RotatePersonalApiKey

POST /cmind.apikey.v2.ApiKeyService/RotatePersonalApiKey

Request: RotateApiKeyRequest

Response: RotateApiKeyResponse

UpdatePersonalApiKeyMetadata

POST /cmind.apikey.v2.ApiKeyService/UpdatePersonalApiKeyMetadata

Request: UpdateApiKeyMetadataRequest

Response: UpdateApiKeyMetadataResponse

RevokePersonalApiKey

POST /cmind.apikey.v2.ApiKeyService/RevokePersonalApiKey

Request: RevokeApiKeyRequest

Response: RevokeApiKeyResponse

ListPersonalApiKeys

GET /cmind.apikey.v2.ApiKeyService/ListPersonalApiKeys

Request: ListApiKeysRequest

Response: ListApiKeysResponse

GetPersonalApiKey

GET /cmind.apikey.v2.ApiKeyService/GetPersonalApiKey

Request: GetApiKeyRequest

Response: GetApiKeyResponse

CreateServiceAccountApiKey

POST /cmind.apikey.v2.ApiKeyService/CreateServiceAccountApiKey

Service-account keys

Request: CreateApiKeyRequest

Response: CreateApiKeyResponse

RotateServiceAccountApiKey

POST /cmind.apikey.v2.ApiKeyService/RotateServiceAccountApiKey

Request: RotateApiKeyRequest

Response: RotateApiKeyResponse

UpdateServiceAccountApiKeyMetadata

POST /cmind.apikey.v2.ApiKeyService/UpdateServiceAccountApiKeyMetadata

Request: UpdateApiKeyMetadataRequest

Response: UpdateApiKeyMetadataResponse

RevokeServiceAccountApiKey

POST /cmind.apikey.v2.ApiKeyService/RevokeServiceAccountApiKey

Request: RevokeApiKeyRequest

Response: RevokeApiKeyResponse

ListServiceAccountApiKeys

GET /cmind.apikey.v2.ApiKeyService/ListServiceAccountApiKeys

Request: ListApiKeysRequest

Response: ListApiKeysResponse

GetServiceAccountApiKey

GET /cmind.apikey.v2.ApiKeyService/GetServiceAccountApiKey

Request: GetApiKeyRequest

Response: GetApiKeyResponse

ImportApiKey

POST /cmind.apikey.v2.ApiKeyService/ImportApiKey

ImportApiKey registers a pre-existing service-account secret. TEMPORARY — remove after the v1 → v2 migration completes.

Request: ImportApiKeyRequest

Response: ImportApiKeyResponse