You need to enable JavaScript to run this app.
文档中心
对象存储

对象存储

复制全文
下载 pdf
临时访问授权
使用 STS 临时 AK/SK+Token 访问火山引擎 TOS
复制全文
下载 pdf
使用 STS 临时 AK/SK+Token 访问火山引擎 TOS
您可以通过 STS 服务,创建一个临时访问凭证,限定用户访问 TOS 资源的时间,过期即失效。本文介绍使用 STS 临时 AK/SK 和 Token 访问火山引擎 TOS 的流程及步骤。​
示例介绍​
您可以参考以下代码示例,快速了解使用 STS 临时 AK/SK 和 Token 访问火山引擎 TOS 的流程及步骤。​
​
return (<iframe width="900" height="450" src="https://lf3-static.bytednsdoc.com/obj/eden-cn/321eh7nuhmpsht/story6/使用 STS 服务访问火山引擎 TOS 2/story.html" allowfullscreen="true"></iframe>); ​
​
使用场景​
在移动 APP 或 PC 客户端直传文件到对象存储的场景中,出于安全考虑,不建议将永久 AK/SK 放到客户端代码中,此时可以由应用服务端通过 STS 机制获取临时 AK/SK,然后再将临时密钥下发给客户端。该方案有以下优点:​
  • 临时密钥具有一定的时效性,过期即无效,保证数据安全。​
  • 您可以限制临时密钥的权限,降低密钥泄露(比如被破解、劫持)的风险。​
使用流程​
​Image​​
操作步骤​
操作流程如下。​
​Image​​
步骤一:创建 IAM 用户并授予 STSAssumeRoleAccess 权限​
本章节以创建 tos_user 用户为例,说明创建 IAM 用户及授予权限的步骤。​
  1. 登录 IAM 控制台。​
  1. 在左侧导航栏中,单击用户管理 > 用户。​
  1. 在用户页面,单击新建用户。​
  1. 在创建用户页面,选择您需要创建用户的方式。​
说明​
本文以通过用户名创建为例,其他创建方式详情,请参见创建用户。​
  1. 在基本信息设置向导页面,设置用户名信息,选中编程访问,单击下一步。​
  1. 在权限设置向导页面,选中 STSAssumeRoleAccess 策略,单击下一步。​
说明​
该策略为系统预置策略,您可以在面板上方搜索该策略并关联。​
  1. 在审阅向导页面,确认用户名信息,单击提交。​
步骤二:创建 IAM 角色​
本章节以创建 tos_role 角色为例,说明创建 IAM 角色的步骤。​
  1. 在左侧导航栏中,单击 角色管理。​
  1. 在角色管理页面,单击新建角色。​
  1. 在新建角色面板,选择信任身份类型为账号,身份为当前账号,然后单击下一步。​
  1. 在配置角色信息面板,设置角色名称等信息,单击下一步。​
  1. 在添加权限面板,单击跳过,完成角色的创建。​
步骤三:指定 TrustPolicy 的用户​
本章节以将 TrustPolicy 的用户修改为 tos_user 为例,说明指定 TrustPolicy 的用户的步骤。​
  1. 在角色管理页面,单击步骤二创建的角色名称。​
  1. 在角色详情页面,单击信任关系页签。​
  1. 在信任关系页签,单击编辑信任策略。​
  1. 将 root 用户修改为 user/步骤一中创建的用户名称,单击保存。​
  • TrustPolicy 示例如下。​
  • ​
    {​
    "Statement": [​
    {​
    "Effect": "Allow",​
    "Action": [​
    "sts:AssumeRole"​
    ],​
    "Principal": {​
    "IAM": [​
    "trn:iam::2100*****4:user/tos_user"​
    ]​
    }​
    }​
    ]​
    }​
    ​
