diff --git a/netbox/netbox/configuration_example.py b/netbox/netbox/configuration_example.py index 612f75a4096..18d30d29a5a 100644 --- a/netbox/netbox/configuration_example.py +++ b/netbox/netbox/configuration_example.py @@ -68,6 +68,16 @@ REDIS = { # https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY SECRET_KEY = '' +# Define a mapping of cryptographic peppers to use when hashing API tokens. A minimum of one pepper is required to +# enable v2 API tokens (NetBox v4.5+). Define peppers as a mapping of numeric ID to pepper value, as shown below. Each +# pepper must be at least 50 characters in length. +# +# API_TOKEN_PEPPERS = { +# 1: "", +# 2: "", +# } +API_TOKEN_PEPPERS = {} + ######################### # # diff --git a/netbox/netbox/configuration_testing.py b/netbox/netbox/configuration_testing.py index 36f9d7338ea..6d1de200872 100644 --- a/netbox/netbox/configuration_testing.py +++ b/netbox/netbox/configuration_testing.py @@ -46,7 +46,7 @@ DEFAULT_PERMISSIONS = {} ALLOW_TOKEN_RETRIEVAL = True API_TOKEN_PEPPERS = { - 1: 'TEST-VALUE-DO-NOT-USE', + 1: 'TEST-VALUE-DO-NOT-USE-TEST-VALUE-DO-NOT-USE-TEST-VALUE-DO-NOT-USE', } LOGGING = { diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index a912c2d6e8f..828f7310905 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -19,6 +19,7 @@ from netbox.plugins import PluginConfig from netbox.registry import registry import storages.utils # type: ignore from utilities.release import load_release_data +from utilities.security import validate_peppers from utilities.string import trailing_slash # @@ -217,10 +218,9 @@ if len(SECRET_KEY) < 50: ) # Validate API token peppers -for key in API_TOKEN_PEPPERS: - if type(key) is not int: - raise ImproperlyConfigured(f"Invalid API_TOKEN_PEPPERS key: {key}. All keys must be integers.") -if not API_TOKEN_PEPPERS: +if API_TOKEN_PEPPERS: + validate_peppers(API_TOKEN_PEPPERS) +else: warnings.warn("API_TOKEN_PEPPERS is not defined. v2 API tokens cannot be used.") # Validate update repo URL and timeout diff --git a/netbox/utilities/security.py b/netbox/utilities/security.py new file mode 100644 index 00000000000..47a18d26539 --- /dev/null +++ b/netbox/utilities/security.py @@ -0,0 +1,24 @@ +from django.core.exceptions import ImproperlyConfigured + +__all__ = ( + 'validate_peppers', +) + + +def validate_peppers(peppers): + """ + Validate the given dictionary of cryptographic peppers for type & sufficient length. + """ + if type(peppers) is not dict: + raise ImproperlyConfigured("API_TOKEN_PEPPERS must be a dictionary.") + for key, pepper in peppers.items(): + if type(key) is not int: + raise ImproperlyConfigured(f"Invalid API_TOKEN_PEPPERS key: {key}. All keys must be integers.") + if not 0 <= key <= 32767: + raise ImproperlyConfigured( + f"Invalid API_TOKEN_PEPPERS key: {key}. Key values must be between 0 and 32767, inclusive." + ) + if type(pepper) is not str: + raise ImproperlyConfigured(f"Invalid pepper {key}: Pepper value must be a string.") + if len(pepper) < 50: + raise ImproperlyConfigured(f"Invalid pepper {key}: Pepper must be at least 50 characters in length.")