akv-manager 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/server.js +25 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akv-manager",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Local web console to browse and manage Azure Key Vaults — secrets, keys, certificates, expiry — using your own az login. No credentials are stored.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "server.js",
|
package/server.js
CHANGED
|
@@ -274,11 +274,20 @@ const VAULT_QUERY =
|
|
|
274
274
|
async function listVaultsRaw(force) {
|
|
275
275
|
if (!force && vaultCache.data && Date.now() - vaultCache.at < VAULT_TTL) return vaultCache.data;
|
|
276
276
|
const subIds = (await listSubscriptions(force)).map((s) => s.subscriptionId);
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
277
|
+
// Resource Graph returns at most 1000 rows per page; follow $skipToken to get them all.
|
|
278
|
+
const data = [];
|
|
279
|
+
let skipToken;
|
|
280
|
+
for (let page = 0; page < 100; page++) { // hard stop at 100k vaults — a safety bound
|
|
281
|
+
const options = { resultFormat: 'objectArray', $top: 1000 };
|
|
282
|
+
if (skipToken) options.$skipToken = skipToken;
|
|
283
|
+
const out = await armFetch('/providers/Microsoft.ResourceGraph/resources?api-version=2021-03-01', {
|
|
284
|
+
method: 'POST',
|
|
285
|
+
body: { subscriptions: subIds, query: VAULT_QUERY, options },
|
|
286
|
+
});
|
|
287
|
+
if (out.data) data.push(...out.data);
|
|
288
|
+
skipToken = out.$skipToken;
|
|
289
|
+
if (!skipToken) break;
|
|
290
|
+
}
|
|
282
291
|
vaultCache = { at: Date.now(), data };
|
|
283
292
|
return data;
|
|
284
293
|
}
|
|
@@ -535,6 +544,15 @@ app.patch('/api/vaults/:name/certificates/:cert', (req, res) => {
|
|
|
535
544
|
send(res, kvWrite(name, 'PATCH', `/certificates/${cert}?api-version=${KV_API}`, { attributes: attrs }));
|
|
536
545
|
});
|
|
537
546
|
|
|
547
|
+
// Turn a write failure into a precise, actionable reason. A 403 from Key Vault is
|
|
548
|
+
// either a network/firewall block (fix: VPN) or a real data-plane permission gap
|
|
549
|
+
// (fix: grant Set on secrets) — never conflate the two as a bare "forbidden".
|
|
550
|
+
function writeReason(e) {
|
|
551
|
+
if (e.firewall) return 'blocked by the vault firewall — your IP is not allowed (connect to the corporate VPN)';
|
|
552
|
+
if (e.forbidden) return 'no write permission — your identity can read but not Set secrets on this vault';
|
|
553
|
+
return e.message || 'failed';
|
|
554
|
+
}
|
|
555
|
+
|
|
538
556
|
// Create one or many secrets in a vault. items: [{name, value}], optional common expires.
|
|
539
557
|
app.post('/api/vaults/:name/secrets-create', async (req, res) => {
|
|
540
558
|
const { name } = req.params;
|
|
@@ -552,7 +570,7 @@ app.post('/api/vaults/:name/secrets-create', async (req, res) => {
|
|
|
552
570
|
if (Object.keys(attrs).length) body.attributes = attrs;
|
|
553
571
|
await kvWrite(name, 'PUT', `/secrets/${it.name}?api-version=${KV_API}`, body);
|
|
554
572
|
return { ...r, ok: true };
|
|
555
|
-
} catch (e) { return { ...r, ok: false, error: e.
|
|
573
|
+
} catch (e) { return { ...r, ok: false, error: writeReason(e), firewall: !!e.firewall, forbidden: !!e.forbidden }; }
|
|
556
574
|
}, 10);
|
|
557
575
|
res.json({ ok: true, results });
|
|
558
576
|
});
|
|
@@ -577,7 +595,7 @@ app.post('/api/batch', async (req, res) => {
|
|
|
577
595
|
await kvWrite(it.vault, 'PATCH', `/secrets/${it.name}?api-version=${KV_API}`, { attributes: attrs });
|
|
578
596
|
}
|
|
579
597
|
return { ...r, ok: true };
|
|
580
|
-
} catch (e) { return { ...r, ok: false, error: e.
|
|
598
|
+
} catch (e) { return { ...r, ok: false, error: writeReason(e), firewall: !!e.firewall, forbidden: !!e.forbidden }; }
|
|
581
599
|
}, 12);
|
|
582
600
|
res.json({ ok: true, results });
|
|
583
601
|
});
|