Secret#

NAME#

Kernel::System::Crypt::Secret - encrypt/decrypt secrets stored in Kernel/Config.pm

DESCRIPTION#

Some credentials (e.g. DatabasePw, the various LDAP SearchUserPwsettings) must be read before SysConfig is available and therefore have to be stored literally in Kernel/Config.pm. This module allows such values to be stored as real, key-based ciphertext instead of plain text.

An encrypted value looks like this and can be pasted directly into Kernel/Config.pm in place of the plain text value:

{AES256:<base64 IV>:<base64 ciphertext and authentication tag>}

Values are encrypted with AES-256 in GCM mode, so a wrong key or a manipulated value is always detected by Decrypt().

Use bin/znuny.Console.pl Maint::Secret::Encrypt to create one.

Values that are not wrapped in {AES256:...} are returned unchanged by Decrypt(), so this can safely be called on any config value, encrypted or not.

Encryption key#

The encryption key is derived from a passphrase which is deliberately NOT stored in Kernel/Config.pm (otherwise nothing would be gained). It is read from, in order of precedence:

  1. The ZNUNY_CONFIG_SECRET_KEY environment variable.

    1. A file whose path is configured via $Self->{ConfigSecretKeyFile} in Kernel/Config.pm. This file should live outside the web root, be owned

by the webserver user and have permissions 0600.

Use bin/znuny.Console.pl Maint::Secret::KeyGenerate to create a new random passphrase.

Threat model#

This protects secrets at rest in Kernel/Config.pm (e.g. against being accidentally committed to version control, included in backups, or read by someone who can view the file but not the key). It does NOT protect against an attacker who can read arbitrary files as the webserver user, since that user needs access to the key at runtime as well. Keep the key file (or the environment variable) at least as well protected as Kernel/Config.pmitself, ideally better (e.g. excluded from routine backups/dumps of the config directory).

Requirements#

Encryption/decryption requires the CPAN module CryptX (for Crypt::AuthEnc::GCM), which is not bundled with Znuny. Install it e.g. via cpanm CryptX or your OS package manager. Random IVs and keys are generated with Crypt::URandom, which is bundled with Znuny.

Values are UTF-8 encoded before encryption, so any character can be used.

Encrypt()#

Encrypts a plain text value for storage in Kernel/Config.pm.

my $CipherText = $SecretObject->Encrypt(
    Value => 'some-pass',
);

Returns undef and logs an error if no key is configured or CryptX is not installed.

Decrypt()#

Decrypts a value previously created by Encrypt(). Values that are not wrapped as {AES256:...} are returned unchanged, so this is safe to call unconditionally on any config value.

my $PlainText = $SecretObject->Decrypt(
    Value => $ConfigObject->Get('DatabasePw'),
);

GenerateKey()#

Generates a new random passphrase suitable for use as the encryption key (as an environment variable value or the content of a key file).

my $Passphrase = $SecretObject->GenerateKey();