iamguard
Version:
A command-line tool for scanning and analyzing AWS IAM configurations for security risks
299 lines (251 loc) • 10.4 kB
JavaScript
import { Command } from "commander";
import chalk from "chalk";
import {
fetchIamPolicies,
analyzeIamPolicies,
checkIamUsers,
checkIamRoles,
checkPasswordPolicy,
generateSecurityReport,
getAccountInfo
} from "../lib/iamScanner.js";
import { checkAwsCredentials, handleError } from './utils.js';
import { spinner } from './spinner.js';
import { CICDHandler } from '../lib/cicdHandler.js';
const program = new Command();
// Read version from package.json
import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8'));
const VERSION = packageJson.version;
const banner = `
╔═══════════════════════════════════════╗
║ IAM Guard ║
║ Security Scan Tool v${VERSION} ║
╚═══════════════════════════════════════╝
`;
try {
program
.name("iamguard")
.description(chalk.cyan(banner))
.version(VERSION);
program
.command("scan")
.description("Scan IAM policies for security risks")
.option("-q, --quiet", "Suppress detailed output")
.action(async (options) => {
try {
if (!options.quiet) {
console.log(chalk.cyan(banner));
}
// Check AWS credentials
const credentialsSpinner = spinner.start('Checking AWS credentials...');
await checkAwsCredentials();
spinner.succeed(credentialsSpinner, 'AWS credentials verified');
const scanSpinner = spinner.start('Starting IAM security scan...');
const startTime = Date.now();
const policies = await fetchIamPolicies();
if (policies.length === 0) {
spinner.info(scanSpinner, "⚠️ No IAM policies found.");
return;
}
spinner.succeed(scanSpinner, 'Policies fetched, analyzing...');
const analysisSpinner = spinner.start('Analyzing IAM policies...');
await analyzeIamPolicies(policies);
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
spinner.succeed(analysisSpinner, `✅ Scan completed in ${duration} seconds`);
} catch (error) {
spinner.fail(scanSpinner, "Error during policy scan");
console.error(chalk.red(error.message));
process.exit(1);
}
});
program
.command("check-users")
.description("Check IAM users for security risks")
.option("-q, --quiet", "Suppress detailed output")
.action(async (options) => {
try {
if (!options.quiet) {
console.log(chalk.cyan(banner));
}
// Check AWS credentials
const credentialsSpinner = spinner.start('Checking AWS credentials...');
await checkAwsCredentials();
spinner.succeed(credentialsSpinner, 'AWS credentials verified');
const userSpinner = spinner.start('Checking IAM users...');
const startTime = Date.now();
await checkIamUsers();
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
spinner.succeed(userSpinner, `✅ User check completed in ${duration} seconds`);
} catch (error) {
spinner.fail(userSpinner, "Error during user check");
console.error(chalk.red(error.message));
process.exit(1);
}
});
program
.command("check-roles")
.description("Check IAM roles for security risks")
.option("-q, --quiet", "Suppress detailed output")
.action(async (options) => {
try {
if (!options.quiet) {
console.log(chalk.cyan(banner));
}
// Check AWS credentials
const credentialsSpinner = spinner.start('Checking AWS credentials...');
await checkAwsCredentials();
spinner.succeed(credentialsSpinner, 'AWS credentials verified');
const roleSpinner = spinner.start('Checking IAM roles...');
const startTime = Date.now();
await checkIamRoles();
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
spinner.succeed(roleSpinner, `✅ Role check completed in ${duration} seconds`);
} catch (error) {
spinner.fail(roleSpinner, "Error during role check");
console.error(chalk.red(error.message));
process.exit(1);
}
});
program
.command("check-password-policy")
.description("Check IAM password policy configuration")
.option("-q, --quiet", "Suppress detailed output")
.action(async (options) => {
try {
if (!options.quiet) {
console.log(chalk.cyan(banner));
}
// Check AWS credentials
const credentialsSpinner = spinner.start('Checking AWS credentials...');
await checkAwsCredentials();
spinner.succeed(credentialsSpinner, 'AWS credentials verified');
const policySpinner = spinner.start('Checking IAM password policy...');
const startTime = Date.now();
await checkPasswordPolicy();
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
spinner.succeed(policySpinner, `✅ Password policy check completed in ${duration} seconds`);
} catch (error) {
spinner.fail(policySpinner, "Error checking password policy");
console.error(chalk.red(error.message));
process.exit(1);
}
});
program
.command("generate-report")
.description("Run all checks and generate a comprehensive security report")
.option("-q, --quiet", "Suppress detailed output")
.option("-f, --format <type>", "Output format (json)", "json")
.option("--cicd", "Enable CI/CD mode with exit codes")
.option("--fail-on-critical", "Exit with code 1 on critical issues")
.option("--fail-on-high", "Exit with code 2 on high severity issues")
.option("--max-medium <number>", "Maximum allowed medium severity issues", "10")
.option("--max-low <number>", "Maximum allowed low severity issues", "50")
.action(async (options) => {
try {
if (!options.quiet) {
console.log(chalk.cyan(banner));
}
// Check AWS credentials
const credentialsSpinner = spinner.start('Checking AWS credentials...');
await checkAwsCredentials();
spinner.succeed(credentialsSpinner, 'AWS credentials verified');
const reportSpinner = spinner.start('Starting comprehensive IAM security scan...');
const startTime = Date.now();
let success = true;
let accountInfo = null;
try {
spinner.info(reportSpinner, 'Getting account information...');
accountInfo = await getAccountInfo();
} catch (error) {
console.warn(chalk.yellow('Warning: Could not retrieve account information'));
}
try {
spinner.info(reportSpinner, 'Fetching and analyzing IAM policies...');
const policies = await fetchIamPolicies();
await analyzeIamPolicies(policies);
} catch (error) {
success = false;
spinner.fail(reportSpinner, "Error during policy scan");
console.error(chalk.red(error.message));
}
try {
spinner.info(reportSpinner, 'Checking IAM users...');
await checkIamUsers();
} catch (error) {
success = false;
spinner.fail(reportSpinner, "Error during user check");
console.error(chalk.red(error.message));
}
try {
spinner.info(reportSpinner, 'Checking IAM roles...');
await checkIamRoles();
} catch (error) {
success = false;
spinner.fail(reportSpinner, "Error during role check");
console.error(chalk.red(error.message));
}
try {
spinner.info(reportSpinner, 'Checking password policy...');
await checkPasswordPolicy();
} catch (error) {
success = false;
spinner.fail(reportSpinner, "Error during password policy check");
console.error(chalk.red(error.message));
}
spinner.info(reportSpinner, 'Generating security report...');
// Configure CI/CD options
const cicdConfig = {
failOnCritical: options.failOnCritical || options.cicd,
failOnHigh: options.failOnHigh,
maxMediumIssues: parseInt(options.maxMedium),
maxLowIssues: parseInt(options.maxLow),
enableExitCodes: options.cicd,
suppressBanner: options.cicd && options.quiet
};
const reportOptions = {
cicdMode: options.cicd,
cicdConfig: cicdConfig,
quiet: options.quiet
};
const analysis = await generateSecurityReport(accountInfo, reportOptions);
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
if (success) {
spinner.succeed(reportSpinner, `✅ Security scan completed successfully in ${duration} seconds`);
} else {
spinner.warn(reportSpinner, `⚠️ Security scan completed with some errors in ${duration} seconds`);
}
// Handle CI/CD exit codes
if (options.cicd && analysis) {
const cicdHandler = new CICDHandler(cicdConfig);
cicdHandler.handleExit(analysis);
} else if (!success) {
process.exit(1);
}
} catch (error) {
spinner.fail(reportSpinner, "Error generating security report");
console.error(chalk.red(error.message));
process.exit(1);
}
});
program.addHelpText('after', `
Examples:
$ iamguard scan # Scan IAM policies
$ iamguard check-users # Check IAM users
$ iamguard check-roles # Check IAM roles
$ iamguard check-password-policy # Check password policy
$ iamguard generate-report # Generate comprehensive report
$ iamguard generate-report -q # Generate report with minimal output
`);
program.parse(process.argv);
if (!process.argv.slice(2).length) {
program.outputHelp();
}
} catch (error) {
handleError(error);
}