aliyun / aliyun-openapi-python-sdk

Alibaba Cloud SDK for Python
Other
1.01k stars 588 forks source link

修复无法在客户端加密方式下使用 STS 上传文件至 OSS 的问题 #457

Closed leafcoder closed 3 years ago

leafcoder commented 3 years ago

在使用阿里云 SDK 上传 OSS 文件时,用到了其中的客户端加密文件上传的功能(文档:https://help.aliyun.com/document_detail/74371.html ,文档中示例 V2版本客户端加密(推荐) --> 普通上传和下载文件),其中示例代码提供了使用主 access_key_id 和 access_key_secret 上传文件的方式。

我根据示例和 OSS2 的 SDK 源码将该示例修改为使用 STS 的方式进行上传,发现了两个问题:

oss2 SDK 中的文件 https://github.com/aliyun/aliyun-oss-python-sdk/blob/master/oss2/crypto.py 使用了 aliyun-python-sdk-kms 中的 GenerateDataKeyRequest, DecryptRequest, EncryptRequest 三个文件中的同名 class,并且使用了代码 req.set_STSToken(self.sts_token),如下:


    # 文件:https://github.com/leafcoder/aliyun-oss-python-sdk/blob/master/oss2/crypto.py 第 350 行

    def __generate_data_key(self):
        req = GenerateDataKeyRequest.GenerateDataKeyRequest()

        req.set_accept_format(format_type.JSON)
        req.set_method(method_type.POST)

        req.set_KeyId(self.custom_master_key_id)
        req.set_KeySpec('AES_256')
        req.set_NumberOfBytes(32)
        req.set_EncryptionContext(self.context)
        if self.sts_token:
            req.set_STSToken(self.sts_token)

        resp = self.__do(req)

        return b64decode_from_string(resp['Plaintext']), resp['CiphertextBlob']

但是经过阅读 aliyun-python-sdk-kms 源码,发现 set_STSTokenget_STSToken 方法已于 https://github.com/leafcoder/aliyun-openapi-python-sdk/commit/6fa406ff50063f59ee947bec6f9df152cd0c1918 被删除,提交的信息中包含内容 “Remove the optional parameter 'STSToken' and replace it with 'SecurityToken'.” ,但实际仅删除了 STSToken 参数的方法,未增加 get 和 set 参数 SecurityToken 的方法。


我发现以上问题使用的代码如下:

from aliyunsdkcore import client as aliyun_client
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdksts.request.v20150401 import AssumeRoleRequest
from oss2.crypto import AliKMSProvider

import json
import os
import oss2

AK = 'Your Access Key ID'  # 需自行更换
AS = 'Your Access Key Secret'  # 需自行更换

REGION = 'cn-shenzhen'
ENDPOINT = 'https://oss-cn-shenzhen.aliyuncs.com'
BUCKET_NAME = 'xxxxxx'  # 需自行更换
ROLE_ARN = 'acs:ram::xxxxxx:role/xxxxxx'  # 需自行更换
CMK_ID = 'xxxxxx'  # 需自行更换(KMS 用户密钥 ID)

import json

clt = aliyun_client.AcsClient(AK, AS, REGION)
req = AssumeRoleRequest.AssumeRoleRequest()
req.set_accept_format('json')
req.set_RoleArn(ROLE_ARN)
req.set_RoleSessionName('test')
req.set_Policy(json.dumps({
    "Version": "1",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "oss:PutObject",
                "oss:GetObject",
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:GenerateDataKey"
            ],
            "Resource": [
                'acs:oss:*:*:%s/*' % BUCKET_NAME,
                "acs:kms:cn-shenzhen:xxxxxxxxxxxx:key/%s" % CMK_ID
            ]
        }
    ]
}))
body = clt.do_action_with_exception(req)
token = json.loads(body.decode('utf-8'))
credentials = token['Credentials']

print(credentials)

# STS 部分
auth = oss2.StsAuth(
    credentials['AccessKeyId'],
    credentials['AccessKeySecret'],
    credentials['SecurityToken'])

# 使用StsAuth实例初始化存储空间。

kms_provider = AliKMSProvider(
    credentials['AccessKeyId'],
    credentials['AccessKeySecret'],
    REGION,
    CMK_ID,
    sts_token=credentials['SecurityToken'])
bucket = oss2.CryptoBucket(
    auth, endpoint, bucket_name, crypto_provider=kms_provider)

content = b'test kms'
content = open('/home/ubuntu/test.db', 'rb').read()
key = 'test.db'
bucket.put_object(key, content)
# 下载OSS文件到本地内存。
result = bucket.get_object(key)

# 验证获取到的文件内容跟上传时的文件内容是否一致。
content_got = b''
for chunk in result:
    content_got += chunk
assert content_got == content

所以,经过如上回搠,需要修复 aliyun-python-sdk-kms 和 oss2 两个项目。

我已提交相关 pull-requests,请核对处理,谢谢。

注意:aliyun-python-sdk-kms 和 oss2 需同步修复 SecurityToken 的问题才行,aliyun-python-sdk-kms 的修复优先级需高于 oss2。

leafcoder commented 3 years ago

pull-requests 信息: