AES encryption change triggers conf file re-encryption

This commit is contained in:
Orsiris de Jong 2023-03-27 15:30:23 +02:00
parent 50a0c19aea
commit fb25d83ebb
2 changed files with 68 additions and 14 deletions

View file

@ -8,29 +8,42 @@ __author__ = "Orsiris de Jong"
__copyright__ = "Copyright (C) 2022-2023 NetInvent" __copyright__ = "Copyright (C) 2022-2023 NetInvent"
__license__ = "GPL-3.0-only" __license__ = "GPL-3.0-only"
__build__ = "2023032601" __build__ = "2023032601"
__version__ = "1.6.3 for npbackup 2.2.0+" __version__ = "1.7.0 for npbackup 2.2.0+"
from typing import Tuple, Optional from typing import Tuple, Optional
import sys import sys
import os
from ruamel.yaml import YAML from ruamel.yaml import YAML
from logging import getLogger from logging import getLogger
import re import re
import platform import platform
from cryptidy import symmetric_encryption as enc from cryptidy import symmetric_encryption as enc
from ofunctions.random import random_string from ofunctions.random import random_string
from npbackup.path_helper import BASEDIR
from npbackup.customization import ID_STRING from npbackup.customization import ID_STRING
sys.path.insert(0, os.path.normpath(os.path.join(os.path.dirname(__file__), "..")))
# Try to import a private key, if not available, fallback to the default key # Try to import a private key, if not available, fallback to the default key
try: try:
from npbackup._private_secret_keys import AES_KEY, DEFAULT_BACKUP_ADMIN_PASSWORD from PRIVATE._private_secret_keys import AES_KEY, DEFAULT_BACKUP_ADMIN_PASSWORD
from npbackup._private_revac import revac from PRIVATE._private_revac import revac
AES_KEY = revac(AES_KEY) AES_KEY = revac(AES_KEY)
IS_PRIV_BUILD = True IS_PRIV_BUILD = True
try:
from PRIVATE._private_secret_keys import OLD_AES_KEY
OLD_AES_KEY = revac(OLD_AES_KEY)
except ImportError:
OLD_AES_KEY = None
except ImportError: except ImportError:
try: try:
from npbackup.secret_keys import AES_KEY, DEFAULT_BACKUP_ADMIN_PASSWORD from npbackup.secret_keys import AES_KEY, DEFAULT_BACKUP_ADMIN_PASSWORD
IS_PRIV_BUILD = False IS_PRIV_BUILD = False
try:
from npbackup.secret_keys import OLD_AES_KEY
except ImportError:
OLD_AES_KEY = None
except ImportError: except ImportError:
print("No secret_keys file. Please read documentation.") print("No secret_keys file. Please read documentation.")
sys.exit(1) sys.exit(1)
@ -94,6 +107,8 @@ empty_config_dict = {
def decrypt_data(config_dict: dict) -> dict: def decrypt_data(config_dict: dict) -> dict:
if not config_dict:
return None
try: try:
for option in ENCRYPTED_OPTIONS: for option in ENCRYPTED_OPTIONS:
try: try:
@ -124,12 +139,13 @@ def decrypt_data(config_dict: dict) -> dict:
) )
) )
logger.debug("Trace:", exc_info=True) logger.debug("Trace:", exc_info=True)
sys.exit(11)
except TypeError:
logger.error(
"Cannot decrypt this configuration file. No base64 encoded strings available."
)
return False return False
except TypeError as exc:
logger.error(
"Cannot decrypt this configuration file. No base64 encoded strings available: {}.".format(exc)
)
logger.debug("Trace:", exc_info=True)
return None
return config_dict return config_dict
@ -233,25 +249,57 @@ def evaluate_variables(config_dict: dict, value: str) -> str:
return value return value
def update_encryption(config_file: str) -> Optional[dict]:
"""
If we changed AES KEY, let's use the old key to update the config file
"""
def load_config(config_file: str) -> Optional[dict]: def load_config(config_file: str) -> Optional[dict]:
""" """
Using ruamel.yaml preserves comments and order of yaml files Using ruamel.yaml preserves comments and order of yaml files
""" """
global AES_KEY
global OLD_AES_KEY
try: try:
logger.debug("Using configuration file {}".format(config_file)) logger.debug("Using configuration file {}".format(config_file))
with open(config_file, "r", encoding="utf-8") as file_handle: with open(config_file, "r", encoding="utf-8") as file_handle:
# RoundTrip loader is default and preserves comments and ordering # RoundTrip loader is default and preserves comments and ordering
yaml = YAML(typ="rt") yaml = YAML(typ="rt")
config_dict = yaml.load(file_handle) config_dict = yaml.load(file_handle)
config_file_needs_save = False
# Check modifications before decrypting since ruamel object is a pointer !!!
is_modified, config_dict = has_random_variables(config_dict) is_modified, config_dict = has_random_variables(config_dict)
if is_modified: if is_modified:
logger.info("Handling random variables in configuration files") logger.info("Handling random variables in configuration files")
save_config(config_file, config_dict) config_file_needs_save = True
if not is_encrypted(config_dict): if not is_encrypted(config_dict):
logger.info("Encrypting non encrypted data in configuration file") logger.info("Encrypting non encrypted data in configuration file")
config_dict = encrypt_data(config_dict) config_file_needs_save = True
config_dict_decrypted = decrypt_data(config_dict)
if config_dict_decrypted == False:
if OLD_AES_KEY:
new_aes_key = AES_KEY
AES_KEY = OLD_AES_KEY
logger.info("Trying to migrate encryption key")
config_dict_decrypted = decrypt_data(config_dict)
if config_dict_decrypted is not False:
AES_KEY = new_aes_key
logger.info("Migrated encryption")
config_file_needs_save = True
new_aes_key = None
OLD_AES_KEY = None
else:
logger.critical("Cannot decrypt config file.")
sys.exit(12)
else:
sys.exit(11)
if config_file_needs_save:
logger.info("Updating config file")
save_config(config_file, config_dict) save_config(config_file, config_dict)
config_dict = decrypt_data(config_dict)
return config_dict return config_dict
except OSError: except OSError:
logger.critical("Cannot load configuration file from %s", config_file) logger.critical("Cannot load configuration file from %s", config_file)

