Generate db_encrypted_fields_keyfile#205
Conversation
|
TODO: Update settings.py (depends on implementation details in pulpcore 3.15) |
| Puppet::Functions.create_function(:generate_fernet_key) do | ||
| # @return 32 byte url-safe base64-encoded (with padding) Fernet symmetric encryption key | ||
| dispatch :generate_fernet_key do | ||
| return_type 'String' |
There was a problem hiding this comment.
You can even give a stronger guarantee. It's at least 32 characters, right?
| return_type 'String' | |
| return_type 'String[32]' |
There was a problem hiding this comment.
I'll try Pattern[/\A([a-zA-Z]|\d|-|_){43}=\z/] since this matches exactly what are the allowed values for 32 bytes in url-safe base64 encoded form
In fact, cryptography.fernet claims that it requires the url-safe base64 encoding, for example here: https://github.com/pyca/cryptography/blob/77fb53c75e47f50e09b1b3be3a4d10c7e4e34dc2/src/cryptography/fernet.py#L37-L41
and also in the docs at https://github.com/pyca/cryptography/blob/77fb53c75e47f50e09b1b3be3a4d10c7e4e34dc2/docs/fernet.rst :
param key: A URL-safe base64-encoded 32-byte key. This must be kept secret. Anyone with this key is able to create and read messages.
With that said, it uses base64.urlsafe_b64decode to load the key, and in fact that performs the translation from the non url-safe alphabet: https://github.com/python/cpython/blob/86eeeb425936ba67d79f32bfbd5c5f8002819438/Lib/base64.py#L108-L133
I tested this and it does in fact work to load a key with either base64 alphabet, even though cryptography.fernet claims it doesn't support that:
>>> from cryptography.fernet import Fernet
>>> urlsafe_key = b'xTjQtHgU6OsktqtDGAG5ogEb8xNjT2DQGytK3hWMg-_='
>>> nonurlsafe_key = b'xTjQtHgU6OsktqtDGAG5ogEb8xNjT2DQGytK3hWMg+/='
>>> f1 = Fernet(key = urlsafe_key)
>>> f2 = Fernet(key = nonurlsafe_key)
>>> f1._encryption_key == f2._encryption_key
True
>>> f1._signing_key == f2._signing_key
TrueNote that it is also possible to use Fernet encryption using an existing password such as the Django SECRET_KEY and generating the Fernet key from that. There is an example provided in cryptography.fernet docs:
>>> import base64
>>> import os
>>> from cryptography.fernet import Fernet
>>> from cryptography.hazmat.primitives import hashes
>>> from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
>>> password = b"password"
>>> salt = os.urandom(16)
>>> kdf = PBKDF2HMAC(
... algorithm=hashes.SHA256(),
... length=32,
... salt=salt,
... iterations=100000,
... )
>>> key = base64.urlsafe_b64encode(kdf.derive(password))
>>> f = Fernet(key)
>>> token = f.encrypt(b"Secret message!")
>>> token
b'...'
>>> f.decrypt(token)
b'Secret message!'django-fernet-fields generates a derived fernet key from the standard Django SECRET_KEY by default[1], although the behavior can be disabled to pass an arbitrary fernet key instead.
[1] https://django-fernet-fields.readthedocs.io/en/latest/#keys
The implementation is similar to the above: https://github.com/orcasgit/django-fernet-fields/blob/master/fernet_fields/hkdf.py#L14-L23
With the approach of generating the Fernet key by hashing the standard Django SECRET_KEY, this PR would become unnecessary, but it does not look like the Pulp team is planning to follow that implementation.
66999c0 to
b40d886
Compare
b378506 to
14279c6
Compare
Pulpcore 3.15 will require a Fernet symmetric encryption key to encrypt certain sensitive database fields. This is expected to contain 32 pseudorandom bytes in url-safe base64-encoded format, with padding.
14279c6 to
d533020
Compare
Pulpcore 3.15 will require a Fernet symmetric encryption
key to encrypt certain sensitive database fields.
This is expected to contain 32 pseudorandom bytes in
url-safe base64-encoded format, with padding.