В своем приложении для узлов я использую пакеты npm "azure-keyvault" и "ms-rest-azure", чтобы загрузить 20 секретов из keyvault в переменные среды process.env
. При запуске приложения происходит сбой с ошибкой:
Ошибка: неверный ответ токена, не найден tokenType. Тело ответа: {"error": "invalid_request", "error_description": "Временно удушено, слишком много запросов"}
at Request.request.get [as _callback] (/app/node_modules/ms-rest-azure/lib/credentials/msiVmTokenCredentials.js:52:17)
at Request.self.callback (/app/node_modules/request/request.js:185:22)
на emitTwo (events.js: 126: 13)
в Request.emit (events.js: 214: 7)
по запросу. (/App/node_modules/request/request.js:1161:10)
в emitOne (events.js: 116: 13)
в Request.emit (events.js: 211: 7)
на входящем сообщении. (/App/node_modules/request/request.js:1083:12)
в Object.onceWrapper (events.js: 313: 30)
на emitNone (events.js: 111: 20)
на IncomingMessage.emit (events.js: 208: 7)
в endReadableNT (_stream_readable.js: 1064: 12)
в _combinedTickCallback (внутренняя / process / next_tick.js: 139: 11)
at process._tickCallback (internal / process / next_tick.js: 181: 9)
Мой подход заключается в том, чтобы получить токен доступа (либо через субъект-службу, либо через MSI, в зависимости от того, работаю ли я локально или в Azure), а затем использовать его для запроса хранилища ключей для секретов.
MS имеет документы, касающиеся регулирования запросов, которые, по сути, keyvault может выполнять 2000 секретных преобразований в каждом интервале 10 с. Очевидно, я не достиг этого предела.
https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#secrets-managed-storage-account-keys-and-vault-transactions
Также, что смешно: у меня нет проблем при запуске его локально. Сейчас он выдает ошибки при попытке запустить его на виртуальной машине в Azure.
Кто-то тоже испытал это?
Вот код
import {ApplicationTokenCredentials, MSIVmTokenCredentials, loginWithServicePrincipalSecret, loginWithMSI} from 'ms-rest-azure';
import {KeyVaultClient} from 'azure-keyvault';
export class Env {
public static getAccessToken(): Promise<ApplicationTokenCredentials> {
// use service principal when running locally because MSI is not available here
if (process.env.NODE_ENV !== 'remote') {
return loginWithServicePrincipalSecret(process.env.SP_ID, process.env.SP_SEC, process.env.SP_TEN);
} else { // remote
return loginWithMSI({resource: 'https://vault.azure.net'});
}
}
public static getSecret(credentials: MSIVmTokenCredentials, secretName: string): Promise<string> {
let client = new KeyVaultClient(credentials);
const keyVaultUrl: string = `https://${process.env.VAULT_NAME}.vault.azure.net`;
return client.getSecret(keyVaultUrl, secretName, "").then(secret => secret.value);
}
public static decodeBase64(base64: string) { return Buffer.from(base64, 'base64').toString("utf8"); }
}
import * as express from 'express';
import {
Env
} from './env';
class Server {
// set app to be of type express.Application
public app: express.Application;
constructor() {
this.app = express();
this._setEnvs().then(() => {
this._config();
this._routes();
this._startReminderCronJob();
});
}
private _setEnvs(): Promise < void > {
return Env.getAccessToken()
.then(token => {
return Promise.all([
Env.getSecret(token, 'my-secret'),
...
Env.getSecret(token, 'another-secret'),
])
}).then(secrets => {
process.env.SECRET_1 = secrets[0];
...
process.env.SECRET_20 = secrets[19];
}).catch(err => console.log(err)); // error is logged here
}
private _config(): void {}
private _routes(): void {}
private _startReminderCronJob(): void {}
}
export default new Server().app;