Multi-sourced (and optionally encrypted) configuration management.
Project description
cconf
cconf
is a library for reading configuration from various sources (such as environment
variables, environment files, and environment directories) and optionally encrypting
sensitive configurations. Sensitive configuration values are encrypted using
Fernet tokens, which provide authenticated
crypography and the ability to specify a maximum valid lifetime (ttl
).
Installation
pip install cconf
Usage
By default, there is a config
singleton set up to read configuration from the process
environment variables (os.environ
):
from cconf import config
DEBUG = config("DEBUG", False, cast=bool)
You can add to the list of configuration sources (this will still read from os.environ
first):
from cconf import config
config.file("/path/to/.env")
config.dir("/path/to/envdir")
Or you may want to set the configuration sources (and their order) manually. The
following will try envdir
first, followed by .env
.
from cconf import config
config.setup("/path/to/envdir", "/path/to/.env")
You can also specify sources that have either a key_file
(a file with Fernet
keys,
one per line), or keys
(a list of Fernet
keys or strings/bytes that will be
converted to Fernet
keys):
from cconf import config, EnvDir, EnvFile, HostEnv
config.setup(
EnvDir("/path/to/envdir", key_file="/path/to/envdir.keys"),
EnvFile("/path/to/.env", key_file="/path/to/env.keys"),
HostEnv(keys=["WQ6g4VBia1fNCuVCrsX5VvGUWYlHssUJLshONLsivhc="]),
)
Encrypting Sensitive Data
Any configuration value can be marked as sensitive
, meaning it will only be read from
sources that have encryption keys, and will always be decrypted using those keys (so no
plaintext values allowed).
from cconf import config, Secret
config.file("/path/to/.env", key_file="/path/to/secret.key")
# This SECRET_KEY is only valid for 24 hours.
SECRET_KEY = config("SECRET_KEY", sensitive=True, cast=Secret, ttl=86400)
Setting a ttl
will ensure the encrypted value is no older than that number of seconds.
Values older than ttl
will emit a warning and return undefined
. You may set a
default value for a sensitive
config value, but a warning will be emitted.
To get started, you can use the cconf
CLI tool to generate a new Fernet
key, then
use that key to encrypt some data:
% cconf genkey > secret.key
% cconf encrypt --keyfile secret.key secretdata
If you've already generated a key and configured the sources with that key in your
settings file, you may also pass -c/--config
to cconf
:
% cconf -c myapp.settings encrypt secretdata
This will encrypt the string secretdata
using all encrypted sources in your config,
and output them along with the source they're encrypted for. You must add this data to
your configuration files manually, cconf
makes no attempt to write to these files for
you.
Key and File Policies
Any source that specifies a key_file
may also specify a key_policy
which will
perform additional checks when opening the key_file
. By default key_policy
is set to
cconf.UserOnly
, which checks that the key file is owned by the current user, and has
no permissions granted to group or other users (i.e. 600
mode).
Similarly, EnvFile
and EnvDir
sources accept a policy
argument (which defaults to
None
) that will perform policy checks when opening the environment files. You may set
this to cconf.UserOnly
or cconf.UserOrGroup
, or write your own policy. A policy is
simply a function that takes a single path
argument and raises cconf.PolicyError
if
the file should not be opened.
Checking Configuration
The cconf
CLI tool includes a check
command which will print out a list of
configuration variables it knows about, grouped by the source. For instance, running it
against the tests.settings.prod
module of a local checkout will produce something that
looks like this:
% python -m cconf.cli -c tests.settings.prod check
EnvFile(/Users/dcwatson/Projects/cconf/tests/envs/prod)
HOSTNAME
'prodhost'
USERNAME
'produser'
API_KEY
'prodkey'
EnvDir(/Users/dcwatson/Projects/cconf/tests/envdirs/prod)
PASSWORD
'cc0nfRul3z!'
(Default)
DEBUG
'false'
Warnings
cconf
will emit warnings (specifically ConfigWarning
, a subclass of UserWarning
)
in certain cases:
- A config value was marked as
sensitive
, but the value extracted from the configuration source has either expired (if attl
was specified), or is improperly encrypted (wrong key, plaintext, etc.) - A config value was marked as
sensitive
, but was not found in any of the sources and a default value is being used. - A config key was not found in any of the sources, and there is no default value
specified. In this case,
undefined
is returned and a warning is emitted. - A
key_file
orkeys
was specified for a configuration source, but no actualFernet
keys were found (empty file, empty list, etc.)
You may choose to silence these warnings, or promote them to exceptions using Python's
warnings
module:
import warnings
from cconf import ConfigWarning
# Silence all ConfigWarnings.
warnings.simplefilter("ignore", ConfigWarning)
# Raise ConfigWarnings as exceptions.
warnings.simplefilter("error", ConfigWarning)
Django Integration
cconf
includes a single management command that wraps the cconf
CLI tool. To use it,
add cconf
to your INSTALLED_APPS
setting, then run manage.py config
. Being a
management command means your settings are already imported, so you don't need to
constantly pass -c myproject.settings
to the cconf
CLI.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.