说明​
信任策略(TrustPolicy)的格式说明如下:​
  • 默认信任策略为 "trn:iam::2100*****4:root",需要将 root 修改为创建的 IAM 用户,如trn:iam::2100*****4:user/tos_user 。​
  • trn 用户格式为:trn:iam::{accountID}:user/{userName},其中 {accountID} 为角色所属的账号 ID,{userName} 为用户名。​
步骤四:创建 IAM 策略​
根据您的业务场景,创建您需要授权的策略。​
  1. 在左侧导航栏,单击权限策略。​
  1. 在权限策略页面,单击新建自定义策略。​
  1. 在新建自定义策略页面,设置策略名称,单击 JSON编辑器页签,设置策略内容。​
  • 本文以授予存储桶 tos-sts 上传及下载对象的权限为例,示例策略如下。​
  • ​
    {​
    "Statement": [​
    {​
    "Effect": "Allow",​
    "Action": [​
    "tos:PutObject",​
    "tos:GetObject"​
    ],​
    "Resource": [​
    "trn:tos:::tos-sts/*"​
    ]​
    }​
    ]​
    }​
    ​
  • 参数说明如下。​
  • ​
    参数​
    是否必选​
    说明​
    代码块​
    Effect​
    是​
    指示策略是允许还是拒绝访问,取值范围为:​
    • Allow:允许​
    • Deny:拒绝​
    ​
    "Effect": "Allow"​
    ​
    Action​
    是​
    指定策略允许或拒绝的操作列表,TOS 支持的操作列表请参见 IAM 策略支持动作。​
    • 以字符串形式表示,不区分大小写,格式为 "Action":["tos:Action名称"]。​
    • 支持通配符*,表示该资源能进行的所有操作。​
    • 例如:"Action":["tos:List*"] 表示该资源能进行的所有列举动作。​
    ​
    "Action": ["tos:List*"]​
    ​
    Resource​
    否​
    设置该策略指定操作适用的资源列表,如果不填则表示所有资源均不匹配。​
    • 以字符串形式表示,不区分大小写,格式为 "Resource": ["trn:tos:::{BucketName}/{ObjectName}"]​
    • 如果您只需要对桶执行相应操作,则资源只设置桶名,例如"Resource": ["trn:tos:::{BucketName}"]。​
    • 如果您只需要对桶中对象执行相应操作,则需要设置桶内资源,例如"Resource": ["trn:tos:::{BucketName}/{ObjectName}"]。​
    • 支持通配符*,表示所有资源。​
    ​
    "Resource": [​
    "trn:tos:::bucket/*",​
    "trn:tos:::bucket"​
    ]​
    ​
    ​
  1. 完成设置后,单击提交。​
步骤五:为角色授予相应权限​
创建策略后,您需要为步骤二创建的角色授予策略权限。​
  1. 在权限策略页面,单击新创建的策略名称。​
  1. 在策略详情页面,单击添加权限。​
  1. 在添加授权页面,设置授权身份为角色,选择步骤二中创建的角色,然后单击提交。​
步骤六:请求 AssumeRole 接口获取临时访问凭证​
注意​
  • 临时密钥的实际权限是角色具有的权限和 IAM 策略的交集。​
  • 如果不指定 IAM 策略,则临时密钥拥有指定角色的预关联策略的权限。​
  • 如果角色没有预关联策略,即使指定了 IAM 策略,实际权限也为无。​
