Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Support both encrypted and non encrypted configuration with aumbry

We have a python application that loads a config.yml with aumbry. For production purpose we need to encrypt this configuration with fernet, which aumbry can load seamlessly.

We want to be able to load both unencrypted and encrypted in a transparent way, for example load unencrypted if found, and if not (production) load encrypted. So far we have implemented this.

Encryption

import cryptography.Fernet as fn
from os.path import split, splitext

def _encrypt_file(path, key):
    with open(path, 'rb') as infile:
        file_data = infile.read()
        nc_data= fn(key).encrypt(file_data)
        infile.close()

        base_path, filename = split(path)
        name, _ = splitext(filename)
        nc_name = "{}.{}".format(name, 'nc')
        with open(join(base_path, nc_name), 'wb') as outfile:
            outfile.write(nc_data)
            outfile.close()

Aumbry configuration

from aumbry.errors import LoadError

def _get_configuration():
    return aumbry.load(
        aumbry.FILE,
        AppConfig,
        options={
            'CONFIG_FILE_PATH': "config.yml"            
        }
    )

def _get_encrypted_configuration():
    return aumbry.load(
        aumbry.FERNET,
        AppConfig,
        options={
            'CONFIG_FILE_PATH': "config.nc",
            'CONFIG_FILE_FERNET_KEY': 'bZhF6nN4A6fhVBPtru2dG1_6d7i0d_B2FxmsybjtE-g='
        }
    )
def load_config():
    """General method to load configuration"""
    try:
        return _get_configuration()
    except LoadError:
        try: 
            return _get_encrypted_configuration()
        except LoadError:
            return None
  • Is there a more elegant way to achieve this behavior?
like image 395
Jav_Rock Avatar asked Sep 26 '18 17:09

Jav_Rock


2 Answers

Depending on the framework on which your python application is built, there is usually some kind of global "mode" value that can be used.

Flask, for example, uses FLASK_ENV environment variable that can be set to either development or production. Within the app, you can use

app.config['DEBUG']  # True if FLASK_ENV is "development"

to differentiate between the 2 modes.

In your case, the ambury loader can be refactored to do:

config_loader_cls = EncryptedConfigLoader if environment=='production' else PlainConfigLoader

I would go even further and have EncryptedConfigLoader fail if the configuration is not encrypted for additional security.

like image 158
James Lim Avatar answered Oct 17 '22 12:10

James Lim


There are a few solutions:

a) Encrypted files use different file names from its unencrypted counterparts. For example, an unencrypted file with the name "config.yml" may be renamed to "config_en.yml". This may not be your option.

b) I notice that "config.yml" normally has "version: 2" in its content. You just need to use Python to check if "version: is in the file, if so, it is unencrypted.

like image 25
yoonghm Avatar answered Oct 17 '22 12:10

yoonghm