diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f7f045d2f0..20be64a44c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -157,6 +157,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 workflow with a defined config. #5594 + Contributed by @dmork123 + * Added garbage collection for rule_enforcement and trace models #5596/5602 Contributed by Amanda McGuinness (@amanda11 intive) diff --git a/st2api/st2api/controllers/v1/keyvalue.py b/st2api/st2api/controllers/v1/keyvalue.py index 6d25261419..c554d97c2c 100644 --- a/st2api/st2api/controllers/v1/keyvalue.py +++ b/st2api/st2api/controllers/v1/keyvalue.py @@ -120,6 +120,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 @@ -212,6 +224,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 @@ -227,6 +240,10 @@ 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"] + ) else: # Otherwise if user is not an admin, then get the list of # system scoped items that user is granted permission to. @@ -241,6 +258,21 @@ def get_all( 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. @@ -257,6 +289,22 @@ 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"] + ] + 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", + }, + ) return kvp_apis_system + kvp_apis_user diff --git a/st2common/st2common/util/config_loader.py b/st2common/st2common/util/config_loader.py index aec424d75e..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