View file

@ -7,16 +7,22 @@ __intname__ = "npbackup.secret_keys"
__author__ = "Orsiris de Jong" __author__ = "Orsiris de Jong"
__copyright__ = "Copyright (C) 2023 NetInvent" __copyright__ = "Copyright (C) 2023 NetInvent"
__license__ = "GPL-3.0-only" __license__ = "GPL-3.0-only"
__build__ = "2022120401" __build__ = "2023032601"
# Encryption key to keep repo settings safe in plain text yaml config file # Encryption key to keep repo settings safe in plain text yaml config file
# This is the default key that comes with NPBackup.. You should change it (and keep a backup copy in case you need to decrypt a config file data) # This is the default key that comes with NPBackup.. You should change it (and keep a backup copy in case you need to decrypt a config file data)
# You can overwrite this by copying this file to `_private_secret_keys.py` and generating a new key # You can overwrite this by copying this file to `../PRIVATE/_private_secret_keys.py` and generating a new key
# Obtain a new key with: # Obtain a new key with:
# from cryptidy.symmetric_encryption import generate_key # from cryptidy.symmetric_encryption import generate_key
# print(generate_key(32)) # print(generate_key(32))
AES_KEY = b"\x9e\xbck\xe4\xc5nkT\x1e\xbf\xb5o\x06\xd3\xc6(\x0e:'i\x1bT\xb3\xf0\x1aC e\x9bd\xa5\xc6" AES_KEY = b"\xc3T\xdci\xe3[s\x87o\x96\x8f\xe5\xee.>\xf1,\x94\x8d\xfe\x0f\xea\x11\x05 \xa0\xe9S\xcf\x82\xad|"
DEFAULT_BACKUP_ADMIN_PASSWORD = "NPBackup_00" DEFAULT_BACKUP_ADMIN_PASSWORD = "NPBackup_00"
"""
If someday we need to change the AES_KEY, copy it's content to OLD_AES_KEY and generate a new one
Keeping OLD_AES_KEY allows to migrate from old configuration files to new ones
"""
EARLIER_AES_KEY = b"\x9e\xbck\xe4\xc5nkT\x1e\xbf\xb5o\x06\xd3\xc6(\x0e:'i\x1bT\xb3\xf0\x1aC e\x9bd\xa5\xc6"