From b83344aebf12f66b14f68aeb2a8d897d6d3e1b33 Mon Sep 17 00:00:00 2001 From: Greg Dubicki Date: Thu, 27 Jul 2023 10:58:35 +0200 Subject: [PATCH 1/3] Stop using default SECRET_KEY and prepare 5.0.0 release https://github.com/voxpupuli/puppetboard/issues/721 https://github.com/voxpupuli/puppetboard/issues/829 --- CHANGELOG.md | 13 +++++++++++++ README.md | 5 +++-- puppetboard/default_settings.py | 4 ++-- puppetboard/docker_settings.py | 4 ++-- puppetboard/utils.py | 24 +++++------------------- puppetboard/version.py | 2 +- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b071d63a..0743e065 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,19 @@ Changelog This is the changelog for Puppetboard. +5.0.0 +----- + +* Stop setting `SECRET_KEY` value to a random string by default. This has caused issues in deployments with more than one app replica or when the app was restarted. Please set this to your own long, random string, **the same for each application replica**. Implements [#721](https://github.com/voxpupuli/puppetboard/issues/721). +* Drop support for Python 3.7 (end-of-life in June 2023). PR [#899](https://github.com/voxpupuli/puppetboard/pull/899) +* Fix broken links in Classes view. PR [#868](https://github.com/voxpupuli/puppetboard/pull/868), fixes [#816](https://github.com/voxpupuli/puppetboard/issues/816). +* Fix if fact is `None` (default for full node view). PR [#908](https://github.com/voxpupuli/puppetboard/pull/908), fixes [#907](https://github.com/voxpupuli/puppetboard/issues/907). +* Dependencies update. + +Thanks to the following contributors of this release: +* [Louis Charreau](https://github.com/lcharreau) +* [Yehuda Katz](https://github.com/yakatz) + 4.3.0 ----- diff --git a/README.md b/README.md index 04a6fa8c..4dbb721c 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,9 @@ to explicitly specify the protocol to be used setting the `PUPPETDB_PROTO` varia Other settings that might be interesting, in no particular order: +- `SECRET_KEY`: set this to a long string, **the same for each application replica** and keep it secret. Refer to + [Flask documentation](https://flask.palletsprojects.com/en/2.1.x/quickstart/#sessions), section + "How to generate good secret keys" for more info. - `FAVORITE_ENVS`: an ordered list of Puppet environment names that will be shown immediately after "All Environments" and before other environments (which are sorted by name) in the dropdown for choosing the environment shown in the top-right of the UI. Environments listed here that do not really exist in your deployment are silently ignored. @@ -175,8 +178,6 @@ Other settings that might be interesting, in no particular order: Defaults to `friendly`. - `CODE_PREFIX_TO_REMOVE`: what code path that should be shortened in "Friendly errors" to "…" for readability. A regexp. Defaults to `/etc/puppetlabs/code/environments(/.*?/modules)?`. -- `SECRET_KEY`: Refer to [Flask documentation](https://flask.palletsprojects.com/en/2.0.x/quickstart/#sessions), - section "How to generate good secret keys" for more info. Defaults to a random 64-char string generated by `secrets.token_hex(32)`, prepended with a `default-` string. **Warning** Leaving SECRET_KEY set to a default value WILL cause issues when the app is restarted or has more than 1 replica (f.e. uWSGI workers, k8s replicas etc.) and some features (in particular: queries) are used. Please set SECRET_KEY to your own value, the same for all app replicas. This will be REQUIRED starting with Puppetboard 5.x which will NOT contain the default value anymore. Please see [#721](https://github.com/voxpupuli/puppetboard/issues/721) for more info. - `PUPPETDB_TIMEOUT`: Defaults to 20 seconds, but you might need to increase this value. It depends on how big the results are when querying PuppetDB. This behaviour will change in a future release when pagination will be introduced. - `UNRESPONSIVE_HOURS`: The amount of hours since the last check-in after which a node is considered unresponsive. diff --git a/puppetboard/default_settings.py b/puppetboard/default_settings.py index ff970459..2f83037a 100644 --- a/puppetboard/default_settings.py +++ b/puppetboard/default_settings.py @@ -8,7 +8,7 @@ PUPPETDB_CERT = None PUPPETDB_TIMEOUT = 20 DEFAULT_ENVIRONMENT = 'production' -SECRET_KEY = f"default-{secrets.token_hex(32)}" +SECRET_KEY = '' UNRESPONSIVE_HOURS = 2 ENABLE_QUERY = True # Uncomment to restrict the enabled PuppetDB endpoints in the query page. @@ -78,7 +78,7 @@ ('noop', 'Noop'), ] # Type of caching object to use when `SCHEDULER_ENABLED` is set to `True`. -# If more than one worker, use a shared backend (e.g. `MemcachedCache`) +# If more than one worker, use a shared backend (e.g. `MemcachedCache`) # to allow the sharing of the cache between the processes. CACHE_TYPE = 'SimpleCache' # Cache litefime in second diff --git a/puppetboard/docker_settings.py b/puppetboard/docker_settings.py index ebf65e5c..9997308f 100644 --- a/puppetboard/docker_settings.py +++ b/puppetboard/docker_settings.py @@ -60,7 +60,7 @@ def coerce_bool(v, default): PUPPETDB_PROTO = os.getenv('PUPPETDB_PROTO', None) PUPPETDB_TIMEOUT = int(os.getenv('PUPPETDB_TIMEOUT', '20')) DEFAULT_ENVIRONMENT = os.getenv('DEFAULT_ENVIRONMENT', 'production') -SECRET_KEY = os.getenv('SECRET_KEY', f"default-{secrets.token_hex(32)}") +SECRET_KEY = os.getenv('SECRET_KEY', '') UNRESPONSIVE_HOURS = int(os.getenv('UNRESPONSIVE_HOURS', '2')) ENABLE_QUERY = coerce_bool(os.getenv('ENABLE_QUERY'), True) # Uncomment to restrict the enabled PuppetDB endpoints in the query page. @@ -177,7 +177,7 @@ def coerce_bool(v, default): CLASS_EVENTS_STATUS_COLUMNS = [(CLASS_EVENTS_STATUS_COLUMNS_STR[i].strip(), CLASS_EVENTS_STATUS_COLUMNS_STR[i + 1].strip()) for i in range(0, len(CLASS_EVENTS_STATUS_COLUMNS_STR), 2)] -# Enabled a scheduler instance to trigger jobs in background. +# Enabled a scheduler instance to trigger jobs in background. SCHEDULER_ENABLED = coerce_bool(os.getenv('SCHEDULER_ENABLED'), False) # Tuples are hard to express as an environment variable, so here diff --git a/puppetboard/utils.py b/puppetboard/utils.py index 36c65659..7e3bff1d 100644 --- a/puppetboard/utils.py +++ b/puppetboard/utils.py @@ -49,25 +49,11 @@ def check_db_version(puppetdb): def check_secret_key(secret_key_value): - """ - Check if the secret key value is set to a default value, that will stop - being accepted in v5.x of the app. - """ - - if type(secret_key_value) is str and secret_key_value.startswith("default-"): - log.warning( - "Leaving SECRET_KEY set to a default value WILL cause issues" - " when the app is restarted or has more than 1 replica" - " (f.e. uWSGI workers, k8s replicas etc.) and some features" - " (in particular: queries) are used.\n" - "Please set SECRET_KEY to your own value, the same for all app" - " replicas.\n" - "This will be REQUIRED starting with Puppetboard 5.x which" - " will NOT contain the default value anymore.\n" - "Please see" - " https://github.com/voxpupuli/puppetboard/issues/721" - " for more info." - ) + if not secret_key_value: + log.critical('Please set SECRET_KEY to a long, random string,' + ' **the same for each application replica**,' + ' and do not share it.') + sys.exit(1) def parse_python(value: str): diff --git a/puppetboard/version.py b/puppetboard/version.py index fe99f799..68ce45b7 100644 --- a/puppetboard/version.py +++ b/puppetboard/version.py @@ -2,4 +2,4 @@ # Puppetboard version module # -__version__ = '4.3.0' +__version__ = '5.0.0' From 80d9008a828ec4a928852187bffd0e35fe137dec Mon Sep 17 00:00:00 2001 From: Greg Dubicki Date: Thu, 27 Jul 2023 11:09:17 +0200 Subject: [PATCH 2/3] Fix tests and update a deprecated API --- puppetboard/app.py | 2 +- puppetboard/core.py | 4 ++-- test/test_form.py | 8 ++++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/puppetboard/app.py b/puppetboard/app.py index 627d1521..ca0759d7 100644 --- a/puppetboard/app.py +++ b/puppetboard/app.py @@ -45,7 +45,7 @@ running_as = os.path.basename(sys.argv[0]) if not is_a_test(): check_db_version(puppetdb) -check_secret_key(app.config.get('SECRET_KEY')) + check_secret_key(app.config.get('SECRET_KEY')) logging.basicConfig(level=app.config['LOGLEVEL'].upper()) log = logging.getLogger(__name__) diff --git a/puppetboard/core.py b/puppetboard/core.py index 4d43b7d0..43ef71a3 100644 --- a/puppetboard/core.py +++ b/puppetboard/core.py @@ -1,8 +1,8 @@ import logging import re import socket +from importlib.metadata import version -import pkg_resources from flask import Flask from flask_caching import Cache from flask_apscheduler import APScheduler @@ -70,7 +70,7 @@ def get_puppetdb(): timeout=app.config['PUPPETDB_TIMEOUT'], protocol=app.config['PUPPETDB_PROTO'], ) - requests_version = pkg_resources.get_distribution("requests").version + requests_version = version("requests") user_agent_header = { "user-agent": f"puppetboard/{own_version} (r/{requests_version})", } diff --git a/test/test_form.py b/test/test_form.py index fbc28c10..a0a44019 100644 --- a/test/test_form.py +++ b/test/test_form.py @@ -1,9 +1,13 @@ -from puppetboard import app, forms +from puppetboard import forms +from puppetboard.core import get_app + +app = get_app() +app.config['SECRET_KEY'] = 'the random string' def test_form_valid(capsys): for form in [forms.QueryForm]: - with app.app.test_request_context(): + with app.test_request_context(): qf = form() out, err = capsys.readouterr() assert qf is not None From b1710fca885d407ad3eeb410ded2ad14bcf0cb66 Mon Sep 17 00:00:00 2001 From: Greg Dubicki Date: Thu, 27 Jul 2023 13:13:51 +0200 Subject: [PATCH 3/3] Explain why security tests should not highlight this line --- puppetboard/default_settings.py | 3 ++- puppetboard/docker_settings.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/puppetboard/default_settings.py b/puppetboard/default_settings.py index 2f83037a..39b290de 100644 --- a/puppetboard/default_settings.py +++ b/puppetboard/default_settings.py @@ -8,7 +8,8 @@ PUPPETDB_CERT = None PUPPETDB_TIMEOUT = 20 DEFAULT_ENVIRONMENT = 'production' -SECRET_KEY = '' +# this empty string has to be changed, we validate it with check_secret_key() +SECRET_KEY = '' # nosec UNRESPONSIVE_HOURS = 2 ENABLE_QUERY = True # Uncomment to restrict the enabled PuppetDB endpoints in the query page. diff --git a/puppetboard/docker_settings.py b/puppetboard/docker_settings.py index 9997308f..ba53563c 100644 --- a/puppetboard/docker_settings.py +++ b/puppetboard/docker_settings.py @@ -60,7 +60,8 @@ def coerce_bool(v, default): PUPPETDB_PROTO = os.getenv('PUPPETDB_PROTO', None) PUPPETDB_TIMEOUT = int(os.getenv('PUPPETDB_TIMEOUT', '20')) DEFAULT_ENVIRONMENT = os.getenv('DEFAULT_ENVIRONMENT', 'production') -SECRET_KEY = os.getenv('SECRET_KEY', '') +# this empty string has to be changed, we validate it with check_secret_key() +SECRET_KEY = os.getenv('SECRET_KEY', '') # nosec UNRESPONSIVE_HOURS = int(os.getenv('UNRESPONSIVE_HOURS', '2')) ENABLE_QUERY = coerce_bool(os.getenv('ENABLE_QUERY'), True) # Uncomment to restrict the enabled PuppetDB endpoints in the query page.