Skip to content

Field encryption

Credentials and other secrets are stored in the database encrypted with AES-256-GCM. They exist as plaintext only briefly in memory — for example when the server delivers a collector its check configuration or runs a check itself.

What is encrypted

Area Values
Hosts SNMP community, SNMPv3 auth and privacy passwords, SSH password, SSH key, password or token secret of the API account
Checks password, key and community fields in the check configuration, script values declared as password
Credential sets all secret fields (SNMP, SSH)
Discovery SNMP communities and SNMPv3 passwords of scans and collector defaults, default community
Notification channels tokens, passwords and webhook addresses
E-mail delivery SMTP password
Login TOTP secrets, SSO client secrets, LDAP bind password
AI API keys of cloud providers
Certificate private key, ACME account key, DNS credentials, EAB key
Push private key of the push key pair (VAPID)

Key

FIELD_ENCRYPTION_KEY is a base64url-encoded 32-byte key. The setup script generates it with:

openssl rand -base64 32 | tr '+/' '-_' | tr -d '='

Only the FIELD_ENCRYPTION_KEY=… line in the .env next to the compose file takes effect (default install: /opt/vesana/.env) — Docker Compose injects it into the containers from there. The setup script sets the .env to mode 600 and the secrets/ directory to 700 (files inside 600); running the installer again repairs permissions that are too open.

secrets/field_encryption_key is only a copy

The setup script also writes the key to secrets/field_encryption_key. That file is read by nothing: no compose file mounts it, no service opens it. Changing only that file during a migration changes nothing — the instance keeps running with the old key.

Flow

sequenceDiagram
    participant U as User
    participant API
    participant DB
    participant C as Collector

    U->>API: Create host with SNMP community
    API->>API: encrypt with FIELD_ENCRYPTION_KEY
    API->>DB: store (nonce + ciphertext + tag)
    Note over DB: Plaintext nowhere stored

    C->>API: Fetch check configuration (HTTPS, API key)
    API->>DB: Read host
    API->>API: decrypt
    API->>C: Configuration with credentials
    Note over C: Plaintext in memory only

Masking in the API

API responses never return encrypted fields in plaintext; they show ***. Even super admins can only set stored credentials, not read them. Saving a form with *** (or an empty password field) keeps the stored value.

Unencrypted legacy values

Values from very old installations may still be stored unencrypted. They keep being read and are encrypted on the next save.

Key loss

Lost key = data lost

Without FIELD_ENCRYPTION_KEY, encrypted fields stay unreadable forever. There is no recovery mechanism.

Consequence: backing up the key is as important as the database backup. Recommendation in Backup & restore. After a restore, Vesana checks whether the encrypted values can be read with the current key and warns if not.

Changing the key

Vesana does not support changing the key — neither in the UI nor with a tool. A new FIELD_ENCRYPTION_KEY makes every previously encrypted value unreadable: credentials on hosts, checks, channels and settings would have to be entered again, and authenticator apps set up again. So don't change the key; store it safely.

Encryption in backups

Database dumps contain the encrypted values (not the plaintext, not the key). Restoring into an instance with a different FIELD_ENCRYPTION_KEY leaves the values unreadable — always restore with the same key.

So a .env backup is mandatory along with the database backup, but not in the same place:

  • Database backup: volume / off-site copy
  • .env: password manager / encrypted separate storage

Next