Bcfg2 Data Encryption

New in version 1.3.0.

Bcfg2 supports encrypting some data on the disk, which can help protect sensitive data from other people who need access to the Bcfg2 repository but are perhaps not authorized to see all data. It supports multiple passphrases, which can be used to enforce separations between teams, environments, etc. Use of the encryption feature requires M2Crypto 0.18 or newer.


This feature is not intended to secure the files against a malicious attacker who has gained access to your Bcfg2 server, as the encryption passphrases are held in plaintext in bcfg2.conf. This is only intended to make it easier to use a single Bcfg2 repository with multiple admins who should not necessarily have access to each other’s sensitive data.

Two types of data can be encrypted:

In general, Properties encryption is preferred for a few reasons:

  • It plays nicely with your VCS. If you change an encrypted Cfg file, then all you can see in your VCS log is that the file changed, no details about how it changed. With an encrypted Properties file, you can see which element changed (although obviously not the changed content).
  • It is faster when you have more than one passphrase. When decrypting a Cfg file, Bcfg2 simply brute-forces it with all known passphrases; when decrypting a Properties element, the passphrase is given by name so only one passphrase must be tried.
  • A Cfg file can only be encrypted with a single passphrase; Properties files can use different passphrases for different elements. If you are using different passphrases to segregate data amongst different teams, this lets teams collaborate more closely on files and other data.


Encrypting and decrypting Cfg and Properties files can be done with the bcfg2-crypt tool, which mostly tries to do the right thing. I.e., it encrypts plaintext files, decrypts encrypted files, and automatically discovers if a file is Cfg or Properties. Its usage is thus generally very simple, e.g.:

bcfg2-crypt foo.conf
bcfg2-crypt foo.xml

Since the behavior of bcfg2-crypt varies significantly depending on whether you are dealing with a Cfg or Properties files, these are documented separately below. It’s also well worthwhile to familiarize yourself with the man page for bcfg2-crypt.

Encrypting Cfg Files

To encrypt a Cfg file, you can simply run:

bcfg2-crypt foo.conf

This will write the encrypted data to foo.conf.crypt. Once you are satisfied that the file has been encrypted as you wish, you can remove the plaintext version, or you can use the --remove flag of bcfg2-crypt.

To decrypt a file, simply run bcfg2-crypt again:

bcfg2-crypt foo.conf.crypt

On Cfg files, bcfg2-crypt is more-or-less equivalent to the following commands (encryption and decryption, respectively):

openssl enc -aes-256-cbc -k <passphrase> -in foo.conf \
    -out foo.conf.crypt -a
openssl enc -d -aes-256-cbc -k <passphrase> -in foo.conf.crypt \
    -out foo.conf -a

Those commands can be used in lieu of bcfg2-crypt if you hate convenience.

Encrypting Properties Files

To encrypt or decrypt a properties file, simply run:

bcfg2-crypt foo.xml

If the top-level tag of a Properties file is not <Properties>, then you need to use the --properties flag to bcfg2-crypt:

bcfg2-crypt --properties foo.xml

The first time you run bcfg2-crypt on a Properties file, it will encrypt all character data of all elements. Additionally, it will add encrypted="<key name>" to each element that has encrypted character data. It also adds encryption="true" to the top-level <Properties> tag as a flag to the server that it should try to decrypt the data in that file. (If you are using Properties schemas, you will need to make sure to add support for these attributes.) On subsequent runs, only those elements flagged with encrypted="*" are encrypted or decrypted.

To decrypt a Properties file, simply re-run bcfg2-crypt:

bcfg2-crypt foo.xml

This decrypts the encrypted elements, but it does not remove the encrypted attribute; this way, you can decrypt a Properties file, modify the contents, and then simply re-run bcfg2-crypt to encrypt it again. If you added elements that you also want to be encrypted, you can either add the encrypted attribute to them manually, or run:

bcfg2-crypt --xpath '*' foo.xml

You can also use the --xpath option to specify more restrictive XPath expressions to only encrypt a subset of elements, or to encrypt different elements with different passphrases. Alternatively, you can manally set the encrypted attribute on various elements and bcfg2-crypt will automatically do the right thing. You can also run bcfg2-crypt in interactive mode to interactively select which attributes should be encrypted:

bcfg2-crypt -I foo.xml

If you want to use different passphrases within a single Properties file, you must manually set the encrypted attribute.

Configuring Encryption


To configure encryption, add a [encryption] section to bcfg2.conf with any number of name-passphrase pairs.

For instance:



The name of a passphrase cannot be algorithm or decrypt, which are reserved for other configuration options.

This would define two separate encryption passphrases, presumably for use by two separate teams. The passphrase names are completely arbitrary.

Note that this does entail a chicken-and-egg problem. In order for the Bcfg2 server to be able to decrypt encrypted files, the passphrases must exist in bcfg2.conf in plaintext; but, if you’re encrypting data, presumably you don’t want to include those plaintext passphrases in your Bcfg2 repository, so you’ll want to encrypt bcfg2.conf. The best way to solve this is:

  1. On your Bcfg2 server, manually add the [encryption] section to bcfg2.conf and restart the Bcfg2 server.
  2. Update bcfg2.conf in your Bcfg2 repository with the passphrases, and encrypt it.

The first (manual) step breaks the mutual dependency.


By default, Bcfg2 uses the AES-256-CBC cipher algorithm. If you wish to change this, you can set the algorithm option in the [encryption] section of bcfg2.conf:

algorithm = bf_cbc

