feat: add assign-role command to manage Key Vault roles for domain certificates
This commit is contained in:
+42
@@ -1,9 +1,17 @@
|
||||
#!/usr/bin/env node
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { writeFileSync } from 'node:fs';
|
||||
import { AuthorizationManagementClient } from '@azure/arm-authorization';
|
||||
import { DefaultAzureCredential } from '@azure/identity';
|
||||
import { Command } from 'commander';
|
||||
import { loadConfig } from './lib/config.js';
|
||||
import { domainToCertName, Provisioner } from './lib/provisioner.js';
|
||||
|
||||
const ROLE_IDS = {
|
||||
'Key Vault Certificate User': 'db79e9a7-68ee-4b58-9aeb-b90e7c24fcba',
|
||||
'Key Vault Secrets User': '4633458b-17de-408a-b874-0445c86b69e6',
|
||||
} as const;
|
||||
|
||||
const program = new Command();
|
||||
|
||||
program
|
||||
@@ -31,6 +39,7 @@ function applyOverrides(options: Record<string, unknown>): void {
|
||||
const sharedOptions = (cmd: Command): Command =>
|
||||
cmd
|
||||
.option('--keyvault-url <url>', 'Azure KeyVault URL')
|
||||
.option('--keyvault-resource-group <rg>', 'Resource group containing the Key Vault')
|
||||
.option('--subscription-id <id>', 'Azure subscription ID')
|
||||
.option('--resource-group <rg>', 'Resource group to scan (repeatable)', collect, [])
|
||||
.option('--dns-zone <zone>', 'Restrict to specific DNS zone (repeatable)', collect, [])
|
||||
@@ -120,6 +129,39 @@ sharedOptions(
|
||||
if (result.errors.length > 0) process.exit(1);
|
||||
});
|
||||
|
||||
sharedOptions(
|
||||
program
|
||||
.command('assign-role <domain>')
|
||||
.description('Assign Key Vault Certificate User and Secrets User roles to a principal for a domain certificate')
|
||||
.requiredOption('--principal-id <id>', 'Azure principal ID to assign roles to')
|
||||
).action(async (domain: string, options: Record<string, unknown>) => {
|
||||
applyOverrides(options);
|
||||
const config = loadConfig();
|
||||
if (!config.subscriptionId) throw new Error('--subscription-id is required');
|
||||
if (!config.keyVaultUrl) throw new Error('--keyvault-url is required');
|
||||
const kvRg = options['keyvaultResourceGroup'];
|
||||
if (!kvRg) throw new Error('--keyvault-resource-group is required');
|
||||
|
||||
const sub = config.subscriptionId;
|
||||
const principalId = String(options['principalId']);
|
||||
const vaultName = new URL(config.keyVaultUrl).hostname.split('.')[0];
|
||||
const certName = domainToCertName(domain);
|
||||
const vaultBase = `/subscriptions/${sub}/resourceGroups/${kvRg}/providers/Microsoft.KeyVault/vaults/${vaultName}`;
|
||||
const credential = new DefaultAzureCredential();
|
||||
const authClient = new AuthorizationManagementClient(credential, sub);
|
||||
|
||||
const assignments = [
|
||||
{ role: 'Key Vault Certificate User' as const, scope: `${vaultBase}/certificates/${certName}` },
|
||||
{ role: 'Key Vault Secrets User' as const, scope: `${vaultBase}/secrets/${certName}` },
|
||||
];
|
||||
|
||||
for (const { role, scope } of assignments) {
|
||||
const roleDefinitionId = `/subscriptions/${sub}/providers/Microsoft.Authorization/roleDefinitions/${ROLE_IDS[role]}`;
|
||||
await authClient.roleAssignments.create(scope, randomUUID(), { roleDefinitionId, principalId });
|
||||
console.log(`Assigned '${role}' to ${principalId} on ${scope}`);
|
||||
}
|
||||
});
|
||||
|
||||
sharedOptions(
|
||||
program
|
||||
.command('download <domain>')
|
||||
|
||||
Reference in New Issue
Block a user