Register Agent Public Key

Registers the AGENT-scoped caller's active RSA public key. The private key stays on the agent runtime and never traverses the server.

POST /api/v1/machine/vault/public-key

Headers

HeaderTypeRequiredDescription
X-API-KeystringYesYour AGENT-scoped API key

Request Body

{
  "encryptionKeyId": "507f1f77bcf86cd799439015",
  "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...\n-----END PUBLIC KEY-----",
  "previousEncryptionKeyId": "507f1f77bcf86cd799439010",
  "rotationSignature": "base64-signature",
  "rewrappedVaultKeys": [
    {
      "vaultId": "507f1f77bcf86cd799439011",
      "encryptionKeyId": "507f1f77bcf86cd799439015",
      "signerEncryptionKeyId": "507f1f77bcf86cd799439015",
      "signerType": "AGENT_ENCRYPTION_KEY",
      "dekVersion": 3,
      "wrappedDek": "base64-ciphertext",
      "wrappedDekSignature": "base64-signature"
    }
  ]
}

Request Fields

FieldTypeRequiredDescription
encryptionKeyIdstringNoOptional client-chosen ID for the new active encryption key. Required when rotating a key that still has active wrapped vault access
publicKeystringYesPEM-encoded RSA public key generated and stored locally by the agent
previousEncryptionKeyIdstringNoPrevious active agent key ID. Required when rotating to a different key
rotationSignaturestringNoRSA-PSS signature from the previous private key approving the new public key
rewrappedVaultKeysarrayNoFull replacement wrapped-DEK batch for every still-active vault assignment on the old key. Required when rotating away from a key that still has active wrapped vault access

Response

Success (201 Created)

{
  "encryptionKeyId": "507f1f77bcf86cd799439015",
  "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...\n-----END PUBLIC KEY-----",
  "fingerprint": "b5d44d6c7c1c1d4b8f31b1d9d8445d6c7c1c1d4b8f31b1d9d8445d6c7c1c1d4b",
  "previousEncryptionKeyId": "507f1f77bcf86cd799439010",
  "rotationSignature": "base64-signature"
}

Response Fields

FieldTypeDescription
encryptionKeyIdstringActive agent encryption key ID used as the wrapped-DEK recipient
publicKeystringPEM-encoded RSA public key currently active for the agent
fingerprintstringSHA-256 fingerprint of the public key
previousEncryptionKeyIdstring | nullPrevious key ID for continuity verification
rotationSignaturestring | nullContinuity signature verifiable by the previous public key

Error Responses

400 Bad Request - Rotation proof missing or invalid

{
  "message": "Key rotation requires previousEncryptionKeyId and rotationSignature."
}

400 Bad Request - Rotation missing the required re-wrap batch

{
  "message": "Rotating an active agent key with wrapped vault access requires encryptionKeyId so the runtime can pre-sign replacement wrapped DEKs."
}

403 Forbidden - Not an AGENT-scoped API key

{
  "error": {
    "code": "agent_scope_required",
    "message": "This endpoint requires an AGENT-scoped API key."
  }
}

404 Not Found - Agent not found

{
  "error": {
    "code": "agent_not_found",
    "message": "Agent not found or you do not have access to it."
  }
}

Example Request

curl -X POST "https://r4.dev/api/v1/machine/vault/public-key" \
  -H "X-API-Key: rk_abc123def456.ghijklmnopqrstuvwxyz" \
  -H "Content-Type: application/json" \
  -d '{
    "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...\n-----END PUBLIC KEY-----"
  }'

Security

  • Requires an AGENT-scoped API key
  • The server stores only the public key, fingerprint, and rotation continuity metadata
  • Re-registering the same public key is idempotent
  • The first successful registration is what makes the agent eligible for security-group, project, and direct vault access
  • Existing pre-registration access is not retroactively wrapped to the new key
  • Rotations require proof from the previous private key
  • Rotations with existing vault access must submit a complete rewrappedVaultKeys batch, and the backend archives the old wrapped-DEK rows plus the old key in one transaction
  • Losing the active private key prevents a normal self-service rotation to a different key

Runtime Flow

  1. Generate and store the RSA key pair locally on the agent runtime.
  2. Call POST /vault/public-key on first boot before operators grant vault-backed access to the agent.
  3. After that registration succeeds, let operators assign security-group, project, or direct vault access.
  4. Fetch GET /vault/:vaultId/wrapped-key for the vault DEK encrypted to encryptionKeyId.
  5. Fetch GET /vault/:vaultId/public-keys to verify the wrapped-DEK signer.
  6. Use the locally stored private key to unwrap the DEK and decrypt vault field ciphertext.

If you are sending a different public key, include previousEncryptionKeyId and a rotationSignature from the current private key. If that old key still has active wrapped vault access, also include encryptionKeyId plus a rewrappedVaultKeys entry for every active vault DEK so the server can rotate and re-wrap atomically.