对象owner给桶owner授予对象的完全控制权限(对象owner和桶owner不属于同一个账号)
本案例介绍当桶中对象来源于其他账号(非桶owner上传)时,桶owner如何获取对象的完全控制权限,即对象owner如何给桶owner授予对象的完全控制权限。例如账号A将对象a上传到账号B的桶b中,如何给账号B授予对象a的完全控制权限。
场景介绍
在使用云服务的过程中,您可能会遇到如下场景:
- 跨账号上传对象后,基于业务诉求,桶owner需要访问和分析对象:桶中的数据需要多个账号进行写入,之后桶owner需要对桶中数据进行访问和分析。例如跨账号的日志存储场景,假设您拥有3个账号,账号A、B用于运行业务生成日志,账号C用于收集和分析日志。账号A、B在使用云服务例如ELB、OBS等的过程中产生的日志文件会统一集中存储到账号C的日志存储桶中,之后账号C需要访问并分析这些日志文件。
- 跨账号上传对象后,桶owner需管理对象:由于业务需要,您的桶可能会涉及到多个账号进行写入,作为桶owner您需要对桶中对象进行统一管理。例如:1)其余账号上传时可能意外将对象设置为公开读,桶owner需要将对象访问权限修正为私有;2)其他账号上传对象后,为了节省成本桶owner需要删除或修改对象的存储类别,或者使用生命周期定期删除、转换对象的存储类别;3)其他账号上传对象后,桶owner需要检查对象是否合规,如不符合要求需要删除。
在以上场景中,桶中的对象虽然并非桶owner上传,但是基于业务和管理的需要,桶owner需要拥有对象的访问和管理权限,OBS支持使用对象ACL完成对象owner对桶owner的授权。
背景介绍
在进行授权操作前,您可能想要了解以下背景知识:
- 桶owner(桶拥有者):创建存储桶的IAM用户。
- 对象owner(对象拥有者):上传对象的IAM用户。当用户A向另一个用户B的桶中上传对象时,用户A是该对象的拥有者。这意味着即使桶属于用户B,用户B也默认没有权限访问或管理这个对象。
- 对象ACL:一种访问控制方式,用于对象owner给其他账号配置对象的访问权限。了解更多请参见ACL。
- bucket-owner-full-control:是对象ACL的一个配置选项。如果您作为对象owner将对象的ACL配置为bucket-owner-full-control,那么就意味着您将该对象的完全控制权授予了桶owner(对象所在桶的桶owner)。授权后,桶owner可以为自己授予对象所有操作的权限,也可以授予其他用户对象的访问权限。了解更多请参见如何设置ACL。
- 桶策略:除了ACL,桶策略是另外一种OBS的权限管理方式,桶owner可以使用桶策略配置的桶及桶内对象的访问权限。了解更多请参见桶策略。
方案架构
如图1所示,账号A上传对象a到账号B的桶b中,此时账号A是对象a的对象owner,账号B是桶b的桶owner:
- 授权前:账号B访问对象a会失败,报错403权限不足,原因是对象默认只有对象owner才能访问。
- 授权后:账号A将对象a的对象ACL配置为bucket-owner-full-control,配置后账号B拥有对象a的完全控制权。账号B自己可以访问和管理对象a,也可以授权其他用户访问对象a。
配置流程
|
序号 |
操作步骤 |
说明 |
详细操作 |
|---|---|---|---|
|
1 |
准备工作 |
桶owner通过桶策略为对象owner开通上传对象(obs:object:PutObject)的权限。 |
|
|
2 |
对象owner配置对象ACL |
对象owner将对象的ACL设置为bucket-owner-full-control,配置后桶owner拥有对象的完全控制权 |
|
|
3 |
【可选】桶owner使用桶策略授权 |
当桶owner作为访问者时,若操作不涉及修改对象元数据或增删改对象标签,可直接访问或管理对象;若操作涉及上述内容,则需通过桶策略为自己授予对应的权限。 如果访问者既不是桶owner也不是对象owner,那么桶owner需要使用桶策略为访问者授予对象操作对应的权限。 |
|
|
4 |
访问或修改对象 |
桶owner或其他用户在授权后可正常访问或修改对象。 |
步骤一:准备工作
为了使其他账号能够向您的桶中上传对象,您需要为这些账号授予上传权限,即桶owner需要为对象owner开通上传对象(obs:object:PutObject)的权限。例如账号A需要上传对象a到账号B的桶b中,那么账号B需要给账号A授予向桶b中上传对象的权限,如何授权请参考对其他账号下的IAM用户授予桶和桶内资源的访问权限。
步骤二:为桶owner授予bucket-owner-full-control权限
您可以在上传对象时直接授权,此处以对象owner将名为exampleobject-a的对象,上传到名为examplebucket的桶中为例,在上传对象的同时将对象的ACL配置为owner bucket-owner-full-control。
您可以使用管理控制台、API、SDK、OBS Browser+、obsutil设置对象的ACL为bucket-owner-full-control:
【可选】步骤三:桶owner使用桶策略授权
- 如果访问者是桶owner并且操作不包含修改对象元数据或者增删改对象标签,那么桶owner可以直接访问或管理对象,无需进行桶策略授权,请直接进行步骤四。
- 如果访问者是桶owner,并且操作包含表3 需要进行桶策略授权的操作中的操作,那么桶owner需要使用桶策略为自己授予相关操作的权限。
- 如果访问者既不是桶owner也不是对象owner,那么桶owner需要使用桶策略为访问者授予相关操作的权限。
OBS支持使用管理控制台、API、SDK、OBS Browser+、obsutil设置桶策略,请以“桶owner”的身份执行本步骤。
此处以桶examplebucket的桶owner,使用桶策略授予exampleobject-a对象的对象元数据修改权限为例,提供以下示例代码供参考:
Java示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
import com.obs.services.ObsClient; import com.obs.services.exception.ObsException; public class SetBucketPolicy001 { public static void main(String[] args) { // 此处的AK/SK是桶owner的AK/SK // 您可以通过环境变量获取访问密钥AK/SK,也可以使用其他外部引入方式传入。如果使用硬编码可能会存在泄露风险。 // 您可以登录访问管理控制台获取访问密钥AK/SK String ak = System.getenv("ACCESS_KEY_ID"); String sk = System.getenv("SECRET_ACCESS_KEY_ID"); // 【可选】如果使用临时AK/SK和SecurityToken访问OBS,同样建议您尽量避免使用硬编码,以降低信息泄露风险。 // 您可以通过环境变量获取访问密钥AK/SK/SecurityToken,也可以使用其他外部引入方式传入。 // String securityToken = System.getenv("SECURITY_TOKEN"); // endpoint填写桶所在的endpoint, 此处以华北-北京四为例,其他地区请按实际情况填写。 String endPoint = "https://obs.cn-north-4.myhuaweicloud.com"; // 您可以通过环境变量获取endPoint,也可以使用其他外部引入方式传入。 //String endPoint = System.getenv("ENDPOINT"); // 创建ObsClient实例 // 使用永久AK/SK初始化客户端 ObsClient obsClient = new ObsClient(ak, sk,endPoint); // 使用临时AK/SK和SecurityToken初始化客户端 // ObsClient obsClient = new ObsClient(ak, sk, securityToken, endPoint); try { // 示例桶名 String exampleBucket = "examplebucket"; // 示例桶策略,Principal字段填写被授权用户的账号ID(domainId)和IAM用户ID(userId),例如要给桶owner授权,就填写桶owner的账号ID和IAM用户ID,要给其他用户授权就填写对应用户的ID String examplePolicy ="{\"Statement\":[{\"Principal\":{\"ID\":[\"domain/YourDomainId:user/YourUserId\"]},\"Effect\":\"Allow\",\"Action\":[\"ModifyObjectMetaData\"],\"Resource\":\"" + exampleBucket + "/exampleobject-a\"}]}"; obsClient.setBucketPolicy(exampleBucket, examplePolicy); System.out.println("SetBucketPolicy successfully"); } catch (ObsException e) { System.out.println("SetBucketPolicy failed"); // 请求失败,打印http状态码 System.out.println("HTTP Code:" + e.getResponseCode()); // 请求失败,打印服务端错误码 System.out.println("Error Code:" + e.getErrorCode()); // 请求失败,打印详细错误信息 System.out.println("Error Message:" + e.getErrorMessage()); // 请求失败,打印请求id System.out.println("Request ID:" + e.getErrorRequestId()); System.out.println("Host ID:" + e.getErrorHostId()); e.printStackTrace(); } catch (Exception e) { System.out.println("SetBucketPolicy failed"); // 其他异常信息打印 e.printStackTrace(); } } } |
Python示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
from obs import ObsClient import os import traceback # 此处的AccessKeyID和SecretAccessKey是桶owner的AK/SK # 推荐通过环境变量获取AKSK,这里也可以使用其他外部引入方式传入,如果使用硬编码可能会存在泄露风险 # 您可以登录访问管理控制台获取访问密钥AK/SK,获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html ak = os.getenv("AccessKeyID") sk = os.getenv("SecretAccessKey") # 【可选】如果使用临时AKSK和SecurityToken访问OBS,则同样推荐通过环境变量获取 # security_token = os.getenv("SecurityToken") # server填写Bucket对应的Endpoint, 这里以华北-北京四为例,其他地区请按实际情况填写 server = "https://obs.cn-north-4.myhuaweicloud.com" # 创建obsClient实例 # 如果使用临时AKSK和SecurityToken访问OBS,需要在创建实例时通过security_token参数指定securityToken值 obsClient = ObsClient(access_key_id=ak, secret_access_key=sk, server=server) try: bucketName = "examplebucket" # 示例桶策略,Principal字段填写被授权用户的账号ID(domainId)和IAM用户ID(userId),例如要给桶owner授权,就填写桶owner的账号ID和IAM用户ID,要给其他用户授权就填写对应用户的ID policyJSON = '{"Statement":[{"Sid":"ExampleStatementID1","Effect":"Allow","Principal":{"ID":["domain/**********:user/**********"]},"Action":["ModifyObjectMetaData"],"Resource":["examplebucket/exampleobject-a"]}]}' # 设置桶策略 resp = obsClient.setBucketPolicy(bucketName, policyJSON) # 返回码为2xx时,接口调用成功,否则接口调用失败 if resp.status < 300: print('Set Bucket Policy Succeeded') print('requestId:', resp.requestId) else: print('Set Bucket Policy Failed') print('requestId:', resp.requestId) print('errorCode:', resp.errorCode) print('errorMessage:', resp.errorMessage) except: print('Set Bucket Policy Failed') print(traceback.format_exc()) |
步骤四:访问或修改对象
桶owner或其他用户在授权后可正常访问或修改对象。OBS支持使用管理控制台、API、SDK、OBS Browser+、obsutil访问或修改对象,请以“桶owner或其他被授权用户”的身份执行本步骤。
此处以桶owner修改examplebucket桶中exampleobject-a对象的存储类别(修改存储类别本质上是修改对象元数据)为例。
Java示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
import com.obs.services.ObsClient; import com.obs.services.exception.ObsException; import com.obs.services.model.ObjectMetadata; import com.obs.services.model.SetObjectMetadataRequest; import java.util.HashMap; public class SetObjectMetadata001 { public static void main(String[] args) { // 此处的AK/SK是被授予对象访问权限的用户的AK/SK,如果是桶owner被授权就是桶owner的AK/SK,如果是其他用户被授权,就是其他用户的AK/SK // 您可以通过环境变量获取访问密钥AK/SK,也可以使用其他外部引入方式传入。如果使用硬编码可能会存在泄露风险。 // 您可以登录访问管理控制台获取访问密钥AK/SK String ak = System.getenv("ACCESS_KEY_ID"); String sk = System.getenv("SECRET_ACCESS_KEY_ID"); // 【可选】如果使用临时AK/SK和SecurityToken访问OBS,同样建议您尽量避免使用硬编码,以降低信息泄露风险。 // 您可以通过环境变量获取访问密钥AK/SK/SecurityToken,也可以使用其他外部引入方式传入。 // String securityToken = System.getenv("SECURITY_TOKEN"); // endpoint填写桶所在的endpoint, 此处以华北-北京四为例,其他地区请按实际情况填写。 String endPoint = "https://obs.cn-north-4.myhuaweicloud.com"; // 您可以通过环境变量获取endPoint,也可以使用其他外部引入方式传入。 //String endPoint = System.getenv("ENDPOINT"); // 创建ObsClient实例 // 使用永久AK/SK初始化客户端 ObsClient obsClient = new ObsClient(ak, sk,endPoint); // 使用临时AK/SK和SecurityToken初始化客户端 // ObsClient obsClient = new ObsClient(ak, sk, securityToken, endPoint); try { // 设置对象元数据 SetObjectMetadataRequest request = new SetObjectMetadataRequest("examplebucket", "exampleobject-a"); // 设置桶的存储类别为标准存储 request.setObjectStorageClass(StorageClassEnum.WARM); ObjectMetadata metadata = obsClient.setObjectMetadata(request); System.out.println("setObjectMetadata successfully"); System.out.println("UserMetadata:" + metadata.toString()); } catch (ObsException e) { System.out.println("setObjectMetadata failed"); // 请求失败,打印http状态码 System.out.println("HTTP Code:" + e.getResponseCode()); // 请求失败,打印服务端错误码 System.out.println("Error Code:" + e.getErrorCode()); // 请求失败,打印详细错误信息 System.out.println("Error Message:" + e.getErrorMessage()); // 请求失败,打印请求id System.out.println("Request ID:" + e.getErrorRequestId()); System.out.println("Host ID:" + e.getErrorHostId()); e.printStackTrace(); } catch (Exception e) { System.out.println("setObjectMetadata failed"); // 其他异常信息打印 e.printStackTrace(); } } } |
Python示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
from obs import SetObjectMetadataHeader from obs import ObsClient import os import traceback # 此处的AccessKeyID和SecretAccessKey是被授予对象访问权限的用户的AK/SK,如果是桶owner被授权就是桶owner的AK/SK,如果是其他用户被授权,就是其他用户的AK/SK # 推荐通过环境变量获取AKSK,这里也可以使用其他外部引入方式传入,如果使用硬编码可能会存在泄露风险 # 您可以登录访问管理控制台获取访问密钥AK/SK,获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html ak = os.getenv("AccessKeyID") sk = os.getenv("SecretAccessKey") # 【可选】如果使用临时AKSK和SecurityToken访问OBS,则同样推荐通过环境变量获取 # security_token = os.getenv("SecurityToken") # server填写Bucket对应的Endpoint, 这里以华北-北京四为例,其他地区请按实际情况填写 server = "https://obs.cn-north-4.myhuaweicloud.com" # 创建obsClient实例 # 如果使用临时AKSK和SecurityToken访问OBS,需要在创建实例时通过security_token参数指定securityToken值 obsClient = ObsClient(access_key_id=ak, secret_access_key=sk, server=server) try: # 设置对象自定义元数据 metadata = {'property1': 'property-value1', 'property2': 'property-value2'} # 设置对象附加头域 headers = SetObjectMetadataHeader() # 【可选】待上传对象的MIME类型 headers.contentType = "Your Content-Type" # 设置目标存储类别 headers.storageClass = "WARM" bucketName = "examplebucket" objectKey = "exampleobject-a" # 设置对象元数据 resp = obsClient.setObjectMetadata(bucketName, objectKey, metadata, headers) # 返回码为2xx时,接口调用成功,否则接口调用失败 if resp.status < 300: print('Set Object Metadata Succeeded') print('requestId:', resp.requestId) else: print('Set Object Metadata Failed') print('requestId:', resp.requestId) print('errorCode:', resp.errorCode) print('errorMessage:', resp.errorMessage) except: print('Set Object Metadata Failed') print(traceback.format_exc()) |






