github.com/aliyun/credentials-go@v1.4.7/credentials/providers/cli_profile.go (about) 1 package providers 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "io/ioutil" 8 "os" 9 "path" 10 "strings" 11 12 "github.com/aliyun/credentials-go/credentials/internal/utils" 13 ) 14 15 type CLIProfileCredentialsProvider struct { 16 profileFile string 17 profileName string 18 innerProvider CredentialsProvider 19 } 20 21 type CLIProfileCredentialsProviderBuilder struct { 22 provider *CLIProfileCredentialsProvider 23 } 24 25 func (b *CLIProfileCredentialsProviderBuilder) WithProfileFile(profileFile string) *CLIProfileCredentialsProviderBuilder { 26 b.provider.profileFile = profileFile 27 return b 28 } 29 30 func (b *CLIProfileCredentialsProviderBuilder) WithProfileName(profileName string) *CLIProfileCredentialsProviderBuilder { 31 b.provider.profileName = profileName 32 return b 33 } 34 35 func (b *CLIProfileCredentialsProviderBuilder) Build() (provider *CLIProfileCredentialsProvider, err error) { 36 // 优先级: 37 // 1. 使用显示指定的 profileFile 38 // 2. 使用环境变量(ALIBABA_CLOUD_CONFIG_FILE)指定的 profileFile 39 // 3. 兜底使用 path.Join(homeDir, ".aliyun/config") 作为 profileFile 40 if b.provider.profileFile == "" { 41 b.provider.profileFile = os.Getenv("ALIBABA_CLOUD_CONFIG_FILE") 42 } 43 // 优先级: 44 // 1. 使用显示指定的 profileName 45 // 2. 使用环境变量(ALIBABA_CLOUD_PROFILE)制定的 profileName 46 // 3. 使用 CLI 配置中的当前 profileName 47 if b.provider.profileName == "" { 48 b.provider.profileName = os.Getenv("ALIBABA_CLOUD_PROFILE") 49 } 50 51 if strings.ToLower(os.Getenv("ALIBABA_CLOUD_CLI_PROFILE_DISABLED")) == "true" { 52 err = errors.New("the CLI profile is disabled") 53 return 54 } 55 56 provider = b.provider 57 return 58 } 59 60 func NewCLIProfileCredentialsProviderBuilder() *CLIProfileCredentialsProviderBuilder { 61 return &CLIProfileCredentialsProviderBuilder{ 62 provider: &CLIProfileCredentialsProvider{}, 63 } 64 } 65 66 type profile struct { 67 Name string `json:"name"` 68 Mode string `json:"mode"` 69 AccessKeyID string `json:"access_key_id"` 70 AccessKeySecret string `json:"access_key_secret"` 71 SecurityToken string `json:"sts_token"` 72 RegionID string `json:"region_id"` 73 RoleArn string `json:"ram_role_arn"` 74 RoleSessionName string `json:"ram_session_name"` 75 DurationSeconds int `json:"expired_seconds"` 76 StsRegion string `json:"sts_region"` 77 EnableVpc bool `json:"enable_vpc"` 78 SourceProfile string `json:"source_profile"` 79 RoleName string `json:"ram_role_name"` 80 OIDCTokenFile string `json:"oidc_token_file"` 81 OIDCProviderARN string `json:"oidc_provider_arn"` 82 Policy string `json:"policy"` 83 ExternalId string `json:"external_id"` 84 SignInUrl string `json:"cloud_sso_sign_in_url"` 85 AccountId string `json:"cloud_sso_account_id"` 86 AccessConfig string `json:"cloud_sso_access_config"` 87 AccessToken string `json:"access_token"` 88 AccessTokenExpire int64 `json:"cloud_sso_access_token_expire"` 89 } 90 91 type configuration struct { 92 Current string `json:"current"` 93 Profiles []*profile `json:"profiles"` 94 } 95 96 func newConfigurationFromPath(cfgPath string) (conf *configuration, err error) { 97 bytes, err := ioutil.ReadFile(cfgPath) 98 if err != nil { 99 err = fmt.Errorf("reading aliyun cli config from '%s' failed %v", cfgPath, err) 100 return 101 } 102 103 conf = &configuration{} 104 105 err = json.Unmarshal(bytes, conf) 106 if err != nil { 107 err = fmt.Errorf("unmarshal aliyun cli config from '%s' failed: %s", cfgPath, string(bytes)) 108 return 109 } 110 111 if conf.Profiles == nil || len(conf.Profiles) == 0 { 112 err = fmt.Errorf("no any configured profiles in '%s'", cfgPath) 113 return 114 } 115 116 return 117 } 118 119 func (conf *configuration) getProfile(name string) (profile *profile, err error) { 120 for _, p := range conf.Profiles { 121 if p.Name == name { 122 profile = p 123 return 124 } 125 } 126 127 err = fmt.Errorf("unable to get profile with '%s'", name) 128 return 129 } 130 131 func (provider *CLIProfileCredentialsProvider) getCredentialsProvider(conf *configuration, profileName string) (credentialsProvider CredentialsProvider, err error) { 132 p, err := conf.getProfile(profileName) 133 if err != nil { 134 return 135 } 136 137 switch p.Mode { 138 case "AK": 139 credentialsProvider, err = NewStaticAKCredentialsProviderBuilder(). 140 WithAccessKeyId(p.AccessKeyID). 141 WithAccessKeySecret(p.AccessKeySecret). 142 Build() 143 case "StsToken": 144 credentialsProvider, err = NewStaticSTSCredentialsProviderBuilder(). 145 WithAccessKeyId(p.AccessKeyID). 146 WithAccessKeySecret(p.AccessKeySecret). 147 WithSecurityToken(p.SecurityToken). 148 Build() 149 case "RamRoleArn": 150 previousProvider, err1 := NewStaticAKCredentialsProviderBuilder(). 151 WithAccessKeyId(p.AccessKeyID). 152 WithAccessKeySecret(p.AccessKeySecret). 153 Build() 154 if err1 != nil { 155 return nil, err1 156 } 157 158 credentialsProvider, err = NewRAMRoleARNCredentialsProviderBuilder(). 159 WithCredentialsProvider(previousProvider). 160 WithRoleArn(p.RoleArn). 161 WithRoleSessionName(p.RoleSessionName). 162 WithDurationSeconds(p.DurationSeconds). 163 WithStsRegionId(p.StsRegion). 164 WithEnableVpc(p.EnableVpc). 165 WithPolicy(p.Policy). 166 WithExternalId(p.ExternalId). 167 Build() 168 case "EcsRamRole": 169 credentialsProvider, err = NewECSRAMRoleCredentialsProviderBuilder().WithRoleName(p.RoleName).Build() 170 case "OIDC": 171 credentialsProvider, err = NewOIDCCredentialsProviderBuilder(). 172 WithOIDCTokenFilePath(p.OIDCTokenFile). 173 WithOIDCProviderARN(p.OIDCProviderARN). 174 WithRoleArn(p.RoleArn). 175 WithStsRegionId(p.StsRegion). 176 WithEnableVpc(p.EnableVpc). 177 WithDurationSeconds(p.DurationSeconds). 178 WithRoleSessionName(p.RoleSessionName). 179 WithPolicy(p.Policy). 180 Build() 181 case "ChainableRamRoleArn": 182 previousProvider, err1 := provider.getCredentialsProvider(conf, p.SourceProfile) 183 if err1 != nil { 184 err = fmt.Errorf("get source profile failed: %s", err1.Error()) 185 return 186 } 187 credentialsProvider, err = NewRAMRoleARNCredentialsProviderBuilder(). 188 WithCredentialsProvider(previousProvider). 189 WithRoleArn(p.RoleArn). 190 WithRoleSessionName(p.RoleSessionName). 191 WithDurationSeconds(p.DurationSeconds). 192 WithStsRegionId(p.StsRegion). 193 WithEnableVpc(p.EnableVpc). 194 WithPolicy(p.Policy). 195 WithExternalId(p.ExternalId). 196 Build() 197 case "CloudSSO": 198 credentialsProvider, err = NewCloudSSOCredentialsProviderBuilder(). 199 WithSignInUrl(p.SignInUrl). 200 WithAccountId(p.AccountId). 201 WithAccessConfig(p.AccessConfig). 202 WithAccessToken(p.AccessToken). 203 WithAccessTokenExpire(p.AccessTokenExpire). 204 Build() 205 default: 206 err = fmt.Errorf("unsupported profile mode '%s'", p.Mode) 207 } 208 209 return 210 } 211 212 // 默认设置为 GetHomePath,测试时便于 mock 213 var getHomePath = utils.GetHomePath 214 215 func (provider *CLIProfileCredentialsProvider) GetCredentials() (cc *Credentials, err error) { 216 if provider.innerProvider == nil { 217 cfgPath := provider.profileFile 218 if cfgPath == "" { 219 homeDir := getHomePath() 220 if homeDir == "" { 221 err = fmt.Errorf("cannot found home dir") 222 return 223 } 224 225 cfgPath = path.Join(homeDir, ".aliyun/config.json") 226 } 227 228 conf, err1 := newConfigurationFromPath(cfgPath) 229 if err1 != nil { 230 err = err1 231 return 232 } 233 234 if provider.profileName == "" { 235 provider.profileName = conf.Current 236 } 237 238 provider.innerProvider, err = provider.getCredentialsProvider(conf, provider.profileName) 239 if err != nil { 240 return 241 } 242 } 243 244 innerCC, err := provider.innerProvider.GetCredentials() 245 if err != nil { 246 return 247 } 248 249 providerName := innerCC.ProviderName 250 if providerName == "" { 251 providerName = provider.innerProvider.GetProviderName() 252 } 253 254 cc = &Credentials{ 255 AccessKeyId: innerCC.AccessKeyId, 256 AccessKeySecret: innerCC.AccessKeySecret, 257 SecurityToken: innerCC.SecurityToken, 258 ProviderName: fmt.Sprintf("%s/%s", provider.GetProviderName(), providerName), 259 } 260 261 return 262 } 263 264 func (provider *CLIProfileCredentialsProvider) GetProviderName() string { 265 return "cli_profile" 266 }