1. Home
  2. Documentation
  3. Running your own server
  4. Keys and secrets

Running your own server

Keys and secrets

The secret key, the data key for encryption at rest, the maintainers' credentials, and what changing each one does.

Joripo documentation · https://joripo.com/docs/running-your-own-server/keys-and-secrets

On this page

A Joripo server has three kinds of secret. None belongs in the storage root, in a backup, or in any shared folder.

The secret key

SECRET_KEY signs every sign-in, and is part of what seals the garbling vault and of the server's identity that phones recognise. Make one:

python -c "import secrets; print(secrets.token_urlsafe(48))"

In production mode (APP_ENV=production) the engine refuses to start without a random key of at least 32 characters.

Changing it has consequences, so choose it once:

  • everyone is signed out;
  • Joripo Collect phones treat the server as a different server (its identity is derived from the key), so moving them to a new address no longer carries their keys across;
  • every garbling key, roster and kept answer becomes unreadable, and new submissions to a garbled form are stored with blank garbled answers and flagged. Joripo refuses to create a garbling scheme on a server without a fixed secret key.

The data key

The data key turns on encryption at rest. It is given to the engine as JORIPO_DATA_KEYS, or in a key file outside the storage root (JORIPO_DATA_KEY_FILE). Make one from the engine's folder:

python scripts\data_key.py new
  • Keep a copy offline (a password manager and a sealed paper copy), apart from the backups. Without it, nobody can read the sealed data or the sealed backups.
  • At every start the engine checks that its keys open what it sealed before, and refuses to start if they do not. JORIPO_REQUIRE_DATA_KEY=true makes a missing key refuse to start too.
  • Rotating: python scripts\data_key.py rotate prints the new value (the new key first, the old after). Deploy it, let the sealing pass finish (Server health shows it), wait until no backup holds data under the old key (Server health names any), then drop the old key.
  • A single sealed file, such as a purge backup, can be opened offline with python scripts\data_key.py open <sealed file> <output file> and the key in the environment.

The sealing pass that seals data already stored runs in the background at start; set JORIPO_SEAL_ON_START=false to run it by hand instead.

The maintainers' credentials

Server administration is reached only by the people in the maintainers file, which holds scrypt hashes of their passwords, their authenticator secrets and hashed recovery codes. scripts\set_maintainer.py writes it, by default in the home folder of the account that runs the server, or where JORIPO_MAINTAINERS_FILE says. On a host with no writable disk of its own, --hash prints an entry for the JORIPO_MAINTAINERS setting instead. Nothing in the console can add a maintainer. If the file is lost, run the script again on the server: there is no other way in, by design. See Maintainers and their sign-in.

Other credentials

  • The database's password is in DATABASE_URL, in the engine's .env file. A local PostgreSQL should listen on 127.0.0.1 only.
  • A Google service-account key or a SurveyCTO password used by field monitoring is uploaded in the console and sealed on the server.
  • A mail service's credentials, if dashboards are shared by email, are server settings.

None of these is ever needed by Joripo's code, its tests or its documentation, and a test fails if a secret is ever written into the code.