@brunsforge/aarm 0.1.0
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/README.md +1180 -0
- package/dist/aarm.cjs +39260 -0
- package/dist/aarm.mjs +39262 -0
- package/dist/commands/apps.d.ts +2 -0
- package/dist/commands/apps.js +32 -0
- package/dist/commands/apps.js.map +1 -0
- package/dist/commands/preflight.d.ts +2 -0
- package/dist/commands/preflight.js +160 -0
- package/dist/commands/preflight.js.map +1 -0
- package/dist/commands/report.d.ts +2 -0
- package/dist/commands/report.js +166 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/commands/secrets.d.ts +2 -0
- package/dist/commands/secrets.js +88 -0
- package/dist/commands/secrets.js.map +1 -0
- package/dist/commands/tenants.d.ts +2 -0
- package/dist/commands/tenants.js +209 -0
- package/dist/commands/tenants.js.map +1 -0
- package/dist/commands/usage.d.ts +2 -0
- package/dist/commands/usage.js +203 -0
- package/dist/commands/usage.js.map +1 -0
- package/dist/config/ConfigStore.d.ts +12 -0
- package/dist/config/ConfigStore.js +53 -0
- package/dist/config/ConfigStore.js.map +1 -0
- package/dist/config/CredentialStore.d.ts +8 -0
- package/dist/config/CredentialStore.js +29 -0
- package/dist/config/CredentialStore.js.map +1 -0
- package/dist/config/HistoryStore.d.ts +19 -0
- package/dist/config/HistoryStore.js +64 -0
- package/dist/config/HistoryStore.js.map +1 -0
- package/dist/exitCodes.d.ts +9 -0
- package/dist/exitCodes.js +10 -0
- package/dist/exitCodes.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/output/formatters.d.ts +10 -0
- package/dist/output/formatters.js +129 -0
- package/dist/output/formatters.js.map +1 -0
- package/dist/shared/context.d.ts +31 -0
- package/dist/shared/context.js +124 -0
- package/dist/shared/context.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { mkdir, readdir, readFile, writeFile, unlink } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const MAX_FILES_PER_SLOT = 50;
|
|
4
|
+
export class HistoryStore {
|
|
5
|
+
configDir;
|
|
6
|
+
constructor(configDir) {
|
|
7
|
+
this.configDir = configDir;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Persist a scan or preflight result.
|
|
11
|
+
* Failures are silently swallowed — history is a side effect, never a blocker.
|
|
12
|
+
*/
|
|
13
|
+
async save(type, tenantId, data) {
|
|
14
|
+
try {
|
|
15
|
+
const dir = this.slotDir(tenantId);
|
|
16
|
+
await mkdir(dir, { recursive: true });
|
|
17
|
+
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
18
|
+
await writeFile(join(dir, `${type}-${ts}.json`), JSON.stringify(data, null, 2), 'utf8');
|
|
19
|
+
await this.prune(type, dir);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// intentionally silent
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Load the most recent saved result for the given type.
|
|
27
|
+
* Returns null if no history exists or on any read error.
|
|
28
|
+
*/
|
|
29
|
+
async loadLatest(type, tenantId) {
|
|
30
|
+
try {
|
|
31
|
+
const dir = this.slotDir(tenantId);
|
|
32
|
+
const files = await this.listFiles(type, dir);
|
|
33
|
+
if (files.length === 0)
|
|
34
|
+
return null;
|
|
35
|
+
const raw = await readFile(join(dir, files[files.length - 1]), 'utf8');
|
|
36
|
+
return JSON.parse(raw);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
slotDir(tenantId) {
|
|
43
|
+
return join(this.configDir, 'history', tenantId);
|
|
44
|
+
}
|
|
45
|
+
async listFiles(type, dir) {
|
|
46
|
+
try {
|
|
47
|
+
const all = await readdir(dir);
|
|
48
|
+
return all
|
|
49
|
+
.filter((f) => f.startsWith(`${type}-`) && f.endsWith('.json'))
|
|
50
|
+
.sort();
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async prune(type, dir) {
|
|
57
|
+
const files = await this.listFiles(type, dir);
|
|
58
|
+
if (files.length <= MAX_FILES_PER_SLOT)
|
|
59
|
+
return;
|
|
60
|
+
const stale = files.slice(0, files.length - MAX_FILES_PER_SLOT);
|
|
61
|
+
await Promise.all(stale.map((f) => unlink(join(dir, f)).catch(() => undefined)));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=HistoryStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HistoryStore.js","sourceRoot":"","sources":["../../src/config/HistoryStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exitCodes.js","sourceRoot":"","sources":["../src/exitCodes.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,EAAE,EAAE,CAAC;IACL,KAAK,EAAE,CAAC;IACR,WAAW,EAAE,CAAC;IACd,kBAAkB,EAAE,CAAC;IACrB,cAAc,EAAE,CAAC;IACjB,cAAc,EAAE,CAAC;IACjB,kBAAkB,EAAE,EAAE;CACd,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { registerAppsCommand } from './commands/apps.js';
|
|
5
|
+
import { registerPreflightCommand } from './commands/preflight.js';
|
|
6
|
+
import { registerSecretsCommand } from './commands/secrets.js';
|
|
7
|
+
import { registerTenantsCommand } from './commands/tenants.js';
|
|
8
|
+
import { registerUsageCommand } from './commands/usage.js';
|
|
9
|
+
import { registerReportCommand } from './commands/report.js';
|
|
10
|
+
const program = new Command();
|
|
11
|
+
program
|
|
12
|
+
.name('aarm')
|
|
13
|
+
.description('Azure App Registration Monitor — inspect and track Entra client secrets')
|
|
14
|
+
.version('0.1.0', '-V, --version', 'Print version')
|
|
15
|
+
.option('--tenant <name-or-id>', 'Tenant display name or ID from local config')
|
|
16
|
+
.option('--config-dir <path>', 'Override default config directory (~/.aarm)')
|
|
17
|
+
.option('--output <format>', 'Output format: table, json', 'table')
|
|
18
|
+
.option('--verbose', 'Enable verbose output', false)
|
|
19
|
+
.option('--no-color', 'Disable color output')
|
|
20
|
+
// Show help when aarm is called with no arguments
|
|
21
|
+
.action(() => program.help());
|
|
22
|
+
// Enable `aarm help [command]` in addition to `aarm [command] --help`
|
|
23
|
+
program.addHelpCommand('help [command]', 'Display help for a command');
|
|
24
|
+
program.hook('preAction', (_thisCommand, actionCommand) => {
|
|
25
|
+
const { color } = program.opts();
|
|
26
|
+
if (!color)
|
|
27
|
+
chalk.level = 0;
|
|
28
|
+
if (actionCommand === program)
|
|
29
|
+
return; // avoid recursion from the .action above
|
|
30
|
+
});
|
|
31
|
+
registerTenantsCommand(program);
|
|
32
|
+
registerAppsCommand(program);
|
|
33
|
+
registerSecretsCommand(program);
|
|
34
|
+
registerPreflightCommand(program);
|
|
35
|
+
registerUsageCommand(program);
|
|
36
|
+
registerReportCommand(program);
|
|
37
|
+
program.parse(process.argv);
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CAAC,yEAAyE,CAAC;KACtF,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,eAAe,CAAC;KAClD,MAAM,CAAC,uBAAuB,EAAE,6CAA6C,CAAC;KAC9E,MAAM,CAAC,qBAAqB,EAAE,6CAA6C,CAAC;KAC5E,MAAM,CAAC,mBAAmB,EAAE,4BAA4B,EAAE,OAAO,CAAC;KAClE,MAAM,CAAC,WAAW,EAAE,uBAAuB,EAAE,KAAK,CAAC;KACnD,MAAM,CAAC,YAAY,EAAE,sBAAsB,CAAC;IAC7C,kDAAkD;KACjD,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAEhC,sEAAsE;AACtE,OAAO,CAAC,cAAc,CAAC,gBAAgB,EAAE,4BAA4B,CAAC,CAAC;AAEvE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,YAAY,EAAE,aAAa,EAAE,EAAE;IACxD,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,IAAI,EAAsB,CAAC;IACrD,IAAI,CAAC,KAAK;QAAE,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;IAC5B,IAAI,aAAa,KAAK,OAAO;QAAE,OAAO,CAAC,yCAAyC;AAClF,CAAC,CAAC,CAAC;AAEH,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,wBAAwB,CAAC,OAAO,CAAC,CAAC;AAClC,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAE/B,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AppRegistrationSummary, SecretSummary, TenantProfile } from '@brunsforge/azure-app-registration-monitor';
|
|
2
|
+
import type { ResultEnvelope } from '@brunsforge/azure-app-registration-monitor';
|
|
3
|
+
export declare function printJson<T>(envelope: ResultEnvelope<T>): void;
|
|
4
|
+
export declare function riskColor(level: string): string;
|
|
5
|
+
export declare function statusColor(status: string): string;
|
|
6
|
+
export declare function printTenantsTable(tenants: TenantProfile[]): void;
|
|
7
|
+
export declare function printAppsTable(apps: AppRegistrationSummary[]): void;
|
|
8
|
+
export declare function secretsToMarkdown(secrets: SecretSummary[], tenantId: string, _envName?: string): string;
|
|
9
|
+
export declare function secretsToCsv(secrets: SecretSummary[]): string;
|
|
10
|
+
export declare function printSecretsTable(secrets: SecretSummary[]): void;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import Table from 'cli-table3';
|
|
3
|
+
export function printJson(envelope) {
|
|
4
|
+
process.stdout.write(JSON.stringify(envelope, null, 2) + '\n');
|
|
5
|
+
}
|
|
6
|
+
export function riskColor(level) {
|
|
7
|
+
switch (level) {
|
|
8
|
+
case 'Critical': return chalk.red.bold(level);
|
|
9
|
+
case 'High': return chalk.red(level);
|
|
10
|
+
case 'Medium': return chalk.yellow(level);
|
|
11
|
+
case 'Low': return chalk.cyan(level);
|
|
12
|
+
default: return chalk.dim(level);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function statusColor(status) {
|
|
16
|
+
switch (status) {
|
|
17
|
+
case 'Expired': return chalk.red.bold(status);
|
|
18
|
+
case 'ExpiringSoon': return chalk.yellow(status);
|
|
19
|
+
case 'Valid': return chalk.green(status);
|
|
20
|
+
default: return chalk.dim(status);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function printTenantsTable(tenants) {
|
|
24
|
+
if (tenants.length === 0) {
|
|
25
|
+
process.stdout.write('No tenants configured. Run "aarm tenants add" to add one.\n');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const table = new Table({
|
|
29
|
+
head: ['Name', 'Tenant ID', 'Auth Mode', 'Client ID', 'Last Scan'],
|
|
30
|
+
style: { head: ['cyan'] },
|
|
31
|
+
});
|
|
32
|
+
for (const t of tenants) {
|
|
33
|
+
table.push([
|
|
34
|
+
t.displayName,
|
|
35
|
+
t.tenantId,
|
|
36
|
+
t.authMode,
|
|
37
|
+
t.clientId ?? '-',
|
|
38
|
+
t.lastSuccessfulScanAt
|
|
39
|
+
? new Date(t.lastSuccessfulScanAt).toLocaleDateString()
|
|
40
|
+
: 'Never',
|
|
41
|
+
]);
|
|
42
|
+
}
|
|
43
|
+
process.stdout.write(table.toString() + '\n');
|
|
44
|
+
}
|
|
45
|
+
export function printAppsTable(apps) {
|
|
46
|
+
if (apps.length === 0) {
|
|
47
|
+
process.stdout.write('No App Registrations found.\n');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const table = new Table({
|
|
51
|
+
head: ['Risk', 'App Name', 'Client ID', 'Secrets', 'Expired', 'Expiring'],
|
|
52
|
+
style: { head: ['cyan'] },
|
|
53
|
+
});
|
|
54
|
+
for (const a of apps) {
|
|
55
|
+
table.push([
|
|
56
|
+
riskColor(a.riskLevel),
|
|
57
|
+
a.displayName,
|
|
58
|
+
a.appId,
|
|
59
|
+
String(a.secretCount),
|
|
60
|
+
a.expiredSecretCount > 0 ? chalk.red(String(a.expiredSecretCount)) : '0',
|
|
61
|
+
a.expiringSecretCount > 0 ? chalk.yellow(String(a.expiringSecretCount)) : '0',
|
|
62
|
+
]);
|
|
63
|
+
}
|
|
64
|
+
process.stdout.write(table.toString() + '\n');
|
|
65
|
+
process.stdout.write(chalk.dim(`${apps.length} app registration(s)\n`));
|
|
66
|
+
}
|
|
67
|
+
export function secretsToMarkdown(secrets, tenantId, _envName) {
|
|
68
|
+
const lines = [
|
|
69
|
+
`# Secret Expiry Report`,
|
|
70
|
+
``,
|
|
71
|
+
`**Tenant:** ${tenantId} **Generated:** ${new Date().toISOString().slice(0, 10)}`,
|
|
72
|
+
``,
|
|
73
|
+
`| Risk | App | Secret | Key ID | Expires | Days | Status |`,
|
|
74
|
+
`|------|-----|--------|--------|---------|------|--------|`,
|
|
75
|
+
];
|
|
76
|
+
for (const s of secrets) {
|
|
77
|
+
const expires = s.endDateTime ? new Date(s.endDateTime).toISOString().slice(0, 10) : '—';
|
|
78
|
+
const days = s.daysUntilExpiry !== null ? String(s.daysUntilExpiry) : '—';
|
|
79
|
+
const keyShort = s.keyId ? s.keyId.slice(0, 8) + '…' : '—';
|
|
80
|
+
lines.push(`| ${s.riskLevel} | ${s.appDisplayName} | ${s.displayName ?? '—'} | ${keyShort} | ${expires} | ${days} | ${s.status} |`);
|
|
81
|
+
}
|
|
82
|
+
lines.push('');
|
|
83
|
+
return lines.join('\n');
|
|
84
|
+
}
|
|
85
|
+
export function secretsToCsv(secrets) {
|
|
86
|
+
const header = 'risk,app,appId,secret,keyId,startDate,endDate,daysUntilExpiry,status';
|
|
87
|
+
const rows = secrets.map((s) => {
|
|
88
|
+
const csv = (v) => `"${(v ?? '').replace(/"/g, '""')}"`;
|
|
89
|
+
return [
|
|
90
|
+
csv(s.riskLevel),
|
|
91
|
+
csv(s.appDisplayName),
|
|
92
|
+
csv(s.appId),
|
|
93
|
+
csv(s.displayName),
|
|
94
|
+
csv(s.keyId),
|
|
95
|
+
csv(s.startDateTime),
|
|
96
|
+
csv(s.endDateTime),
|
|
97
|
+
String(s.daysUntilExpiry ?? ''),
|
|
98
|
+
csv(s.status),
|
|
99
|
+
].join(',');
|
|
100
|
+
});
|
|
101
|
+
return [header, ...rows, ''].join('\n');
|
|
102
|
+
}
|
|
103
|
+
export function printSecretsTable(secrets) {
|
|
104
|
+
if (secrets.length === 0) {
|
|
105
|
+
process.stdout.write('No secrets found.\n');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const table = new Table({
|
|
109
|
+
head: ['Risk', 'App', 'Secret', 'Expires', 'Days', 'Status'],
|
|
110
|
+
style: { head: ['cyan'] },
|
|
111
|
+
});
|
|
112
|
+
for (const s of secrets) {
|
|
113
|
+
const expires = s.endDateTime
|
|
114
|
+
? new Date(s.endDateTime).toLocaleDateString()
|
|
115
|
+
: '-';
|
|
116
|
+
const days = s.daysUntilExpiry !== null ? String(s.daysUntilExpiry) : '-';
|
|
117
|
+
table.push([
|
|
118
|
+
riskColor(s.riskLevel),
|
|
119
|
+
s.appDisplayName,
|
|
120
|
+
s.displayName ?? s.keyId,
|
|
121
|
+
expires,
|
|
122
|
+
days,
|
|
123
|
+
statusColor(s.status),
|
|
124
|
+
]);
|
|
125
|
+
}
|
|
126
|
+
process.stdout.write(table.toString() + '\n');
|
|
127
|
+
process.stdout.write(chalk.dim(`${secrets.length} secret(s)\n`));
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=formatters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatters.js","sourceRoot":"","sources":["../../src/output/formatters.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createCredential, createGraphClient, GraphApplicationReader, PreflightService, SecretInventoryService, type AuthMode, type TenantProfile } from '@brunsforge/azure-app-registration-monitor';
|
|
2
|
+
import { ConfigStore } from '../config/ConfigStore.js';
|
|
3
|
+
import { CredentialStore } from '../config/CredentialStore.js';
|
|
4
|
+
type Credential = ReturnType<typeof createCredential>;
|
|
5
|
+
type GraphClient = ReturnType<typeof createGraphClient>;
|
|
6
|
+
export interface GlobalOptions {
|
|
7
|
+
tenant?: string;
|
|
8
|
+
configDir?: string;
|
|
9
|
+
output: string;
|
|
10
|
+
verbose: boolean;
|
|
11
|
+
color: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface CommandContext {
|
|
14
|
+
configStore: ConfigStore;
|
|
15
|
+
credentialStore: CredentialStore;
|
|
16
|
+
credential: Credential;
|
|
17
|
+
graphClient: GraphClient;
|
|
18
|
+
graphReader: GraphApplicationReader;
|
|
19
|
+
inventoryService: SecretInventoryService;
|
|
20
|
+
preflightService: PreflightService;
|
|
21
|
+
tenant: TenantProfile;
|
|
22
|
+
tenantId: string;
|
|
23
|
+
environmentName: string;
|
|
24
|
+
authMode: AuthMode;
|
|
25
|
+
logAnalyticsWorkspaceId?: string;
|
|
26
|
+
isJson: boolean;
|
|
27
|
+
verbose: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare function buildContext(opts: GlobalOptions): Promise<CommandContext>;
|
|
30
|
+
export declare function handleError(err: unknown): never;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { AuthError, ConfigError, GraphError, PermissionError, createCredential, createGraphClient, GraphApplicationReader, PreflightService, SecretInventoryService, } from '@brunsforge/azure-app-registration-monitor';
|
|
2
|
+
import { ConfigStore } from '../config/ConfigStore.js';
|
|
3
|
+
import { CredentialStore } from '../config/CredentialStore.js';
|
|
4
|
+
import { EXIT } from '../exitCodes.js';
|
|
5
|
+
export async function buildContext(opts) {
|
|
6
|
+
const configStore = new ConfigStore(opts.configDir);
|
|
7
|
+
const credentialStore = new CredentialStore();
|
|
8
|
+
if (!opts.tenant) {
|
|
9
|
+
process.stderr.write('Error: --tenant is required. Run "aarm tenants list" to see configured tenants.\n');
|
|
10
|
+
process.exit(EXIT.CONFIG_INVALID);
|
|
11
|
+
}
|
|
12
|
+
const tenant = await configStore.getTenant(opts.tenant);
|
|
13
|
+
if (!tenant) {
|
|
14
|
+
process.stderr.write(`Error: Tenant "${opts.tenant}" not found. Run "aarm tenants add" to configure it.\n`);
|
|
15
|
+
process.exit(EXIT.CONFIG_INVALID);
|
|
16
|
+
}
|
|
17
|
+
let authConfig;
|
|
18
|
+
if (tenant.authMode === 'client-secret') {
|
|
19
|
+
if (!tenant.clientId) {
|
|
20
|
+
process.stderr.write(`Error: Tenant "${tenant.displayName}" has no client ID configured.\n`);
|
|
21
|
+
process.exit(EXIT.CONFIG_INVALID);
|
|
22
|
+
}
|
|
23
|
+
const secret = await credentialStore.getClientSecret(tenant.tenantId, tenant.clientId);
|
|
24
|
+
if (!secret) {
|
|
25
|
+
process.stderr.write(`Error: No client secret found for tenant "${tenant.displayName}". Re-run "aarm tenants add".\n`);
|
|
26
|
+
process.exit(EXIT.CONFIG_INVALID);
|
|
27
|
+
}
|
|
28
|
+
authConfig = {
|
|
29
|
+
mode: 'client-secret',
|
|
30
|
+
tenantId: tenant.tenantId,
|
|
31
|
+
clientId: tenant.clientId,
|
|
32
|
+
clientSecret: secret,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
else if (tenant.authMode === 'username-password') {
|
|
36
|
+
if (!tenant.clientId || !tenant.username) {
|
|
37
|
+
process.stderr.write(`Error: Tenant "${tenant.displayName}" is missing clientId or username. Re-run "aarm tenants add".\n`);
|
|
38
|
+
process.exit(EXIT.CONFIG_INVALID);
|
|
39
|
+
}
|
|
40
|
+
const password = await credentialStore.getUserPassword(tenant.tenantId, tenant.clientId, tenant.username);
|
|
41
|
+
if (!password) {
|
|
42
|
+
process.stderr.write(`Error: No password found for "${tenant.username}". Re-run "aarm tenants add".\n`);
|
|
43
|
+
process.exit(EXIT.CONFIG_INVALID);
|
|
44
|
+
}
|
|
45
|
+
authConfig = {
|
|
46
|
+
mode: 'username-password',
|
|
47
|
+
tenantId: tenant.tenantId,
|
|
48
|
+
clientId: tenant.clientId,
|
|
49
|
+
username: tenant.username,
|
|
50
|
+
password,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
else if (tenant.authMode === 'azure-cli') {
|
|
54
|
+
authConfig = { mode: 'azure-cli', tenantId: tenant.tenantId };
|
|
55
|
+
}
|
|
56
|
+
else if (tenant.authMode === 'workload-identity-federation') {
|
|
57
|
+
process.stderr.write(`Error: The "workload-identity-federation" auth mode requires an Azure-hosted runtime\n` +
|
|
58
|
+
`(Function App, VM, ACI) and cannot be used with the aarm CLI.\n` +
|
|
59
|
+
`For unattended automation use "client-secret" or "certificate".\n` +
|
|
60
|
+
`For interactive use on a developer workstation use "device-code".\n`);
|
|
61
|
+
process.exit(EXIT.CONFIG_INVALID);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
if (!tenant.clientId) {
|
|
65
|
+
process.stderr.write(`Error: Tenant "${tenant.displayName}" has no client ID configured.\n`);
|
|
66
|
+
process.exit(EXIT.CONFIG_INVALID);
|
|
67
|
+
}
|
|
68
|
+
authConfig = {
|
|
69
|
+
mode: tenant.authMode,
|
|
70
|
+
tenantId: tenant.tenantId,
|
|
71
|
+
clientId: tenant.clientId,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const credential = createCredential(authConfig);
|
|
75
|
+
const graphClient = createGraphClient(credential);
|
|
76
|
+
const graphReader = new GraphApplicationReader(graphClient);
|
|
77
|
+
const inventoryService = new SecretInventoryService(graphReader);
|
|
78
|
+
const preflightService = new PreflightService(graphClient, credential);
|
|
79
|
+
return {
|
|
80
|
+
configStore,
|
|
81
|
+
credentialStore,
|
|
82
|
+
credential,
|
|
83
|
+
graphClient,
|
|
84
|
+
graphReader,
|
|
85
|
+
inventoryService,
|
|
86
|
+
preflightService,
|
|
87
|
+
tenant,
|
|
88
|
+
tenantId: tenant.tenantId,
|
|
89
|
+
environmentName: tenant.defaultEnvironmentName ?? 'default',
|
|
90
|
+
authMode: tenant.authMode,
|
|
91
|
+
logAnalyticsWorkspaceId: tenant.logAnalyticsWorkspaceId,
|
|
92
|
+
isJson: opts.output === 'json',
|
|
93
|
+
verbose: opts.verbose,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export function handleError(err) {
|
|
97
|
+
if (err instanceof AuthError) {
|
|
98
|
+
process.stderr.write(`Authentication failed: ${err.message}\n`);
|
|
99
|
+
process.stderr.write('Check: correct tenant ID, client ID, secret value, and that the App Registration exists.\n');
|
|
100
|
+
process.exit(EXIT.AUTH_FAILED);
|
|
101
|
+
}
|
|
102
|
+
if (err instanceof PermissionError) {
|
|
103
|
+
process.stderr.write(`Permission denied: ${err.message}\n`);
|
|
104
|
+
process.stderr.write('Check: Application.Read.All is in API permissions AND admin consent has been granted.\n' +
|
|
105
|
+
'Run "aarm --tenant <name> preflight explain" for detailed grant instructions.\n');
|
|
106
|
+
process.exit(EXIT.PERMISSION_MISSING);
|
|
107
|
+
}
|
|
108
|
+
if (err instanceof GraphError) {
|
|
109
|
+
process.stderr.write(`Graph API error: ${err.message}\n`);
|
|
110
|
+
process.exit(EXIT.ERROR);
|
|
111
|
+
}
|
|
112
|
+
if (err instanceof ConfigError) {
|
|
113
|
+
process.stderr.write(`Configuration error: ${err.message}\n`);
|
|
114
|
+
process.exit(EXIT.CONFIG_INVALID);
|
|
115
|
+
}
|
|
116
|
+
if (err instanceof Error) {
|
|
117
|
+
process.stderr.write(`Error: ${err.message}\n`);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
process.stderr.write(`Unexpected error: ${String(err)}\n`);
|
|
121
|
+
}
|
|
122
|
+
process.exit(EXIT.ERROR);
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/shared/context.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@brunsforge/aarm",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Azure App Registration Monitor CLI — aarm binary for monitoring Entra client secrets",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"private": false,
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"aarm": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=18"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/brunsforge/AzureAppRegistrationSecretMonitor.git",
|
|
24
|
+
"directory": "packages/cli"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc",
|
|
28
|
+
"build:bundle": "node esbuild.config.mjs",
|
|
29
|
+
"dev": "node --import tsx/esm src/index.ts"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@brunsforge/azure-app-registration-monitor": "^0.1.0",
|
|
33
|
+
"chalk": "^5.3.0",
|
|
34
|
+
"cli-table3": "^0.6.5",
|
|
35
|
+
"commander": "^12.0.0",
|
|
36
|
+
"keytar": "^7.9.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^22.0.0",
|
|
40
|
+
"esbuild": "^0.21.0",
|
|
41
|
+
"typescript": "^5.5.0"
|
|
42
|
+
}
|
|
43
|
+
}
|