@@ -14,6 +14,7 @@ import (
14
14
"net"
15
15
"net/http"
16
16
"os"
17
+ "strconv"
17
18
"strings"
18
19
"time"
19
20
@@ -22,7 +23,25 @@ import (
22
23
"github.com/aws/aws-sdk-go-v2/aws/defaults"
23
24
)
24
25
25
- const disableServiceEnvVar = "AWS_EC2_METADATA_DISABLED"
26
+ const (
27
+ // ServiceName is the name of the service.
28
+ ServiceName = "ec2metadata"
29
+ disableServiceEnvVar = "AWS_EC2_METADATA_DISABLED"
30
+
31
+ // Headers for Token and TTL
32
+ ttlHeader = "x-aws-ec2-metadata-token-ttl-seconds"
33
+ tokenHeader = "x-aws-ec2-metadata-token"
34
+
35
+ // Named Handler constants
36
+ fetchTokenHandlerName = "FetchTokenHandler"
37
+ unmarshalMetadataHandlerName = "unmarshalMetadataHandler"
38
+ unmarshalTokenHandlerName = "unmarshalTokenHandler"
39
+ enableTokenProviderHandlerName = "enableTokenProviderHandler"
40
+
41
+ // TTL constants
42
+ defaultTTL = 21600 * time .Second
43
+ ttlExpirationWindow = 30 * time .Second
44
+ )
26
45
27
46
// A Client is an EC2 Instance Metadata service Client.
28
47
type Client struct {
@@ -61,7 +80,20 @@ func New(config aws.Config) *Client {
61
80
),
62
81
}
63
82
64
- svc .Handlers .Unmarshal .PushBack (unmarshalHandler )
83
+ // token provider instance
84
+ tp := newTokenProvider (svc , defaultTTL )
85
+ // NamedHandler for fetching token
86
+ svc .Handlers .Sign .PushBackNamed (aws.NamedHandler {
87
+ Name : fetchTokenHandlerName ,
88
+ Fn : tp .fetchTokenHandler ,
89
+ })
90
+ // NamedHandler for enabling token provider
91
+ svc .Handlers .Complete .PushBackNamed (aws.NamedHandler {
92
+ Name : enableTokenProviderHandlerName ,
93
+ Fn : tp .enableTokenProviderHandler ,
94
+ })
95
+
96
+ svc .Handlers .Unmarshal .PushBackNamed (unmarshalHandler )
65
97
svc .Handlers .UnmarshalError .PushBack (unmarshalError )
66
98
svc .Handlers .Validate .Clear ()
67
99
svc .Handlers .Validate .PushBack (validateEndpointHandler )
@@ -91,30 +123,74 @@ type metadataOutput struct {
91
123
Content string
92
124
}
93
125
94
- func unmarshalHandler (r * aws.Request ) {
95
- defer r .HTTPResponse .Body .Close ()
96
- b := & bytes.Buffer {}
97
- if _ , err := io .Copy (b , r .HTTPResponse .Body ); err != nil {
98
- r .Error = awserr .New ("SerializationError" , "unable to unmarshal EC2 metadata respose" , err )
99
- return
100
- }
126
+ type tokenOutput struct {
127
+ Token string
128
+ TTL time.Duration
129
+ }
101
130
102
- if data , ok := r .Data .(* metadataOutput ); ok {
103
- data .Content = b .String ()
104
- }
131
+ // unmarshal token handler is used to parse the response of a getToken operation
132
+ var unmarshalTokenHandler = aws.NamedHandler {
133
+ Name : unmarshalTokenHandlerName ,
134
+ Fn : func (r * aws.Request ) {
135
+ defer r .HTTPResponse .Body .Close ()
136
+ var b bytes.Buffer
137
+ if _ , err := io .Copy (& b , r .HTTPResponse .Body ); err != nil {
138
+ r .Error = awserr .NewRequestFailure (awserr .New (aws .ErrCodeSerialization ,
139
+ "unable to unmarshal EC2 metadata response" , err ), r .HTTPResponse .StatusCode , r .RequestID )
140
+ return
141
+ }
142
+
143
+ v := r .HTTPResponse .Header .Get (ttlHeader )
144
+ data , ok := r .Data .(* tokenOutput )
145
+ if ! ok {
146
+ return
147
+ }
148
+
149
+ data .Token = b .String ()
150
+ // TTL is in seconds
151
+ i , err := strconv .ParseInt (v , 10 , 64 )
152
+ if err != nil {
153
+ r .Error = awserr .NewRequestFailure (awserr .New (aws .ParamFormatErrCode ,
154
+ "unable to parse EC2 token TTL response" , err ), r .HTTPResponse .StatusCode , r .RequestID )
155
+ return
156
+ }
157
+ t := time .Duration (i ) * time .Second
158
+ data .TTL = t
159
+ },
160
+ }
161
+
162
+ var unmarshalHandler = aws.NamedHandler {
163
+ Name : unmarshalMetadataHandlerName ,
164
+ Fn : func (r * aws.Request ) {
165
+ defer r .HTTPResponse .Body .Close ()
166
+ var b bytes.Buffer
167
+ if _ , err := io .Copy (& b , r .HTTPResponse .Body ); err != nil {
168
+ r .Error = awserr .NewRequestFailure (awserr .New (aws .ErrCodeSerialization ,
169
+ "unable to unmarshal EC2 metadata response" , err ), r .HTTPResponse .StatusCode , r .RequestID )
170
+ return
171
+ }
172
+
173
+ if data , ok := r .Data .(* metadataOutput ); ok {
174
+ data .Content = b .String ()
175
+ }
176
+ },
105
177
}
106
178
107
179
func unmarshalError (r * aws.Request ) {
108
180
defer r .HTTPResponse .Body .Close ()
109
- b := & bytes.Buffer {}
110
- if _ , err := io .Copy (b , r .HTTPResponse .Body ); err != nil {
111
- r .Error = awserr .New ("SerializationError" , "unable to unmarshal EC2 metadata error respose" , err )
181
+ var b bytes.Buffer
182
+
183
+ if _ , err := io .Copy (& b , r .HTTPResponse .Body ); err != nil {
184
+ r .Error = awserr .NewRequestFailure (
185
+ awserr .New (aws .ErrCodeSerialization , "unable to unmarshal EC2 metadata error response" , err ),
186
+ r .HTTPResponse .StatusCode , r .RequestID )
112
187
return
113
188
}
114
189
115
190
// Response body format is not consistent between metadata endpoints.
116
191
// Grab the error message as a string and include that as the source error
117
- r .Error = awserr .New ("EC2MetadataError" , "failed to make Client request" , errors .New (b .String ()))
192
+ r .Error = awserr .NewRequestFailure (awserr .New ("EC2MetadataError" , "failed to make EC2Metadata request" , errors .New (b .String ())),
193
+ r .HTTPResponse .StatusCode , r .RequestID )
118
194
}
119
195
120
196
func validateEndpointHandler (r * aws.Request ) {
0 commit comments