當您通過阿里雲SDK調用OpenAPI進行資源操作時,必須正確配置憑證資訊。阿里雲的Credentials工具提供了一套強大的功能,使您能夠輕鬆地擷取和管理這些訪問憑證。無論是利用預設憑證,AccessKey(AK),還是Security Token Service(STS)令牌等,Credentials工具都能為您提供相應支援。此外,本文檔將詳細闡述如何根據優先順序使用預設憑證。您將深入理解如何在阿里雲SDK中配置和維護憑證,從而確保您對雲資源的操作既有效率又具有高度安全性。
背景資訊
憑據是指使用者證明其身份的一組資訊。使用者在系統中進行登入時,需要提供正確的憑據才能驗證身份。常見的憑據類型有:
阿里雲主帳號和RAM使用者的永久憑據 AccessKey(簡稱AK)。一組由AccessKey ID和AccessKey Secret組成的金鑰組。
阿里雲RAM角色的STS臨時訪問Token,簡稱STS Token。它是可以自訂時效和存取權限的臨時身份憑據,詳情請參見臨時訪問憑證STS概念。
Bearer Token。它是一種身分識別驗證和授權的令牌類型。
前提條件
使用Credentials工具要求Go版本 >= 1.10.x。
使用V2.0版本的阿里雲SDK。
自建網關類產品的自研SDK無法使用。
安裝Credentials工具
使用
go get
下載安裝。
$ go get -u github.com/aliyun/credentials-go
如果您使用
dep
來管理的依賴包,您可以使用以下命令。
$ dep ensure -add github.com/aliyun/credentials-go
建議使用最新發行的Credentials工具版本。
初始化憑據用戶端
Credentials工具支援多種方式初始化憑據用戶端,您可根據實際情況選擇合適的方式進行憑據用戶端初始化。
方式一:使用預設憑據鏈
當您在初始化憑據用戶端不傳入任何參數時,Credentials會使用預設憑據鏈方式初始化用戶端。預設憑據的讀取邏輯請參見預設憑據鏈。
import (
"fmt"
"github.com/aliyun/credentials-go/credentials"
)
func main(){
// 不指定參數
config := new(credentials.Config)
credential, err := credentials.NewCredential(config)
}
介面調用方法
方式二:使用AK
阿里雲帳號、RAM使用者可產生調用OpenAPI的金鑰組AK。如何擷取AK請參見文檔建立AccessKey。您可使用AK初始化憑據用戶端。
阿里雲主帳號擁有資源的全部許可權,AK一旦泄露,會給系統帶來巨大風險,不建議使用。
推薦使用最小化授權的RAM使用者的AK。
import (
"fmt"
"os"
"github.com/aliyun/credentials-go/credentials"
)
func main(){
config := new(credentials.Config).
SetType("access_key").
SetAccessKeyId(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")).
SetAccessKeySecret(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"))
akCredential, err := credentials.NewCredential(config)
if err != nil {
return
}
accessKeyId, err := akCredential.GetAccessKeyId()
accessSecret, err := akCredential.GetAccessKeySecret()
credentialType := akCredential.GetType()
fmt.Println(accessKeyId, accessSecret, credentialType)
}
介面調用方法
方式三:使用STS Token
以一個RAM使用者的身份調用STS服務的AssumeRole介面,設定Token的最大到期時間,即可換取到臨時憑據STS Token。以下樣本示範如何使用STS Token初始化憑據用戶端(不包含如何擷取到STS Token的過程)。
{
"RequestId": "EA7A3526-F7DB-54A5-8300-9B742CFAA5EA",
"AssumedRoleUser": {
"Arn": "acs:ram::125499367423****:role/STStokenTestRole/STSsessionName",
"AssumedRoleId": "35219123109646****:STSsessionName"
},
"Credentials": {
"SecurityToken": "exampleToken",
"AccessKeyId": "STS.exampleAccessKeyID",
"AccessKeySecret": "exampleAccessKeySecret",
"Expiration": "2023-03-26T05:26:06Z"
}
}
import (
"fmt"
"os"
"github.com/aliyun/credentials-go/credentials"
)
func main() {
config := new(credentials.Config).
SetType("sts").
// <ALIBABA_CLOUD_ACCESS_KEY_ID>需替換為返回資料中擷取的臨時AccessKeyId。
SetAccessKeyId("<ALIBABA_CLOUD_ACCESS_KEY_ID>").
// <ALIBABA_CLOUD_ACCESS_KEY_SECRET>需替換為返回資料中擷取的臨時AccessKeySecret。
SetAccessKeySecret("<ALIBABA_CLOUD_ACCESS_KEY_SECRET>").
// <ALIBABA_CLOUD_SECURITY_TOKEN>需替換為返回資料中擷取的臨時SecurityToken。
SetSecurityToken("<ALIBABA_CLOUD_SECURITY_TOKEN>")
stsCredential, err := credentials.NewCredential(config)
if err != nil {
return
}
accessKeyId, err := stsCredential.GetAccessKeyId()
accessSecret, err := stsCredential.GetAccessKeySecret()
securityToken, err := stsCredential.GetSecurityToken()
credentialType := stsCredential.GetType()
fmt.Println(accessKeyId, accessSecret, securityToken, credentialType)
}
介面調用方法
方式四:使用AK及RamRoleArn
該方式底層實現是STS Token。通過指定RAM角色的ARN(Alibabacloud Resource Name),Credentials工具可以協助開發人員前往STS換取STS Token。您也可以通過為SetPolicy
賦值來限制RAM角色到一個更小的許可權集合。
import (
"fmt"
"os"
"github.com/aliyun/credentials-go/credentials"
)
func main(){
config := new(credentials.Config).
SetType("ram_role_arn").
SetAccessKeyId(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")).
SetAccessKeySecret(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")).
// 要扮演的RAM角色ARN,樣本值:acs:ram::123456789012****:role/adminrole
SetRoleArn("<RoleArn>").
// 角色會話名稱
SetRoleSessionName("<RoleSessionName>").
// 設定更小的權限原則,非必填。樣本值:{"Statement": [{"Action": ["*"],"Effect": "Allow","Resource": ["*"]}],"Version":"1"}
SetPolicy("<Policy>").
SetRoleSessionExpiration(3600)
arnCredential, err := credentials.NewCredential(config)
if err != nil {
return
}
accessKeyId, err := arnCredential.GetAccessKeyId()
accessSecret, err := arnCredential.GetAccessKeySecret()
securityToken, err := arnCredential.GetSecurityToken()
credentialType := arnCredential.GetType()
fmt.Println(accessKeyId, accessSecret, securityToken, credentialType)
}
介面調用方法
方式五:使用ECS執行個體RAM角色和中繼資料普通模式
該方式底層實現是STS Token。Credentials工具會自動擷取ECS執行個體綁定的RAM角色,調用ECS的中繼資料服務(Meta Data Server)換取STS Token,完成憑據用戶端初始化。ECI執行個體,Container Service for Kubernetes的Worker節點均支援綁定執行個體RAM角色。
import (
"fmt"
"github.com/aliyun/credentials-go/credentials"
)
func main(){
config := new(credentials.Config).
SetType("ecs_ram_role").
// 選填,該ECS角色的角色名稱,不填會自動擷取,但是建議加上以減少請求次數
SetRoleName("<RoleName>")
ecsCredential, err := credentials.NewCredential(config)
if err != nil {
return
}
accessKeyId, err := ecsCredential.GetAccessKeyId()
accessSecret, err := ecsCredential.GetAccessKeySecret()
securityToken, err := ecsCredential.GetSecurityToken()
credentialType := ecsCredential.GetType()
fmt.Println(accessKeyId, accessSecret, securityToken, credentialType)
}
介面調用方法
方式六:使用ECS執行個體RAM角色和中繼資料加固模式
什麼是加固模式,請參見加固模式的介紹。通過採用ECS執行個體的中繼資料加固策略來擷取RAM角色的初始化憑據。相較於普通模式,此方式採納了一種更為嚴謹的安全邏輯:首先在ECS執行個體內部自動產生一個具有時效限制的token,利用此token作為憑據,向中繼資料服務(Metadata Server)請求獲得STS(Security Token Service)臨時憑證。這一系列操作構成了憑據用戶端的安全初始化流程。
加固模式的核心優勢在於,ECS執行個體內部產生的token不僅具備動態性,還嚴格限制了有效時間,大大降低了外部攻擊者通過預測或偽造token來非法訪問中繼資料服務的可能性,從而有效抵禦了伺服器端請求偽造(SSRF, Server-Side Request Forgery)等多種網路安全隱患。總之,採用ECS執行個體中繼資料加固模式,不僅加強了身分識別驗證的嚴密性,還顯著提高了整體系統的安全性,為雲上資源的訪問與管理增設了一道堅固的防線。
import (
"fmt"
"github.com/aliyun/credentials-go/credentials"
)
func main() {
config := new(credentials.Config).
// Which type of credential you want
SetType("ecs_ram_role").
// `roleName` is optional. It will be retrieved automatically if not set. It is highly recommended to set it up to reduce requests
SetRoleName("<RoleName>").
// `EnableIMDSv2` is optional and is recommended to be turned on. It can be replaced by setting environment variable: ALIBABA_CLOUD_ECS_IMDSV2_ENABLE
SetEnableIMDSv2(true)
ecsCredential, err := credentials.NewCredential(config)
if err != nil {
return
}
accessKeyId, err := ecsCredential.GetAccessKeyId()
accessSecret, err := ecsCredential.GetAccessKeySecret()
securityToken, err := ecsCredential.GetSecurityToken()
credentialType := ecsCredential.GetType()
fmt.Println(accessKeyId, accessSecret, securityToken, credentialType)
}
enable_imds_v2
的預設值為false
,表示通過ECS執行個體中繼資料普通模式擷取RAM角色初始化憑據用戶端。通過ECS執行個體中繼資料加固模式擷取RAM角色初始化憑據用戶端時,
enable_imds_v2
的值為true
。
介面調用方法
本樣本以調用Elastic Compute Service的DescribeRegions介面為例,因此需先安裝。
package main
import (
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
ecs20140526 "github.com/alibabacloud-go/ecs-20140526/v4/client"
util "github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
credentials "github.com/aliyun/credentials-go/credentials"
)
func _main(args []*string) {
// 使用EcsRamRole初始化Credentials Client。
credentialsConfig := new(credentials.Config).
// 憑證類型。
SetType("ecs_ram_role").
// 選填,該ECS角色的角色名稱,不填會自動擷取,但是建議加上以減少請求次數
SetRoleName("<RoleName>").
// 是否開啟ECS IMDSv2
SetEnableIMDSv2(true)
credentialClient, _err := credentials.NewCredential(credentialsConfig)
if _err != nil {
panic(_err)
}
ecsConfig := &openapi.Config{}
// 配置雲產品服務接入地址(endpoint)。
ecsConfig.Endpoint = tea.String("ecs.cn-beijing.aliyuncs.com")
// 使用Credentials配置憑證。
ecsConfig.Credential = credentialClient
// 初始化ECS Client。
ecsClient, _err := ecs20140526.NewClient(ecsConfig)
// 初始化DescribeRegions請求。
describeInstancesRequest := &ecs20140526.DescribeRegionsRequest{}
// 初始化運行時配置。
runtime := &util.RuntimeOptions{}
// 調用DescribeRegions介面並獲得響應。
response, _err := ecsClient.DescribeRegionsWithOptions(describeInstancesRequest, runtime)
if _err != nil {
panic(_err)
}
panic(response.Body.String())
}
方式七:使用OIDCRoleArn
在Container Service for Kubernetes中設定了Worker節點RAM角色後,對應節點內的Pod中的應用也就可以像ECS上部署的應用一樣,通過中繼資料服務(Meta Data Server)擷取關聯角色的STS Token。但如果容器叢集上部署的是不可信的應用(比如部署您的客戶提交的應用,代碼也沒有對您開放),您可能並不希望它們能通過中繼資料服務擷取Worker節點關聯執行個體RAM角色的STS Token。為了避免影響雲上資源的安全,同時又能讓這些不可信的應用安全地擷取所需的 STS Token,實現應用層級的許可權最小化,您可以使用RRSA(RAM Roles for Service Account)功能。阿里雲容器叢集會為不同的應用Pod建立和掛載相應的服務賬戶OIDC Token檔案,並將相關配置資訊注入到環境變數中,Credentials工具通過擷取環境變數的配置資訊,調用STS服務的AssumeRoleWithOIDC - OIDC角色SSO時擷取扮演角色的臨時身份憑證介面換取綁定角色的STS Token。詳情請參見通過RRSA配置ServiceAccount的RAM許可權實現Pod許可權隔離。
注入的環境變數如下:
ALIBABA_CLOUD_ROLE_ARN:RAM角色名稱ARN;
ALIBABA_CLOUD_OIDC_PROVIDER_ARN:OIDC供應商ARN;
ALIBABA_CLOUD_OIDC_TOKEN_FILE:OIDC Token檔案路徑;
package main
import (
"fmt"
"net/http"
"os"
"github.com/aliyun/credentials-go/credentials"
)
func main() {
config := new(credentials.Config).
SetType("oidc_role_arn").
SetOIDCProviderArn(os.Getenv("ALIBABA_CLOUD_OIDC_PROVIDER_ARN")).
SetOIDCTokenFilePath(os.Getenv("ALIBABA_CLOUD_OIDC_TOKEN_FILE")).
// 角色會話名稱
SetRoleSessionName("<RoleSessionName>").
// 設定更小的權限原則,非必填。樣本值:{"Statement": [{"Action": ["*"],"Effect": "Allow","Resource": ["*"]}],"Version":"1"}
SetPolicy("<Policy>").
SetRoleArn("ALIBABA_CLOUD_ROLE_ARN").
// 設定session到期時間
SetSessionExpiration(3600)
oidcCredential, err := credentials.NewCredential(config)
if err != nil {
return
}
accessKeyId, err := oidcCredential.GetAccessKeyId()
accessKeySecret, err := oidcCredential.GetAccessKeySecret()
token, err := oidcCredential.GetSecurityToken()
fmt.Println(accessKeyId, accessKeySecret, token)
}
介面調用方法
方式八:使用Bearer Token
目前只有Cloud Call CenterCCC這款產品支援Bearer Token的憑據初始化方式。
import (
"fmt"
"github.com/aliyun/credentials-go/credentials"
)
func main(){
config := new(credentials.Config).
SetType("bearer").
// 填入您的Bearer Token
SetBearerToken("<BearerToken>")
bearerCredential, err := credentials.NewCredential(config)
if err != nil {
return
}
bearerToken := bearerCredential.GetBearerToken()
credentialType := bearerCredential.GetType()
fmt.Println(bearerToken, credentialType)
}
介面調用方法
預設憑據鏈
當您的程式開發環境和生產環境採用不同的憑據類型,常見做法是在代碼中擷取當前環境資訊,編寫擷取不同憑據的分支代碼。藉助Credentials工具的預設憑據鏈,您可以用同一套代碼,通過程式之外的配置來控制不同環境下的憑據擷取方式。當您在不傳入參數的情況下,直接使用NewCredential()
初始化憑據用戶端時,阿里雲SDK將會嘗試按照如下順序尋找相關憑據資訊。
1. 使用環境變數
Credentials工具優先在環境變數中擷取憑據資訊。如果系統內容變數ALIBABA_CLOUD_ACCESS_KEY_ID(密鑰Key) 和 ALIBABA_CLOUD_ACCESS_KEY_SECRET(密鑰Value) 不為空白,Credentials工具會優先使用它們作為預設憑據。
2. 使用OIDC RAM角色
若不存在優先順序更高的憑據資訊,Credentials工具會在環境變數中擷取如下內容:
ALIBABA_CLOUD_ROLE_ARN:RAM角色名稱ARN;
ALIBABA_CLOUD_OIDC_PROVIDER_ARN:OIDC供應商ARN;
ALIBABA_CLOUD_OIDC_TOKEN_FILE:OIDC Token檔案路徑;
若以上三個環境變數都有設定內容,Credentials工具將會使用變數內容調用STS服務的AssumeRoleWithOIDC - OIDC角色SSO時擷取扮演角色的臨時身份憑證介面換取STS Token作為預設憑據。
3. 使用設定檔
若不存在優先順序更高的憑據資訊,Credentials工具優先在如下位置尋找檔案是否存在。
Linux系統:~/.alibabacloud/credentials
Windows系統:C:\Users\USER_NAME\.alibabacloud\credentials
您也可通過指定 ALIBABA_CLOUD_CREDENTIALS_FILE 指定設定檔路徑。如果檔案存在,程式將會使用設定檔中default 指定的憑據資訊初始化憑據用戶端,當然您也可以通過設定 ALIBABA_CLOUD_PROFILE 環境變數修改預設讀取的憑據資訊。
配置樣本資訊如下:
[default]
type = access_key
access_key_id = foo
access_key_secret = bar
4. 使用ECS執行個體RAM角色
若不存在優先順序更高的憑據資訊,Credentials工具會在環境變數中擷取ALIBABA_CLOUD_ECS_METADATA(ECS執行個體RAM角色名稱),若存在,程式將會通過ECS的中繼資料服務(Meta Data Server)擷取ECS執行個體RAM角色的STS Token作為預設憑據資訊。
如何保護憑據資訊
憑據資訊泄露導致系統被攻擊是雲上業務普遍存在的一種安全問題,您可通過如下方案避免在代碼中暴露明文憑據資訊,降低憑據泄露的風險。
推薦使用ECS執行個體RAM角色或者使用STS方式。
推薦使用預設憑據鏈,使用環境變數或者設定檔記錄憑據資訊。
如使用顯示初始化方案初始化憑據用戶端,推薦使用系統屬性及環境變數記錄憑據資訊,通過
os.Getenv
擷取。
import (
"fmt"
"os"
"github.com/aliyun/credentials-go/credentials"
)
func main(){
config := new(credentials.Config).
SetType("access_key").
SetAccessKeyId(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")).
SetAccessKeySecret(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"))
akCredential, err := credentials.NewCredential(config)
if err != nil {
return
}
accessKeyId, err := akCredential.GetAccessKeyId()
accessSecret, err := akCredential.GetAccessKeySecret()
credentialType := akCredential.GetType()
fmt.Println(accessKeyId, accessSecret, credentialType)
}
如何切換憑據
當您想要在程式中使用不同的訪問憑據調用不同OpenAPI時,可以通過如下方式。
使用多個憑據用戶端
通過初始化多個憑據用戶端,傳入到不同的介面請求用戶端。
import (
"fmt"
"github.com/aliyun/credentials-go/credentials"
)
func main(){
config1 := new(credentials.Config).
SetType("access_key").
SetAccessKeyId("<ALIBABA_CLOUD_ACCESS_KEY_ID>").
SetAccessKeySecret("<ALIBABA_CLOUD_ACCESS_KEY_SECRET>")
akCredential, err1 := credentials.NewCredential(config1)
config2 := new(credentials.Config).
SetType("access_key").
SetAccessKeyId("<ALIBABA_CLOUD_ACCESS_KEY_ID>").
SetAccessKeySecret("<ALIBABA_CLOUD_ACCESS_KEY_SECRET>")
akCredential, err2 := credentials.NewCredential(config2)
}