11import * as fs from 'node:fs'
22import * as path from 'node:path'
3- import { createPrivateKey , sign } from 'node:crypto'
3+ import { constants , createPrivateKey , sign } from 'node:crypto'
44import { CredentialsProvider } from '@ydbjs/auth'
55import { loggers } from '@ydbjs/debug'
66import { type RetryConfig , retry } from '@ydbjs/retry'
@@ -80,12 +80,18 @@ export class ServiceAccountCredentialsProvider extends CredentialsProvider {
8080 )
8181 }
8282
83+ // Yandex Cloud authorized keys may contain a warning line before the PEM key
84+ // Remove it if present to get clean PEM format
85+ if ( key . private_key . includes ( 'PLEASE DO NOT REMOVE' ) ) {
86+ key . private_key = key . private_key . replace ( / ^ .* ?- - - - - B E G I N P R I V A T E K E Y - - - - - / s, '-----BEGIN PRIVATE KEY-----' )
87+ }
88+
8389 this . #key = key
8490 if ( options ?. iamEndpoint ) {
8591 this . #iamEndpoint = options . iamEndpoint
8692 }
8793
88- dbg . log ( 'creating service account credentials provider for SA: %s' , key . service_account_id )
94+ dbg . log ( 'creating service account credentials provider for SA: %s (key ID: %s) ' , key . service_account_id , key . id )
8995 }
9096
9197 /**
@@ -161,12 +167,16 @@ export class ServiceAccountCredentialsProvider extends CredentialsProvider {
161167 return this . #promise
162168 }
163169
164- dbg . log ( 'fetching new IAM token (token expired or force=true)' )
170+ dbg . log ( 'fetching new IAM token (token expired or force=true, key ID: %s)' , this . #key . id )
165171
166172 this . #promise = ( async ( ) : Promise < string > => {
167173 try {
168174 this . #token = await this . #fetchIamToken( signal )
169- dbg . log ( 'IAM token fetched successfully, expires at %s' , new Date ( this . #token. expires_at ) . toISOString ( ) )
175+ dbg . log (
176+ 'IAM token fetched successfully, expires at %s (key ID: %s)' ,
177+ new Date ( this . #token. expires_at ) . toISOString ( ) ,
178+ this . #key. id
179+ )
170180 return this . #token. value
171181 } finally {
172182 this . #promise = null
@@ -191,14 +201,15 @@ export class ServiceAccountCredentialsProvider extends CredentialsProvider {
191201 try {
192202 this . #token = await this . #fetchIamToken( signal )
193203 dbg . log (
194- 'background IAM token refresh successful, expires at %s' ,
195- new Date ( this . #token. expires_at ) . toISOString ( )
204+ 'background IAM token refresh successful, expires at %s (key ID: %s)' ,
205+ new Date ( this . #token. expires_at ) . toISOString ( ) ,
206+ this . #key. id
196207 )
197208 return this . #token. value
198209 } catch ( error ) {
199210 // Don't throw - failed background refresh will retry on next getToken call
200211 // Return existing token if available to avoid breaking ongoing requests
201- dbg . log ( 'background IAM token refresh failed: %O' , error )
212+ dbg . log ( 'background IAM token refresh failed: %O (key ID: %s) ' , error , this . #key . id )
202213 if ( this . #token) {
203214 return this . #token. value
204215 }
@@ -296,7 +307,7 @@ export class ServiceAccountCredentialsProvider extends CredentialsProvider {
296307 // - https://datatracker.ietf.org/doc/html/rfc7518#section-3.5 (JWT PS256 algorithm specification)
297308 let signature = sign ( 'sha256' , Buffer . from ( unsignedToken ) , {
298309 key : privateKey ,
299- padding : 1 , // RSA_PKCS1_PSS_PADDING constant value
310+ padding : constants . RSA_PKCS1_PSS_PADDING ,
300311 saltLength : 32 ,
301312 } )
302313
@@ -325,7 +336,12 @@ export class ServiceAccountCredentialsProvider extends CredentialsProvider {
325336 return strategy ? strategy ( ctx , cfg ) : 0
326337 } ,
327338 onRetry : ( ctx ) => {
328- dbg . log ( 'retrying IAM token fetch, attempt %d, error: %O' , ctx . attempt , ctx . error )
339+ dbg . log (
340+ 'retrying IAM token fetch, attempt %d, error: %O (key ID: %s)' ,
341+ ctx . attempt ,
342+ ctx . error ,
343+ this . #key. id
344+ )
329345 } ,
330346 }
331347
0 commit comments