github.com/aliyun/credentials-go@v1.4.7/credentials/credential.go (about) 1 package credentials 2 3 import ( 4 "bufio" 5 "errors" 6 "fmt" 7 "net/http" 8 "net/url" 9 "os" 10 "strings" 11 "time" 12 13 "github.com/alibabacloud-go/debug/debug" 14 "github.com/alibabacloud-go/tea/tea" 15 "github.com/aliyun/credentials-go/credentials/internal/utils" 16 "github.com/aliyun/credentials-go/credentials/providers" 17 "github.com/aliyun/credentials-go/credentials/request" 18 "github.com/aliyun/credentials-go/credentials/response" 19 ) 20 21 var debuglog = debug.Init("credential") 22 23 var hookParse = func(err error) error { 24 return err 25 } 26 27 // Credential is an interface for getting actual credential 28 type Credential interface { 29 // Deprecated: GetAccessKeyId is deprecated, use GetCredential instead of. 30 GetAccessKeyId() (*string, error) 31 // Deprecated: GetAccessKeySecret is deprecated, use GetCredential instead of. 32 GetAccessKeySecret() (*string, error) 33 // Deprecated: GetSecurityToken is deprecated, use GetCredential instead of. 34 GetSecurityToken() (*string, error) 35 GetBearerToken() *string 36 GetType() *string 37 GetCredential() (*CredentialModel, error) 38 } 39 40 // Config is important when call NewCredential 41 type Config struct { 42 // Credential type, including access_key, sts, bearer, ecs_ram_role, ram_role_arn, rsa_key_pair, oidc_role_arn, credentials_uri 43 Type *string `json:"type"` 44 AccessKeyId *string `json:"access_key_id"` 45 AccessKeySecret *string `json:"access_key_secret"` 46 SecurityToken *string `json:"security_token"` 47 BearerToken *string `json:"bearer_token"` 48 49 // Used when the type is ram_role_arn or oidc_role_arn 50 OIDCProviderArn *string `json:"oidc_provider_arn"` 51 OIDCTokenFilePath *string `json:"oidc_token"` 52 RoleArn *string `json:"role_arn"` 53 RoleSessionName *string `json:"role_session_name"` 54 RoleSessionExpiration *int `json:"role_session_expiration"` 55 Policy *string `json:"policy"` 56 ExternalId *string `json:"external_id"` 57 STSEndpoint *string `json:"sts_endpoint"` 58 59 // Used when the type is ecs_ram_role 60 RoleName *string `json:"role_name"` 61 // Deprecated 62 EnableIMDSv2 *bool `json:"enable_imds_v2"` 63 DisableIMDSv1 *bool `json:"disable_imds_v1"` 64 // Deprecated 65 MetadataTokenDuration *int `json:"metadata_token_duration"` 66 67 // Used when the type is credentials_uri 68 Url *string `json:"url"` 69 70 // Deprecated 71 // Used when the type is rsa_key_pair 72 SessionExpiration *int `json:"session_expiration"` 73 PublicKeyId *string `json:"public_key_id"` 74 PrivateKeyFile *string `json:"private_key_file"` 75 Host *string `json:"host"` 76 77 // Read timeout, in milliseconds. 78 // The default value for ecs_ram_role is 1000ms, the default value for ram_role_arn is 5000ms, and the default value for oidc_role_arn is 5000ms. 79 Timeout *int `json:"timeout"` 80 // Connection timeout, in milliseconds. 81 // The default value for ecs_ram_role is 1000ms, the default value for ram_role_arn is 10000ms, and the default value for oidc_role_arn is 10000ms. 82 ConnectTimeout *int `json:"connect_timeout"` 83 84 Proxy *string `json:"proxy"` 85 InAdvanceScale *float64 `json:"inAdvanceScale"` 86 } 87 88 func (s Config) String() string { 89 return tea.Prettify(s) 90 } 91 92 func (s Config) GoString() string { 93 return s.String() 94 } 95 96 func (s *Config) SetAccessKeyId(v string) *Config { 97 s.AccessKeyId = &v 98 return s 99 } 100 101 func (s *Config) SetAccessKeySecret(v string) *Config { 102 s.AccessKeySecret = &v 103 return s 104 } 105 106 func (s *Config) SetSecurityToken(v string) *Config { 107 s.SecurityToken = &v 108 return s 109 } 110 111 func (s *Config) SetRoleArn(v string) *Config { 112 s.RoleArn = &v 113 return s 114 } 115 116 func (s *Config) SetRoleSessionName(v string) *Config { 117 s.RoleSessionName = &v 118 return s 119 } 120 121 func (s *Config) SetPublicKeyId(v string) *Config { 122 s.PublicKeyId = &v 123 return s 124 } 125 126 func (s *Config) SetRoleName(v string) *Config { 127 s.RoleName = &v 128 return s 129 } 130 131 func (s *Config) SetEnableIMDSv2(v bool) *Config { 132 s.EnableIMDSv2 = &v 133 return s 134 } 135 136 func (s *Config) SetDisableIMDSv1(v bool) *Config { 137 s.DisableIMDSv1 = &v 138 return s 139 } 140 141 func (s *Config) SetMetadataTokenDuration(v int) *Config { 142 s.MetadataTokenDuration = &v 143 return s 144 } 145 146 func (s *Config) SetSessionExpiration(v int) *Config { 147 s.SessionExpiration = &v 148 return s 149 } 150 151 func (s *Config) SetPrivateKeyFile(v string) *Config { 152 s.PrivateKeyFile = &v 153 return s 154 } 155 156 func (s *Config) SetBearerToken(v string) *Config { 157 s.BearerToken = &v 158 return s 159 } 160 161 func (s *Config) SetRoleSessionExpiration(v int) *Config { 162 s.RoleSessionExpiration = &v 163 return s 164 } 165 166 func (s *Config) SetPolicy(v string) *Config { 167 s.Policy = &v 168 return s 169 } 170 171 func (s *Config) SetHost(v string) *Config { 172 s.Host = &v 173 return s 174 } 175 176 func (s *Config) SetTimeout(v int) *Config { 177 s.Timeout = &v 178 return s 179 } 180 181 func (s *Config) SetConnectTimeout(v int) *Config { 182 s.ConnectTimeout = &v 183 return s 184 } 185 186 func (s *Config) SetProxy(v string) *Config { 187 s.Proxy = &v 188 return s 189 } 190 191 func (s *Config) SetType(v string) *Config { 192 s.Type = &v 193 return s 194 } 195 196 func (s *Config) SetOIDCTokenFilePath(v string) *Config { 197 s.OIDCTokenFilePath = &v 198 return s 199 } 200 201 func (s *Config) SetOIDCProviderArn(v string) *Config { 202 s.OIDCProviderArn = &v 203 return s 204 } 205 206 func (s *Config) SetURLCredential(v string) *Config { 207 if v == "" { 208 v = os.Getenv("ALIBABA_CLOUD_CREDENTIALS_URI") 209 } 210 s.Url = &v 211 return s 212 } 213 214 func (s *Config) SetSTSEndpoint(v string) *Config { 215 s.STSEndpoint = &v 216 return s 217 } 218 219 func (s *Config) SetExternalId(v string) *Config { 220 s.ExternalId = &v 221 return s 222 } 223 224 // NewCredential return a credential according to the type in config. 225 // if config is nil, the function will use default provider chain to get credentials. 226 // please see README.md for detail. 227 func NewCredential(config *Config) (credential Credential, err error) { 228 if config == nil { 229 provider := providers.NewDefaultCredentialsProvider() 230 credential = FromCredentialsProvider("default", provider) 231 return 232 } 233 switch tea.StringValue(config.Type) { 234 case "credentials_uri": 235 provider, err := providers.NewURLCredentialsProviderBuilder(). 236 WithUrl(tea.StringValue(config.Url)). 237 WithHttpOptions(&providers.HttpOptions{ 238 Proxy: tea.StringValue(config.Proxy), 239 ReadTimeout: tea.IntValue(config.Timeout), 240 ConnectTimeout: tea.IntValue(config.ConnectTimeout), 241 }). 242 Build() 243 244 if err != nil { 245 return nil, err 246 } 247 credential = FromCredentialsProvider("credentials_uri", provider) 248 case "oidc_role_arn": 249 provider, err := providers.NewOIDCCredentialsProviderBuilder(). 250 WithRoleArn(tea.StringValue(config.RoleArn)). 251 WithOIDCTokenFilePath(tea.StringValue(config.OIDCTokenFilePath)). 252 WithOIDCProviderARN(tea.StringValue(config.OIDCProviderArn)). 253 WithDurationSeconds(tea.IntValue(config.RoleSessionExpiration)). 254 WithPolicy(tea.StringValue(config.Policy)). 255 WithRoleSessionName(tea.StringValue(config.RoleSessionName)). 256 WithSTSEndpoint(tea.StringValue(config.STSEndpoint)). 257 WithHttpOptions(&providers.HttpOptions{ 258 Proxy: tea.StringValue(config.Proxy), 259 ReadTimeout: tea.IntValue(config.Timeout), 260 ConnectTimeout: tea.IntValue(config.ConnectTimeout), 261 }). 262 Build() 263 264 if err != nil { 265 return nil, err 266 } 267 credential = FromCredentialsProvider("oidc_role_arn", provider) 268 case "access_key": 269 provider, err := providers.NewStaticAKCredentialsProviderBuilder(). 270 WithAccessKeyId(tea.StringValue(config.AccessKeyId)). 271 WithAccessKeySecret(tea.StringValue(config.AccessKeySecret)). 272 Build() 273 if err != nil { 274 return nil, err 275 } 276 277 credential = FromCredentialsProvider("access_key", provider) 278 case "sts": 279 provider, err := providers.NewStaticSTSCredentialsProviderBuilder(). 280 WithAccessKeyId(tea.StringValue(config.AccessKeyId)). 281 WithAccessKeySecret(tea.StringValue(config.AccessKeySecret)). 282 WithSecurityToken(tea.StringValue(config.SecurityToken)). 283 Build() 284 if err != nil { 285 return nil, err 286 } 287 288 credential = FromCredentialsProvider("sts", provider) 289 case "ecs_ram_role": 290 provider, err := providers.NewECSRAMRoleCredentialsProviderBuilder(). 291 WithRoleName(tea.StringValue(config.RoleName)). 292 WithDisableIMDSv1(tea.BoolValue(config.DisableIMDSv1)). 293 Build() 294 295 if err != nil { 296 return nil, err 297 } 298 299 credential = FromCredentialsProvider("ecs_ram_role", provider) 300 case "ram_role_arn": 301 var credentialsProvider providers.CredentialsProvider 302 if config.SecurityToken != nil && *config.SecurityToken != "" { 303 credentialsProvider, err = providers.NewStaticSTSCredentialsProviderBuilder(). 304 WithAccessKeyId(tea.StringValue(config.AccessKeyId)). 305 WithAccessKeySecret(tea.StringValue(config.AccessKeySecret)). 306 WithSecurityToken(tea.StringValue(config.SecurityToken)). 307 Build() 308 } else { 309 credentialsProvider, err = providers.NewStaticAKCredentialsProviderBuilder(). 310 WithAccessKeyId(tea.StringValue(config.AccessKeyId)). 311 WithAccessKeySecret(tea.StringValue(config.AccessKeySecret)). 312 Build() 313 } 314 315 if err != nil { 316 return nil, err 317 } 318 319 provider, err := providers.NewRAMRoleARNCredentialsProviderBuilder(). 320 WithCredentialsProvider(credentialsProvider). 321 WithRoleArn(tea.StringValue(config.RoleArn)). 322 WithRoleSessionName(tea.StringValue(config.RoleSessionName)). 323 WithPolicy(tea.StringValue(config.Policy)). 324 WithDurationSeconds(tea.IntValue(config.RoleSessionExpiration)). 325 WithExternalId(tea.StringValue(config.ExternalId)). 326 WithStsEndpoint(tea.StringValue(config.STSEndpoint)). 327 WithHttpOptions(&providers.HttpOptions{ 328 Proxy: tea.StringValue(config.Proxy), 329 ReadTimeout: tea.IntValue(config.Timeout), 330 ConnectTimeout: tea.IntValue(config.ConnectTimeout), 331 }). 332 Build() 333 if err != nil { 334 return nil, err 335 } 336 337 credential = FromCredentialsProvider("ram_role_arn", provider) 338 case "rsa_key_pair": 339 err = checkRSAKeyPair(config) 340 if err != nil { 341 return 342 } 343 file, err1 := os.Open(tea.StringValue(config.PrivateKeyFile)) 344 if err1 != nil { 345 err = fmt.Errorf("InvalidPath: Can not open PrivateKeyFile, err is %s", err1.Error()) 346 return 347 } 348 defer file.Close() 349 var privateKey string 350 scan := bufio.NewScanner(file) 351 for scan.Scan() { 352 if strings.HasPrefix(scan.Text(), "----") { 353 continue 354 } 355 privateKey += scan.Text() + "\n" 356 } 357 runtime := &utils.Runtime{ 358 Host: tea.StringValue(config.Host), 359 Proxy: tea.StringValue(config.Proxy), 360 ReadTimeout: tea.IntValue(config.Timeout), 361 ConnectTimeout: tea.IntValue(config.ConnectTimeout), 362 STSEndpoint: tea.StringValue(config.STSEndpoint), 363 } 364 credential = newRsaKeyPairCredential( 365 privateKey, 366 tea.StringValue(config.PublicKeyId), 367 tea.IntValue(config.SessionExpiration), 368 runtime) 369 case "bearer": 370 if tea.StringValue(config.BearerToken) == "" { 371 err = errors.New("BearerToken cannot be empty") 372 return 373 } 374 credential = newBearerTokenCredential(tea.StringValue(config.BearerToken)) 375 default: 376 err = errors.New("invalid type option, support: access_key, sts, bearer, ecs_ram_role, ram_role_arn, rsa_key_pair, oidc_role_arn, credentials_uri") 377 return 378 } 379 return credential, nil 380 } 381 382 func checkRSAKeyPair(config *Config) (err error) { 383 if tea.StringValue(config.PrivateKeyFile) == "" { 384 err = errors.New("PrivateKeyFile cannot be empty") 385 return 386 } 387 if tea.StringValue(config.PublicKeyId) == "" { 388 err = errors.New("PublicKeyId cannot be empty") 389 return 390 } 391 return 392 } 393 394 func doAction(request *request.CommonRequest, runtime *utils.Runtime) (content []byte, err error) { 395 var urlEncoded string 396 if request.BodyParams != nil { 397 urlEncoded = utils.GetURLFormedMap(request.BodyParams) 398 } 399 httpRequest, err := http.NewRequest(request.Method, request.URL, strings.NewReader(urlEncoded)) 400 if err != nil { 401 return 402 } 403 httpRequest.Proto = "HTTP/1.1" 404 httpRequest.Host = request.Domain 405 debuglog("> %s %s %s", httpRequest.Method, httpRequest.URL.RequestURI(), httpRequest.Proto) 406 debuglog("> Host: %s", httpRequest.Host) 407 for key, value := range request.Headers { 408 if value != "" { 409 debuglog("> %s: %s", key, value) 410 httpRequest.Header[key] = []string{value} 411 } 412 } 413 debuglog(">") 414 httpClient := &http.Client{} 415 httpClient.Timeout = time.Duration(runtime.ReadTimeout) * time.Second 416 proxy := &url.URL{} 417 if runtime.Proxy != "" { 418 proxy, err = url.Parse(runtime.Proxy) 419 if err != nil { 420 return 421 } 422 } 423 transport := &http.Transport{} 424 if proxy != nil && runtime.Proxy != "" { 425 transport.Proxy = http.ProxyURL(proxy) 426 } 427 transport.DialContext = utils.Timeout(time.Duration(runtime.ConnectTimeout) * time.Second) 428 httpClient.Transport = transport 429 httpResponse, err := hookDo(httpClient.Do)(httpRequest) 430 if err != nil { 431 return 432 } 433 debuglog("< %s %s", httpResponse.Proto, httpResponse.Status) 434 for key, value := range httpResponse.Header { 435 debuglog("< %s: %v", key, strings.Join(value, "")) 436 } 437 debuglog("<") 438 439 resp := &response.CommonResponse{} 440 err = hookParse(resp.ParseFromHTTPResponse(httpResponse)) 441 if err != nil { 442 return 443 } 444 debuglog("%s", resp.GetHTTPContentString()) 445 if resp.GetHTTPStatus() != http.StatusOK { 446 err = fmt.Errorf("httpStatus: %d, message = %s", resp.GetHTTPStatus(), resp.GetHTTPContentString()) 447 return 448 } 449 return resp.GetHTTPContentBytes(), nil 450 } 451 452 type credentialsProviderWrap struct { 453 typeName string 454 provider providers.CredentialsProvider 455 } 456 457 // Deprecated: use GetCredential() instead of 458 func (cp *credentialsProviderWrap) GetAccessKeyId() (accessKeyId *string, err error) { 459 cc, err := cp.provider.GetCredentials() 460 if err != nil { 461 return 462 } 463 accessKeyId = &cc.AccessKeyId 464 return 465 } 466 467 // Deprecated: use GetCredential() instead of 468 func (cp *credentialsProviderWrap) GetAccessKeySecret() (accessKeySecret *string, err error) { 469 cc, err := cp.provider.GetCredentials() 470 if err != nil { 471 return 472 } 473 accessKeySecret = &cc.AccessKeySecret 474 return 475 } 476 477 // Deprecated: use GetCredential() instead of 478 func (cp *credentialsProviderWrap) GetSecurityToken() (securityToken *string, err error) { 479 cc, err := cp.provider.GetCredentials() 480 if err != nil { 481 return 482 } 483 securityToken = &cc.SecurityToken 484 return 485 } 486 487 // Deprecated: don't use it 488 func (cp *credentialsProviderWrap) GetBearerToken() (bearerToken *string) { 489 return tea.String("") 490 } 491 492 // Get credentials 493 func (cp *credentialsProviderWrap) GetCredential() (cm *CredentialModel, err error) { 494 c, err := cp.provider.GetCredentials() 495 if err != nil { 496 return 497 } 498 499 cm = &CredentialModel{ 500 AccessKeyId: &c.AccessKeyId, 501 AccessKeySecret: &c.AccessKeySecret, 502 SecurityToken: &c.SecurityToken, 503 Type: &cp.typeName, 504 ProviderName: &c.ProviderName, 505 } 506 return 507 } 508 509 func (cp *credentialsProviderWrap) GetType() *string { 510 return &cp.typeName 511 } 512 513 func FromCredentialsProvider(typeName string, cp providers.CredentialsProvider) Credential { 514 return &credentialsProviderWrap{ 515 typeName: typeName, 516 provider: cp, 517 } 518 }