The modules documented in this gist present the crux of my idea for Secrets Manager for the Django framework. The complete prototype can be view and played around with here.
env.py (included in this gist: env.py)
env.py resides in the env/ folder in the Django root, the directory where settings.py resides in a new project.
This is the entry point for a developer to register secrets sources with the SecretsManager. An object of class
SecretsManager is instantiated here. Any environment secrets sources can be registered here to be used later anywhere
in the project.
settings.py (included in this gist: settings.py)
The developer will retrieve the created SecretsManager object (singleton, so developer doesn't have to do much). get_secrets()/get_secrets(env_name) is triggered as per requirement to get secrets from the appropriate source as a dict.
secrets_manager.py (included in this gist: secrets_manager.py)
In this prototype, secrets_manager.py resides in secrets_manager package. However, it will reside in the Django codebase
later.
The SecretsManager class is an instance of Singleton. Singleton is a design pattern that ensures that only one object is
created throughout the project life cycle. This pattern facilitates the use of a SecretsManager instantiated once, to be used throughout the project in any other module.
The SecretsManager's instantiating parameters define how the SecretsManager is constructed:
- default_env_name defines the default environment secrets source to be returned by default.
- --env=$env_name passed to manage.py can override this
- env_name passed to get_secrets(env_name) can overide this
- lazy_loading defines if secrets sources are read when registered or when requested. (True by default)
- auto_register defines if SecretsManager should automatically register .env and python module secret sources present
in the env/ directory (False by default)
- The naming convention for auto registered environment sources in the prototype can be viewed in SecretsManager's instance method auto_register(). This convention is only for demonstration purposes and will be perfected later.
- during automatic registration, if there is a source file that contains 'base' in it's name, that source will be set as the base.
The SecretsManager's instance methods allow the developer work the required magic:
- register(env_name, src, auto_reload=False, payload=None, headers=None, Auth=None) allows registration of a secrets source with the secrets manager.
- set_base(env_name) allows the developer to set base environment secrets, pulling from a registered source.
- auto_register() can be triggered by the developer in case (s)he wants to trigger automatic registration inspite of setting auto_register=False while instantiating SecretsManager.
- get_secrets(env_name=None) returns secrets of the specified environment, if env_name is passed. It env_name is not passed, Returns secrets of environment name passed to manage.py using --env argument. If --env is not passed, SecretsManager's default environment's secrets are returned. A dict is returned to the calling module.
- reload_secrets(env_name) allows developer to force reload/re-read of secrets associated with env_name even if the source was registered with auto_reload=False
- unregister(env_name) allows the developer to unregister a previously registered secrets source.
secrets.py (included in this gist: secrets.py)
In this prototype, secrets.py resides in secrets_manager module. However, it will reside in the Django codebase
later.
The SecretsAbstract class is an instance of SingletonByArgument. SingletonByArgument is a design pattern that ensures that
only one object is created for a particular combination of registration parameters.
DotEnvSecrets, ModuleSecrets, HTTPSecrets implement SecretsAbstract and implement the abstract method read_secrets() and
read corresponding types of secret sources.
HTTPSecrets in particular needs more parameters, payload, headers and Auth.
- Auth is the type of authentication, if required, for an API based secrets source. HTTPSecrets will inspect this authentication type's constructor and request CLI input for the required parameters.