更新时间:2024-02-01 GMT+08:00

服务端加密(Go SDK)

功能说明

用户可以使用普通方式上传、下载对象,也可以使用服务端加密方式进行上传、下载对象。

OBS支持服务端加密功能,使加密的行为在服务端进行。

用户可以根据自身的需求,使用不同的密钥管理方式来使用服务端加密功能。当前支持两种服务端加密方式: KMS托管密钥的服务端加密(SSE-KMS)和客户提供加密密钥的服务端加密(SSE-C)。上述两种方式都采用行业标准的AES256加密算法。

SSE-KMS方式,OBS使用KMS(Key Management Service)服务提供的密钥进行服务端加密。

SSE-C方式,OBS使用用户提供的密钥和密钥的MD5值进行服务端加密。

使用服务端加密,返回的ETag值不是对象的MD5值。无论是否使用服务端加密上传对象,请求消息头中加入Content-MD5参数时,OBS均会对对象进行MD5校验。

更多关于服务端加密的内容请参考服务端加密

接口约束

  • 您必须是桶拥有者或拥有上传对象的权限,才能上传对象。建议使用IAM或桶策略进行授权,如果使用IAM则需授予obs:object:PutObject权限,如果使用桶策略则需授予PutObject权限。相关授权方式介绍可参见OBS权限控制概述,配置方式详见使用IAM自定义策略配置对象策略
  • OBS支持的Region与Endpoint的对应关系,详细信息请参见地区与终端节点

方法定义

func (obsClient ObsClient) PutFile(input *PutFileInput) (output *PutObjectOutput, err error)

支持接口

OBS Go SDK支持服务端加密的接口见下表:

OBS Go SDK接口方法

描述

支持加密类型

ObsClient.PutObject

上传对象时设置加密算法、密钥,对对象启用服务端加密。

SSE-KMS

SSE-C

ObsClient.PutFile

上传文件时设置加密算法、密钥,对对象启用服务端加密。

SSE-KMS

SSE-C

ObsClient.GetObject

下载对象时设置解密算法、密钥,用于解密对象。

SSE-C

ObsClient.CopyObject

  1. 复制对象时设置源对象的解密算法、密钥,用于解密源对象。
  2. 复制对象时设置目标对象的加密算法、密钥,对目标对象启用加密算法。

SSE-KMS

SSE-C

ObsClient.GetObjectMetadata

获取对象元数据时设置解密算法、密钥,用于解密对象。

SSE-C

ObsClient.InitiateMultipartUpload

初始化分段上传任务时设置加密算法、密钥,对分段上传任务最终生成的对象启用服务端加密。

SSE-KMS

SSE-C

ObsClient.UploadPart

上传段时设置加密算法、密钥,对分段数据启用服务端加密。

SSE-C

ObsClient.CopyPart

  1. 复制段时设置源对象的解密算法、密钥,用于解密源对象。
  2. 复制段时设置目标段的加密算法、密钥,对目标段启用加密算法。

SSE-C

代码示例

本示例用于加密流式上传到examplebucket桶中的example/objectname对象

 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
54
55
56
57
58
59
package main
import (
    "crypto/md5"
    "encoding/base64"
    "fmt"
    "os"
    "strings"
    obs "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs"
)
func main() {
    //推荐通过环境变量获取AKSK,这里也可以使用其他外部引入方式传入,如果使用硬编码可能会存在泄露风险。
    //您可以登录访问管理控制台获取访问密钥AK/SK,获取方式请参见https://support.huaweicloud.com/intl/zh-cn/usermanual-ca/ca_01_0003.html。
    ak := os.Getenv("AccessKeyID")
    sk := os.Getenv("SecretAccessKey")
    // 【可选】如果使用临时AK/SK和SecurityToken访问OBS,同样建议您尽量避免使用硬编码,以降低信息泄露风险。您可以通过环境变量获取访问密钥AK/SK,也可以使用其他外部引入方式传入。
    // securityToken := os.Getenv("SecurityToken")
    // endpoint填写Bucket对应的Endpoint, 这里以中国-香港为例,其他地区请按实际情况填写。
    endPoint := "https://obs.ap-southeast-1.myhuaweicloud.com"
    // 创建obsClient实例
    // 如果使用临时AKSK和SecurityToken访问OBS,需要在创建实例时通过obs.WithSecurityToken方法指定securityToken值。
    obsClient, err := obs.New(ak, sk, endPoint/*, obs.WithSecurityToken(securityToken)*/)
    if err != nil {
        fmt.Printf("Create obsClient error, errMsg: %s", err.Error())
    }
    input := &obs.PutObjectInput{}
    // 指定存储桶名称
    input.Bucket = "examplebucket"
    // 指定上传对象名,此处以 example/objectname 为例。
    input.Key = "example/objectname"
    // 指定上传的内容
    input.Body = strings.NewReader("Hello OBS")
    // 指定服务端加密头信息,此处以 obs.SseCHeader为例
    key := os.Getenv("Key")
    digest := md5.New()
    digest.Write([]byte(key))
    bodyHash := digest.Sum(nil)
    input.SseHeader = obs.SseCHeader{
        Encryption: "AES256",
        Key:        base64.StdEncoding.EncodeToString([]byte(key)), // 32byteslongsecretkeymustprovided
        KeyMD5:     base64.StdEncoding.EncodeToString(bodyHash),
    }
    // 流式上传本地文件
    output, err := obsClient.PutObject(input)
    if err == nil {
        fmt.Printf("Put object(%s) under the bucket(%s) successful!\n", input.Key, input.Bucket)
        fmt.Printf("RequestId:%s\n", output.RequestId)
        fmt.Printf("StorageClass:%s, ETag:%s\n",
            output.StorageClass, output.ETag)
        return
    }
    fmt.Printf("Put object(%s) under the bucket(%s) fail!\n", input.Key, input.Bucket)
    if obsError, ok := err.(obs.ObsError); ok {
        fmt.Println("An ObsError was found, which means your request sent to OBS was rejected with an error response.")
        fmt.Println(obsError.Error())
    } else {
        fmt.Println("An Exception was found, which means the client encountered an internal problem when attempting to communicate with OBS, for example, the client was unable to access the network.")
        fmt.Println(err)
    }
}

