Distributing Python modules to untrusted environments requires securing the code. In the case of an inference package, this includes obfuscating the code as well as any model files.
This repo demonstrates how to:
- Secure code by obfuscating it with PyArmor
- Securing the model file using a Fernet key
- Writing the inference code such that it decrypts the model file in memory and uses it to perform predictions
encryption/fernet_encryption.py
is a utility that can:
- Generate new Fernet keys
- Encrypt and decrypt files with specified keys
train/train.py
contains a simple training script that produces a joblib model
model
package contains the dumped joblib model
inference.py
simulates usage of the model during inference.
Loads the model from its encrypted path and decrypts it in memory using the key
key/fernet_key.py
a module containing the key used to encrypt/decrypt the pickled model file.
Note: This file is replaced by the github action during step 2 of the worklfow (see below)
test/test_secure_inference.py
validates that the encryption/decryption of the model file
doesn't change its behavior
github-actions-secure.yaml
contains the workflow for automatically
securing the package on every push to main branch
This workflow happens inside the github actions.
-
Pull a pre-generated Fernet key from the *github repository secret.
-
Generate a local key/fernet_key.py file containing the key
-
Encrypt the model pickle file with the key
-
Test that the encryption didn't change the model by decrypting and validating
-
Obfuscate the entire codebase with PyArmor
-
Copy the encrypted model file and .env file into the obfuscated library
-
Test that the obfuscated inference.py file runs without exception
-
Tar.gz the obfuscated codebase and upload it into the workflow's artifacts