]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/qa: added test case to assume a role after role creation 56576/head
authorPritha Srivastava <prsrivas@redhat.com>
Mon, 1 Apr 2024 15:57:06 +0000 (21:27 +0530)
committerPritha Srivastava <prsrivas@redhat.com>
Sat, 26 Apr 2025 09:42:52 +0000 (15:12 +0530)
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 <prsrivas@redhat.com>
qa/suites/rgw/multisite/overrides.yaml
src/test/rgw/rgw_multi/conn.py
src/test/rgw/rgw_multi/multisite.py
src/test/rgw/rgw_multi/tests.py
src/test/rgw/rgw_multi/zone_cloud.py
src/test/rgw/rgw_multi/zone_es.py
src/test/rgw/rgw_multi/zone_rados.py

index fad120bf2ed9b3507ae2a8318505ce4a25a0e365..7d0018e0e528af055d01e19568f499b59649edcb 100644 (file)
@@ -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
index 2805579e062fec8dbcf4150c29d3b30906fbca2a..e3f7cd7770405586a182fd463a276bb6fda7e156 100644 (file)
@@ -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
index 4f61425684f0f1edd3bb290cf5e35435129f2b9e..982ebe3ea7d8d483354365369f5bfc95cb7c1697 100644 (file)
@@ -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
 
index a4eec298de4dc955f0c5cd155ffa52b7917416e9..4595ca50dea58790712f600385e6fb2f21447ff8 100644 (file)
@@ -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')
index fdec751ff5222e5db1c4a609169726bb0b35cf6e..b7b5de1aeb69a01850d8671ee51e1ed6ceca65f2 100644 (file)
@@ -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)
 
index 2ccdcf042332333d4c16303007085e7bb66f8a97..f619394e12cb807580aa8c7a3b09919d9e15dfb6 100644 (file)
@@ -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)
 
index ce0530543e061f7f199b741c84f709eb6347c6e5..191aaf7b1b344f9312d6bfda6a3513801bffefb6 100644 (file)
@@ -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)