From f135e6a73f599cda62d10e96cc9eaf5885caad2d Mon Sep 17 00:00:00 2001 From: David Date: Thu, 24 Mar 2022 09:19:03 +1100 Subject: [PATCH 01/31] added an optional security_audit flag which users can specify in the st2,conf file, This is used to track when keys are being decrypted either manually in the container or when a workflow is triggered and contains an encrypted key in its config. --- conf/st2.conf.sample | 2 ++ st2api/st2api/controllers/v1/keyvalue.py | 4 +++- st2common/st2common/config.py | 5 +++++ st2common/st2common/util/config_loader.py | 2 ++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/conf/st2.conf.sample b/conf/st2.conf.sample index 9009cd0199..95d879023c 100644 --- a/conf/st2.conf.sample +++ b/conf/st2.conf.sample @@ -319,6 +319,8 @@ validate_output_schema = False validate_trigger_parameters = True # True to validate payload for non-system trigger types when dispatching a trigger inside the sensor. By default, only payload for system triggers is validated. validate_trigger_payload = True +# Enable security audit +security_audit = True [system_user] # SSH private key for the system user. diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index 6d25261419..ecb643b113 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -97,6 +97,8 @@ def get_one(self, name, requester_user, scope=None, user=None, decrypt=False): key_ref = get_key_reference(scope=scope, name=name, user=user) extra = {"scope": scope, "name": name, "user": user, "key_ref": key_ref} LOG.debug("GET /v1/keys/%s", name, extra=extra) + if decrypt and cfg.CONF.system.security_audit: + LOG.info("User %s decrypted the value %s ", user, name) # Setup a kvp database object used for verifying permission kvp_db = KeyValuePairDB( @@ -473,4 +475,4 @@ def _validate_scope(self, scope): raise ValueError(msg) -key_value_pair_controller = KeyValuePairController() +key_value_pair_controller = KeyValuePairController() \ No newline at end of file diff --git a/st2common/st2common/config.py b/st2common/st2common/config.py index 8ad2f5d1e8..f3e441a414 100644 --- a/st2common/st2common/config.py +++ b/st2common/st2common/config.py @@ -122,6 +122,11 @@ def register_opts(ignore_errors=False): default=False, help="True to validate action and runner output against schema.", ), + cfg.BoolOpt( + "security_audit", + default=False, + help="Audits a log message which notifies users that a key will be decrypted" + ) ] do_register_opts(system_opts, "system", ignore_errors) diff --git a/st2common/st2common/util/config_loader.py b/st2common/st2common/util/config_loader.py index aec424d75e..7552b37386 100644 --- a/st2common/st2common/util/config_loader.py +++ b/st2common/st2common/util/config_loader.py @@ -169,6 +169,8 @@ def _assign_dynamic_config_values(self, schema, config, parent_keys=None): is_jinja_expression = jinja_utils.is_jinja_expression( value=config_item_value ) + if "decrypt_kv" in config_item_value and cfg.CONF.system.security_audit: + LOG.info("User %s is decrypting the value %s from the config within pack %s", self.user, config_item_value, self.pack_name) if is_jinja_expression: # Resolve / render the Jinja template expression From cb3a36d806ac47dd5d77fdaf5652e4651d8b0c82 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 24 Mar 2022 16:15:35 +1100 Subject: [PATCH 02/31] updated ChangeLog --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9041981db5..c34bdde22b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -43,6 +43,7 @@ Fixed Added ~~~~~ +* Added security_audit flag that users can specify in st2.conf, provides logs anytime a decryption of st2 keys occurs in stackstorm. * Minor updates for RockyLinux. #5552 Contributed by Amanda McGuinness (@amanda11 intive) @@ -128,7 +129,6 @@ Fixed Added ~~~~~ - * Added possibility to add new values to the KV store via CLI without leaking them to the shell history. #5164 * ``st2.conf`` is now the only place to configure ports for ``st2api``, ``st2auth``, and ``st2stream``. From 64b9a2bf0418d88430a2c34b23cb49654e473226 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 24 Mar 2022 16:27:52 +1100 Subject: [PATCH 03/31] removed update to conf --- conf/st2.conf.sample | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/conf/st2.conf.sample b/conf/st2.conf.sample index 95d879023c..2c47177dd8 100644 --- a/conf/st2.conf.sample +++ b/conf/st2.conf.sample @@ -319,8 +319,7 @@ validate_output_schema = False validate_trigger_parameters = True # True to validate payload for non-system trigger types when dispatching a trigger inside the sensor. By default, only payload for system triggers is validated. validate_trigger_payload = True -# Enable security audit -security_audit = True + [system_user] # SSH private key for the system user. From a08a34aa974e1b18939dda956a14949c95a85ad0 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 24 Mar 2022 17:14:13 +1100 Subject: [PATCH 04/31] fixing for unit test --- st2common/st2common/util/config_loader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/st2common/st2common/util/config_loader.py b/st2common/st2common/util/config_loader.py index 7552b37386..c7b63c5026 100644 --- a/st2common/st2common/util/config_loader.py +++ b/st2common/st2common/util/config_loader.py @@ -169,7 +169,7 @@ def _assign_dynamic_config_values(self, schema, config, parent_keys=None): is_jinja_expression = jinja_utils.is_jinja_expression( value=config_item_value ) - if "decrypt_kv" in config_item_value and cfg.CONF.system.security_audit: + if "decrypt_kv" in str(config_item_value) and cfg.CONF.system.security_audit: LOG.info("User %s is decrypting the value %s from the config within pack %s", self.user, config_item_value, self.pack_name) if is_jinja_expression: From 117b6cbfa5710a4de673310c11910cc66c65f0e6 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 25 Mar 2022 09:07:28 +1100 Subject: [PATCH 05/31] updated st2 conf sample --- conf/st2.conf.sample | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conf/st2.conf.sample b/conf/st2.conf.sample index 2c47177dd8..43ceb205e4 100644 --- a/conf/st2.conf.sample +++ b/conf/st2.conf.sample @@ -319,7 +319,8 @@ validate_output_schema = False validate_trigger_parameters = True # True to validate payload for non-system trigger types when dispatching a trigger inside the sensor. By default, only payload for system triggers is validated. validate_trigger_payload = True - +# Audits a log message which notifies users that a key will be decrypted +security_audit = False [system_user] # SSH private key for the system user. From f63ab65bbcaef26debcc1401f979302193c31dcd Mon Sep 17 00:00:00 2001 From: David Date: Fri, 25 Mar 2022 09:51:03 +1100 Subject: [PATCH 06/31] updated conf file --- conf/st2.conf.sample | 57 ++++---------------------------------------- 1 file changed, 5 insertions(+), 52 deletions(-) diff --git a/conf/st2.conf.sample b/conf/st2.conf.sample index 43ceb205e4..40584b5f11 100644 --- a/conf/st2.conf.sample +++ b/conf/st2.conf.sample @@ -38,16 +38,10 @@ workflows_pool_size = 40 [api] # List of origins allowed for api, auth and stream allow_origin = http://127.0.0.1:3000 # comma separated list allowed here. -# None -debug = False # StackStorm API server host host = 127.0.0.1 -# location of the logging.conf file -logging = /etc/st2/logging.api.conf # True to mask secrets in the API responses mask_secrets = True -# Maximum limit (page size) argument which can be specified by the user in a query string. -max_page_size = 100 # StackStorm API server port port = 9101 @@ -57,42 +51,16 @@ port = 9101 # Base URL to the API endpoint excluding the version api_url = None -# Specify to enable debug mode. -debug = False # Enable authentication middleware. enable = True -# Path to the logging config. -logging = /etc/st2/logging.auth.conf -# Authentication mode (proxy,standalone) -mode = standalone # Service token ttl in seconds. service_token_ttl = 86400 -# Enable Single Sign On for GUI if true. -sso = False -# Single Sign On backend to use when SSO is enabled. Available backends: noop, saml2. -sso_backend = noop -# JSON serialized arguments which are passed to the SSO backend. -sso_backend_kwargs = None # Access token ttl in seconds. token_ttl = 86400 # Standalone mode options - options below only apply when auth service is running in the standalone # mode. -# Authentication backend to use in a standalone mode. Available backends: ldap, flat_file. -backend = flat_file -# JSON serialized arguments which are passed to the authentication backend in a standalone mode. -backend_kwargs = None -# Path to the SSL certificate file. Only used when "use_ssl" is specified. -cert = /etc/apache2/ssl/mycert.crt -# Host on which the service should listen on. -host = 127.0.0.1 -# Path to the SSL private key file. Only used when "use_ssl" is specified. -key = /etc/apache2/ssl/mycert.key -# Port on which the service should listen on. -port = 9100 -# Specify to enable SSL / TLS mode -use_ssl = False [content] # A URL pointing to the pack index. StackStorm Exchange is used by default. Use a comma-separated list for multiple indexes if you want to get other packs discovered with "st2 pack search". @@ -104,9 +72,9 @@ packs_base_paths = None # Paths which will be searched for runners. NOTE: This option has been deprecated and it's unused since StackStorm v3.0.0 runners_base_paths = None # Path to the directory which contains system packs. -system_packs_base_path = /opt/stackstorm/packs +system_packs_base_path = /opt/stackstorm\packs # Path to the directory which contains system runners. NOTE: This option has been deprecated and it's unused since StackStorm v3.0.0 -system_runners_base_path = /opt/stackstorm/runners +system_runners_base_path = /opt/stackstorm\runners [coordination] # TTL for the lock if backend suports it. @@ -154,12 +122,6 @@ username = None # Compression level when compressors is set to zlib. Valid calues are -1 to 9. Defaults to 6. zlib_compression_level = -[exporter] -# Directory to dump data to. -dump_dir = /opt/stackstorm/exports/ -# location of the logging.exporter.conf file -logging = /etc/st2/logging.exporter.conf - [garbagecollector] # Action execution output objects (ones generated by action output streaming) older than this value (days) will be automatically deleted. action_executions_output_ttl = 7 @@ -287,16 +249,8 @@ ssh_connect_timeout = 60 use_ssh_config = False [stream] -# Specify to enable debug mode. -debug = False # Send empty message every N seconds to keep connection open heartbeat = 25 -# StackStorm stream API server host -host = 127.0.0.1 -# location of the logging.conf file -logging = /etc/st2/logging.stream.conf -# StackStorm API stream, server port -port = 9102 [syslog] # Syslog facility level. @@ -313,14 +267,14 @@ protocol = udp base_path = /opt/stackstorm # Enable debug mode. debug = False +# Audits a log message which notifies users that a key will be decrypted +security_audit = False # True to validate action and runner output against schema. validate_output_schema = False # True to validate parameters for non-system trigger types when creatinga rule. By default, only parameters for system triggers are validated. validate_trigger_parameters = True # True to validate payload for non-system trigger types when dispatching a trigger inside the sensor. By default, only payload for system triggers is validated. validate_trigger_payload = True -# Audits a log message which notifies users that a key will be decrypted -security_audit = False [system_user] # SSH private key for the system user. @@ -358,5 +312,4 @@ retry_max_jitter_msec = 1000 # Max time to stop retrying. retry_stop_max_msec = 60000 # Interval inbetween retries. -retry_wait_fixed_msec = 1000 - +retry_wait_fixed_msec = 1000 \ No newline at end of file From 7e21921fdc57a1f2048a03d59c3b3a1ce5b86dfd Mon Sep 17 00:00:00 2001 From: David Date: Fri, 25 Mar 2022 09:54:39 +1100 Subject: [PATCH 07/31] updated conf file --- conf/st2.conf.sample | 52 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/conf/st2.conf.sample b/conf/st2.conf.sample index 40584b5f11..6e38c9ca0b 100644 --- a/conf/st2.conf.sample +++ b/conf/st2.conf.sample @@ -38,10 +38,16 @@ workflows_pool_size = 40 [api] # List of origins allowed for api, auth and stream allow_origin = http://127.0.0.1:3000 # comma separated list allowed here. +# None +debug = False # StackStorm API server host host = 127.0.0.1 +# location of the logging.conf file +logging = /etc/st2/logging.api.conf # True to mask secrets in the API responses mask_secrets = True +# Maximum limit (page size) argument which can be specified by the user in a query string. +max_page_size = 100 # StackStorm API server port port = 9101 @@ -51,16 +57,42 @@ port = 9101 # Base URL to the API endpoint excluding the version api_url = None +# Specify to enable debug mode. +debug = False # Enable authentication middleware. enable = True +# Path to the logging config. +logging = /etc/st2/logging.auth.conf +# Authentication mode (proxy,standalone) +mode = standalone # Service token ttl in seconds. service_token_ttl = 86400 +# Enable Single Sign On for GUI if true. +sso = False +# Single Sign On backend to use when SSO is enabled. Available backends: noop, saml2. +sso_backend = noop +# JSON serialized arguments which are passed to the SSO backend. +sso_backend_kwargs = None # Access token ttl in seconds. token_ttl = 86400 # Standalone mode options - options below only apply when auth service is running in the standalone # mode. +# Authentication backend to use in a standalone mode. Available backends: ldap, flat_file. +backend = flat_file +# JSON serialized arguments which are passed to the authentication backend in a standalone mode. +backend_kwargs = None +# Path to the SSL certificate file. Only used when "use_ssl" is specified. +cert = /etc/apache2/ssl/mycert.crt +# Host on which the service should listen on. +host = 127.0.0.1 +# Path to the SSL private key file. Only used when "use_ssl" is specified. +key = /etc/apache2/ssl/mycert.key +# Port on which the service should listen on. +port = 9100 +# Specify to enable SSL / TLS mode +use_ssl = False [content] # A URL pointing to the pack index. StackStorm Exchange is used by default. Use a comma-separated list for multiple indexes if you want to get other packs discovered with "st2 pack search". @@ -72,9 +104,9 @@ packs_base_paths = None # Paths which will be searched for runners. NOTE: This option has been deprecated and it's unused since StackStorm v3.0.0 runners_base_paths = None # Path to the directory which contains system packs. -system_packs_base_path = /opt/stackstorm\packs +system_packs_base_path = /opt/stackstorm/packs # Path to the directory which contains system runners. NOTE: This option has been deprecated and it's unused since StackStorm v3.0.0 -system_runners_base_path = /opt/stackstorm\runners +system_runners_base_path = /opt/stackstorm/runners [coordination] # TTL for the lock if backend suports it. @@ -122,6 +154,12 @@ username = None # Compression level when compressors is set to zlib. Valid calues are -1 to 9. Defaults to 6. zlib_compression_level = +[exporter] +# Directory to dump data to. +dump_dir = /opt/stackstorm/exports/ +# location of the logging.exporter.conf file +logging = /etc/st2/logging.exporter.conf + [garbagecollector] # Action execution output objects (ones generated by action output streaming) older than this value (days) will be automatically deleted. action_executions_output_ttl = 7 @@ -249,8 +287,16 @@ ssh_connect_timeout = 60 use_ssh_config = False [stream] +# Specify to enable debug mode. +debug = False # Send empty message every N seconds to keep connection open heartbeat = 25 +# StackStorm stream API server host +host = 127.0.0.1 +# location of the logging.conf file +logging = /etc/st2/logging.stream.conf +# StackStorm API stream, server port +port = 9102 [syslog] # Syslog facility level. @@ -267,8 +313,6 @@ protocol = udp base_path = /opt/stackstorm # Enable debug mode. debug = False -# Audits a log message which notifies users that a key will be decrypted -security_audit = False # True to validate action and runner output against schema. validate_output_schema = False # True to validate parameters for non-system trigger types when creatinga rule. By default, only parameters for system triggers are validated. From b6ab6d563a14811ed5e6bc5140f172187670ccf1 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 25 Mar 2022 10:01:27 +1100 Subject: [PATCH 08/31] updated conf file --- conf/st2.conf.sample | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/st2.conf.sample b/conf/st2.conf.sample index 6e38c9ca0b..0a9c1e0bcb 100644 --- a/conf/st2.conf.sample +++ b/conf/st2.conf.sample @@ -313,6 +313,8 @@ protocol = udp base_path = /opt/stackstorm # Enable debug mode. debug = False +# Audits a log message which notifies users that a key will be decrypted +security_audit = False # True to validate action and runner output against schema. validate_output_schema = False # True to validate parameters for non-system trigger types when creatinga rule. By default, only parameters for system triggers are validated. From c6602ce937d02b385cfdac8465f3a8ee5d3ed932 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 25 Mar 2022 10:04:48 +1100 Subject: [PATCH 09/31] updated conf file --- conf/st2.conf.sample | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/st2.conf.sample b/conf/st2.conf.sample index 0a9c1e0bcb..b7f451117a 100644 --- a/conf/st2.conf.sample +++ b/conf/st2.conf.sample @@ -358,4 +358,4 @@ retry_max_jitter_msec = 1000 # Max time to stop retrying. retry_stop_max_msec = 60000 # Interval inbetween retries. -retry_wait_fixed_msec = 1000 \ No newline at end of file +retry_wait_fixed_msec = 1000 From ae8f864ebfa681e11d3bbb5607b8cea97e04ca62 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 25 Mar 2022 10:12:53 +1100 Subject: [PATCH 10/31] updated conf file --- conf/st2.conf.sample | 52 +++----------------------------------------- 1 file changed, 3 insertions(+), 49 deletions(-) diff --git a/conf/st2.conf.sample b/conf/st2.conf.sample index b7f451117a..e0e460cfb8 100644 --- a/conf/st2.conf.sample +++ b/conf/st2.conf.sample @@ -1,6 +1,5 @@ # Sample config which contains all the available options which the corresponding descriptions # Note: This file is automatically generated using tools/config_gen.py - DO NOT UPDATE MANUALLY - [action_sensor] # List of execution statuses for which a trigger will be emitted. emit_when = succeeded,failed,timeout,canceled,abandoned # comma separated list allowed here. @@ -38,16 +37,10 @@ workflows_pool_size = 40 [api] # List of origins allowed for api, auth and stream allow_origin = http://127.0.0.1:3000 # comma separated list allowed here. -# None -debug = False # StackStorm API server host host = 127.0.0.1 -# location of the logging.conf file -logging = /etc/st2/logging.api.conf # True to mask secrets in the API responses mask_secrets = True -# Maximum limit (page size) argument which can be specified by the user in a query string. -max_page_size = 100 # StackStorm API server port port = 9101 @@ -57,42 +50,16 @@ port = 9101 # Base URL to the API endpoint excluding the version api_url = None -# Specify to enable debug mode. -debug = False # Enable authentication middleware. enable = True -# Path to the logging config. -logging = /etc/st2/logging.auth.conf -# Authentication mode (proxy,standalone) -mode = standalone # Service token ttl in seconds. service_token_ttl = 86400 -# Enable Single Sign On for GUI if true. -sso = False -# Single Sign On backend to use when SSO is enabled. Available backends: noop, saml2. -sso_backend = noop -# JSON serialized arguments which are passed to the SSO backend. -sso_backend_kwargs = None # Access token ttl in seconds. token_ttl = 86400 # Standalone mode options - options below only apply when auth service is running in the standalone # mode. -# Authentication backend to use in a standalone mode. Available backends: ldap, flat_file. -backend = flat_file -# JSON serialized arguments which are passed to the authentication backend in a standalone mode. -backend_kwargs = None -# Path to the SSL certificate file. Only used when "use_ssl" is specified. -cert = /etc/apache2/ssl/mycert.crt -# Host on which the service should listen on. -host = 127.0.0.1 -# Path to the SSL private key file. Only used when "use_ssl" is specified. -key = /etc/apache2/ssl/mycert.key -# Port on which the service should listen on. -port = 9100 -# Specify to enable SSL / TLS mode -use_ssl = False [content] # A URL pointing to the pack index. StackStorm Exchange is used by default. Use a comma-separated list for multiple indexes if you want to get other packs discovered with "st2 pack search". @@ -104,9 +71,9 @@ packs_base_paths = None # Paths which will be searched for runners. NOTE: This option has been deprecated and it's unused since StackStorm v3.0.0 runners_base_paths = None # Path to the directory which contains system packs. -system_packs_base_path = /opt/stackstorm/packs +system_packs_base_path = /opt/stackstorm\packs # Path to the directory which contains system runners. NOTE: This option has been deprecated and it's unused since StackStorm v3.0.0 -system_runners_base_path = /opt/stackstorm/runners +system_runners_base_path = /opt/stackstorm\runners [coordination] # TTL for the lock if backend suports it. @@ -154,12 +121,6 @@ username = None # Compression level when compressors is set to zlib. Valid calues are -1 to 9. Defaults to 6. zlib_compression_level = -[exporter] -# Directory to dump data to. -dump_dir = /opt/stackstorm/exports/ -# location of the logging.exporter.conf file -logging = /etc/st2/logging.exporter.conf - [garbagecollector] # Action execution output objects (ones generated by action output streaming) older than this value (days) will be automatically deleted. action_executions_output_ttl = 7 @@ -287,16 +248,8 @@ ssh_connect_timeout = 60 use_ssh_config = False [stream] -# Specify to enable debug mode. -debug = False # Send empty message every N seconds to keep connection open heartbeat = 25 -# StackStorm stream API server host -host = 127.0.0.1 -# location of the logging.conf file -logging = /etc/st2/logging.stream.conf -# StackStorm API stream, server port -port = 9102 [syslog] # Syslog facility level. @@ -359,3 +312,4 @@ retry_max_jitter_msec = 1000 retry_stop_max_msec = 60000 # Interval inbetween retries. retry_wait_fixed_msec = 1000 + From 40f1d3844e382366697d367db7bdd3e4a2d2b742 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 25 Mar 2022 15:32:21 +1100 Subject: [PATCH 11/31] removed the need of having another flag in st2,conf, changed the log.info to a log.audit --- CHANGELOG.rst | 2 - conf/st2.conf.sample | 54 ++++++++++++++++++++--- st2api/st2api/controllers/v1/keyvalue.py | 3 +- st2common/st2common/config.py | 5 --- st2common/st2common/util/config_loader.py | 4 +- 5 files changed, 52 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c34bdde22b..ed2b0ca859 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -43,8 +43,6 @@ Fixed Added ~~~~~ -* Added security_audit flag that users can specify in st2.conf, provides logs anytime a decryption of st2 keys occurs in stackstorm. - * Minor updates for RockyLinux. #5552 Contributed by Amanda McGuinness (@amanda11 intive) diff --git a/conf/st2.conf.sample b/conf/st2.conf.sample index e0e460cfb8..55f3b43554 100644 --- a/conf/st2.conf.sample +++ b/conf/st2.conf.sample @@ -1,5 +1,6 @@ # Sample config which contains all the available options which the corresponding descriptions # Note: This file is automatically generated using tools/config_gen.py - DO NOT UPDATE MANUALLY + [action_sensor] # List of execution statuses for which a trigger will be emitted. emit_when = succeeded,failed,timeout,canceled,abandoned # comma separated list allowed here. @@ -37,10 +38,16 @@ workflows_pool_size = 40 [api] # List of origins allowed for api, auth and stream allow_origin = http://127.0.0.1:3000 # comma separated list allowed here. +# None +debug = False # StackStorm API server host host = 127.0.0.1 +# location of the logging.conf file +logging = /etc/st2/logging.api.conf # True to mask secrets in the API responses mask_secrets = True +# Maximum limit (page size) argument which can be specified by the user in a query string. +max_page_size = 100 # StackStorm API server port port = 9101 @@ -50,16 +57,42 @@ port = 9101 # Base URL to the API endpoint excluding the version api_url = None +# Specify to enable debug mode. +debug = False # Enable authentication middleware. enable = True +# Path to the logging config. +logging = /etc/st2/logging.auth.conf +# Authentication mode (proxy,standalone) +mode = standalone # Service token ttl in seconds. service_token_ttl = 86400 +# Enable Single Sign On for GUI if true. +sso = False +# Single Sign On backend to use when SSO is enabled. Available backends: noop, saml2. +sso_backend = noop +# JSON serialized arguments which are passed to the SSO backend. +sso_backend_kwargs = None # Access token ttl in seconds. token_ttl = 86400 # Standalone mode options - options below only apply when auth service is running in the standalone # mode. +# Authentication backend to use in a standalone mode. Available backends: ldap, flat_file. +backend = flat_file +# JSON serialized arguments which are passed to the authentication backend in a standalone mode. +backend_kwargs = None +# Path to the SSL certificate file. Only used when "use_ssl" is specified. +cert = /etc/apache2/ssl/mycert.crt +# Host on which the service should listen on. +host = 127.0.0.1 +# Path to the SSL private key file. Only used when "use_ssl" is specified. +key = /etc/apache2/ssl/mycert.key +# Port on which the service should listen on. +port = 9100 +# Specify to enable SSL / TLS mode +use_ssl = False [content] # A URL pointing to the pack index. StackStorm Exchange is used by default. Use a comma-separated list for multiple indexes if you want to get other packs discovered with "st2 pack search". @@ -71,9 +104,9 @@ packs_base_paths = None # Paths which will be searched for runners. NOTE: This option has been deprecated and it's unused since StackStorm v3.0.0 runners_base_paths = None # Path to the directory which contains system packs. -system_packs_base_path = /opt/stackstorm\packs +system_packs_base_path = /opt/stackstorm/packs # Path to the directory which contains system runners. NOTE: This option has been deprecated and it's unused since StackStorm v3.0.0 -system_runners_base_path = /opt/stackstorm\runners +system_runners_base_path = /opt/stackstorm/runners [coordination] # TTL for the lock if backend suports it. @@ -121,6 +154,12 @@ username = None # Compression level when compressors is set to zlib. Valid calues are -1 to 9. Defaults to 6. zlib_compression_level = +[exporter] +# Directory to dump data to. +dump_dir = /opt/stackstorm/exports/ +# location of the logging.exporter.conf file +logging = /etc/st2/logging.exporter.conf + [garbagecollector] # Action execution output objects (ones generated by action output streaming) older than this value (days) will be automatically deleted. action_executions_output_ttl = 7 @@ -248,8 +287,16 @@ ssh_connect_timeout = 60 use_ssh_config = False [stream] +# Specify to enable debug mode. +debug = False # Send empty message every N seconds to keep connection open heartbeat = 25 +# StackStorm stream API server host +host = 127.0.0.1 +# location of the logging.conf file +logging = /etc/st2/logging.stream.conf +# StackStorm API stream, server port +port = 9102 [syslog] # Syslog facility level. @@ -266,8 +313,6 @@ protocol = udp base_path = /opt/stackstorm # Enable debug mode. debug = False -# Audits a log message which notifies users that a key will be decrypted -security_audit = False # True to validate action and runner output against schema. validate_output_schema = False # True to validate parameters for non-system trigger types when creatinga rule. By default, only parameters for system triggers are validated. @@ -312,4 +357,3 @@ retry_max_jitter_msec = 1000 retry_stop_max_msec = 60000 # Interval inbetween retries. retry_wait_fixed_msec = 1000 - diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index ecb643b113..0b07466501 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -97,8 +97,7 @@ def get_one(self, name, requester_user, scope=None, user=None, decrypt=False): key_ref = get_key_reference(scope=scope, name=name, user=user) extra = {"scope": scope, "name": name, "user": user, "key_ref": key_ref} LOG.debug("GET /v1/keys/%s", name, extra=extra) - if decrypt and cfg.CONF.system.security_audit: - LOG.info("User %s decrypted the value %s ", user, name) + LOG.audit("User %s decrypted the value %s ", user, name) # Setup a kvp database object used for verifying permission kvp_db = KeyValuePairDB( diff --git a/st2common/st2common/config.py b/st2common/st2common/config.py index f3e441a414..39ed7efc4e 100644 --- a/st2common/st2common/config.py +++ b/st2common/st2common/config.py @@ -121,11 +121,6 @@ def register_opts(ignore_errors=False): "validate_output_schema", default=False, help="True to validate action and runner output against schema.", - ), - cfg.BoolOpt( - "security_audit", - default=False, - help="Audits a log message which notifies users that a key will be decrypted" ) ] diff --git a/st2common/st2common/util/config_loader.py b/st2common/st2common/util/config_loader.py index c7b63c5026..2a5544384c 100644 --- a/st2common/st2common/util/config_loader.py +++ b/st2common/st2common/util/config_loader.py @@ -169,8 +169,8 @@ def _assign_dynamic_config_values(self, schema, config, parent_keys=None): is_jinja_expression = jinja_utils.is_jinja_expression( value=config_item_value ) - if "decrypt_kv" in str(config_item_value) and cfg.CONF.system.security_audit: - LOG.info("User %s is decrypting the value %s from the config within pack %s", self.user, config_item_value, self.pack_name) + if "decrypt_kv" in str(config_item_value): + LOG.audit("User %s is decrypting the value %s from the config within pack %s", self.user, config_item_value, self.pack_name) if is_jinja_expression: # Resolve / render the Jinja template expression From 5c84fe39a5a86953453f01280e675c344ba3e398 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 26 Mar 2022 00:39:22 +1100 Subject: [PATCH 12/31] reverted back conf file --- conf/st2.conf.sample | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/st2.conf.sample b/conf/st2.conf.sample index 55f3b43554..9009cd0199 100644 --- a/conf/st2.conf.sample +++ b/conf/st2.conf.sample @@ -357,3 +357,4 @@ retry_max_jitter_msec = 1000 retry_stop_max_msec = 60000 # Interval inbetween retries. retry_wait_fixed_msec = 1000 + From 09744121029ccf5cea89e1ad6068f4481be33545 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 28 Mar 2022 09:17:46 +1100 Subject: [PATCH 13/31] added extra argument for better search ability --- CHANGELOG.rst | 46 ++++++++++++++++++++++- st2api/st2api/controllers/v1/keyvalue.py | 3 +- st2common/st2common/util/config_loader.py | 5 ++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ed2b0ca859..86aacd05c3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -43,6 +43,7 @@ Fixed Added ~~~~~ + * Minor updates for RockyLinux. #5552 Contributed by Amanda McGuinness (@amanda11 intive) @@ -109,6 +110,48 @@ Added Contributed by Amanda McGuinness (@amanda11 Intive) +* Add new ``api.auth_cookie_secure`` and ``api.auth_cookie_same_site`` config options which + specify values which are set for ``secure`` and ``SameSite`` attribute for the auth cookie + we set when authenticating via token / api key in query parameter value (e.g. via st2web). + + For security reasons, ``api.auth_cookie_secure`` defaults to ``True``. This should only be + changed to ``False`` if you have a valid reason to not run StackStorm behind HTTPs proxy. + + Default value for ``api.auth_cookie_same_site`` is ``lax``. If you want to disable this + functionality so it behaves the same as in the previous releases, you can set that option + to ``None``. + + #5248 + + Contributed by @Kami. + +* Add new ``st2 action-alias test `` CLI command which allows users to easily + test action alias matching and result formatting. + + This command will first try to find a matching alias (same as ``st2 action-alias match`` + command) and if a match is found, trigger an execution (same as ``st2 action-alias execute`` + command) and format the execution result. + + This means it uses exactly the same flow as commands on chat, but the interaction avoids + chat and hubot which should make testing and developing aliases easier and faster. #5143 + + #5143 + + Contributed by @Kami. + +* Add new ``credentials.basic_auth = username:password`` CLI configuration option. + + This argument allows client to use additional set of basic auth credentials when talking to the + StackStorm API endpoints (api, auth, stream) - that is, in addition to the token / api key + native StackStorm auth. + + This allows for simple basic auth based multi factor authentication implementation for + installations which don't utilize SSO. + + #5152 + + Contributed by @Kami. + Fixed ~~~~~ @@ -127,6 +170,7 @@ Fixed Added ~~~~~ + * Added possibility to add new values to the KV store via CLI without leaking them to the shell history. #5164 * ``st2.conf`` is now the only place to configure ports for ``st2api``, ``st2auth``, and ``st2stream``. @@ -4288,4 +4332,4 @@ v0.5.1 - November 3rd, 2014 Added ~~~~~ -* Initial public release +* Initial public release \ No newline at end of file diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index 0b07466501..160523368f 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -97,7 +97,8 @@ def get_one(self, name, requester_user, scope=None, user=None, decrypt=False): key_ref = get_key_reference(scope=scope, name=name, user=user) extra = {"scope": scope, "name": name, "user": user, "key_ref": key_ref} LOG.debug("GET /v1/keys/%s", name, extra=extra) - LOG.audit("User %s decrypted the value %s ", user, name) + LOG.audit("User %s decrypted the value %s ", user, name, + extra={"user": user, "scope": scope, "key_name": name, "operation": "decrypt"}) # Setup a kvp database object used for verifying permission kvp_db = KeyValuePairDB( diff --git a/st2common/st2common/util/config_loader.py b/st2common/st2common/util/config_loader.py index 2a5544384c..501f447a50 100644 --- a/st2common/st2common/util/config_loader.py +++ b/st2common/st2common/util/config_loader.py @@ -170,7 +170,10 @@ def _assign_dynamic_config_values(self, schema, config, parent_keys=None): value=config_item_value ) if "decrypt_kv" in str(config_item_value): - LOG.audit("User %s is decrypting the value %s from the config within pack %s", self.user, config_item_value, self.pack_name) + LOG.audit("User %s is decrypting the value %s from the config within pack %s", self.user, + config_item_value, self.pack_name, + extra = {"user": self.user, "key_name": config_item_key, "pack_name": self.pack_name, + "config_item_value": config_item_value, "operation": "pack_config_value_decrypt"}) if is_jinja_expression: # Resolve / render the Jinja template expression From 98c10eef3e7bbaebad305517cb70307116578233 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 28 Mar 2022 09:26:14 +1100 Subject: [PATCH 14/31] updating as it was before --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 86aacd05c3..aa4439df03 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4332,4 +4332,4 @@ v0.5.1 - November 3rd, 2014 Added ~~~~~ -* Initial public release \ No newline at end of file +* Initial public release From fe624e6f7ec4ea24388af0c2430ff150183d12c9 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 28 Mar 2022 09:28:10 +1100 Subject: [PATCH 15/31] reverting back to what is was before --- st2common/st2common/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/st2common/st2common/config.py b/st2common/st2common/config.py index 9745bdaa57..59cb9d01ab 100644 --- a/st2common/st2common/config.py +++ b/st2common/st2common/config.py @@ -121,7 +121,7 @@ def register_opts(ignore_errors=False): "validate_output_schema", default=False, help="True to validate action and runner output against schema.", - ) + ), ] do_register_opts(system_opts, "system", ignore_errors) From f2f3f062a0b38ad17d3a5e5d7a860656d1151bc6 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 28 Mar 2022 09:39:22 +1100 Subject: [PATCH 16/31] updated changelog --- CHANGELOG.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index aa4439df03..5e3e559995 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -152,6 +152,10 @@ Added Contributed by @Kami. +* Add new audit message when a user has decrypted a key whether manually in the container (st2 key get [] --decrypt) + or through a stack-storm workflow with a defined config. + Contributed by @dmork123 + Fixed ~~~~~ From 22da65ca77f6f61fa51a4aa6e8f237378eeac86d Mon Sep 17 00:00:00 2001 From: David Date: Wed, 30 Mar 2022 09:14:21 +1100 Subject: [PATCH 17/31] fix formatting --- st2api/st2api/controllers/v1/keyvalue.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index 160523368f..ed22809eca 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -99,7 +99,6 @@ def get_one(self, name, requester_user, scope=None, user=None, decrypt=False): LOG.debug("GET /v1/keys/%s", name, extra=extra) LOG.audit("User %s decrypted the value %s ", user, name, extra={"user": user, "scope": scope, "key_name": name, "operation": "decrypt"}) - # Setup a kvp database object used for verifying permission kvp_db = KeyValuePairDB( uid="%s:%s:%s" % (ResourceType.KEY_VALUE_PAIR, scope, key_ref), @@ -475,4 +474,4 @@ def _validate_scope(self, scope): raise ValueError(msg) -key_value_pair_controller = KeyValuePairController() \ No newline at end of file +key_value_pair_controller = KeyValuePairController() From 2921a6b5ecb38a577380644e84934261ee57e637 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 31 Mar 2022 09:20:42 +1100 Subject: [PATCH 18/31] excluded jinja parts from the logs --- st2common/st2common/util/config_loader.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/st2common/st2common/util/config_loader.py b/st2common/st2common/util/config_loader.py index 501f447a50..d03ae96b25 100644 --- a/st2common/st2common/util/config_loader.py +++ b/st2common/st2common/util/config_loader.py @@ -170,10 +170,10 @@ def _assign_dynamic_config_values(self, schema, config, parent_keys=None): value=config_item_value ) if "decrypt_kv" in str(config_item_value): - LOG.audit("User %s is decrypting the value %s from the config within pack %s", self.user, - config_item_value, self.pack_name, + LOG.audit("User %s is decrypting the value for key %s from the config within pack %s", self.user, + config_item_key, self.pack_name, extra = {"user": self.user, "key_name": config_item_key, "pack_name": self.pack_name, - "config_item_value": config_item_value, "operation": "pack_config_value_decrypt"}) + "operation": "pack_config_value_decrypt"}) if is_jinja_expression: # Resolve / render the Jinja template expression From 84fc5360d2b32f1ac906f0b270463d03d920a980 Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Thu, 31 Mar 2022 15:58:16 -0500 Subject: [PATCH 19/31] reformat with black --- st2api/st2api/controllers/v1/keyvalue.py | 13 +++++++++++-- st2common/st2common/util/config_loader.py | 16 ++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index ed22809eca..6d68d51f89 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -97,8 +97,17 @@ def get_one(self, name, requester_user, scope=None, user=None, decrypt=False): key_ref = get_key_reference(scope=scope, name=name, user=user) extra = {"scope": scope, "name": name, "user": user, "key_ref": key_ref} LOG.debug("GET /v1/keys/%s", name, extra=extra) - LOG.audit("User %s decrypted the value %s ", user, name, - extra={"user": user, "scope": scope, "key_name": name, "operation": "decrypt"}) + LOG.audit( + "User %s decrypted the value %s ", + user, + name, + extra={ + "user": user, + "scope": scope, + "key_name": name, + "operation": "decrypt", + }, + ) # Setup a kvp database object used for verifying permission kvp_db = KeyValuePairDB( uid="%s:%s:%s" % (ResourceType.KEY_VALUE_PAIR, scope, key_ref), diff --git a/st2common/st2common/util/config_loader.py b/st2common/st2common/util/config_loader.py index d03ae96b25..545689d2c9 100644 --- a/st2common/st2common/util/config_loader.py +++ b/st2common/st2common/util/config_loader.py @@ -170,10 +170,18 @@ def _assign_dynamic_config_values(self, schema, config, parent_keys=None): value=config_item_value ) if "decrypt_kv" in str(config_item_value): - LOG.audit("User %s is decrypting the value for key %s from the config within pack %s", self.user, - config_item_key, self.pack_name, - extra = {"user": self.user, "key_name": config_item_key, "pack_name": self.pack_name, - "operation": "pack_config_value_decrypt"}) + LOG.audit( + "User %s is decrypting the value for key %s from the config within pack %s", + self.user, + config_item_key, + self.pack_name, + extra={ + "user": self.user, + "key_name": config_item_key, + "pack_name": self.pack_name, + "operation": "pack_config_value_decrypt", + }, + ) if is_jinja_expression: # Resolve / render the Jinja template expression From 1cd7d297c599879e8a4733f9848950981a5ae291 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 1 Apr 2022 09:31:57 +1100 Subject: [PATCH 20/31] updated location of where audit takes place to occur right after decryption of value occurs --- st2common/st2common/util/config_loader.py | 25 +++++++++++------------ 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/st2common/st2common/util/config_loader.py b/st2common/st2common/util/config_loader.py index 545689d2c9..385c19dc92 100644 --- a/st2common/st2common/util/config_loader.py +++ b/st2common/st2common/util/config_loader.py @@ -169,19 +169,6 @@ def _assign_dynamic_config_values(self, schema, config, parent_keys=None): is_jinja_expression = jinja_utils.is_jinja_expression( value=config_item_value ) - if "decrypt_kv" in str(config_item_value): - LOG.audit( - "User %s is decrypting the value for key %s from the config within pack %s", - self.user, - config_item_key, - self.pack_name, - extra={ - "user": self.user, - "key_name": config_item_key, - "pack_name": self.pack_name, - "operation": "pack_config_value_decrypt", - }, - ) if is_jinja_expression: # Resolve / render the Jinja template expression @@ -267,6 +254,18 @@ def _get_datastore_value_for_expression(self, key, value, config_schema_item=Non if value: # Deserialize the value value = deserialize_key_value(value=value, secret=secret) + LOG.audit( + "User %s has decrypted the value for key %s from the config within pack %s", + self.user, + key, + self.pack_name, + extra={ + "user": self.user, + "key_name": key, + "pack_name": self.pack_name, + "operation": "pack_config_value_decrypt", + }, + ) else: value = None From 8f8470f8a6c1a6865325d263d7feb9a67b93b7c1 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 1 Apr 2022 09:32:20 +1100 Subject: [PATCH 21/31] added audit security check in get_all function as well --- st2api/st2api/controllers/v1/keyvalue.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index 6d68d51f89..ac741080f7 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -171,7 +171,17 @@ def get_all( self._validate_decrypt_query_parameter( decrypt=decrypt, scope=scope, requester_user=requester_user ) - + LOG.audit( + "User %s decrypted the value %s ", + user, + name, + extra={ + "user": user, + "scope": scope, + "key_name": name, + "operation": "decrypt", + }, + ) current_user = requester_user.name user = user or requester_user.name From 7570e78605eb80dc1aad9727d2538f2e99a0aa48 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 1 Apr 2022 09:36:04 +1100 Subject: [PATCH 22/31] added if user decrypts the key --- st2api/st2api/controllers/v1/keyvalue.py | 46 ++++++++++++------------ 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index ac741080f7..2996f19b3d 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -97,17 +97,18 @@ def get_one(self, name, requester_user, scope=None, user=None, decrypt=False): key_ref = get_key_reference(scope=scope, name=name, user=user) extra = {"scope": scope, "name": name, "user": user, "key_ref": key_ref} LOG.debug("GET /v1/keys/%s", name, extra=extra) - LOG.audit( - "User %s decrypted the value %s ", - user, - name, - extra={ - "user": user, - "scope": scope, - "key_name": name, - "operation": "decrypt", - }, - ) + if decrypt: + LOG.audit( + "User %s decrypted the value %s ", + user, + name, + extra={ + "user": user, + "scope": scope, + "key_name": name, + "operation": "decrypt", + }, + ) # Setup a kvp database object used for verifying permission kvp_db = KeyValuePairDB( uid="%s:%s:%s" % (ResourceType.KEY_VALUE_PAIR, scope, key_ref), @@ -171,17 +172,18 @@ def get_all( self._validate_decrypt_query_parameter( decrypt=decrypt, scope=scope, requester_user=requester_user ) - LOG.audit( - "User %s decrypted the value %s ", - user, - name, - extra={ - "user": user, - "scope": scope, - "key_name": name, - "operation": "decrypt", - }, - ) + if decrypt: + LOG.audit( + "User %s decrypted the value %s ", + user, + name, + extra={ + "user": user, + "scope": scope, + "key_name": name, + "operation": "decrypt", + }, + ) current_user = requester_user.name user = user or requester_user.name From e979b05132fedbcd05e46e109ec85577a009f752 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 1 Apr 2022 10:29:17 +1100 Subject: [PATCH 23/31] added condition for when the user audits decryption event. --- st2common/st2common/util/config_loader.py | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/st2common/st2common/util/config_loader.py b/st2common/st2common/util/config_loader.py index 385c19dc92..657d209d82 100644 --- a/st2common/st2common/util/config_loader.py +++ b/st2common/st2common/util/config_loader.py @@ -235,7 +235,19 @@ def _get_datastore_value_for_expression(self, key, value, config_schema_item=Non config_schema_item = config_schema_item or {} secret = config_schema_item.get("secret", False) - + if secret or "decrypt_kv" in value: + LOG.audit( + "User %s is decrypting the value for key %s from the config within pack %s", + self.user, + key, + self.pack_name, + extra={ + "user": self.user, + "key_name": key, + "pack_name": self.pack_name, + "operation": "pack_config_value_decrypt", + }, + ) try: value = render_template_with_system_and_user_context( value=value, user=self.user @@ -254,18 +266,6 @@ def _get_datastore_value_for_expression(self, key, value, config_schema_item=Non if value: # Deserialize the value value = deserialize_key_value(value=value, secret=secret) - LOG.audit( - "User %s has decrypted the value for key %s from the config within pack %s", - self.user, - key, - self.pack_name, - extra={ - "user": self.user, - "key_name": key, - "pack_name": self.pack_name, - "operation": "pack_config_value_decrypt", - }, - ) else: value = None From e64a466316229d4c95e4afc45b223191e56e91bf Mon Sep 17 00:00:00 2001 From: David Date: Mon, 4 Apr 2022 09:18:16 +1000 Subject: [PATCH 24/31] updated get_all to account for all decryption events --- st2api/st2api/controllers/v1/keyvalue.py | 33 +++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index 2996f19b3d..b62a98935b 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -234,6 +234,7 @@ def get_all( kvp_apis_user = [] if scope in [ALL_SCOPE, SYSTEM_SCOPE, FULL_SYSTEM_SCOPE]: + decrypted_keys = [] # If user has system role, then retrieve all system scoped items if has_system_role: raw_filters["scope"] = FULL_SYSTEM_SCOPE @@ -249,6 +250,20 @@ def get_all( ) kvp_apis_system.extend(items.json or []) + if decrypt and items.json: + decrypted_keys.extend(kv_api.name for kv_api in items.json if kv_api.secret) + if decrypted_keys: + LOG.audit( + "User %s decrypted the value %s ", + decrypted_keys, + extra={ + "User": user, + "scope": FULL_SYSTEM_SCOPE, + "key_name": decrypted_keys, + "operation": "decrypt" + } + + ) else: # Otherwise if user is not an admin, then get the list of # system scoped items that user is granted permission to. @@ -259,10 +274,26 @@ def get_all( scope=FULL_SYSTEM_SCOPE, name=key, ) - kvp_apis_system.append(item) except Exception as e: LOG.error("Unable to get key %s: %s", key, str(e)) + continue + if decrypt and item.secret: + decrypted_keys.append(key) + + if decrypted_keys: + LOG.audit( + "User %s decrypted the value %s ", + user, + name, + extra={ + "user": user, + "scope": FULL_SYSTEM_SCOPE, + "key_name": key, + "operation": "decrypt", + }, + ) + if scope in [ALL_SCOPE, USER_SCOPE, FULL_USER_SCOPE]: # Retrieves all the user scoped items that the current user owns. From 9f90ddc77b41ca839acee5da1d8e4ba086f22e04 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 5 Apr 2022 08:25:33 +1000 Subject: [PATCH 25/31] added log audit message after _get_one_by_scope_and_name --- st2api/st2api/controllers/v1/keyvalue.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index b62a98935b..1390245aa5 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -274,6 +274,18 @@ def get_all( scope=FULL_SYSTEM_SCOPE, name=key, ) + if decrypt: + LOG.audit( + "User %s decrypted the value %s ", + user, + name, + extra={ + "user": user, + "scope": FULL_SYSTEM_SCOPE, + "key_name": key, + "operation": "decrypt", + }, + ) kvp_apis_system.append(item) except Exception as e: LOG.error("Unable to get key %s: %s", key, str(e)) From 7f440e152dfe881e8da6a5c8266fa2abe12d2c78 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 5 Apr 2022 08:45:57 +1000 Subject: [PATCH 26/31] updated the get_all function added user scope --- st2api/st2api/controllers/v1/keyvalue.py | 47 +++++++++--------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index 1390245aa5..522cef27e3 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -172,18 +172,6 @@ def get_all( self._validate_decrypt_query_parameter( decrypt=decrypt, scope=scope, requester_user=requester_user ) - if decrypt: - LOG.audit( - "User %s decrypted the value %s ", - user, - name, - extra={ - "user": user, - "scope": scope, - "key_name": name, - "operation": "decrypt", - }, - ) current_user = requester_user.name user = user or requester_user.name @@ -254,8 +242,9 @@ def get_all( decrypted_keys.extend(kv_api.name for kv_api in items.json if kv_api.secret) if decrypted_keys: LOG.audit( - "User %s decrypted the value %s ", - decrypted_keys, + "User %s decrypted the values %s ", + user, + decrypted_keys, extra={ "User": user, "scope": FULL_SYSTEM_SCOPE, @@ -278,7 +267,7 @@ def get_all( LOG.audit( "User %s decrypted the value %s ", user, - name, + key, extra={ "user": user, "scope": FULL_SYSTEM_SCOPE, @@ -293,20 +282,6 @@ def get_all( if decrypt and item.secret: decrypted_keys.append(key) - if decrypted_keys: - LOG.audit( - "User %s decrypted the value %s ", - user, - name, - extra={ - "user": user, - "scope": FULL_SYSTEM_SCOPE, - "key_name": key, - "operation": "decrypt", - }, - ) - - if scope in [ALL_SCOPE, USER_SCOPE, FULL_USER_SCOPE]: # Retrieves all the user scoped items that the current user owns. raw_filters["scope"] = FULL_USER_SCOPE @@ -320,6 +295,20 @@ def get_all( raw_filters=raw_filters, requester_user=requester_user, ) + if decrypt and items.json: + decrypted_keys.extend(kv_api.name for kv_api in items.json if kv_api.secret) + if decrypted_keys: + LOG.audit( + "User %s decrypted the values %s ", + user, + decrypted_keys, + extra={ + "User": user, + "scope": FULL_USER_SCOPE, + "key_name": decrypted_keys, + "operation": "decrypt" + } + ) kvp_apis_user.extend(items.json) From 234968bcbf3e381a5c3e70b12f09aadef48bd22b Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Mon, 4 Apr 2022 19:40:00 -0500 Subject: [PATCH 27/31] adjust location of some security_audit logs --- st2api/st2api/controllers/v1/keyvalue.py | 69 ++++++++++-------------- 1 file changed, 29 insertions(+), 40 deletions(-) diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index 522cef27e3..fced48a3da 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -97,18 +97,6 @@ def get_one(self, name, requester_user, scope=None, user=None, decrypt=False): key_ref = get_key_reference(scope=scope, name=name, user=user) extra = {"scope": scope, "name": name, "user": user, "key_ref": key_ref} LOG.debug("GET /v1/keys/%s", name, extra=extra) - if decrypt: - LOG.audit( - "User %s decrypted the value %s ", - user, - name, - extra={ - "user": user, - "scope": scope, - "key_name": name, - "operation": "decrypt", - }, - ) # Setup a kvp database object used for verifying permission kvp_db = KeyValuePairDB( uid="%s:%s:%s" % (ResourceType.KEY_VALUE_PAIR, scope, key_ref), @@ -131,6 +119,18 @@ def get_one(self, name, requester_user, scope=None, user=None, decrypt=False): kvp_api = self._get_one_by_scope_and_name( name=key_ref, scope=scope, from_model_kwargs=from_model_kwargs ) + if decrypt and kvp_api.secret: + LOG.audit( + "User %s decrypted the value %s ", + user, + name, + extra={ + "user": user, + "scope": scope, + "key_name": name, + "operation": "decrypt", + }, + ) return kvp_api @@ -172,6 +172,7 @@ def get_all( self._validate_decrypt_query_parameter( decrypt=decrypt, scope=scope, requester_user=requester_user ) + current_user = requester_user.name user = user or requester_user.name @@ -240,19 +241,6 @@ def get_all( kvp_apis_system.extend(items.json or []) if decrypt and items.json: decrypted_keys.extend(kv_api.name for kv_api in items.json if kv_api.secret) - if decrypted_keys: - LOG.audit( - "User %s decrypted the values %s ", - user, - decrypted_keys, - extra={ - "User": user, - "scope": FULL_SYSTEM_SCOPE, - "key_name": decrypted_keys, - "operation": "decrypt" - } - - ) else: # Otherwise if user is not an admin, then get the list of # system scoped items that user is granted permission to. @@ -263,24 +251,25 @@ def get_all( scope=FULL_SYSTEM_SCOPE, name=key, ) - if decrypt: - LOG.audit( - "User %s decrypted the value %s ", - user, - key, - extra={ - "user": user, - "scope": FULL_SYSTEM_SCOPE, - "key_name": key, - "operation": "decrypt", - }, - ) kvp_apis_system.append(item) except Exception as e: LOG.error("Unable to get key %s: %s", key, str(e)) continue if decrypt and item.secret: decrypted_keys.append(key) + if decrypted_keys: + LOG.audit( + "User %s decrypted the values %s ", + user, + decrypted_keys, + extra={ + "User": user, + "scope": FULL_SYSTEM_SCOPE, + "key_name": decrypted_keys, + "operation": "decrypt" + } + + ) if scope in [ALL_SCOPE, USER_SCOPE, FULL_USER_SCOPE]: # Retrieves all the user scoped items that the current user owns. @@ -295,8 +284,10 @@ def get_all( raw_filters=raw_filters, requester_user=requester_user, ) + + kvp_apis_user.extend(items.json) if decrypt and items.json: - decrypted_keys.extend(kv_api.name for kv_api in items.json if kv_api.secret) + decrypted_keys = [kvp_api.name for kvp_api in items.json if kvp_api.secret] if decrypted_keys: LOG.audit( "User %s decrypted the values %s ", @@ -310,8 +301,6 @@ def get_all( } ) - kvp_apis_user.extend(items.json) - return kvp_apis_system + kvp_apis_user def put(self, kvp, name, requester_user, scope=None): From 32e4337a35089f4bc1b439f99a0ee0f2b55dfb97 Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Mon, 4 Apr 2022 19:41:41 -0500 Subject: [PATCH 28/31] restore whitespace --- st2api/st2api/controllers/v1/keyvalue.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index fced48a3da..c155a4ef2a 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -97,6 +97,7 @@ def get_one(self, name, requester_user, scope=None, user=None, decrypt=False): key_ref = get_key_reference(scope=scope, name=name, user=user) extra = {"scope": scope, "name": name, "user": user, "key_ref": key_ref} LOG.debug("GET /v1/keys/%s", name, extra=extra) + # Setup a kvp database object used for verifying permission kvp_db = KeyValuePairDB( uid="%s:%s:%s" % (ResourceType.KEY_VALUE_PAIR, scope, key_ref), @@ -251,6 +252,7 @@ def get_all( scope=FULL_SYSTEM_SCOPE, name=key, ) + kvp_apis_system.append(item) except Exception as e: LOG.error("Unable to get key %s: %s", key, str(e)) From dac5d22dc9cfd49b50c8715bd0cb48c5a96f0644 Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Mon, 4 Apr 2022 20:17:13 -0500 Subject: [PATCH 29/31] reformat with black --- st2api/st2api/controllers/v1/keyvalue.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index c155a4ef2a..7c9322b386 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -241,7 +241,9 @@ def get_all( kvp_apis_system.extend(items.json or []) if decrypt and items.json: - decrypted_keys.extend(kv_api.name for kv_api in items.json if kv_api.secret) + decrypted_keys.extend( + kv_api.name for kv_api in items.json if kv_api.secret + ) else: # Otherwise if user is not an admin, then get the list of # system scoped items that user is granted permission to. @@ -268,9 +270,8 @@ def get_all( "User": user, "scope": FULL_SYSTEM_SCOPE, "key_name": decrypted_keys, - "operation": "decrypt" - } - + "operation": "decrypt", + }, ) if scope in [ALL_SCOPE, USER_SCOPE, FULL_USER_SCOPE]: @@ -289,7 +290,9 @@ def get_all( kvp_apis_user.extend(items.json) if decrypt and items.json: - decrypted_keys = [kvp_api.name for kvp_api in items.json if kvp_api.secret] + decrypted_keys = [ + kvp_api.name for kvp_api in items.json if kvp_api.secret + ] if decrypted_keys: LOG.audit( "User %s decrypted the values %s ", @@ -299,8 +302,8 @@ def get_all( "User": user, "scope": FULL_USER_SCOPE, "key_name": decrypted_keys, - "operation": "decrypt" - } + "operation": "decrypt", + }, ) return kvp_apis_system + kvp_apis_user From a881762afd7af3edd62f5540d2e38ecdf1147c33 Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Mon, 4 Apr 2022 20:44:44 -0500 Subject: [PATCH 30/31] fix json/dict access --- st2api/st2api/controllers/v1/keyvalue.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index 7c9322b386..6086323f9a 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -242,7 +242,7 @@ def get_all( kvp_apis_system.extend(items.json or []) if decrypt and items.json: decrypted_keys.extend( - kv_api.name for kv_api in items.json if kv_api.secret + kv_api.name for kv_api in items.json if kv_api["secret"] ) else: # Otherwise if user is not an admin, then get the list of @@ -291,7 +291,7 @@ def get_all( kvp_apis_user.extend(items.json) if decrypt and items.json: decrypted_keys = [ - kvp_api.name for kvp_api in items.json if kvp_api.secret + kvp_api.name for kvp_api in items.json if kvp_api["secret"] ] if decrypted_keys: LOG.audit( From f8282a2b8453b9dab18fc2cceca6765a65e96da4 Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Mon, 4 Apr 2022 21:31:04 -0500 Subject: [PATCH 31/31] fix json/dict access --- st2api/st2api/controllers/v1/keyvalue.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index 6086323f9a..c554d97c2c 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -242,7 +242,7 @@ def get_all( kvp_apis_system.extend(items.json or []) if decrypt and items.json: decrypted_keys.extend( - kv_api.name for kv_api in items.json if kv_api["secret"] + kv_api["name"] for kv_api in items.json if kv_api["secret"] ) else: # Otherwise if user is not an admin, then get the list of @@ -291,7 +291,7 @@ def get_all( kvp_apis_user.extend(items.json) if decrypt and items.json: decrypted_keys = [ - kvp_api.name for kvp_api in items.json if kvp_api["secret"] + kvp_api["name"] for kvp_api in items.json if kvp_api["secret"] ] if decrypted_keys: LOG.audit(