Skip to content

Commit d2fb97e

Browse files
authored
Fix/workaround secret leak2 (#898)
* Delete all secrets with the matching name/id. This introduces two changes: (1) If there are many matches, we delete all matching secrets. Due to a previous issue, we may have many ... (2) We extract the UUID from the id string and pass it to delete_secret(). This is a workaround to something that looks like a bug in the SDK to me. * Comment on the workaround. Robust against fixed SDK ... Let's comment on the SDK issue here. If it should change to return a UUID in the id attribute, we would now still work, so we are robust against a possible direction that a fix might take. * Appease flake8. * Cosmetic: Use plural in fn name. More SDK explanation. Improve comment explaining the SDK (and possibly API) misbehavior. Also add comment on chosen workaround with robustness in mind, but without taking it to the extreme of adding 5 additional API calls. * Add wrapper _delete_secret() that accepts a Secret object. This keeps the code cleaner. * More elegant UUID extraction avoiding case distinction. ... based on suggestion by @mbuechse. Signed-off-by: Kurt Garloff <[email protected]>
1 parent 8ebb19d commit d2fb97e

File tree

1 file changed

+34
-9
lines changed

1 file changed

+34
-9
lines changed

Tests/iaas/key-manager/check-for-key-manager.py

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,39 @@ def check_presence_of_key_manager(conn: openstack.connection.Connection) -> None
5757
return True
5858

5959

60-
def _find_secret(conn: openstack.connection.Connection, secret_name_or_id: str):
60+
def _find_secrets(conn: openstack.connection.Connection, secret_name_or_id: str) -> list:
6161
"""Replacement method for finding secrets.
6262
6363
Mimicks the behavior of Connection.key_manager.find_secret()
6464
but fixes an issue with the internal implementation raising an
6565
exception due to an unexpected microversion parameter.
66+
Unlike find_secret(), we return a list with all secrets that match.
6667
"""
6768
secrets = conn.key_manager.secrets()
68-
for s in secrets:
69-
if s.name == secret_name_or_id or s.id == secret_name_or_id:
70-
return s
69+
return [s for s in secrets if s.name == secret_name_or_id or s.id == secret_name_or_id]
70+
71+
72+
def _delete_secret(conn: openstack.connection.Connection, secret: openstack.key_manager.v1.secret.Secret):
73+
"""Replacement method for deleting secrets
74+
_delete_secret(connection, secret object)
75+
76+
Workaround for SDK bugs:
77+
- The id field in reality is a href (containg the UUID at the end)
78+
- The delete_secret() function contrary to the documentation does
79+
not accept openstack.key_manager.v1.secret.Secret objects nor the
80+
hrefs, just plain UUIDs.
81+
- It does not return an error when I try to delete a secret passing
82+
an object or href, just silently does nothing.
83+
The code here assumes that the SDK (when fixed) will continue to
84+
accept UUIDs as argument for delete_secret() in the future.
85+
Code is robust against those being passed directly in the .id attr
86+
of the objects. (It would be even more robust to try to pass the
87+
object first, then the href, then the UUID extracted from the href,
88+
each time checking whether it was effective. But that's three delete
89+
plus list calls and very ugly.)
90+
"""
91+
uuid = secret.id.rsplit('/', 1)[-1]
92+
conn.key_manager.delete_secret(uuid)
7193

7294

7395
def check_key_manager_permissions(conn: openstack.connection.Connection) -> None:
@@ -78,9 +100,12 @@ def check_key_manager_permissions(conn: openstack.connection.Connection) -> None
78100
"""
79101
secret_name = "scs-member-role-test-secret"
80102
try:
81-
existing_secret = _find_secret(conn, secret_name)
82-
if existing_secret:
83-
conn.key_manager.delete_secret(existing_secret)
103+
existing_secrets = _find_secrets(conn, secret_name)
104+
for secret in existing_secrets:
105+
_delete_secret(conn, secret)
106+
107+
if existing_secrets:
108+
logger.debug(f'Deleted {len(existing_secrets)} secrets')
84109

85110
conn.key_manager.create_secret(
86111
name=secret_name,
@@ -89,11 +114,11 @@ def check_key_manager_permissions(conn: openstack.connection.Connection) -> None
89114
payload="foo",
90115
)
91116
try:
92-
new_secret = _find_secret(conn, secret_name)
117+
new_secret = _find_secrets(conn, secret_name)
93118
if not new_secret:
94119
raise ValueError(f"Secret '{secret_name}' was not discoverable by the user")
95120
finally:
96-
conn.key_manager.delete_secret(new_secret)
121+
_delete_secret(conn, new_secret[0])
97122
except openstack.exceptions.ForbiddenException:
98123
logger.debug('exception details', exc_info=True)
99124
logger.error(

0 commit comments

Comments
 (0)