55
66import openstack
77
8- # Name of the application credential that will be created during the test
9- # to temporarily scope the authentication to a specific role for testing
10- # purposes.
11- APP_CREDENTIAL_NAME = "scs-member-role-credential"
12-
138CORE_ROLES = {
9+ "reader" ,
1410 "member" ,
1511 "admin" ,
1612 "service"
1713}
1814
19- # The dict index key here equals the corresponding endpoint type as per
20- # Keystone's service catalog. Those roles will only be checked if that
21- # endpoint type is registered.
22- # Denoted by a colon, optionally the service name can also be matched against.
23- SERVICE_ROLES = {
24- "load-balancer" : {
25- "load-balancer_observer" ,
26- "load-balancer_global_observer" ,
27- "load-balancer_member" ,
28- "load-balancer_quota_admin" ,
29- "load-balancer_admin " ,
30- },
31- "identity" : {
32- "manager" ,
33- },
34- "key-manager" : {
35- "key-manager:service-admin" ,
36- "creator" ,
37- "observer" ,
38- "audit" ,
39- },
40- "object-store:swift" : {
41- "ResellerAdmin" ,
42- },
43- "orchestration:heat" : {
44- "heat_stack_user" ,
45- }
46- }
47-
4815
4916def connect (cloud_name : str , password : typing .Optional [str ] = None
5017 ) -> openstack .connection .Connection :
@@ -70,55 +37,6 @@ def connect(cloud_name: str, password: typing.Optional[str] = None
7037 )
7138
7239
73- def delete_application_credential (conn : openstack .connection .Connection ,
74- credential_name : str ) -> None :
75- existing_credential = conn .identity .find_application_credential (
76- conn .current_user_id ,
77- credential_name
78- )
79- if existing_credential :
80- print (
81- f"INFO: deleting application credential "
82- f"'{ credential_name } ' ..."
83- )
84- conn .identity .delete_application_credential (
85- conn .current_user_id ,
86- existing_credential
87- )
88-
89-
90- def reconnect_with_role (conn : openstack .connection .Connection ,
91- target_role_name : str
92- ) -> openstack .connection .Connection :
93- """
94- Uses the existing cloud connection to create a new application credential
95- in the Identity API limited to the role specified via target_role_name.
96- Creates a new cloud connection using the application credential and
97- returns it, effectively scoping the returned connection to the specific
98- role.
99- """
100- credential_name = APP_CREDENTIAL_NAME
101- delete_application_credential (conn , credential_name )
102- app_credential = conn .identity .create_application_credential (
103- conn .current_user_id ,
104- credential_name ,
105- roles = [{"name" : target_role_name }]
106- )
107-
108- # Open a new connection using the application credential
109- new_conn = openstack .connect (
110- region_name = conn .config .config ["region" ],
111- auth_type = "v3applicationcredential" ,
112- auth = {
113- "auth_url" : conn .auth ["auth_url" ],
114- "application_credential_id" : app_credential .id ,
115- "application_credential_secret" : app_credential .secret ,
116- },
117- )
118-
119- return new_conn
120-
121-
12240def check_list_of_roles (conn : openstack .connection .Connection ,
12341 expected_roles : typing .Iterable [str ]) -> None :
12442 """
@@ -133,62 +51,6 @@ def check_list_of_roles(conn: openstack.connection.Connection,
13351 print (f"Role '{ role } ' is present: PASS" )
13452
13553
136- def check_key_manager_permissions (conn : openstack .connection .Connection
137- ) -> None :
138- """
139- Limits the authentication to the "member" role using an application
140- credentials restricted to that role and verifies that the member role
141- has sufficient access to the Key Manager API functionality.
142- """
143- secret_name = "scs-member-role-test-secret"
144- member_conn = reconnect_with_role (conn , "member" )
145-
146- def _find_secret (secret_name_or_id : str ):
147- """Replacement method for finding secrets.
148-
149- Mimicks the behavior of Connection.key_manager.find_secret()
150- but fixes an issue with the internal implementation raising an
151- exception due to an unexpected microversion parameter.
152- """
153- secrets = member_conn .key_manager .secrets ()
154- for s in secrets :
155- if s .name == secret_name_or_id or s .id == secret_name_or_id :
156- return s
157- return None
158-
159- try :
160- existing_secret = _find_secret (secret_name )
161- if existing_secret :
162- member_conn .key_manager .delete_secret (existing_secret )
163-
164- member_conn .key_manager .create_secret (
165- name = secret_name ,
166- payload_content_type = "text/plain" ,
167- secret_type = "opaque" ,
168- payload = "foo"
169- )
170-
171- new_secret = _find_secret (secret_name )
172- assert new_secret , (
173- f"Secret created with name '{ secret_name } ' was not discoverable by "
174- f"the user"
175- )
176- member_conn .key_manager .delete_secret (new_secret )
177- except openstack .exceptions .ForbiddenException as e :
178- print (
179- "Users of the 'member' role can use Key Manager API: FAIL"
180- )
181- print (
182- f"ERROR: { str (e )} "
183- )
184- exit (1 )
185- finally :
186- delete_application_credential (conn , APP_CREDENTIAL_NAME )
187- print (
188- "Users of the 'member' role can use Key Manager API: PASS"
189- )
190-
191-
19254def main ():
19355 parser = argparse .ArgumentParser (
19456 description = "SCS Standard Roles Conformance Checker" )
@@ -222,28 +84,8 @@ def main():
22284 cloud ,
22385 password = getpass .getpass ("Enter password: " ) if args .ask else None
22486 )
225- service_catalog = [
226- (svc .get ("type" ), svc .get ("name" )) for svc in conn .service_catalog
227- ]
22887
22988 check_list_of_roles (conn , CORE_ROLES )
230- for service_identifier in SERVICE_ROLES :
231- if ":" in service_identifier :
232- # match both service type and service name
233- svc_type , svc_name = service_identifier .split (":" , 1 )
234- if (svc_type , svc_name ) not in service_catalog :
235- # if the service is not present, do not check its roles
236- continue
237- else :
238- # match only service type
239- if service_identifier not in [svc [0 ] for svc in service_catalog ]:
240- # if the service is not present, do not check its roles
241- continue
242- print (f"INFO: service '{ service_identifier } ' is present and its "
243- f"roles will be checked ..." )
244- check_list_of_roles (conn , SERVICE_ROLES [service_identifier ])
245-
246- check_key_manager_permissions (conn )
24789
24890
24991if __name__ == "__main__" :
0 commit comments