火山引擎 API 请求的签名算法,和 AWS V4 基本一致(部分 Header 不同),详情请参见签名机制。您可以调用 STS 服务接口 AssumeRole 来获取临时访问凭证。您可以通过以下 SDK 调用该接口:​
完整的请求参数如下。​
​
GET /?RoleTrn=trn:iam::2100****4:role/tos_role&RoleSessionName=tos_role_session&DurationSeconds=3600&Action=AssumeRole&Version=2018-01-01 HTTP/1.1​
Accept: application/json​
Content-Type: application/x-www-form-urlencoded​
Host: open.volcengineapi.com​
X-Date: 发请求时指定​
​
Authorization: 待签算(此处用IAM用户tos_user的密钥)​
​
说明​
调用 AssumeRole 获取临时访问凭证时,您可以通过 DurationSeconds 参数来设置临时访问凭证的有效时长,详细介绍,请参见AssumeRole。​
您也可以通过如下代码计算签名并发送请求获取临时访问凭证,如下以 Python 和 Go 为例。​
​
Go
Python
​
​
package main​
​
import (​
"crypto/hmac"​
"crypto/sha256"​
"encoding/hex"​
"fmt"​
"io/ioutil"​
"net/http"​
"net/url"​
"time"​
)​
​
func sign(key []byte, value string) []byte {​
h := hmac.New(sha256.New, key)​
h.Write([]byte(value))​
return h.Sum(nil)​
}​
​
func getSigningKey(key []byte, dateStamp string, regionName, serviceName string) []byte {​
kDate := sign(key, dateStamp)​
kRegion := sign(kDate, regionName)​
kService := sign(kRegion, serviceName)​
kSigning := sign(kService, "request")​
return kSigning​
}​
​
type SignHeaderInput struct {​
method string​
service string​
host string​
region string​
params url.Values​
accessKey string​
secretKey string​
}​
​
const (​
iso8601Layout = "20060102T150405Z"​
yyMMdd = "20060102"​
emptySHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"​
)​
​
func getSigningHeader(input SignHeaderInput) map[string]string {​
contentType := "application/x-www-form-urlencoded"​
accept := "application/json"​
t := time.Now().UTC()​
xdate := t.Format(iso8601Layout)​
datestamp := t.Format(yyMMdd)​
// ************* 1: 拼接规范请求串*************​
canonicalUri := "/"​
canonicalQueryString := input.params.Encode()​
canonicalHeaders := "content-type:" + contentType + "\\n" + "host:" + input.host + "\\n" + "x-date:" + xdate + "\\n"​
signedHeaders := "content-type;host;x-date"​
canonicalRequest := input.method + "\\n" + canonicalUri + "\\n" + canonicalQueryString + "\\n" + canonicalHeaders + "\\n" + signedHeaders + "\\n" + emptySHA256​
// ************* 2:拼接待签名字符串*************​
algorithm := "HMAC-SHA256"​
credentialScope := datestamp + "/" + input.region + "/" + input.service + "/" + "request"​
cr256 := sha256.Sum256([]byte(canonicalRequest))​
stringToSign := algorithm + "\\n" + xdate + "\\n" + credentialScope + "\\n" + hex.EncodeToString(cr256[:])​
​
// ************* 3:计算签名 *************​
signingKey := getSigningKey([]byte(input.secretKey), datestamp, input.region, input.service)​
​
signature := sign(signingKey, stringToSign)​
// *************4:添加签名到请求header中 * ************​
authorizationHeader := algorithm + " " + "Credential=" + input.accessKey + "/" + credentialScope + ", " + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + hex.EncodeToString(signature)​
​
headers := map[string]string{"Accept": accept, "Content-Type": contentType, "X-Date": xdate, "Authorization": authorizationHeader}​
return headers​
}​
​
func main() {​
service := "sts"​
host := "open.volcengineapi.com"​
endpoint := "https://open.volcengineapi.com"​
region := "{your region ID}"​
accessKey := "{your access key}"​
secretKey := "{your secret key}"​
queryParams := url.Values{"Action": []string{"AssumeRole"},​
"RoleSessionName": []string{"{your session name}"},​
"RoleTrn": []string{"trn:iam::{your account ID}:role/{your role name}"},​
"Version": []string{"2018-01-01"},​
​
}​
header := getSigningHeader(SignHeaderInput{​
method: http.MethodGet,​
service: service,​
host: host,​
region: region,​
params: queryParams,​
accessKey: accessKey,​
secretKey: secretKey,​
})​
req, err := http.NewRequest(http.MethodGet, endpoint+"?"+queryParams.Encode(), nil)​
if err != nil {​
panic(err)​
}​
for key, value := range header {​
req.Header.Set(key, value)​
}​
resp, err := http.DefaultClient.Do(req)​
if err != nil {​
panic(err)​
}​
defer resp.Body.Close()​
body, err := ioutil.ReadAll(resp.Body)​
if err != nil {​
panic(err)​
}​
fmt.Println(fmt.Sprintf("status code:%d, body: %s", resp.Status, string(body)))​
}​
​
​
参数说明如下。​
​
参数​
示例值​
说明​
service​
sts​
请求的服务,默认为 sts。​
host​
open.volcengineapi.com​
请求的 host 地址,默认为 open.volcengineapi.com。​
endpoint​
https://open.volcengineapi.com​
请求的 Endpoint 地址,默认为https://open.volcengineapi.com。​
说明​
如果您想生成访问内网的临时访问凭证,您需要设置 Endpoint 为内网 Endpoint,例如 https://tos-cn-beijing.ivolces.com。​
region​
cn-beijing​
请求的地域信息。 TOS 支持的地域信息,请参见访问域名 Endpoint。​
accessKey​
AKLTYTMyNTRlMTY5NmM0NDdiMjg3MmRlMzFl****NjU​
步骤一创建的用户的 AK 信息。​
secretKey​
TWpoaU9HRmlPV1ZrTURJNExxxxxx4WkRoaF****​
步骤一创建的用户的 SK 信息。查看 AK/SK 信息的具体步骤,请参见查看 AK/SK 信息。​
action​
AssumeRole​
请求的 API 名称,默认为 AssumeRole。​
RoleSessionName​
tos_role_session​
请求的临时名称,可根据需要设置。​
RoleTrn​
trn:iam::2100xxxx4:role/tos_role​
步骤二创建的角色 trn,格式为:trn:iam::{accountID}:role/{roleName},说明如下:​
  • {accountID}:角色所属的账号 ID。​
  • {roleName}:角色名。​
