github.com/aliyun/credentials-go@v1.4.7/credentials/ecs_ram_role_credentials_provider.go (about) 1 package credentials 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strconv" 7 "time" 8 9 "github.com/alibabacloud-go/tea/tea" 10 "github.com/aliyun/credentials-go/credentials/internal/utils" 11 "github.com/aliyun/credentials-go/credentials/request" 12 ) 13 14 var securityCredURL = "http://100.100.100.200/latest/meta-data/ram/security-credentials/" 15 var securityCredTokenURL = "http://100.100.100.200/latest/api/token" 16 17 const defaultMetadataTokenDuration = int(21600) 18 19 // ECSRAMRoleCredentialsProvider is a kind of credentials provider 20 type ECSRAMRoleCredentialsProvider struct { 21 *credentialUpdater 22 RoleName string 23 EnableIMDSv2 bool 24 MetadataTokenDuration int 25 sessionCredential *sessionCredential 26 runtime *utils.Runtime 27 metadataToken string 28 staleTime int64 29 } 30 31 type ecsRAMRoleResponse struct { 32 Code string `json:"Code" xml:"Code"` 33 AccessKeyId string `json:"AccessKeyId" xml:"AccessKeyId"` 34 AccessKeySecret string `json:"AccessKeySecret" xml:"AccessKeySecret"` 35 SecurityToken string `json:"SecurityToken" xml:"SecurityToken"` 36 Expiration string `json:"Expiration" xml:"Expiration"` 37 } 38 39 func newEcsRAMRoleCredentialWithEnableIMDSv2(roleName string, enableIMDSv2 bool, metadataTokenDuration int, inAdvanceScale float64, runtime *utils.Runtime) *ECSRAMRoleCredentialsProvider { 40 credentialUpdater := new(credentialUpdater) 41 if inAdvanceScale < 1 && inAdvanceScale > 0 { 42 credentialUpdater.inAdvanceScale = inAdvanceScale 43 } 44 return &ECSRAMRoleCredentialsProvider{ 45 RoleName: roleName, 46 EnableIMDSv2: enableIMDSv2, 47 MetadataTokenDuration: metadataTokenDuration, 48 credentialUpdater: credentialUpdater, 49 runtime: runtime, 50 } 51 } 52 53 func (e *ECSRAMRoleCredentialsProvider) GetCredential() (credentials *CredentialModel, err error) { 54 if e.sessionCredential == nil || e.needUpdateCredential() { 55 err = e.updateCredential() 56 if err != nil { 57 if e.credentialExpiration > (int(time.Now().Unix()) - int(e.lastUpdateTimestamp)) { 58 // 虽然有错误,但是已有的 credentials 还有效 59 } else { 60 return 61 } 62 } 63 } 64 65 credentials = &CredentialModel{ 66 AccessKeyId: tea.String(e.sessionCredential.AccessKeyId), 67 AccessKeySecret: tea.String(e.sessionCredential.AccessKeySecret), 68 SecurityToken: tea.String(e.sessionCredential.SecurityToken), 69 Type: tea.String("ecs_ram_role"), 70 } 71 72 return 73 } 74 75 // GetAccessKeyId reutrns EcsRAMRoleCredential's AccessKeyId 76 // if AccessKeyId is not exist or out of date, the function will update it. 77 func (e *ECSRAMRoleCredentialsProvider) GetAccessKeyId() (accessKeyId *string, err error) { 78 c, err := e.GetCredential() 79 if err != nil { 80 return 81 } 82 83 accessKeyId = c.AccessKeyId 84 return 85 } 86 87 // GetAccessSecret reutrns EcsRAMRoleCredential's AccessKeySecret 88 // if AccessKeySecret is not exist or out of date, the function will update it. 89 func (e *ECSRAMRoleCredentialsProvider) GetAccessKeySecret() (accessKeySecret *string, err error) { 90 c, err := e.GetCredential() 91 if err != nil { 92 return 93 } 94 95 accessKeySecret = c.AccessKeySecret 96 return 97 } 98 99 // GetSecurityToken reutrns EcsRAMRoleCredential's SecurityToken 100 // if SecurityToken is not exist or out of date, the function will update it. 101 func (e *ECSRAMRoleCredentialsProvider) GetSecurityToken() (securityToken *string, err error) { 102 c, err := e.GetCredential() 103 if err != nil { 104 return 105 } 106 107 securityToken = c.SecurityToken 108 return 109 } 110 111 // GetBearerToken is useless for EcsRAMRoleCredential 112 func (e *ECSRAMRoleCredentialsProvider) GetBearerToken() *string { 113 return tea.String("") 114 } 115 116 // GetType reutrns EcsRAMRoleCredential's type 117 func (e *ECSRAMRoleCredentialsProvider) GetType() *string { 118 return tea.String("ecs_ram_role") 119 } 120 121 func getRoleName() (string, error) { 122 runtime := utils.NewRuntime(1, 1, "", "") 123 request := request.NewCommonRequest() 124 request.URL = securityCredURL 125 request.Method = "GET" 126 content, err := doAction(request, runtime) 127 if err != nil { 128 return "", err 129 } 130 return string(content), nil 131 } 132 133 func (e *ECSRAMRoleCredentialsProvider) getMetadataToken() (err error) { 134 if e.needToRefresh() { 135 if e.MetadataTokenDuration <= 0 { 136 e.MetadataTokenDuration = defaultMetadataTokenDuration 137 } 138 tmpTime := time.Now().Unix() + int64(e.MetadataTokenDuration*1000) 139 request := request.NewCommonRequest() 140 request.URL = securityCredTokenURL 141 request.Method = "PUT" 142 request.Headers["X-aliyun-ecs-metadata-token-ttl-seconds"] = strconv.Itoa(e.MetadataTokenDuration) 143 content, err := doAction(request, e.runtime) 144 if err != nil { 145 return err 146 } 147 e.staleTime = tmpTime 148 e.metadataToken = string(content) 149 } 150 return 151 } 152 153 func (e *ECSRAMRoleCredentialsProvider) updateCredential() (err error) { 154 if e.runtime == nil { 155 e.runtime = new(utils.Runtime) 156 } 157 request := request.NewCommonRequest() 158 if e.RoleName == "" { 159 e.RoleName, err = getRoleName() 160 if err != nil { 161 return fmt.Errorf("refresh Ecs sts token err: %s", err.Error()) 162 } 163 } 164 if e.EnableIMDSv2 { 165 err = e.getMetadataToken() 166 if err != nil { 167 return fmt.Errorf("failed to get token from ECS Metadata Service: %s", err.Error()) 168 } 169 request.Headers["X-aliyun-ecs-metadata-token"] = e.metadataToken 170 } 171 request.URL = securityCredURL + e.RoleName 172 request.Method = "GET" 173 content, err := doAction(request, e.runtime) 174 if err != nil { 175 return fmt.Errorf("refresh Ecs sts token err: %s", err.Error()) 176 } 177 var resp *ecsRAMRoleResponse 178 err = json.Unmarshal(content, &resp) 179 if err != nil { 180 return fmt.Errorf("refresh Ecs sts token err: Json Unmarshal fail: %s", err.Error()) 181 } 182 if resp.Code != "Success" { 183 return fmt.Errorf("refresh Ecs sts token err: Code is not Success") 184 } 185 if resp.AccessKeyId == "" || resp.AccessKeySecret == "" || resp.SecurityToken == "" || resp.Expiration == "" { 186 return fmt.Errorf("refresh Ecs sts token err: AccessKeyId: %s, AccessKeySecret: %s, SecurityToken: %s, Expiration: %s", resp.AccessKeyId, resp.AccessKeySecret, resp.SecurityToken, resp.Expiration) 187 } 188 189 expirationTime, err := time.Parse("2006-01-02T15:04:05Z", resp.Expiration) 190 e.lastUpdateTimestamp = time.Now().Unix() 191 e.credentialExpiration = int(expirationTime.Unix() - time.Now().Unix()) 192 e.sessionCredential = &sessionCredential{ 193 AccessKeyId: resp.AccessKeyId, 194 AccessKeySecret: resp.AccessKeySecret, 195 SecurityToken: resp.SecurityToken, 196 } 197 198 return 199 } 200 201 func (e *ECSRAMRoleCredentialsProvider) needToRefresh() (needToRefresh bool) { 202 needToRefresh = time.Now().Unix() >= e.staleTime 203 return 204 }