The value of algorithm must be a valid OpenSSL cipher algorithm according the naming model of the Python M2Crypto module. To get a list of valid algorithms, you can run:

openssl list-cipher-algorithms | grep -v ' => ' | \
    tr 'A-Z-' 'a-z_' | sort -u

Lax vs. Strict decryption

By default, Bcfg2 expects to be able to decrypt every encrypted datum. Depending on how encryption is implemented at your site, though, that may not be possible. (For instance, if you use encryption to protect data for your production environment from your staging Bcfg2 server, then you would not expect the staging server to be able to decrypt everything.) In this case, you want to enable lax decryption in the [encryption] section of bcfg2.conf:

decrypt = lax

This causes a failed decrypt to produce a warning only, not an error.

This can be overridden by individual XML files by setting decrypt="strict" on the top-level tag (or, vice-versa; if strict is the default an XML file can specify decrypt="lax".

Encryption API

Bcfg2.Encryption provides a number of convenience methods for handling encryption in Bcfg2. See Bcfg2 Data Encryption for more details.

Bcfg2.Encryption.ALGORITHM = 'aes_256_cbc'

Default cipher algorithm. To get a full list of valid algorithms, you can run:

openssl list-cipher-algorithms | grep -v ' => ' | \
    tr 'A-Z-' 'a-z_' | sort -u
Bcfg2.Encryption.CFG_ALGORITHM = 'algorithm'

The config option used to store the algorithm

Bcfg2.Encryption.CFG_DECRYPT = 'decrypt'

The config option used to store the decryption strictness

Bcfg2.Encryption.CFG_SECTION = 'encryption'

The config file section encryption options and passphrases are stored in

Bcfg2.Encryption.DECRYPT = 0

Constant representing the decryption operation for M2Crypto.EVP.Cipher, which uses a simple integer. This makes our code more readable.

Bcfg2.Encryption.ENCRYPT = 1

Constant representing the encryption operation for M2Crypto.EVP.Cipher, which uses a simple integer. This makes our code more readable.

Bcfg2.Encryption.IV = '\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0'

Default initialization vector. For best security, you should use a unique IV for each message. ssl_encrypt() does this in an automated fashion.

Bcfg2.Encryption.bruteforce_decrypt(crypted, passphrases=None, setup=None, algorithm='aes_256_cbc')[source]

Convenience method to decrypt the given encrypted string by trying the given passphrases or all passphrases (as returned by get_passphrases()) sequentially until one is found that works.

Either passphrases or setup must be provided.

  • crypted (string) – The data to decrypt
  • passphrases (list) – The passphrases to try.
  • setup (Bcfg2.Options.OptionParser) – A Bcfg2 option set to extract passphrases from
  • algorithm (string) – The cipher algorithm to use

string - The decrypted data

Raises :

M2Crypto.EVP.EVPError, if the data cannot be decrypted


Get the cipher algorithm from the config file. This is used in case someone uses the OpenSSL algorithm name (e.g., “AES-256-CBC”) instead of the M2Crypto name (e.g., “aes_256_cbc”), and to handle errors in a sensible way and deduplicate this code.

Parameters:setup (Bcfg2.Options.OptionParser) – The Bcfg2 option set to extract passphrases from
Returns:dict - a dict of <passphrase name>: <passphrase>

Get all candidate encryption passphrases from the config file.

Parameters:setup (Bcfg2.Options.OptionParser) – The Bcfg2 option set to extract passphrases from
Returns:dict - a dict of <passphrase name>: <passphrase>
Bcfg2.Encryption.ssl_decrypt(data, passwd, algorithm='aes_256_cbc')[source]

Decrypt openssl-encrypted data. This can decrypt data encrypted by ssl_encrypt(), or openssl enc. It performs a base64 decode first if the data is base64 encoded, and automatically determines the salt and initialization vector (both of which are embedded in the encrypted data).

  • data (string) – The encrypted data (either base64-encoded or raw binary) to decrypt
  • passwd (string) – The password to use to decrypt the data
  • algorithm (string) – The cipher algorithm to use

string - The decrypted data

Bcfg2.Encryption.ssl_encrypt(plaintext, passwd, algorithm='aes_256_cbc', salt=None)[source]

Encrypt data in a format that is openssl compatible.

  • plaintext (string) – The plaintext data to encrypt
  • passwd (string) – The password to use to encrypt the data
  • algorithm (string) – The cipher algorithm to use
  • salt (bytes) – The salt to use. If none is provided, one will be randomly generated.

string - The base64-encoded, salted, encrypted string. The string includes a trailing newline to make it fully compatible with openssl command-line tools.

Bcfg2.Encryption.str_decrypt(crypted, key, iv='\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0', algorithm='aes_256_cbc')[source]

Decrypt a string with a key. For a higher-level decryption interface, see ssl_decrypt().

  • crypted (string) – The raw binary encrypted data
  • key (string) – The encryption key to decrypt with
  • iv (string) – The initialization vector
  • algorithm (string) – The cipher algorithm to use

string - The decrypted data

Bcfg2.Encryption.str_encrypt(plaintext, key, iv='\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0', algorithm='aes_256_cbc', salt=None)[source]

Encrypt a string with a key. For a higher-level encryption interface, see ssl_encrypt().

  • plaintext (string) – The plaintext data to encrypt
  • key (string) – The key to encrypt the data with
  • iv (string) – The initialization vector
  • algorithm (string) – The cipher algorithm to use
  • salt (string) – The salt to use

string - The decrypted data