First let's setup our environment, and create a couple of s3 users: laura, and randy.

[ramartin@tower-osd4 ~]$ radosgw-admin user create --tenant laura --uid laura --display-name laura --access_key laura_access --secret laura_secret
[ramartin@tower-osd4 ~]$ radosgw-admin user create --tenant randy --uid randy --display-name randy --access_key randy_access --secret randy_secret

Remember with using clients like s3cmd, that the RGW will use an implicit tenant name based on the requestor, unless explicitly specified otherwise. Here we're going to create a bucket called 'share-bucket' and upload an object:

[ramartin@tower-osd4 ~]$ s3cmd ls -c laura.cfg 
[ramartin@tower-osd4 ~]$ s3cmd mb s3://share-bucket -c laura.cfg 
Bucket 's3://share-bucket/' created
[ramartin@tower-osd4 ~]$ s3cmd ls -c laura.cfg 
2020-03-24 01:59  s3://share-bucket
[ramartin@tower-osd4 ~]$ s3cmd info s3://share-bucket -c laura.cfg 
s3://share-bucket/ (bucket):
   Location:  default
   Payer:     BucketOwner
   Expiration Rule: none
   Policy:    none
   CORS:      none
   ACL:       laura: FULL_CONTROL
[ramartin@tower-osd4 ~]$ s3cmd put example.txt s3://share-bucket -c laura.cfg 
upload: 'example.txt' -> 's3://share-bucket/example.txt'  [1 of 1]

Next we'll use my example script to have laura's user create a bucket policy granting user randy access to 'share-bucket'. In addition, the script will also list contents of 'share-bucket' and download a predefined file to the current users home_directory/Downloads folder:

#!/usr/bin/python3
import boto3
import botocore
import json
import os
from botocore.handlers import validate_bucket_name

tenant = 'randy' # --tenant
tenant_user = 'randy' # --uid
target_tenant = 'laura' # --tenant
target_user = 'laura' # --uid
target_bucket = 'share-bucket' # bucket to be shared with tenant$tenant_user

# set access/secret ids from environment variables
randy_access = os.environ.get('randy_access')
randy_secret = os.environ.get('randy_secret')
laura_access = os.environ.get('laura_access')
laura_secret = os.environ.get('laura_secret')

# configure endpoint url 
endpoint = 'https://tower-osd4.cephtips.com'
# file to download
file_to_download = 'example.txt'
# download file destination
dest_file = os.path.expanduser('~')+'/Downloads/'+f'{file_to_download}'

# create s3 client
randy = boto3.client('s3', endpoint_url=endpoint, use_ssl=True, aws_access_key_id=randy_access, aws_secret_access_key=randy_secret)
# unregister bucket name validation
randy.meta.events.unregister('before-parameter-build.s3', validate_bucket_name)

# create s3 client
laura = boto3.client('s3', endpoint_url=endpoint, use_ssl=True, aws_access_key_id=laura_access, aws_secret_access_key=laura_secret)
# unregister bucket name validation
laura.meta.events.unregister('before-parameter-build.s3', validate_bucket_name)

try:
    # Grant tenanted user access to: target_tenant, target_bucket
    bucket_policy = {
        'Version': '2012-10-17',
        'Statement': [{
            'Sid': 'ListBucket',
            'Effect': 'Allow',
            'Principal': {
                 "AWS": f"arn:aws:iam::{tenant}:user/{tenant_user}"
            },
            'Action': [
              's3:ListBucket'
             ],
            'Resource': f"arn:aws:s3::{target_tenant}:{target_bucket}"
             },  {
            'Sid': 'GetObject',
            'Effect': 'Allow',
            'Principal': {
                 "AWS": f"arn:aws:iam::{tenant}:user/{tenant_user}"
            },
            'Action': [
              's3:GetObject'
             ],
            'Resource': f"arn:aws:s3::{target_tenant}:{target_bucket}/*"

        }]
    }
    # Convert the policy to a JSON string
    bucket_policy = json.dumps(bucket_policy)
    # Set the new policy on the given bucket as laura
    laura.put_bucket_policy(Bucket=target_bucket, Policy=bucket_policy)
    print( "\r\n" + "Bucket policy configured.")
except botocore.exceptions.ClientError as e: 
    print(e)

try:
   # Get a list of objects in target_bucket as tenant_user
   objects = randy.list_objects(Bucket=f'{target_tenant}:{target_bucket}')
   print("\r\n" + "The following objects are in " + f'{target_tenant}' + "'s" + " [bucket=" + f'{target_bucket}' + "] :")
   print(objects)
except botocore.exceptions.ClientError as e:
   print(e)

try:
  # Download f'{dest_file}' from share-bucket as randy
    randy.download_file(f'{target_tenant}:{target_bucket}', f'{file_to_download}', f'{dest_file}')
    print( "\r\n" + f'{dest_file}' + " File Download Complete. ")
except botocore.exceptions.ClientError as e:
    print(e)

stdout Reference:

[ramartin@tower-osd4 ~]$ python randy.py 

Bucket policy configured.

The following objects are in laura's [bucket=share-bucket] :
{'ResponseMetadata': {'RequestId': 'tx000000000000000000114-005e798920-8589-default', 'HostId': '', 'HTTPStatusCode': 200, 'HTTPHeaders': {'transfer-encoding': 'chunked', 'x-amz-request-id': 'tx000000000000000000114-005e798920-8589-default', 'content-type': 'application/xml', 'date': 'Tue, 24 Mar 2020 04:14:24 GMT', 'connection': 'Keep-Alive'}, 'RetryAttempts': 0}, 'IsTruncated': False, 'Marker': '', 'Contents': [{'Key': 'example.txt', 'LastModified': datetime.datetime(2020, 3, 24, 3, 25, 37, 682000, tzinfo=tzutc()), 'ETag': '"a80903d14ce564dd34939eecce1fd0d4"', 'Size': 2088, 'StorageClass': 'STANDARD', 'Owner': {'DisplayName': 'laura', 'ID': 'laura$laura'}}], 'Name': 'share-bucket', 'Prefix': '', 'MaxKeys': 1000, 'EncodingType': 'url'}

/home/ramartin/Downloads/example.txt File Download Complete. 

[ramartin@tower-osd4 ~]$ s3cmd info s3://share-bucket -c laura.cfg 
s3://share-bucket/ (bucket):
   Location:  default
   Payer:     BucketOwner
   Expiration Rule: none
   Policy:    {"Version": "2012-10-17", "Statement": [{"Sid": "ListBucket", "Effect": "Allow", "Principal": {"AWS": "arn:aws:iam::randy:user/randy"}, "Action": ["s3:ListBucket"], "Resource": "arn:aws:s3::laura:share-bucket"}, {"Sid": "GetObject", "Effect": "Allow", "Principal": {"AWS": "arn:aws:iam::randy:user/randy"}, "Action": ["s3:GetObject"], "Resource": "arn:aws:s3::laura:share-bucket/*"}]}
   CORS:      none
   ACL:       laura: FULL_CONTROL