最近更新时间:2024-05-31 11:51:21
无论是主账号还是IAM子用户都是可以长期正常使用的,对应的AK/SK发生泄露之后如果无法及时解除权限的话会很危险。如果众多的客户端需要直接与KS3交互,可以让客户端获取一个临时的、有一定的有效期的最小权限的凭证(即临时身份凭证),从而最大程度上保护用户数据安全。
考虑到如下的案例:
客户开发的App会分发给终端用户,终端用户的数据需要直接上传到KS3,如果将主账号或者IAM子用户的AK/SK嵌入到App都是非常危险的行为,那如何才能安全的授权给众多的App用户上传数据呢,以及如何保证多个用户之间存储的隔离。
类似这种需要临时访问的场景可以使用临时身份凭证来应对,其主要操作步骤为:
在当前的主账号下创建一个角色,指定角色授信的主账户,并且给角色通过用户策略(user policy)授予一个最小权限。
然后在授信主账号下创建一个子用户,并授权给子用户角色(让这个子用户扮演这个角色),子用户就可以通过STS服务获取临时AK/SK及token,去访问KS3了,为了提升安全性该token还有一定的过期时间。
原理图如下:
安全的STS服务,需要设置两个自定义策略:
子用户策略:保证子用户有扮演角色的权限
角色策略:保证角色对目标资源有对应权限
1. 进入KS3控制台,点击左侧导航栏最下方中的访问控制(或点击右上角账号名称下拉框里的访问控制),进入访问控制管理页面,点击左侧导航栏中权限管理→策略,进入策略管理页面,选择自定义策略→新建策略。
2. 在新建策略中,输入策略名,此处假设为"test-policy",然后选择 可视化配置→添加策略语句。
3. 侧边弹出添加策略语句弹窗,产品服务下拉框中选择临时身份验证,在操作中选择获取角色的一个临时安全令牌*,该权限表示可以扮演角色,点击确定按钮,之后点击左下方创建策略按钮,至此子用户策略创建完成。
4. 再次创建自定义策略,假设名称为“role-test-policy”,设置策略类型为 策略语法 ,可以通过模板来简化创建策略过程,选择复制系统模板,模板名称选择KS3ReadOnlyAccess,点击下一步。
也可以直接通过可视化配置来创建策略,产品服务选择对象存储,根据需求选择对应的操作权限即可。
如果需要列出某个bucket下所有文件的权限,需要同时设置查询bucket列表和查询bucket ACL的权限。
选择可视化配置时,可以对所有资源授予权限,也可以对特定资源授予权限(如某个bucket),填写特定资源信息方式参见文档:资源说明。
5. 编辑相应的权限,如下载文件、查看bucket列表等,编辑完成之后点击创建策略按钮,至此角色策略创建完成。
如下示例为对桶examplebucket及其内文件有get和ListBucket权限:
{
"Version":"2015-11-01",
"Statement": [
{
"Sid":"1",
"Effect":"Allow",
"Action":[
"ks3:ListBucket",
"ks3:GetObject"
],
"Resource":["krn:ksc:ks3:::examplebucket","krn:ksc:ks3:::examplebucket/*"]
}
]
}
有关用户策略的更多详情请参见文档:用户策略。
主账户是不能扮演角色的,需要受信主账户通过用户权限(user policy)把扮演角色的权限授权给IAM子用户。
1. 进入KS3控制台,点击左侧导航栏下方的访问控制(或点击右上角账号名称下拉框里的访问控制),点击左侧导航栏中的子用户 ,进入子用户管理界面。点击新建用户按钮(根据需求选择快速创建或者自定义创建),输入子用户登录账户等信息,此处假设为test-subuser,选中编程访问复选框为子用户创建AK和SK。
2. 创建成功后在子用户页面选中刚创建的子用户,点击右侧添加权限来为子用户授权。
3. 在选择权限的下拉框中选择自定义策略,选中在创建策略步骤中创建的test-policy策略,这样子用户就具有了扮演角色的权限,但是现在还没有角色,因此接下来要创建角色。
1. 进入KS3控制台,点击左侧导航栏下方的访问控制(或点击右上角账号名称下拉框里的访问控制),点击左侧导航栏下方的角色管理,进入角色管理界面。
2. 点击新建角色按钮,选择金山云账号。假设创建一个名为test-role的角色,设置载体信息为当前账号(也可以选择其他账号,载体信息即授信账号,比如你在账号1下创建角色授信给账号2,则账号2的子用户就可以扮演账号1下的角色)。新创建的角色是没有任何权限的,点击下一步来设置角色权限,设置结束后点击完成按钮。
3. 创建完角色之后,回到角色管理页面,点击刚刚创建的角色名,进入角色详情页。需要记录下角色的KRN字段。角色是没有任何权限的,点击关联策略,点击添加授权按钮,弹出添加权限弹窗。在策略下拉框中选择自定义策略,选择策略role-test-policy,点击确定按钮。这样角色test-role就具有了相应的权限。
至此该子用户仅具有了扮演角色的权限,但还没有关联具体的角色,因此还需要添加权限对应的资源,即角色ID。点击导航栏左侧策略页签,点击自定义策略,点击所创建的test-policy策略名称,在策略内容中的Resource字段值中填入角色的KRN。
1. 使用子用户test-subuser的AK/SK 去调用STS服务获取临时权限。详见文档获取角色的临时身份。
http://sts.cn-beijing-6.api.ksyun.com/?Action=AssumeRole
&Version=2019-11-01
&RoleSessionName=Bob
&RoleKrn=krn:ksc:iam::Account_ID:role/test-role
&AUTHPARAMS
返回的内容如下:
<AssumeRoleResponse>
<AssumeRoleResult>
<Credentials>
<SecretAccessKey>wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY</SecretAccessKey>
<Expiration>2017-07-15T23:28:33.359Z</Expiration>
<AccessKeyId>AKIAIOSFODNN7EXAMPLE</AccessKeyId>
<SecurityToken>V1xxxxxxxxxxxx</SecurityToken>
</Credentials>
<AssumedRoleUser>
<Krn>krn:ksc:sts::123456789012:assumed-role/demo/Bob</Krn>
<AssumedRoleId>ARO123EXAMPLE123:Bob</AssumedRoleId>
</AssumedRoleUser>
</AssumeRoleResult>
<ResponseMetadata>
<RequestId>c6104cbe-af31-11e0-8154-cbc7ccf896c7</RequestId>
</ResponseMetadata>
</AssumeRoleResponse>
2. 从返回的XML结果中找到临时权限:AccessKeyId、SecretAccessKey及SecurityToken,然后通过KS3 API或JAVA SDK去访问相应的资源。
GO示例:
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/KscSDK/ksc-sdk-go/ksc"
"github.com/KscSDK/ksc-sdk-go/ksc/utils"
"github.com/KscSDK/ksc-sdk-go/service/sts"
"github.com/ks3sdklib/aws-sdk-go/aws"
"github.com/ks3sdklib/aws-sdk-go/aws/credentials"
"github.com/ks3sdklib/aws-sdk-go/service/s3"
"os"
)
func main() {
ak := "<AccessKeyID>"
sk := "<AccessKeySecret>"
stsRegion := "cn-beijing-6"
assumeRole := assumeRoleRequest(ak, sk, stsRegion) //调用ksc-go-sdk的sts服务
var data Response
_ = json.Unmarshal(assumeRole, &data)
stsAk := data.AssumeRoleResult.Credentials.AccessKeyId // sts ak
stsSk := data.AssumeRoleResult.Credentials.SecretAccessKey // sts sk
stsToken := data.AssumeRoleResult.Credentials.SecurityToken // sts token
//create ks3 client with sts ak,sk,token
credentials := credentials.NewStaticCredentials(stsAk, stsSk, stsToken)
client := s3.New(&aws.Config{
Region: "BEIJING",
Credentials: credentials,
Endpoint: "ks3-cn-beijing.ksyuncs.com", //ks3地址
DisableSSL: true, //是否禁用https
LogLevel: 1, //是否开启日志,0为关闭日志,1为开启日志 n
S3ForcePathStyle: false, //是否强制使用path style方式访问
LogHTTPBody: true, //是否把HTTP请求body打入日志
Logger: os.Stdout, //打日志的位置
})
// example for uploading file
params := &s3.PutObjectInput{
Bucket: aws.String("BucketName"), // bucket名称
Key: aws.String("ObjectKey"), // object key
ACL: aws.String("public-read"), //权限,支持private(私有),public-read(公开读)
Body: bytes.NewReader([]byte("PAYLOAD")), //要上传的内容
ContentType: aws.String("application/ocet-stream"), //设置content-type
Metadata: map[string]*string{
//"Key": aws.String("MetadataValue"), // 设置用户元数据
// More values...
},
}
resp, err := client.PutObject(params)
if err != nil {
panic(err)
}
fmt.Println(resp)
//获取新的文件名
fmt.Println(*resp.NewFileName)
}
func assumeRoleRequest(ak string, sk string, region string) []byte { //调用ksc-go-sdk的sts服务
svc := sts.SdkNew(ksc.NewClient(ak, sk /*,true*/), &ksc.Config{Region: ®ion}, &utils.UrlInfo{ //debug模式的话,打开true开关
UseSSL: true,
UseInternal: false,
})
var resp *map[string]interface{}
var err error
//set your assumeRole here
assumeRoleInput := make(map[string]interface{})
assumeRoleInput["RoleKrn"] = "<YourRoleKrn>"
assumeRoleInput["RoleSessionName"] = "Bob"
assumeRoleInput["DurationSeconds"] = "3600"
//assumeRole["Policy"] = ""
resp, err = svc.AssumeRole(&assumeRoleInput)
if err != nil {
fmt.Println("error:", err.Error())
return nil
}
var str []byte
if resp != nil {
str, _ = json.Marshal(&resp)
//fmt.Printf("%+v\n", string(str))
}
return str
}
type (
Response struct {
AssumeRoleResult struct {
Credentials struct {
SecretAccessKey string `json:"SecretAccessKey"`
Expiration string `json:"Expiration"`
AccessKeyId string `json:"AccessKeyId"`
SecurityToken string `json:"SecurityToken"`
} `json:"Credentials"`
AssumedRoleUser struct {
Krn string `json:"Krn"`
AssumedRoleId string `json:"AssumedRoleId"`
} `json:"AssumedRoleUser"`
} `json:AssumeRoleResult`
RequestId string `json:"RequestId"`
}
)
纯净模式