@@ -32,33 +32,48 @@ namespace Aliyun.Acs.Core.Auth
32
32
public class ECSMetadataServiceCredentialsFetcher : AlibabaCloudCredentialsProvider
33
33
{
34
34
private const string URL_IN_ECS_METADATA = "/latest/meta-data/ram/security-credentials/" ;
35
- private const int DEFAULT_TIMEOUT_IN_MILLISECONDS = 5000 ;
35
+ private const string URL_IN_ECS_METADATA_TOKEN = "/latest/api/token" ;
36
+ private const int DEFAULT_TIMEOUT_IN_MILLISECONDS = 1000 ;
36
37
37
38
private const string ECS_METADAT_FETCH_ERROR_MSG =
38
39
"Failed to get RAM session credentials from ECS metadata service." ;
39
40
40
41
// stands for 3600 s
41
42
private const int DEFAULT_ECS_SESSION_TOKEN_DURATION_SECONDS = 3600 ;
42
- private int connectionTimeoutInMilliseconds ;
43
43
private string credentialUrl ;
44
44
private string metadataServiceHost = "100.100.100.200" ;
45
45
private string roleName ;
46
+ private readonly bool disableIMDSv1 ;
47
+ private const int metadataTokenDuration = 21600 ;
48
+ private int connectionTimeout ;
49
+ private int readTimeout ;
46
50
47
51
public ECSMetadataServiceCredentialsFetcher ( )
48
52
{
49
- connectionTimeoutInMilliseconds = DEFAULT_TIMEOUT_IN_MILLISECONDS ;
53
+ this . connectionTimeout = DEFAULT_TIMEOUT_IN_MILLISECONDS ;
54
+ this . readTimeout = DEFAULT_TIMEOUT_IN_MILLISECONDS ;
55
+ this . disableIMDSv1 = false ;
56
+ }
57
+
58
+ public ECSMetadataServiceCredentialsFetcher ( string roleName , bool ? disableIMDSv1 , int ? connectionTimeout , int ? readTimeout )
59
+ {
60
+ this . roleName = roleName ;
61
+ this . disableIMDSv1 = disableIMDSv1 != null && ( bool ) disableIMDSv1 ;
62
+ this . connectionTimeout = connectionTimeout == null ? 1000 : connectionTimeout . Value ;
63
+ this . readTimeout = readTimeout == null ? 1000 : readTimeout . Value ;
50
64
}
51
65
52
66
public AlibabaCloudCredentials GetCredentials ( )
53
67
{
54
68
return Fetch ( ) ;
55
69
}
56
70
71
+ [ Obsolete ]
57
72
public void SetRoleName ( string roleName )
58
73
{
59
74
if ( string . IsNullOrEmpty ( roleName ) )
60
75
{
61
- throw new ArgumentNullException ( "You must specifiy a valid role name." ) ;
76
+ throw new ArgumentException ( "You must specify a valid role name." ) ;
62
77
}
63
78
64
79
this . roleName = roleName ;
@@ -75,33 +90,54 @@ private void SetCredentialUrl()
75
90
credentialUrl = "http://" + metadataServiceHost + URL_IN_ECS_METADATA + roleName ;
76
91
}
77
92
93
+ [ Obsolete ]
78
94
public void WithECSMetadataServiceHost ( string host )
79
95
{
80
96
metadataServiceHost = host ;
81
97
SetCredentialUrl ( ) ;
82
98
}
83
99
100
+ [ Obsolete ]
84
101
public void WithConnectionTimeout ( int milliseconds )
85
102
{
86
- connectionTimeoutInMilliseconds = milliseconds ;
103
+ this . connectionTimeout = milliseconds ;
104
+ this . readTimeout = milliseconds ;
87
105
}
88
106
107
+ [ Obsolete ]
89
108
public string GetMetadata ( )
90
109
{
91
- var request = new HttpRequest ( credentialUrl ) ;
110
+ return GetMetadata ( credentialUrl ) ;
111
+ }
112
+
113
+ private string GetMetadata ( string url )
114
+ {
115
+ var request = new HttpRequest ( url ) ;
92
116
request . Method = MethodType . GET ;
93
- request . SetConnectTimeoutInMilliSeconds ( connectionTimeoutInMilliseconds ) ;
117
+ request . SetConnectTimeoutInMilliSeconds ( this . connectionTimeout ) ;
118
+ request . SetReadTimeoutInMilliSeconds ( this . readTimeout ) ;
119
+ var metadataToken = this . GetMetadataToken ( ) ;
120
+
121
+ if ( metadataToken != null )
122
+ {
123
+ request . Headers . Add ( "X-aliyun-ecs-metadata-token" , metadataToken ) ;
124
+ }
94
125
95
126
HttpResponse response ;
96
127
try
97
128
{
98
129
response = GetResponse ( request ) ;
99
130
}
100
- catch ( WebException e )
131
+ catch ( Exception e )
101
132
{
102
133
throw new ClientException ( "Failed to connect ECS Metadata Service: " + e ) ;
103
134
}
104
135
136
+ if ( 404 == response . Status )
137
+ {
138
+ throw new ClientException ( "The role name was not found in the instance." ) ;
139
+ }
140
+
105
141
if ( response . Status != 200 )
106
142
{
107
143
throw new ClientException ( ECS_METADAT_FETCH_ERROR_MSG + " HttpCode=" + response . Status ) ;
@@ -110,12 +146,60 @@ public string GetMetadata()
110
146
return Encoding . UTF8 . GetString ( response . Content ) ;
111
147
}
112
148
149
+ private string GetMetadataToken ( )
150
+ {
151
+ try
152
+ {
153
+ HttpRequest httpRequest = new HttpRequest ( "http://" + metadataServiceHost + URL_IN_ECS_METADATA_TOKEN )
154
+ {
155
+ Method = MethodType . PUT
156
+ } ;
157
+ httpRequest . SetConnectTimeoutInMilliSeconds ( this . connectionTimeout ) ;
158
+ httpRequest . SetReadTimeoutInMilliSeconds ( this . readTimeout ) ;
159
+ httpRequest . Headers . Add ( "X-aliyun-ecs-metadata-token-ttl-seconds" , metadataTokenDuration . ToString ( ) ) ;
160
+
161
+ HttpResponse httpResponse ;
162
+ try
163
+ {
164
+ httpResponse = GetResponse ( httpRequest ) ;
165
+ }
166
+ catch ( Exception ex )
167
+ {
168
+ throw new ClientException ( "Failed to connect ECS Metadata Service: " + ex ) ;
169
+ }
170
+ if ( httpResponse != null && httpResponse . Status != 200 )
171
+ {
172
+ throw new ClientException ( "Failed to get token from ECS Metadata Service. HttpCode=" + httpResponse . Status + ", ResponseMessage=" + httpResponse . GetHttpContentString ( ) ) ;
173
+ }
174
+ return httpResponse . GetHttpContentString ( ) ;
175
+ }
176
+ catch ( Exception ex )
177
+ {
178
+ return ThrowErrorOrReturn ( ex ) ;
179
+ }
180
+ }
181
+
182
+ private string ThrowErrorOrReturn ( Exception e )
183
+ {
184
+ if ( this . disableIMDSv1 )
185
+ {
186
+ throw new ClientException ( "Failed to get token from ECS Metadata Service, and fallback to IMDS v1 is disabled via the disableIMDSv1 configuration is turned on. Original error: " + e . Message ) ;
187
+ }
188
+ return null ;
189
+ }
190
+
113
191
public virtual InstanceProfileCredentials Fetch ( )
114
192
{
115
193
Dictionary < string , string > dic ;
194
+ var roleName = this . roleName ;
195
+ if ( string . IsNullOrEmpty ( this . roleName ) )
196
+ {
197
+ roleName = GetMetadata ( "http://" + metadataServiceHost + URL_IN_ECS_METADATA ) ;
198
+ }
199
+
116
200
try
117
201
{
118
- var jsonContent = GetMetadata ( ) ;
202
+ var jsonContent = GetMetadata ( "http://" + metadataServiceHost + URL_IN_ECS_METADATA + roleName ) ;
119
203
120
204
IReader reader = new JsonReader ( ) ;
121
205
dic = reader . Read ( jsonContent , "" ) ;
0 commit comments