Architecture & OperationsData Isolation
On this page0

Unfamiliar word? See Glossary: words used in these docs. Looking for the tasks in order? Begin at Start Here.

Reference

Data Isolation

Where each kind of your data is stored, what protects it, and what Zonitix can and cannot reach on your server.

Where Your Data Lives

Shared multi-tenant SaaS co-mingles every customer in one database, while Zonitix runs a separate dedicated instance per customer.TYPICAL MULTI-TENANT SAASOne database · every customer co-mingledZONITIX · DEDICATED INSTANCEYour instanceAES-256-GCM · yours aloneAnother customerAnother customer

Your instance has its own database, used by your company only. Employee profiles, candidate names, CV files, cloud tokens and invoice records stay on that single-tenant instance and are never pooled with another customer’s records.

  • Candidate résumés and files: on your instance, stored encrypted.
  • Keys for your cloud providers and connected apps: on your instance, stored encrypted with a key that exists only on your server.
  • Billing and plan: on the Zonitix licensing server (the store). It holds license and billing details and no user data.
  • Apple MDM records, only if you use Apple MDM (a preview feature): on a Zonitix-hosted service shared across customers, with each customer’s records in a separate tenant. This is the one kind of data that is not on your dedicated server. What it holds is in the Trust Center sub-processor list.

What Zonitix Can Reach On Your Server

We host and monitor your server. Zonitix releases are installed automatically in a weekly maintenance window when that is switched on and email is set up, which is the choice pre-selected in the first-run setup wizard; an administrator can apply them by hand instead. Operating-system security patches follow the same window or are applied by hand. Backups and restores are your administrator’s to set up and run. Hosting the server gives us three kinds of access, and they are different from each other.

AccessWhat we holdWhen it is used
Your Zonitix appNothing. Zonitix support has no sign-in to your app.Only when one of your administrators grants support access, for 1 to 72 hours, read-only unless they choose a role. The grant, what the support account does and the ending are written to your audit log. See Give Zonitix support temporary access.
The server itselfOne SSH deploy key with root access to your server.To provision the server and, at the end, tear it down. We do not use it to access your instance or your data unless you ask us to in writing (see Terms §5).
The hosting-provider accountAs the holder of the hosting-provider account your server runs on, we can reach its provider console, rescue mode and snapshots without that key.Our deployment tooling does not use them.

What we receive without using any of these is the license heartbeat your instance sends. It carries counts and no employee or business data; the fields are listed on Heartbeat (License Check-In).

What A Key Change Means For You

The keys that protect your data are files on your server, outside the app. Each key and what replacing it does are listed in the technical part below, under Keys And Rotation.

  • You cannot rotate a key from the app, and you cannot log in to the server itself. A key change is a change on the server, so it is a request to Zonitix support. No rotation interval and no turnaround time for such a request is published.
  • If the application data key or the backup key ever changes, the escrow shares your trustees hold open the old key. The escrow status marks them stale, and you issue new shares. Keep the old shares for as long as you keep backups written under the old key. See Key Escrow & Recovery.
  • If the session secret changes, every user signs in again. Personal API tokens are not signed with it and keep working.
  • The license secret is issued by the Zonitix licensing server and is covered on License Verification.

If something here is not working as you expect, start with When something goes wrong.

The plain explanation is above. This part is for IT and developers: the exact settings, permission names, API addresses and data fields behind it. Closed: select the heading above to open it. While it is closed, your browser’s find-on-page (Ctrl+F or Cmd+F) does not search this part.

Storage And Protection By Data Type

Data TypeStorage LocationSecurity Boundary
Candidate Resumes & FilesYour Dedicated InstanceStored on a dedicated, single-tenant volume attached to your instance only, never pooled with other customers. Résumés/CVs and offer supporting documents are encrypted at rest with AES-256-GCM as they are written, and a daily sweep seals any file stored before that change. The documents Zonitix Sign stores are encrypted with the same AES-256-GCM envelope (see the Zonitix Sign page). Sensitive database fields are separately AES-256-GCM encrypted; see the next rows.
Cloud Provider API KeysYour Dedicated InstanceEncrypted in Postgres with AES-256-GCM, using a per-instance key (ENCRYPTION_KEY) held only on your instance. It is delivered to each service as a mounted secret file and read into the process at start, so the value does not appear in the container’s configuration. The e-signature sealing keys are separate from it: each is a 3072-bit RSA private key that the signature service generates on your instance the first time it seals a document, kept as a file in that service’s own storage directory on your server with read and write permission for the file’s owner only. See Zonitix Sign.
Billing & Plan TiersZonitix licensing serverStores license flags and billing metadata, and the operational figures from the heartbeat (see Heartbeat (License Check-In)). No user data.
Apple MDM Records (preview, optional)Zonitix Apple MDM service (shared)One service for all customers, with a separate tenant per customer. Your instance authenticates to it with a key that belongs to your tenant, stored on your instance encrypted with AES-256-GCM. A server that was given an MDM token when it was provisioned registers its customer id and company name with the service at each deploy, before any Mac is enrolled; a server without the token sends it nothing. See Design Philosophy.

Encryption Of The Disk Itself

The application does not encrypt the server’s disk or the database volume as a whole. What it encrypts is the listed fields and files, one by one, before they are written. Everything else in the database is stored as the database writes it, on a volume of your dedicated server. Whether the disk under that volume is encrypted is a property of the hosting provider’s storage, which the application neither sets nor checks; no statement about it is published here.

