Package: cconf
cconfcconfis 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 usingFernettokens, which provide authenticated
crypography and the ability to specify a maximum valid lifetime (ttl).Installationpip install cconfTo useFernetkeys for encrypting sensitive settings,cconfrequires thecryptographymodule, which can be installed as an extra:pip install cconf[fernet]UsageBy default, there is aconfigsingleton set up to read configuration from the process
environment variables (os.environ):fromcconfimportconfigDEBUG=config("DEBUG",False,cast=bool)You can add to the list of configuration sources (this will still read fromos.environfirst):fromcconfimportconfigconfig.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 tryenvdirfirst, followed by.env.fromcconfimportconfigconfig.setup("/path/to/envdir","/path/to/.env")You can also specify sources that havekeys, which can be the path to a file withFernetkeys, one per line, or a list ofstr|byteskeys that will be converted toFernetkeys:fromcconfimportconfig,EnvDir,EnvFile,HostEnvconfig.setup(EnvDir("/path/to/envdir",keys="/path/to/envdir.keys"),EnvFile("/path/to/.env",keys="/path/to/env.keys"),HostEnv(keys=["WQ6g4VBia1fNCuVCrsX5VvGUWYlHssUJLshONLsivhc="]),)Encrypting Sensitive DataAny configuration value can be marked assensitive, meaning it must be encrypted (or
base64-encoded if not usingFernetkeys) and will never be read from a plaintext
source.fromcconfimportconfig,Secretconfig.file("/path/to/.env",keys="/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 attlwill ensure the encrypted value is no older than that number of seconds.
Values older thanttlwill emit a warning and returnundefined. You may set a
default value for asensitiveconfig value, but a warning will be emitted.To get started, you can use thecconfCLI tool to generate a newFernetkey, then
use that key to encrypt some data:% cconf genkey > secret.key
% cconf encrypt --keyfile secret.key secretdataIf you've already generated a key and configured the sources with that key in your
settings file, you may also pass-c/--configtocconf:% cconf -c myapp.settings encrypt secretdataThis will encrypt the stringsecretdatausing 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,cconfmakes no attempt to write to these files for
you.Key and File PoliciesA source may specify a key file policy (keys=cconf.KeyFile(name, policy=...)) which
performs additional checks when opening the key file. By defaultKeyFile.policyis
set tocconf.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.600mode).Similarly,EnvFileandEnvDirsources accept apolicyargument (which defaults toNone) that will perform policy checks when opening the environment files. You may set
this tocconf.UserOnlyorcconf.UserOrGroup, or write your own policy. A policy is
simply a function that takes a singlepathargument and raisescconf.PolicyErrorif
the file should not be opened.Checking ConfigurationThecconfCLI tool includes acheckcommand which will print out a list of
configuration variables it knows about, grouped by the source. For instance, running it
against thetests.settings.prodmodule 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'Warningscconfwill emit warnings (specificallyConfigWarning, a subclass ofUserWarning)
in certain cases:A config value was marked assensitive, but the value extracted from the
configuration source has either expired (if attlwas specified), or is improperly
encrypted (wrong key, plaintext, etc.)A config value was marked assensitive, 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,undefinedis returned and a warning is emitted.You may choose to silence these warnings, or promote them to exceptions using Python'swarningsmodule:importwarningsfromcconfimportConfigWarning# Silence all ConfigWarnings.warnings.simplefilter("ignore",ConfigWarning)# Raise ConfigWarnings as exceptions.warnings.simplefilter("error",ConfigWarning)Django Integrationcconfincludes a single management command that wraps thecconfCLI tool. To use it,
addcconfto yourINSTALLED_APPSsetting, then runmanage.py config. Being a
management command means your settings are already imported, so you don't need to
constantly pass-c myproject.settingsto thecconfCLI.