/
config.go
194 lines (177 loc) · 6.01 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
package connectivity
import (
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"github.com/jmespath/go-jmespath"
)
var securityCredURL = "http://100.100.100.200/latest/meta-data/ram/security-credentials/"
// Config of aliyun
type Config struct {
AccessKey string
SecretKey string
EcsRoleName string
Region Region
RegionID string
SecurityToken string
OtsInstanceName string
AccountID string
RAMRoleArn string
RAMRoleSessionName string
RAMRolePolicy string
RAMRoleSessionExpiration int
EcsEndpoint string
RdsEndpoint string
SlbEndpoint string
VpcEndpoint string
CenEndpoint string
EssEndpoint string
OssEndpoint string
OnsEndpoint string
AlikafkaEndpoint string
DNSEndpoint string
RAMEndpoint string
CsEndpoint string
CrEndpoint string
CdnEndpoint string
KmsEndpoint string
OtsEndpoint string
CmsEndpoint string
PvtzEndpoint string
StsEndpoint string
LogEndpoint string
DrdsEndpoint string
DdsEndpoint string
GpdbEnpoint string
KVStoreEndpoint string
FcEndpoint string
ApigatewayEndpoint string
DatahubEndpoint string
MnsEndpoint string
LocationEndpoint string
ElasticsearchEndpoint string
NasEndpoint string
ActionTrailEndpoint string
BssOpenAPIEndpoint string
DdoscooEndpoint string
DdosbgpEndpoint string
SkipRegionValidation bool
ConfigurationSource string
}
func (c *Config) loadAndValidate() error {
err := c.validateRegion()
if err != nil {
return err
}
return nil
}
func (c *Config) validateRegion() error {
for _, valid := range ValidRegions {
if c.Region == valid {
return nil
}
}
return fmt.Errorf("Invalid Alibaba Cloud region: %s", c.RegionID)
}
func (c *Config) getAuthCredential() auth.Credential {
if c.AccessKey != "" && c.SecretKey != "" {
if c.SecurityToken != "" {
return credentials.NewStsTokenCredential(c.AccessKey, c.SecretKey, c.SecurityToken)
}
if c.RAMRoleArn != "" {
log.Printf("[INFO] Assume RAM Role specified in provider block assume_role { ... }")
return credentials.NewRamRoleArnWithPolicyCredential(
c.AccessKey, c.SecretKey, c.RAMRoleArn,
c.RAMRoleSessionName, c.RAMRolePolicy, c.RAMRoleSessionExpiration)
}
return credentials.NewAccessKeyCredential(c.AccessKey, c.SecretKey)
}
if c.EcsRoleName != "" {
return credentials.NewEcsRamRoleCredential(c.EcsRoleName)
}
return credentials.NewAccessKeyCredential(c.AccessKey, c.SecretKey)
}
// getAuthCredentialByEcsRoleName aims to access meta to get sts credential
// Actually, the job should be done by sdk, but currently not all resources and products support alibaba-cloud-sdk-go,
// and their go sdk does support ecs role name.
// This method is a temporary solution and it should be removed after all go sdk support ecs role name
// The related PR: https://github.com/terraform-providers/terraform-provider-alicloud/pull/731
func (c *Config) getAuthCredentialByEcsRoleName() (accessKey, secretKey, token string, err error) {
if c.AccessKey != "" {
return c.AccessKey, c.SecretKey, c.SecurityToken, nil
}
if c.EcsRoleName == "" {
return
}
requestURL := securityCredURL + c.EcsRoleName
httpRequest, err := http.NewRequest(requests.GET, requestURL, strings.NewReader(""))
if err != nil {
err = fmt.Errorf("build sts requests err: %s", err.Error())
return
}
httpClient := &http.Client{}
httpResponse, err := httpClient.Do(httpRequest)
if err != nil {
err = fmt.Errorf("get Ecs sts token err : %s", err.Error())
return
}
response := responses.NewCommonResponse()
err = responses.Unmarshal(response, httpResponse, "")
if err != nil {
err = fmt.Errorf("Unmarshal Ecs sts token response err : %s", err.Error())
return
}
if response.GetHttpStatus() != http.StatusOK {
err = fmt.Errorf("get Ecs sts token err, httpStatus: %d, message = %s", response.GetHttpStatus(), response.GetHttpContentString())
return
}
var data interface{}
err = json.Unmarshal(response.GetHttpContentBytes(), &data)
if err != nil {
err = fmt.Errorf("refresh Ecs sts token err, json.Unmarshal fail: %s", err.Error())
return
}
code, err := jmespath.Search("Code", data)
if err != nil {
err = fmt.Errorf("refresh Ecs sts token err, fail to get Code: %s", err.Error())
return
}
if code.(string) != "Success" {
err = fmt.Errorf("refresh Ecs sts token err, Code is not Success")
return
}
accessKeyID, err := jmespath.Search("AccessKeyId", data)
if err != nil {
err = fmt.Errorf("refresh Ecs sts token err, fail to get AccessKeyId: %s", err.Error())
return
}
accessKeySecret, err := jmespath.Search("AccessKeySecret", data)
if err != nil {
err = fmt.Errorf("refresh Ecs sts token err, fail to get AccessKeySecret: %s", err.Error())
return
}
securityToken, err := jmespath.Search("SecurityToken", data)
if err != nil {
err = fmt.Errorf("refresh Ecs sts token err, fail to get SecurityToken: %s", err.Error())
return
}
if accessKeyID == nil || accessKeySecret == nil || securityToken == nil {
err = fmt.Errorf("there is no any available accesskey, secret and security token for Ecs role %s", c.EcsRoleName)
return
}
return accessKeyID.(string), accessKeySecret.(string), securityToken.(string), nil
}
func (c *Config) MakeConfigByEcsRoleName() error {
accessKey, secretKey, token, err := c.getAuthCredentialByEcsRoleName()
if err != nil {
return err
}
c.AccessKey, c.SecretKey, c.SecurityToken = accessKey, secretKey, token
return nil
}