A simple configuration parser with transparent secret decryption via GPG, AWS KMS, and AWS SSM Parameter Store.
Requires Python 3.10+.
pip install figgypyOr with uv:
uv add figgypyimport figgypy
cfg = figgypy.Config("config.yaml")
# Access values as attributes (set from top-level keys).
cfg.db["host"]
# Or use the values dict directly.
cfg.values.get("db")
# Or use the get_value helper.
cfg.get_value("db")A Config can be created with a filename, relative path, or absolute path. For non-absolute paths, figgypy searches in order:
- Current directory
~/.config/<file_name>/etc/<file_name>
Including your __package__ in the path is a good practice:
cfg = figgypy.Config(os.path.join(__package__, "config.yaml"))Configuration files can be YAML, JSON, or XML. The format is determined by file extension (.yaml, .yml, .json, .xml). Unrecognized extensions fall back to YAML parsing.
For XML, the root element becomes a top-level key since XML requires a single root:
<config>
<db>
<host>db.example.com</host>
</db>
</config>cfg = figgypy.Config("config.xml")
cfg.config["db"]["host"] # "db.example.com"A Config instance can be shared globally across modules:
# app.py
import figgypy
cfg = figgypy.Config(config_file="config.yaml")
figgypy.set_config(cfg)
# elsewhere.py
import figgypy
figgypy.get_value("db")No file is required. Values can be set directly:
cfg = figgypy.Config()
cfg.set_value("db", {"host": "localhost", "port": 5432})Use Config.setup to reconfigure an existing instance with new settings:
cfg.setup(config_file="other.yaml", decrypt_kms=False, gpg_config=gpg_conf)Secrets in configuration files are decrypted transparently at load time. All three decryption methods (GPG, KMS, SSM) are enabled by default. Disable any of them at construction:
cfg = figgypy.Config("config.yaml", decrypt_gpg=False, decrypt_kms=False, decrypt_ssm=False)Setting a decrypt flag back to True triggers reprocessing:
cfg.decrypt_kms = TruePGP-encrypted values are detected automatically when they contain a BEGIN PGP block:
db:
host: db.example.com
pass: |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v2
hQIMAzf92ZrOUZL3ARAAgW...
-----END PGP MESSAGE-----Alternatively, use the _gpg key to wrap an encrypted value:
db:
pass:
_gpg: |
-----BEGIN PGP MESSAGE-----
...
-----END PGP MESSAGE-----To encrypt a value:
echo -n "your secret" | gpg --encrypt --armor -r KEY_IDGPG configuration can be passed in:
gpg_config = {"homedir": "~/.gnupg/", "binary": "gpg", "keyring": "pubring.kbx"}
cfg = figgypy.Config("config.yaml", gpg_config=gpg_config)Use the _kms key with a base64-encoded ciphertext blob:
db:
pass:
_kms: AQICAHg...base64...==To encrypt a value:
aws kms encrypt --key-id 'alias/your-key' --plaintext "your secret" \
--query CiphertextBlob --output textOr use the Python helper:
from figgypy.util import kms_encrypt
encrypted = kms_encrypt("your secret", "alias/your-key")Use the _ssm key with the parameter name:
db:
pass:
_ssm: /myapp/db/passwordParameters are fetched with decryption enabled (WithDecryption=True).
To store a parameter:
from figgypy.util import ssm_store_parameter
ssm_store_parameter("/myapp/db/password", "your secret")AWS credentials follow the standard boto3 resolution order: explicit config, environment variables, then machine configuration (instance profile, config files).
Pass credentials explicitly when needed:
aws_config = {
"aws_access_key_id": "...",
"aws_secret_access_key": "...",
"region_name": "us-east-1",
}
cfg = figgypy.Config("config.yaml", aws_config=aws_config)This project uses uv for dependency management.
uv sync
uv run pytest
uv run ruff check .