skip to content

Operations Without the Key

An application that encrypts and signs by calling a service and never holds key material. Asked because it moves custody and algorithm choice out of the app and onto the request path.

on this pageshow

questions

4

A worker encrypts an applicant field by calling a central service that holds the key — which decisions has the worker stopped making?

level: middleimportance: must knowfreq 54%

answer

  1. custody moves, and choices move with it
  2. who picks the key version now
  3. algorithm can change without a redeploy
  4. ciphertext the caller cannot open alone
  5. rotation becomes a service-side act

basics

~20 s

Key selection, key version, algorithm and rotation all move to the service. The worker still chooses which fields to protect and which logical key name they use, but it keeps ciphertext it cannot read on its own.

solid answer

~40 s

The worker sends a plaintext value and a key *name*; it gets back ciphertext and, usually, a reference recording which key and version produced it. Everything between those two points belongs to the service: which key version encrypts a new write, which algorithm that version uses, when the key is rotated, and whether this caller may ask at all. So an algorithm or version change can happen with no redeploy — and with no say from the caller. What the worker gains is that no key material sits in its process, image, configuration or heap dump. What it takes on is a round trip per operation, a hard runtime dependency, and ciphertext it cannot open by itself. Rotation stops being a code change and becomes a service-side act the worker never coordinates.

code

json · 9 lines
json
{
  "claimRef": "CLM-91847",
  "applicantIdCiphertext": "b64:9f3a7c21...e0",
  "encryptedUnder": {
    "keyName": "claims-applicant-field",
    "keyVersion": 7
  },
  "encryptedAt": "2026-09-20T09:14:22Z"
}

go deeper

for a junior

Recall the shape: the application sends a value and a key name, gets ciphertext back, and never sees key material. Nothing about the key lives in the code, the image or the configuration file.

for a middle

List what moved — key selection, key version, algorithm, rotation and the right to ask at all — and say what the caller still decides, such as which fields are worth protecting and which key name they use.

for a senior

Show the consequences you have operated: a round trip per operation, ciphertext your own database restore cannot open, and an attacker inside the process who can still ask the service for plaintext.

for a principal

Frame it as custody against coupling. A team adopting this shape trades a local failure mode for a shared dependency and a shared bill; say which class of data makes that trade worth signing.

