@@ -16,6 +16,8 @@ class Iam implements IamTokenContract
16
16
17
17
const IAM_TOKEN_API_URL = 'https://iam.api.cloud.yandex.net/iam/v1/tokens ' ;
18
18
19
+ const METADATA_URL = 'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token ' ;
20
+
19
21
const DEFAULT_TOKEN_EXPIRES_AT = 2 ; // hours
20
22
21
23
/**
@@ -86,7 +88,11 @@ public function newToken()
86
88
{
87
89
$ this ->logger ()->info ('YDB: Obtaining new IAM token... ' );
88
90
89
- if ($ this ->config ('private_key ' ))
91
+ if ($ this ->config ('use_metadata ' ))
92
+ {
93
+ return $ this ->requestTokenFromMetadata ();
94
+ }
95
+ else if ($ this ->config ('private_key ' ))
90
96
{
91
97
$ token = $ this ->getJwtToken ();
92
98
@@ -174,7 +180,11 @@ protected function initConfig()
174
180
$ this ->config ['temp_dir ' ] = sys_get_temp_dir ();
175
181
}
176
182
177
- if (!empty ($ this ->config ['service_file ' ]))
183
+ if (!empty ($ this ->config ['use_metadata ' ]))
184
+ {
185
+ $ this ->logger ()->info ('YDB: Authentication method: Metadata URL ' );
186
+ }
187
+ else if (!empty ($ this ->config ['service_file ' ]))
178
188
{
179
189
if (is_file ($ this ->config ['service_file ' ]))
180
190
{
@@ -250,6 +260,67 @@ protected function getJwtToken()
250
260
return $ token ;
251
261
}
252
262
263
+ /**
264
+ * @return string|null
265
+ * @throws Exception
266
+ */
267
+ protected function requestTokenFromMetadata ()
268
+ {
269
+ $ curl = curl_init (static ::METADATA_URL );
270
+
271
+ curl_setopt_array ($ curl , [
272
+ CURLOPT_RETURNTRANSFER => 1 ,
273
+ CURLOPT_SSL_VERIFYPEER => 0 ,
274
+ CURLOPT_SSL_VERIFYHOST => 0 ,
275
+ CURLOPT_HEADER => 0 ,
276
+ CURLOPT_HTTPHEADER => [
277
+ 'Accept: application/json ' ,
278
+ 'Metadata-Flavor:Google ' ,
279
+ ],
280
+ ]);
281
+
282
+ $ result = curl_exec ($ curl );
283
+
284
+ $ status = curl_getinfo ($ curl , CURLINFO_HTTP_CODE );
285
+
286
+ if ($ status === 200 )
287
+ {
288
+ $ rawToken = json_decode ($ result );
289
+
290
+ if (isset ($ rawToken ->access_token ))
291
+ {
292
+ $ token = (object )[
293
+ 'iamToken ' => $ rawToken ->access_token ,
294
+ ];
295
+ if (isset ($ rawToken ->expires_in ))
296
+ {
297
+ $ token ->expiresAt = time () + $ rawToken ->expires_in ;
298
+ }
299
+ $ this ->logger ()->info ('YDB: Obtained new IAM token from Metadata [... ' . substr ($ token ->iamToken , -6 ) . ']. ' );
300
+ $ this ->saveToken ($ token );
301
+ return $ token ->iamToken ;
302
+ }
303
+ else
304
+ {
305
+ $ this ->logger ()->error ('YDB: Failed to obtain new IAM token from Metadata ' , [
306
+ 'status ' => $ status ,
307
+ 'result ' => $ result ,
308
+ ]);
309
+ throw new Exception ('Failed to obtain new iamToken from Metadata: no token was received. ' );
310
+ }
311
+ }
312
+ else
313
+ {
314
+ $ this ->logger ()->error ('YDB: Failed to obtain new IAM token from Metadata ' , [
315
+ 'status ' => $ status ,
316
+ 'result ' => $ result ,
317
+ ]);
318
+ throw new Exception ('Failed to obtain new iamToken from Metadata: response status is ' . $ status );
319
+ }
320
+
321
+
322
+ }
323
+
253
324
/**
254
325
* @var string
255
326
*/
@@ -325,7 +396,7 @@ protected function saveToken($token)
325
396
$ tokenFile = $ this ->getTokenTempFile ();
326
397
327
398
$ this ->iam_token = $ token ->iamToken ;
328
- $ this ->expires_at = $ this ->convertExpiresAt ($ token ->expiresAt );
399
+ $ this ->expires_at = $ this ->convertExpiresAt ($ token ->expiresAt ?? '' );
329
400
330
401
file_put_contents ($ tokenFile , json_encode ([
331
402
'iamToken ' => $ this ->iam_token ,
@@ -339,6 +410,11 @@ protected function saveToken($token)
339
410
*/
340
411
protected function convertExpiresAt ($ expiresAt )
341
412
{
413
+ if (is_int ($ expiresAt ))
414
+ {
415
+ return $ expiresAt ;
416
+ }
417
+
342
418
$ time = time () + 60 * 60 * static ::DEFAULT_TOKEN_EXPIRES_AT ;
343
419
if (preg_match ('/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.\d+)?(.*)$/ ' , $ expiresAt , $ matches ))
344
420
{
0 commit comments