例如本文中创建的角色为 tos_role,则 trn 为 trn:iam::2100xxxx4:role/tos_role。​
Version​
2018-01-01​
请求的版本信息,默认为 2018-01-01。​
​
成功响应示例如下。​
​
Response code: 200​
{​
"ResponseMetadata": {​
"RequestId": "20220626182126010212063166****",​
"Action": "AssumeRole",​
"Version": "2018-01-01",​
"Service": "sts"​
},​
"Result": {​
"Credentials": {​
"CurrentTime": "2022-06-26T18:21:27+08:00",​
"ExpiredTime": "2022-06-26T19:21:27+08:00",​
"AccessKeyId": "AKTPYmI1ZGQwMDA0NjlhNGFkMzhjNzM0N2Q0OTQ3ZTV****",​
"SecretAccessKey": "T1dJM01UUXpOak0wTVdWak5EUmtOR0poWldJNU1HWmxaV1V5TkdReVl6****",​
"SessionToken": "STSeyJBY2NvdW50SWQiOjIxMDAwMDUyMjQsIklkZW50aXR5VHlwZSI6NCwiSWRlbnRpdHlJZCI6MTE3MjI5NiwiQ2hhbm5lbCI6IlVzZXIiLCJBY2Nlc3NLZXlJZCI6IkFLVFBZbUkxWkdRd01EQTBOamxoTkdGa016aGpOek0wTjJRME9UUTNaVFZqTXpFIiwiU2lnbmVkU2VjcmV0QWNjZXNzS2V5IjoidVIvMmhvTE9Yd1lwNlR6QkxUOVZQVDQrbVVaQjMzMEJoQ0NPWk9JMVBRWkpZMFZPcGRPendybFNVYytGNlorRVR1ZDJsMlg0UkUyMWJEYnZ1QWl6S3c9PSIsIkV4cGlyZWRUaW1lIjoxNjU2MjQyNDg3LCJQb2xpY3lTdHJpbmciOiIiLCJTaWduYXR1cmUiOiIzOTlmMjZkNjIzZWUxMmU2NWViMDIwY2RlOWZkMDZkZDc4MTBkNjhkYjQyYzBjZTE3ZDA5MjY4NWYwMDQyYThlIiwiU2Vzc2lvbk5hbWUiOiJ0b3Nfcm9sZV9z************"​
},​
"AssumedRoleUser": {​
"Trn": "trn:sts::21000****4:assumed-role/tos_role/tos_role_session",​
"AssumedRoleId": "117****:tos_role_session"​
}​
}​
}​
​
步骤七:使用临时密钥访问 TOS​
获取临时 AK/SK+Token 之后,您可以使用 TOS SDK 或者 AWS S3 SDK 访问 TOS 了,本文以 TOS Go SDK 为例,介绍示例代码。​
说明​
  • 使用 SDK 配置 STS 的示例代码,请参见以下文档:​