## The shape of the call When an application encrypts by calling a service, two values cross the wire in each direction and no key ever does. The caller sends the plaintext it wants protected plus a **name** for the key to use — a logical name, not the key itself. The service returns **ciphertext**, and usually a reference recording which key and which version produced it. To read the value back the caller sends that ciphertext and receives plaintext, provided its identity is still allowed to ask. The key material is generated inside the service, used inside it, rotated inside it, and never serialised out. That is the whole mechanism. Everything else here is a consequence of it. ## What moved, and to whom | Decision | Key held in the process | Operation performed as a call | |---|---|---| | Where key material exists | the application's configuration or image | the service, and nowhere else | | Which key version encrypts a new write | whatever the process was given | the service's current version | | Which algorithm and parameters | compiled or configured into the caller | the key's definition, service-side | | When rotation happens | a deploy of the caller | a service-side action, no deploy | | Whether this caller may decrypt | any code in the process can | the service's rule for that caller | | Whether an operation leaves evidence | it does not | every operation is a request | The row that surprises people is **algorithm choice**. Once the key's definition carries the algorithm, a new version of that key can move to a different algorithm, and callers that only ever name the key and hand over bytes follow along with no code change. That is a real benefit — an algorithm migration stops being a fleet-wide redeploy — and a real loss of control, because the caller no longer pins what it is getting. Designs differ on whether a caller may pin a version or an algorithm at all. ## What the caller still owns Moving custody does not move judgment. The application still decides: - **which fields are worth encrypting**, since the service will happily encrypt a postcode nobody cares about and charge a round trip for it; - **which logical key name a class of data uses**, which is what scopes a later compromise to one class instead of all of them; - **what it stores beside the ciphertext** — most importantly a key reference, so a value written before a rotation can still be routed to the version that produced it; - **what happens to plaintext after the decrypt returns**, because the service's custody ends at the response. ## Three things this does not buy 1. **It does not make a compromised caller harmless.** An attacker who controls the worker holds the worker's identity, and the service answers the worker. What the attacker cannot do is take the key away and open a stolen copy of the database offline, later, indefinitely — the difference between a bounded window of live abuse and a permanent, silent capability. 2. **It does not re-protect what already leaked.** Rotating the key changes what *future* writes are encrypted under. Ciphertext someone already copied stays decryptable under the version that produced it, for as long as that version is retained. 3. **It does not remove the plaintext problem.** Every decrypt puts plaintext back in the caller's process. Custody of the key is not custody of the data. ## Signing has the same shape Ask the service to sign and nothing structural changes: the caller sends the message, or a digest of it, and receives a signature; the private key never arrives. The consequence is sharper than for encryption, because an application that physically cannot produce a signature on its own means every signature in existence corresponds to one request the service served. What a signature then proves to a verifier is a different subject entirely. ## The cost you signed up for The caller has taken a **hard runtime dependency** on the service for something that used to be a local function call, and pays a network round trip per operation. It also holds ciphertext it cannot read alone: restoring the application's database into an isolated environment produces rows nobody can open unless that environment can also reach the service *and* be authorised by it. That is exactly the property you wanted, and it is exactly the property that surprises the team doing the restore. Where a workload genuinely cannot afford to ask on every operation, the answer is a different arrangement of where key material sits — and the thing that arrangement gives up is precisely the property described above, that every operation passes through the service.

  • Why store a key reference beside the ciphertext rather than letting the service work it out?
    A decrypt has to reach the key and version that produced the value, and a data class may be re-pointed at a different key over its life. Designs differ — some services carry the version inside the ciphertext itself — but a reference you control survives a change of arrangement and lets you answer which data sits under which key without decrypting anything.
  • What changes when the operation is signing rather than encrypting?
    Nothing in the shape: the caller sends the message or its digest and gets a signature back, and the private key never arrives. The consequence is stronger, because the application cannot produce a signature on its own, so every signature that exists corresponds to a request the service served. What a signature proves to a verifier is a separate subject.

It is a safe-deposit room where the clerk does the locking: you hand over the envelope and get back a sealed box, and you never touch the key — which also means you cannot open the box anywhere the bank cannot be reached.

saying these in an interview costs you the question

  • Thinks a compromised worker is harmless because it never held the key
  • Assumes rotation at the service re-encrypts every stored record
  • Believes the caller still pins the algorithm and the key version
  • Says the ciphertext can be opened offline from a backup of the key
  • Treats a per-operation network call as free
open as a page

A worker makes one encrypt call to a central service per record at hundreds of records a second — what does batching those calls buy?

level: middleimportance: should knowfreq 41%

basics

~20 s

Batching removes round trips, not work. A hundred fields in one call is still a hundred encryptions inside the service; what falls is the number of network waits, request authorisations and concurrent calls the worker must keep in flight.

open as a page

Every decrypt of an applicant field goes to the central service holding the key — what becomes countable that a key inside the worker would hide?

level: seniorimportance: should knowfreq 37%

basics

~20 s

Volume, per caller. Because each decrypt must be asked for, ten thousand decrypts in an hour is a number that exists outside the application and can be capped. A key inside the worker decrypts silently and leaves nothing to count.

open as a page

You are choosing which data across the estate must be encrypted by calling a central service on every operation — what decides where that line falls?

level: principalimportance: nice to knowfreq 22%

basics

~20 s

Read shape and the value of custody, per data class. A field read once at case closure pays one call; one rendered on every page view pays a call every time. Weigh that against what custody buys here.

open as a page