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
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.
| Access | What we hold | When it is used |
|---|---|---|
| Your Zonitix app | Nothing. 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 itself | One 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 account | As 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 Type | Storage Location | Security Boundary |
|---|---|---|
| Candidate Resumes & Files | Your Dedicated Instance | Stored 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 Keys | Your Dedicated Instance | Encrypted 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 Tiers | Zonitix licensing server | Stores 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. keyIdis 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
keyIdnames, 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
v1or 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.
| Key | What it protects | Class | What replacing it does |
|---|---|---|---|
| Application data key (ENCRYPTION_KEY) | Encrypted database fields and encrypted files. | Set once | Values written under the old key need that key to be read. See below. |
| Backup encryption key (BACKUP_ENCRYPTION_KEY) | Every off-site backup. | Set once | A backup written under the old key needs that key to be restored. See below. |
| Session secret | Signs session tokens, interim sign-in tokens and emailed sign-in links. | Replaceable | There 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 secret | Signs the 60-second token between the gateway and the services, and the 10-minute cookie that carries a single sign-on attempt. | Replaceable | Protects 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 secret | Signs the 60-second token on requests to the document parser, which is not given the internal service secret. | Replaceable | Protects 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. | Replaceable | Protects 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_KEYand a comma-separated list of earlier keys fromENCRYPTION_KEYS_RETIRED; the backup code does the same withBACKUP_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.