Field-Level Encryption

Your instance applies field-level AES-256-GCM encryption to sensitive fields through hooks in the ORM model layer (not whole-database encryption) (the shared/models package every service on your instance imports — shared between services, never between customers). The key is a 32-character value (about 128 bits of entropy) generated uniquely per instance at provisioning time. Those 32 characters are used directly as the 32 bytes of the AES-256 key, as the snippet below shows. It reaches each service as a file-based secret mounted into the container (not a value written into the container’s environment configuration); the service’s start-up script loads it into the process as ENCRYPTION_KEY, which is where the code below reads it.

// What the model hooks do to one field. Runs as it stands in Node.js with ENCRYPTION_KEY set.

const crypto = require('crypto');

// The key text's first 32 bytes are used directly as the 32-byte AES-256 key.

const key = Buffer.from(String(process.env.ENCRYPTION_KEY)).slice(0, 32);

const keyId = crypto.createHash('sha256').update(key).digest('hex').slice(0, 8);

const plainText = 'value to protect';

const iv = crypto.randomBytes(12); // a fresh random IV for every value

const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);

let ciphertext = cipher.update(plainText, 'utf8', 'hex');

ciphertext += cipher.final('hex');

const tag = cipher.getAuthTag().toString('hex'); // 16-byte authentication tag

console.log(`v1:${keyId}:${iv.toString('hex')}:${tag}:${ciphertext}`); // the stored form

// Reading reverses this in the model hooks: the tag is checked before the value is returned.

Stored Formats

  • An encrypted field is stored as v1:<keyId>:<iv>:<tag>:<ciphertext>, every part hex-encoded: a 12-byte IV (24 hex characters), a 16-byte GCM authentication tag (32 hex characters), then the ciphertext.
  • keyId is the first 8 hex characters of the SHA-256 of the key. It records which key sealed the value.
  • The encryption code holds a key ring: the current key plus any retired keys it is given. New values are written under the current key; a value written under an earlier key is read with the key its keyId names, when that key is in the ring. Whether a retired key is in the ring today is under Keys And Rotation below.
  • Values written before versioning (<iv>:<tag>:<ciphertext>) carry no key id and are read under the current key only.
  • A v1 or unversioned GCM value that does not authenticate, or whose key is no longer in the ring, reads as empty. A value in the oldest two-part AES-CBC format (<iv>:<ciphertext>) that cannot be decrypted is returned as stored, and a value in none of these formats is passed through unchanged.
  • Encrypted files (résumés, signed documents) start with a header that carries the same 8-character key id, the IV and the tag.

Keys And Rotation

The keys that protect your data are files on your server, outside the app. Nothing in the app can show, change or replace them, and none of them is replaced on a schedule. What a key change means for you is in the plain part above, under What A Key Change Means For You.

KeyWhat it protectsClassWhat replacing it does
Application data key (ENCRYPTION_KEY)Encrypted database fields and encrypted files.Set onceValues written under the old key need that key to be read. See below.
Backup encryption key (BACKUP_ENCRYPTION_KEY)Every off-site backup.Set onceA backup written under the old key needs that key to be restored. See below.
Session secretSigns session tokens, interim sign-in tokens and emailed sign-in links.ReplaceableThere is one secret and no ring, so every token issued before the change stops verifying. Everyone signs in again; no stored data is affected.
Internal service secretSigns the 60-second token between the gateway and the services, and the 10-minute cookie that carries a single sign-on attempt.ReplaceableProtects no stored data. Every service except the document parser must start with the new value together. A single sign-on attempt that is in progress at the moment of the change has to be started again.
Document parser secretSigns the 60-second token on requests to the document parser, which is not given the internal service secret.ReplaceableProtects no stored data. The parser and the services that call it must start with the new value together.
Identity signing key pair (Ed25519)Signs the caller identity the gateway forwards.ReplaceableProtects no stored data. The public key has to reach every service with the same change.
  • Set once means the server’s set-up script creates the key on a new server and refuses to create a new one on a server that already has a database, because data encrypted under the missing key could not be read. Replaceable means the script creates a new value whenever the file is absent.
  • Each key is a file readable only by the server’s administrator account, mounted into the services that need it. The backup key is mounted into the compliance service only.
  • The key ring. The encryption code reads the current key from ENCRYPTION_KEY and a comma-separated list of earlier keys from ENCRYPTION_KEYS_RETIRED; the backup code does the same with BACKUP_ENCRYPTION_KEYS_RETIRED. New values are always written under the current key, and a stored value or a backup names the key that wrote it.
  • What is not there yet. The stack definition in the current release hands the services the current key only; it does not pass either retired-key list to them. There is also no job in the product that re-encrypts existing values under a new key. So if the application data key were replaced on a running instance today, values written under the old key would read as empty, and backups written under the old backup key would be refused on restore. Values in the format written before key ids were added are readable under the current key only in any case.
  • The e-signature sealing keys are not in the table. The set-up script does not create them. The signature service generates two 3072-bit RSA key pairs itself, one for signed offers and one for report evidence, each with a self-signed certificate valid for ten years, the first time each is needed, and reuses them from then on. Each private key is a file in that service’s storage directory, readable and writable by its owner only. They sign documents and encrypt nothing, so no stored data depends on them to be read. See Zonitix Sign.
  • Old backups offline. The published backup decryptor accepts the current key and a list of earlier keys, so a backup can be opened outside the server with the key that wrote it. See Recovery Tools.

Related reference