diff options
author | Jake Hunsaker <jhunsake@redhat.com> | 2019-04-10 11:55:53 -0400 |
---|---|---|
committer | Bryn M. Reeves <bmr@redhat.com> | 2019-05-14 11:25:01 +0100 |
commit | 762765cfabb1ac62864f6a0552f7eda46112f9e1 (patch) | |
tree | 9dfb76f8e8165e1c9f5b01c3012ea799e796abc0 | |
parent | 877014bbfd85c02083a716212a5cbbe715f4b96a (diff) | |
download | sos-762765cfabb1ac62864f6a0552f7eda46112f9e1.tar.gz |
[Plugin] Allow plugins to capture environment variables
Adds a new 'add_env_var()' method to the Plugin class, which allows
plugins to specify which environment variables should be recorded in the
sos archive. This functions as a whitelist, as only environment
variables requested by plugins will be captured. The new method accepts
either a single string, or a list of strings.
Collection of environment variables is done _after_ we have run
collect() for each plugin, and will be written to the 'environment' file
in the archive root. Only environment variables that exist will be
written, so if a plugin requests an environment variable be captured and
it does not appear in the file the chances are good that the variable is
not set on the system.
Each environment variable will only be captured once - so multiple
plugins may specify the same environment variable without an issue.
Additionally, when a plugin uses add_env_var(), the value passed as well
as an upper- and lower- cased variant of the value will be added to the
list of variables to be collected as well. This is because it is a
frequent support issue where end users set an incorrectly-cased
variable, and support representatives will want to know when this is the
case.
Because this functionality works off of a whitelist, environment
variable values are not sanitized. Note also that due to the variable
name casing functionality mentioned above, this means there is a small
chance where sensitive data stored in differently-cased variables of the
same name as common variables could be unintentionally captured.
Use the --no-env-vars option to prevent capturing any environment
variables wholesale.
Fixes: #1396
Resolves: #1643
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
-rw-r--r-- | sos/__init__.py | 9 | ||||
-rw-r--r-- | sos/plugins/__init__.py | 16 | ||||
-rw-r--r-- | sos/sosreport.py | 17 |
3 files changed, 38 insertions, 4 deletions
diff --git a/sos/__init__.py b/sos/__init__.py index ed59025a..9cd71728 100644 --- a/sos/__init__.py +++ b/sos/__init__.py @@ -54,9 +54,9 @@ _arg_names = [ 'chroot', 'compression_type', 'config_file', 'desc', 'debug', 'del_preset', 'dry_run', 'enableplugins', 'encrypt_key', 'encrypt_pass', 'experimental', 'label', 'list_plugins', 'list_presets', 'list_profiles', 'log_size', - 'noplugins', 'noreport', 'note', 'onlyplugins', 'plugin_timeout', - 'plugopts', 'preset', 'profiles', 'quiet', 'sysroot', 'threads', 'tmp_dir', - 'verbosity', 'verify' + 'noplugins', 'noreport', 'no_env_vars', 'note', 'onlyplugins', + 'plugin_timeout', 'plugopts', 'preset', 'profiles', 'quiet', 'sysroot', + 'threads', 'tmp_dir', 'verbosity', 'verify' ] #: Arguments with non-zero default values @@ -179,6 +179,7 @@ class SoSOptions(object): self.log_size = _arg_defaults["log_size"] self.noplugins = [] self.noreport = False + self.no_env_vars = False self.note = "" self.onlyplugins = [] self.plugin_timeout = None @@ -220,7 +221,7 @@ class SoSOptions(object): no_value = ( "alloptions", "all-logs", "batch", "build", "debug", "experimental", "list-plugins", "list-presets", "list-profiles", - "noreport", "quiet", "verify" + "noreport", "no-env-vars", "quiet", "verify" ) count = ("verbose",) if opt in no_value: diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py index 09a90c7f..8fbceeb3 100644 --- a/sos/plugins/__init__.py +++ b/sos/plugins/__init__.py @@ -242,6 +242,7 @@ class Plugin(object): self.copied_files = [] self.executed_commands = [] + self._env_vars = set() self.alerts = [] self.custom_text = "" self.opt_names = [] @@ -969,6 +970,21 @@ class Plugin(object): return outfn + def add_env_var(self, name): + """Add an environment variable to the list of to-be-collected env vars. + + Accepts either a single variable name or a list of names. Any value + given will be added as provided to the method, as well as an upper- + and lower- cased version. + """ + if not isinstance(name, list): + name = [name] + for env in name: + # get both upper and lower cased vars since a common support issue + # is setting the env vars to the wrong case, and if the plugin + # adds a mixed case variable name, still get that as well + self._env_vars.update([env, env.upper(), env.lower()]) + def add_string_as_file(self, content, filename, pred=None): """Add a string to the archive as a file named `filename`""" diff --git a/sos/sosreport.py b/sos/sosreport.py index c13142c7..058868c7 100644 --- a/sos/sosreport.py +++ b/sos/sosreport.py @@ -180,6 +180,9 @@ def _get_parser(): parser.add_argument("--no-report", action="store_true", dest="noreport", help="disable plaintext/HTML reporting", default=False) + parser.add_argument("--no-env-vars", action="store_true", default=False, + dest="no_env_vars", + help="Do not collect environment variables") parser.add_argument("--note", type=str, action="store", default="", help="Behaviour notes for new preset") parser.add_argument("-o", "--only-plugins", action="extend", @@ -245,6 +248,7 @@ class SoSReport(object): self.loaded_plugins = [] self.skipped_plugins = [] self.all_options = [] + self.env_vars = set() self.archive = None self.tempfile_util = None self._args = args @@ -931,6 +935,7 @@ class SoSReport(object): try: plug.archive = self.archive plug.setup() + self.env_vars.update(plug._env_vars) if self.opts.verify: plug.setup_verify() except KeyboardInterrupt: @@ -1062,6 +1067,16 @@ class SoSReport(object): sys.stdout.write(status_line) sys.stdout.flush() + def collect_env_vars(self): + if not self.env_vars: + return + env = '\n'.join([ + "%s=%s" % (name, val) for (name, val) in + [(name, '%s' % os.environ.get(name)) for name in self.env_vars if + os.environ.get(name) is not None] + ]) + '\n' + self.archive.add_string(env, 'environment') + def plain_report(self): report = Report() @@ -1356,6 +1371,8 @@ class SoSReport(object): self.prework() self.setup() self.collect() + if not self.opts.no_env_vars: + self.collect_env_vars() if not self.opts.noreport: self.html_report() self.plain_report() |