From: Pritha Srivastava Date: Mon, 1 Apr 2024 15:57:06 +0000 (+0530) Subject: rgw/qa: added test case to assume a role after role creation X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=855db87f4addec8576708d56b6f6d6554caf8b37;p=ceph.git rgw/qa: added test case to assume a role after role creation syncs, and then creating a bucket on both primary and secondary. The test name is test_assume_role_after_sync. Signed-off-by: Pritha Srivastava --- diff --git a/qa/suites/rgw/multisite/overrides.yaml b/qa/suites/rgw/multisite/overrides.yaml index fad120bf2ed9b..7d0018e0e528a 100644 --- a/qa/suites/rgw/multisite/overrides.yaml +++ b/qa/suites/rgw/multisite/overrides.yaml @@ -20,5 +20,7 @@ overrides: rgw sync obj etag verify: true rgw sync meta inject err probability: 0 rgw sync data inject err probability: 0 + rgw s3 auth use sts: true + rgw sts key: abcdefghijklmnoq rgw: compression type: random diff --git a/src/test/rgw/rgw_multi/conn.py b/src/test/rgw/rgw_multi/conn.py index 2805579e062fe..e3f7cd7770405 100644 --- a/src/test/rgw/rgw_multi/conn.py +++ b/src/test/rgw/rgw_multi/conn.py @@ -1,7 +1,9 @@ import boto import boto.s3.connection import boto.iam.connection +import boto.sts.connection import boto3 +from boto.regioninfo import RegionInfo def get_gateway_connection(gateway, credentials): """ connect to the given gateway """ @@ -45,6 +47,20 @@ def get_gateway_iam_connection(gateway, credentials, region): use_ssl = False) return gateway.iam_connection +def get_gateway_sts_connection(gateway, credentials, region): + """ connect to sts api of the given gateway """ + if gateway.sts_connection is None: + endpoint = f'http://{gateway.host}:{gateway.port}' + print(endpoint) + gateway.sts_connection = boto3.client( + service_name = 'sts', + aws_access_key_id = credentials.access_key, + aws_secret_access_key = credentials.secret, + endpoint_url = endpoint, + region_name=region, + use_ssl = False) + return gateway.sts_connection + def get_gateway_s3_client(gateway, credentials, region): """ connect to boto3 s3 client api of the given gateway """ @@ -68,3 +84,13 @@ def get_gateway_sns_client(gateway, credentials, region): aws_secret_access_key=credentials.secret, region_name=region) return gateway.sns_client + +def get_gateway_temp_s3_client(gateway, credentials, session_token, region): + """ connect to boto3 s3 client api using temporary credntials """ + gateway.temp_s3_client = boto3.client('s3', + endpoint_url='http://' + gateway.host + ':' + str(gateway.port), + aws_access_key_id=credentials.access_key, + aws_secret_access_key=credentials.secret, + aws_session_token = session_token, + region_name=region) + return gateway.temp_s3_client \ No newline at end of file diff --git a/src/test/rgw/rgw_multi/multisite.py b/src/test/rgw/rgw_multi/multisite.py index 4f61425684f0f..982ebe3ea7d8d 100644 --- a/src/test/rgw/rgw_multi/multisite.py +++ b/src/test/rgw/rgw_multi/multisite.py @@ -3,7 +3,7 @@ from io import StringIO import json -from .conn import get_gateway_connection, get_gateway_iam_connection, get_gateway_secure_connection, get_gateway_s3_client, get_gateway_sns_client +from .conn import get_gateway_connection, get_gateway_iam_connection, get_gateway_secure_connection, get_gateway_s3_client, get_gateway_sns_client, get_gateway_sts_connection, get_gateway_temp_s3_client class Cluster: """ interface to run commands against a distinct ceph cluster """ @@ -29,6 +29,7 @@ class Gateway: self.iam_connection = None self.s3_client = None self.sns_client = None + self.sts_connection = None @abstractmethod def start(self, args = []): @@ -195,7 +196,7 @@ class ZoneConn(object): self.iam_conn = get_gateway_iam_connection(self.zone.gateways[0], self.credentials, region) self.s3_client = get_gateway_s3_client(self.zone.gateways[0], self.credentials, region) self.sns_client = get_gateway_sns_client(self.zone.gateways[0], self.credentials, region) - + self.temp_s3_client = None # create connections for the rest of the gateways (if exist) for gw in list(self.zone.gateways): get_gateway_connection(gw, self.credentials) @@ -209,6 +210,11 @@ class ZoneConn(object): def get_iam_connection(self): return self.iam_conn + def get_temp_s3_connection(self, credentials, session_token): + region = "" if self.zone.zonegroup is None else self.zone.zonegroup.name + self.temp_s3_client = get_gateway_temp_s3_client(self.zone.gateways[0], credentials, session_token, region) + return self.temp_s3_client + def get_bucket(self, bucket_name, credentials): raise NotImplementedError diff --git a/src/test/rgw/rgw_multi/tests.py b/src/test/rgw/rgw_multi/tests.py index a4eec298de4dc..4595ca50dea58 100644 --- a/src/test/rgw/rgw_multi/tests.py +++ b/src/test/rgw/rgw_multi/tests.py @@ -2258,6 +2258,40 @@ def test_object_acl(): after_set_acl = bucket2.get_acl(k) assert(len(after_set_acl.acl.grants) == 2) # read grant added on AllUsers +def test_assume_role_after_sync(): + zonegroup = realm.master_zonegroup() + zonegroup_conns = ZonegroupConns(zonegroup) + access_key = 'abcd' + secret_key = 'efgh' + tenant = 'testx' + uid = 'test' + cmd = ['user', 'create', '--tenant', tenant, '--uid', uid, '--access-key', access_key, '--secret-key', secret_key, '--display-name', 'tenanted-user'] + zonegroup_conns.master_zone.zone.cluster.admin(cmd) + credentials = Credentials(access_key, secret_key) + + role_name = gen_role_name() + log.info('create role zone=%s name=%s', zonegroup_conns.master_zone.name, role_name) + policy_document = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"arn:aws:iam::testx:user/test\"]},\"Action\":[\"sts:AssumeRole\"]}]}" + role = zonegroup_conns.master_zone.create_role("/", role_name, policy_document, "") + policy_document = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Resource\":\"*\",\"Action\":\"s3:*\"}]}" + zonegroup_conns.master_zone.put_role_policy(role_name, "Policy1", policy_document) + + zonegroup_meta_checkpoint(zonegroup) + + for zone in zonegroup_conns.zones: + log.info(f'checking if zone: {zone.name} has role: {role_name}') + assert(zone.has_role(role_name)) + log.info(f'success, zone: {zone.name} has role: {role_name}') + + for zone in zonegroup_conns.zones: + if zone == zonegroup_conns.master_zone: + log.info(f'creating bucket in primary zone') + bucket = "bucket1" + zone.assume_role_create_bucket(bucket, role['Role']['Arn'], "primary", credentials) + if zone != zonegroup_conns.master_zone: + log.info(f'creating bucket in secondary zone') + bucket = "bucket2" + zone.assume_role_create_bucket(bucket, role['Role']['Arn'], "secondary", credentials) @attr('fails_with_rgw') @attr('data_sync_init') diff --git a/src/test/rgw/rgw_multi/zone_cloud.py b/src/test/rgw/rgw_multi/zone_cloud.py index fdec751ff5222..b7b5de1aeb69a 100644 --- a/src/test/rgw/rgw_multi/zone_cloud.py +++ b/src/test/rgw/rgw_multi/zone_cloud.py @@ -310,6 +310,9 @@ class CloudZone(Zone): def has_role(self, role_name): assert False + def put_role_policy(self, rolename, policyname, policy_document): + assert False + def create_topic(self, topicname, attributes): assert False @@ -331,6 +334,9 @@ class CloudZone(Zone): def list_notifications(self, bucket_name): assert False + def assume_role(self, role_arn, session_name, policy, duration_seconds): + assert False + def get_conn(self, credentials): return self.Conn(self, credentials) diff --git a/src/test/rgw/rgw_multi/zone_es.py b/src/test/rgw/rgw_multi/zone_es.py index 2ccdcf0423323..f619394e12cb8 100644 --- a/src/test/rgw/rgw_multi/zone_es.py +++ b/src/test/rgw/rgw_multi/zone_es.py @@ -252,6 +252,9 @@ class ESZone(Zone): def has_role(self, role_name): assert False + def put_role_policy(self, rolename, policyname, policy_document): + assert False + def create_topic(self, topicname, attributes): assert False @@ -273,6 +276,9 @@ class ESZone(Zone): def list_notifications(self, bucket_name): assert False + def assume_role(self, role_arn, session_name, policy, duration_seconds): + assert False + def get_conn(self, credentials): return self.Conn(self, credentials) diff --git a/src/test/rgw/rgw_multi/zone_rados.py b/src/test/rgw/rgw_multi/zone_rados.py index ce0530543e061..191aaf7b1b344 100644 --- a/src/test/rgw/rgw_multi/zone_rados.py +++ b/src/test/rgw/rgw_multi/zone_rados.py @@ -8,6 +8,8 @@ from nose.tools import eq_ as eq from .multisite import * +from .conn import get_gateway_sts_connection + log = logging.getLogger(__name__) def check_object_eq(k1, k2, check_extra = True): @@ -106,7 +108,7 @@ class RadosZone(Zone): return True def get_role(self, role_name): - return self.iam_conn.get_role(role_name) + return self.iam_conn.get_role(RoleName=role_name) def check_role_eq(self, zone_conn, role_name): log.info('comparing role=%s zones={%s, %s}', role_name, self.name, zone_conn.name) @@ -130,10 +132,10 @@ class RadosZone(Zone): def create_role(self, path, rolename, policy_document, tag_list): if policy_document is None: policy_document = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"arn:aws:iam:::user/testuser\"]},\"Action\":[\"sts:AssumeRole\"]}]}" - return self.iam_conn.create_role(rolename, policy_document, path) + return self.iam_conn.create_role(RoleName=rolename, AssumeRolePolicyDocument=policy_document, Path=path) def delete_role(self, role_name): - return self.iam_conn.delete_role(role_name) + return self.iam_conn.delete_role(RoleName=role_name) def has_role(self, role_name): try: @@ -142,6 +144,11 @@ class RadosZone(Zone): return False return True + def put_role_policy(self, rolename, policyname, policy_document): + if policy_document is None: + policy_document = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Resource\":\"*\",\"Action\":\"s3:*\"}]}" + return self.iam_conn.put_role_policy(RoleName=rolename, PolicyName=policyname, PolicyDocument=policy_document) + def create_topic(self, topicname, attributes): result = self.sns_client.create_topic(Name=topicname, Attributes=attributes) self.topic_arn = result['TopicArn'] @@ -173,6 +180,17 @@ class RadosZone(Zone): def head_object(self, bucket_name, obj_name): return self.s3_client.head_object(Bucket=bucket_name, Key=obj_name) + def assume_role_create_bucket(self, bucket, role_arn, session_name, alt_user_creds): + region = "" if self.zone.zonegroup is None else self.zone.zonegroup.name + sts_conn = None + if self.zone.gateways is not None: + sts_conn = get_gateway_sts_connection(self.zone.gateways[0], alt_user_creds, region) + assumed_role_object = sts_conn.assume_role(RoleArn=role_arn, RoleSessionName=session_name) + assumed_role_credentials = assumed_role_object['Credentials'] + credentials = Credentials(assumed_role_credentials['AccessKeyId'], assumed_role_credentials['SecretAccessKey']) + self.get_temp_s3_connection(credentials, assumed_role_credentials['SessionToken']) + self.temp_s3_client.create_bucket(Bucket=bucket) + def get_conn(self, credentials): return self.Conn(self, credentials)