​
package main​
​
import (​
"context"​
"fmt"​
"strings"​
​
"github.com/volcengine/ve-tos-golang-sdk/v2/tos"​
)​
​
func main() {​
// 使用上一步中获取的临时AK/SK+Token​
ak := "AKTPYmI1ZGQwMDA0NjlhNGFkMzhjNzM0N2Q0OTQ3ZTV****"​
sk := "T1dJM01UUXpOak0wTVdWak5EUmtOR0poWldJNU1HWmxaV1V5TkdReVl6****"​
stToken := "STSeyJBY2NvdW50SWQiOjIxMDAwMDUyMjQsIklkZW50aXR5VHlwZSI6NCwiSWRlbnRpdHlJZCI6MTE3MjI5NiwiQ2hhbm5lbCI6IlVzZXIiLCJBY2Nlc3NLZXlJZCI6IkFLVFBZbUkxWkdRd01EQTBOamxoTkdGa016aGpOek0wTjJRME9UUTNaVFZqTXpFIiwiU2lnbmVkU2VjcmV0QWNjZXNzS2V5IjoidVIvMmhvTE9Yd1lwNlR6QkxUOVZQVDQrbVVaQjMzMEJoQ0NPWk9JMVBRWkpZMFZPcGRPendybFNVYytGNlorRVR1ZDJsMlg0UkUyMWJEYnZ1QWl6S3c9PSIsIkV4cGlyZWRUaW1lIjoxNjU2MjQyNDg3LCJQb2xpY3lTdHJpbmciOiIiLCJTaWduYXR1cmUiOiIzOTlmMjZkNjIzZWUxMmU2NWViMDIwY2RlOWZkMDZkZDc4MTBkNjhkYjQyYzBjZTE3ZDA5MjY4NWYwMDQyYThlIiwiU2Vzc2lvbk5hbWUiOiJ0b3Nfcm9sZV9z************"​
// 使用tos Endpoint 请参考https://www.volcengine.com/docs/6349/107356​
endpoint := "https://tos-cn-beijing.volces.com"​
region := "cn-beijing"​
// 创建TosClient实例​
cred := tos.NewStaticCredentials(ak, sk)​
cred.WithSecurityToken(stToken)​
client, err := tos.NewClientV2(endpoint, tos.WithRegion(region), tos.WithCredentials(cred))​
if err != nil {​
panic(err)​
}​
res, err := client.PutObjectV2(context.Background(), &tos.PutObjectV2Input{PutObjectBasicInput: tos.PutObjectBasicInput{Bucket: "tos-sts", Key: "sts.txt"}, Content: strings.NewReader("hello STS")})​
​
if err != nil {​
panic(err)​
}​
fmt.Println(res)​
}​
​
​
最近更新时间:2026.08.10 17:35:57
这个页面对您有帮助吗?
有用
有用
无用
无用