本示例用于流式下载examplebucket桶中的example/objectname加密对象

 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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package main
import (
    "crypto/md5"
    "encoding/base64"
    "fmt"
    "os"
    obs "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs"
)
func main() {
    // 您可以通过环境变量获取访问密钥AK/SK,也可以使用其他外部引入方式传入。如果使用硬编码可能会存在泄露风险。
    // 您可以登录访问管理控制台获取访问密钥AK/SK,获取方式请参见https://support.huaweicloud.com/intl/zh-cn/usermanual-ca/ca_01_0003.html
    ak := os.Getenv("AccessKeyID")
    sk := os.Getenv("SecretAccessKey")
    // 【可选】如果使用临时AK/SK和SecurityToken访问OBS,同样建议您尽量避免使用硬编码,以降低信息泄露风险。您可以通过环境变量获取访问密钥AK/SK,也可以使用其他外部引入方式传入。
    // securityToken := os.Getenv("SecurityToken")
    // endpoint填写Bucket对应的Endpoint, 这里以中国-香港为例,其他地区请按实际情况填写。
    endPoint := "https://obs.ap-southeast-1.myhuaweicloud.com"
    // 创建obsClient实例
    // 如果使用临时AKSK和SecurityToken访问OBS,需要在创建实例时通过obs.WithSecurityToken方法指定securityToken值。
    obsClient, err := obs.New(ak, sk, endPoint/*, obs.WithSecurityToken(securityToken)*/)
    if err != nil {
        fmt.Printf("Create obsClient error, errMsg: %s", err.Error())
    }
    input := &obs.GetObjectInput{}
    // 指定存储桶名称
    input.Bucket = "examplebucket"
    // 指定下载对象,此处以 example/objectname 为例。
    input.Key = "example/objectname"
    // 指定服务端加密头信息,此处以 obs.SseCHeader为例
    key := os.Getenv("Key")
    digest := md5.New()
    digest.Write([]byte(key))
    bodyHash := digest.Sum(nil)
    input.SseHeader = obs.SseCHeader{
        Encryption: "AES256",
        Key:        base64.StdEncoding.EncodeToString([]byte(key)), // 32byteslongsecretkeymustprovided
        KeyMD5:     base64.StdEncoding.EncodeToString(bodyHash),
    }
    // 流式下载对象
    output, err := obsClient.GetObject(input)
    if err == nil {
        // output.Body 在使用完毕后必须关闭,否则会造成连接泄漏。
        defer output.Body.Close()
        fmt.Printf("Get object(%s) under the bucket(%s) successful!\n", input.Key, input.Bucket)
        fmt.Printf("StorageClass:%s, ETag:%s, ContentType:%s, ContentLength:%d, LastModified:%s\n",
            output.StorageClass, output.ETag, output.ContentType, output.ContentLength, output.LastModified)
        // 读取对象内容
        p := make([]byte, 1024)
        var readErr error
        var readCount int
        for {
            readCount, readErr = output.Body.Read(p)
            if readCount > 0 {
                fmt.Printf("%s", p[:readCount])
            }
            if readErr != nil {
                break
            }
        }
        return
    }
    fmt.Printf("List objects under the bucket(%s) fail!\n", input.Bucket)
    if obsError, ok := err.(obs.ObsError); ok {
        fmt.Println("An ObsError was found, which means your request sent to OBS was rejected with an error response.")
        fmt.Println(obsError.Error())
    } else {
        fmt.Println("An Exception was found, which means the client encountered an internal problem when attempting to communicate with OBS, for example, the client was unable to access the network.")
        fmt.Println(err)
    }
}

相关链接

  • 关于服务端加密的API说明,请参见服务端加密简介
  • 更多关于服务端加密的示例代码,请参见Github示例
  • 服务端加密接口返回的错误码含义、问题原因及处理措施可参考OBS错误码