@mtndev/cli 1.1.0 → 2.0.1
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/CHANGELOG.md +91 -0
- package/cjs/__chunks/VH7oDXx4.cjs +28 -0
- package/cjs/commands/aws/ec2/allow-ip/handler.cjs +261 -0
- package/cjs/commands/aws/ec2/allow-ip/handler.d.ts +6 -0
- package/cjs/commands/aws/ec2/allow-ip/index.cjs +25 -0
- package/cjs/commands/aws/ec2/allow-ip/index.d.ts +3 -0
- package/cjs/commands/aws/ec2/allow-ip/schema.cjs +33 -0
- package/cjs/commands/aws/ec2/allow-ip/schema.d.ts +33 -0
- package/cjs/commands/aws/ec2/allow-ip/utils.cjs +379 -0
- package/cjs/commands/aws/ec2/allow-ip/utils.d.ts +189 -0
- package/cjs/commands/aws/iam/admin-group.cjs +111 -0
- package/cjs/commands/aws/iam/admin-group.d.ts +55 -0
- package/cjs/commands/aws/iam/break-glass/handler.cjs +127 -0
- package/cjs/commands/aws/iam/break-glass/handler.d.ts +7 -0
- package/cjs/commands/aws/iam/break-glass/index.cjs +7 -0
- package/cjs/commands/aws/iam/break-glass/index.d.ts +2 -0
- package/cjs/commands/aws/iam/break-glass/schema.cjs +21 -0
- package/cjs/commands/aws/iam/break-glass/schema.d.ts +25 -0
- package/cjs/commands/aws/iam/check-admin/handler.cjs +89 -0
- package/cjs/commands/aws/iam/check-admin/handler.d.ts +5 -0
- package/cjs/commands/aws/iam/check-admin/index.cjs +7 -0
- package/cjs/commands/aws/iam/check-admin/index.d.ts +2 -0
- package/cjs/commands/aws/iam/check-admin/schema.cjs +19 -0
- package/cjs/commands/aws/iam/check-admin/schema.d.ts +19 -0
- package/cjs/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.json +20 -0
- package/cjs/commands/aws/iam/policies/sts-federation.json +11 -0
- package/cjs/commands/aws/iam/policies/user-admins-deny-list.json +175 -0
- package/cjs/commands/aws/iam/policies/user-admins-deny-regions-list.json +41 -0
- package/cjs/commands/aws/iam/policies/user-admins-self-service-iam.json +56 -0
- package/cjs/commands/aws/iam/policies/user-admins-write-list.json +117 -0
- package/cjs/commands/aws/iam/remove-admin/handler.cjs +120 -0
- package/cjs/commands/aws/iam/remove-admin/handler.d.ts +6 -0
- package/cjs/commands/aws/iam/remove-admin/index.cjs +7 -0
- package/cjs/commands/aws/iam/remove-admin/index.d.ts +2 -0
- package/cjs/commands/aws/iam/remove-admin/schema.cjs +22 -0
- package/cjs/commands/aws/iam/remove-admin/schema.d.ts +28 -0
- package/cjs/commands/aws/iam/setup-acl/handler.cjs +227 -0
- package/cjs/commands/aws/iam/setup-acl/handler.d.ts +6 -0
- package/cjs/commands/aws/iam/setup-acl/index.cjs +13 -0
- package/cjs/commands/aws/iam/setup-acl/index.d.ts +3 -0
- package/cjs/commands/aws/iam/setup-acl/schema.cjs +19 -0
- package/cjs/commands/aws/iam/setup-acl/schema.d.ts +24 -0
- package/cjs/commands/aws/iam/setup-acl/utils.cjs +305 -0
- package/cjs/commands/aws/iam/setup-acl/utils.d.ts +61 -0
- package/cjs/commands/aws/iam/users/handler.cjs +59 -0
- package/cjs/commands/aws/iam/users/handler.d.ts +5 -0
- package/cjs/commands/aws/iam/users/index.cjs +18 -0
- package/cjs/commands/aws/iam/users/index.d.ts +3 -0
- package/cjs/commands/aws/iam/users/schema.cjs +17 -0
- package/cjs/commands/aws/iam/users/schema.d.ts +18 -0
- package/cjs/commands/aws/iam/users/utils.cjs +454 -0
- package/cjs/commands/aws/iam/users/utils.d.ts +119 -0
- package/cjs/commands/aws/index.cjs +223 -0
- package/cjs/commands/aws/index.d.ts +14 -0
- package/cjs/commands/aws/route53/add-record/handler.cjs +264 -0
- package/cjs/commands/aws/route53/add-record/handler.d.ts +36 -0
- package/cjs/commands/aws/route53/add-record/index.cjs +26 -0
- package/cjs/commands/aws/route53/add-record/index.d.ts +3 -0
- package/cjs/commands/aws/route53/add-record/schema.cjs +43 -0
- package/cjs/commands/aws/route53/add-record/schema.d.ts +45 -0
- package/cjs/commands/aws/route53/add-record/utils.cjs +404 -0
- package/cjs/commands/aws/route53/add-record/utils.d.ts +216 -0
- package/cjs/commands/aws/route53/remove-record/handler.cjs +114 -0
- package/cjs/commands/aws/route53/remove-record/handler.d.ts +6 -0
- package/cjs/commands/aws/route53/remove-record/index.cjs +5 -0
- package/cjs/commands/aws/route53/remove-record/index.d.ts +2 -0
- package/cjs/commands/aws/route53/remove-record/schema.cjs +22 -0
- package/cjs/commands/aws/route53/remove-record/schema.d.ts +30 -0
- package/cjs/commands/aws/schema.cjs +19 -0
- package/cjs/commands/aws/schema.d.ts +13 -0
- package/cjs/commands/aws/ses/send-email/handler.cjs +73 -0
- package/cjs/commands/aws/ses/send-email/handler.d.ts +5 -0
- package/cjs/commands/aws/ses/send-email/index.cjs +9 -0
- package/cjs/commands/aws/ses/send-email/index.d.ts +3 -0
- package/cjs/commands/aws/ses/send-email/schema.cjs +24 -0
- package/cjs/commands/aws/ses/send-email/schema.d.ts +39 -0
- package/cjs/commands/aws/ses/send-email/utils.cjs +87 -0
- package/cjs/commands/aws/ses/send-email/utils.d.ts +47 -0
- package/cjs/commands/aws/ses/smtp-password.cjs +72 -0
- package/cjs/commands/aws/ses/smtp-password.d.ts +21 -0
- package/cjs/commands/aws/utils/exec-aws.cjs +145 -0
- package/cjs/commands/aws/utils/exec-aws.d.ts +79 -0
- package/cjs/commands/aws/utils/resolve-policy-path.cjs +15 -0
- package/cjs/commands/aws/utils/resolve-policy-path.d.ts +8 -0
- package/cjs/commands/aws/utils/resolve-profile.cjs +93 -0
- package/cjs/commands/aws/utils/resolve-profile.d.ts +28 -0
- package/cjs/commands/aws/utils/tty.cjs +54 -0
- package/cjs/commands/aws/utils/tty.d.ts +24 -0
- package/cjs/commands/db/create-readonly-user/handler.cjs +254 -0
- package/cjs/commands/db/create-readonly-user/handler.d.ts +5 -0
- package/cjs/commands/db/create-readonly-user/index.cjs +18 -0
- package/cjs/commands/db/create-readonly-user/index.d.ts +3 -0
- package/cjs/commands/db/create-readonly-user/mysql.cjs +102 -0
- package/cjs/commands/db/create-readonly-user/mysql.d.ts +33 -0
- package/cjs/commands/db/create-readonly-user/postgres.cjs +209 -0
- package/cjs/commands/db/create-readonly-user/postgres.d.ts +31 -0
- package/cjs/commands/db/create-readonly-user/schema.cjs +39 -0
- package/cjs/commands/db/create-readonly-user/schema.d.ts +55 -0
- package/cjs/commands/db/create-readonly-user/utils.cjs +160 -0
- package/cjs/commands/db/create-readonly-user/utils.d.ts +112 -0
- package/cjs/commands/db/index.cjs +46 -0
- package/cjs/commands/db/index.d.ts +6 -0
- package/cjs/commands/doppler/handler.cjs +95 -9
- package/cjs/commands/doppler/index.cjs +33 -41
- package/cjs/commands/doppler/index.d.ts +1 -0
- package/cjs/commands/doppler/schema.cjs +130 -6
- package/cjs/commands/doppler/schema.d.ts +233 -17
- package/cjs/commands/doppler/set-secret.cjs +378 -0
- package/cjs/commands/doppler/set-secret.d.ts +113 -0
- package/cjs/commands/doppler/utils/exec.cjs +106 -12
- package/cjs/commands/doppler/utils.cjs +412 -30
- package/cjs/commands/doppler/utils.d.ts +32 -8
- package/cjs/commands/icons/handler.cjs +82 -8
- package/cjs/commands/icons/index.cjs +15 -31
- package/cjs/commands/icons/schema.cjs +101 -13
- package/cjs/commands/icons/schema.d.ts +1 -1
- package/cjs/commands/icons/utils.cjs +131 -13
- package/cjs/commands/index.cjs +54 -82
- package/cjs/commands/schema.cjs +25 -8
- package/cjs/index.cjs +3 -4
- package/esm/commands/aws/ec2/allow-ip/handler.d.ts +6 -0
- package/esm/commands/aws/ec2/allow-ip/handler.js +258 -0
- package/esm/commands/aws/ec2/allow-ip/index.d.ts +3 -0
- package/esm/commands/aws/ec2/allow-ip/index.js +4 -0
- package/esm/commands/aws/ec2/allow-ip/schema.d.ts +33 -0
- package/esm/commands/aws/ec2/allow-ip/schema.js +29 -0
- package/esm/commands/aws/ec2/allow-ip/utils.d.ts +189 -0
- package/esm/commands/aws/ec2/allow-ip/utils.js +363 -0
- package/esm/commands/aws/iam/admin-group.d.ts +55 -0
- package/esm/commands/aws/iam/admin-group.js +104 -0
- package/esm/commands/aws/iam/break-glass/handler.d.ts +7 -0
- package/esm/commands/aws/iam/break-glass/handler.js +124 -0
- package/esm/commands/aws/iam/break-glass/index.d.ts +2 -0
- package/esm/commands/aws/iam/break-glass/index.js +4 -0
- package/esm/commands/aws/iam/break-glass/schema.d.ts +25 -0
- package/esm/commands/aws/iam/break-glass/schema.js +19 -0
- package/esm/commands/aws/iam/check-admin/handler.d.ts +5 -0
- package/esm/commands/aws/iam/check-admin/handler.js +86 -0
- package/esm/commands/aws/iam/check-admin/index.d.ts +2 -0
- package/esm/commands/aws/iam/check-admin/index.js +4 -0
- package/esm/commands/aws/iam/check-admin/schema.d.ts +19 -0
- package/esm/commands/aws/iam/check-admin/schema.js +17 -0
- package/esm/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.json +20 -0
- package/esm/commands/aws/iam/policies/sts-federation.json +11 -0
- package/esm/commands/aws/iam/policies/user-admins-deny-list.json +175 -0
- package/esm/commands/aws/iam/policies/user-admins-deny-regions-list.json +41 -0
- package/esm/commands/aws/iam/policies/user-admins-self-service-iam.json +56 -0
- package/esm/commands/aws/iam/policies/user-admins-write-list.json +117 -0
- package/esm/commands/aws/iam/remove-admin/handler.d.ts +6 -0
- package/esm/commands/aws/iam/remove-admin/handler.js +117 -0
- package/esm/commands/aws/iam/remove-admin/index.d.ts +2 -0
- package/esm/commands/aws/iam/remove-admin/index.js +4 -0
- package/esm/commands/aws/iam/remove-admin/schema.d.ts +28 -0
- package/esm/commands/aws/iam/remove-admin/schema.js +20 -0
- package/esm/commands/aws/iam/setup-acl/handler.d.ts +6 -0
- package/esm/commands/aws/iam/setup-acl/handler.js +224 -0
- package/esm/commands/aws/iam/setup-acl/index.d.ts +3 -0
- package/esm/commands/aws/iam/setup-acl/index.js +4 -0
- package/esm/commands/aws/iam/setup-acl/schema.d.ts +24 -0
- package/esm/commands/aws/iam/setup-acl/schema.js +18 -0
- package/esm/commands/aws/iam/setup-acl/utils.d.ts +61 -0
- package/esm/commands/aws/iam/setup-acl/utils.js +298 -0
- package/esm/commands/aws/iam/users/handler.d.ts +5 -0
- package/esm/commands/aws/iam/users/handler.js +56 -0
- package/esm/commands/aws/iam/users/index.d.ts +3 -0
- package/esm/commands/aws/iam/users/index.js +4 -0
- package/esm/commands/aws/iam/users/schema.d.ts +18 -0
- package/esm/commands/aws/iam/users/schema.js +16 -0
- package/esm/commands/aws/iam/users/utils.d.ts +119 -0
- package/esm/commands/aws/iam/users/utils.js +440 -0
- package/esm/commands/aws/index.d.ts +14 -0
- package/esm/commands/aws/index.js +142 -0
- package/esm/commands/aws/route53/add-record/handler.d.ts +36 -0
- package/esm/commands/aws/route53/add-record/handler.js +258 -0
- package/esm/commands/aws/route53/add-record/index.d.ts +3 -0
- package/esm/commands/aws/route53/add-record/index.js +4 -0
- package/esm/commands/aws/route53/add-record/schema.d.ts +45 -0
- package/esm/commands/aws/route53/add-record/schema.js +40 -0
- package/esm/commands/aws/route53/add-record/utils.d.ts +216 -0
- package/esm/commands/aws/route53/add-record/utils.js +389 -0
- package/esm/commands/aws/route53/remove-record/handler.d.ts +6 -0
- package/esm/commands/aws/route53/remove-record/handler.js +111 -0
- package/esm/commands/aws/route53/remove-record/index.d.ts +2 -0
- package/esm/commands/aws/route53/remove-record/index.js +3 -0
- package/esm/commands/aws/route53/remove-record/schema.d.ts +30 -0
- package/esm/commands/aws/route53/remove-record/schema.js +21 -0
- package/esm/commands/aws/schema.d.ts +13 -0
- package/esm/commands/aws/schema.js +16 -0
- package/esm/commands/aws/ses/send-email/handler.d.ts +5 -0
- package/esm/commands/aws/ses/send-email/handler.js +70 -0
- package/esm/commands/aws/ses/send-email/index.d.ts +3 -0
- package/esm/commands/aws/ses/send-email/index.js +4 -0
- package/esm/commands/aws/ses/send-email/schema.d.ts +39 -0
- package/esm/commands/aws/ses/send-email/schema.js +23 -0
- package/esm/commands/aws/ses/send-email/utils.d.ts +47 -0
- package/esm/commands/aws/ses/send-email/utils.js +84 -0
- package/esm/commands/aws/ses/smtp-password.d.ts +21 -0
- package/esm/commands/aws/ses/smtp-password.js +69 -0
- package/esm/commands/aws/utils/exec-aws.d.ts +79 -0
- package/esm/commands/aws/utils/exec-aws.js +137 -0
- package/esm/commands/aws/utils/resolve-policy-path.d.ts +8 -0
- package/esm/commands/aws/utils/resolve-policy-path.js +14 -0
- package/esm/commands/aws/utils/resolve-profile.d.ts +28 -0
- package/esm/commands/aws/utils/resolve-profile.js +88 -0
- package/esm/commands/aws/utils/tty.d.ts +24 -0
- package/esm/commands/aws/utils/tty.js +51 -0
- package/esm/commands/db/create-readonly-user/handler.d.ts +5 -0
- package/esm/commands/db/create-readonly-user/handler.js +251 -0
- package/esm/commands/db/create-readonly-user/index.d.ts +3 -0
- package/esm/commands/db/create-readonly-user/index.js +4 -0
- package/esm/commands/db/create-readonly-user/mysql.d.ts +33 -0
- package/esm/commands/db/create-readonly-user/mysql.js +98 -0
- package/esm/commands/db/create-readonly-user/postgres.d.ts +31 -0
- package/esm/commands/db/create-readonly-user/postgres.js +205 -0
- package/esm/commands/db/create-readonly-user/schema.d.ts +55 -0
- package/esm/commands/db/create-readonly-user/schema.js +35 -0
- package/esm/commands/db/create-readonly-user/utils.d.ts +112 -0
- package/esm/commands/db/create-readonly-user/utils.js +151 -0
- package/esm/commands/db/index.d.ts +6 -0
- package/esm/commands/db/index.js +31 -0
- package/esm/commands/doppler/handler.js +92 -9
- package/esm/commands/doppler/index.d.ts +1 -0
- package/esm/commands/doppler/index.js +6 -41
- package/esm/commands/doppler/schema.d.ts +233 -17
- package/esm/commands/doppler/schema.js +125 -7
- package/esm/commands/doppler/set-secret.d.ts +113 -0
- package/esm/commands/doppler/set-secret.js +370 -0
- package/esm/commands/doppler/utils/exec.js +100 -12
- package/esm/commands/doppler/utils.d.ts +32 -8
- package/esm/commands/doppler/utils.js +396 -30
- package/esm/commands/icons/handler.js +79 -8
- package/esm/commands/icons/index.js +4 -31
- package/esm/commands/icons/schema.d.ts +1 -1
- package/esm/commands/icons/schema.js +97 -15
- package/esm/commands/icons/utils.js +125 -13
- package/esm/commands/index.js +49 -78
- package/esm/commands/schema.js +22 -7
- package/esm/index.js +3 -4
- package/package.json +12 -2
- package/vitest.config.ts +11 -0
- package/cjs/__chunks/4GFJUCSP.cjs +0 -52
- package/cjs/__chunks/4SFWHCB3.cjs +0 -133
- package/cjs/__chunks/B2KFW7T7.cjs +0 -1
- package/cjs/__chunks/EMMC33QA.cjs +0 -401
- package/cjs/__chunks/INFOPAHN.cjs +0 -117
- package/cjs/__chunks/J36P6UNE.cjs +0 -75
- package/cjs/__chunks/NIMXXHJQ.cjs +0 -92
- package/cjs/__chunks/NSRFG4DF.cjs +0 -100
- package/cjs/__chunks/WNJ3ZYLI.cjs +0 -1
- package/cjs/__chunks/ZMDIOZPT.cjs +0 -22
- package/esm/__chunks/46HGXFME.js +0 -0
- package/esm/__chunks/6G4PXXKF.js +0 -75
- package/esm/__chunks/6L5RNR7G.js +0 -100
- package/esm/__chunks/FL7AILGH.js +0 -133
- package/esm/__chunks/HJSXC6HP.js +0 -117
- package/esm/__chunks/O262GK4B.js +0 -401
- package/esm/__chunks/O3CCA76Q.js +0 -22
- package/esm/__chunks/SJXQJ7RS.js +0 -92
- package/esm/__chunks/SNCKIAOR.js +0 -0
- package/esm/__chunks/X3R5PSWH.js +0 -52
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { promptYesNo } from "../../utils/tty.js";
|
|
2
|
+
import { requireCommands } from "../../utils/exec-aws.js";
|
|
3
|
+
import { ADMIN_GROUP_NAME, resolveAdminScanProfiles, resolveProfileScan } from "../admin-group.js";
|
|
4
|
+
import { removeAdminOptionsSchema } from "./schema.js";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { ZodError } from "zod";
|
|
7
|
+
//#region src/commands/aws/iam/remove-admin/handler.js
|
|
8
|
+
/**
|
|
9
|
+
* `aws iam remove-admin` handler: remove users from the break-glass
|
|
10
|
+
* acl-admin-do-not-use group, either for one profile or every aws-vault profile.
|
|
11
|
+
* @param {unknown} options
|
|
12
|
+
*/
|
|
13
|
+
async function removeAdminCommand(options) {
|
|
14
|
+
try {
|
|
15
|
+
const { profile, all, user, yes, dryRun, verbose } = removeAdminOptionsSchema.parse(options);
|
|
16
|
+
requireCommands(["aws"]);
|
|
17
|
+
const userFilter = new Set(user);
|
|
18
|
+
if (all || !(profile ?? process.env.AWS_PROFILE)) requireCommands(["aws-vault"]);
|
|
19
|
+
/** @type {string[]} */
|
|
20
|
+
let profiles;
|
|
21
|
+
try {
|
|
22
|
+
profiles = resolveAdminScanProfiles({
|
|
23
|
+
profile,
|
|
24
|
+
all
|
|
25
|
+
});
|
|
26
|
+
} catch (resolveError) {
|
|
27
|
+
if (resolveError instanceof Error && resolveError.message === "No aws-vault profiles with credentials found.") {
|
|
28
|
+
console.error(chalk.red(resolveError.message));
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
throw resolveError;
|
|
32
|
+
}
|
|
33
|
+
console.log(chalk.blue(`\n==> Removing break-glass access (${ADMIN_GROUP_NAME}) across ${profiles.length} profile(s)\n`));
|
|
34
|
+
if (dryRun) console.log(chalk.yellow("[dry-run] No changes will be made.\n"));
|
|
35
|
+
let removed = 0;
|
|
36
|
+
let cleaned = 0;
|
|
37
|
+
let skipped = 0;
|
|
38
|
+
for (const candidate of profiles) {
|
|
39
|
+
const scan = resolveProfileScan({
|
|
40
|
+
profile: candidate,
|
|
41
|
+
verbose
|
|
42
|
+
});
|
|
43
|
+
if (!scan) {
|
|
44
|
+
skipped += 1;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (scan.users.length === 0) {
|
|
48
|
+
if (verbose) console.log(chalk.green(`OK ${candidate} (${scan.accountId}) — 0 users`));
|
|
49
|
+
cleaned += 1;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const targets = userFilter.size > 0 ? scan.users.filter((name) => userFilter.has(name)) : scan.users;
|
|
53
|
+
if (targets.length === 0) {
|
|
54
|
+
console.log(chalk.dim(`-- ${candidate} (${scan.accountId}) — has users but none match --user`));
|
|
55
|
+
skipped += 1;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
console.log(chalk.red(`FOUND ${candidate} (${scan.accountId}) — ${targets.length} user(s): ${targets.join(", ")}`));
|
|
59
|
+
if (dryRun) {
|
|
60
|
+
for (const name of targets) console.log(chalk.yellow(` [dry-run] would remove ${name} from ${ADMIN_GROUP_NAME}`));
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
let confirmed = yes;
|
|
64
|
+
if (!confirmed) confirmed = await promptYesNo({
|
|
65
|
+
message: ` Remove ${targets.length} user(s) from ${ADMIN_GROUP_NAME} in ${candidate}?`,
|
|
66
|
+
defaultYes: false
|
|
67
|
+
});
|
|
68
|
+
if (!confirmed) {
|
|
69
|
+
console.log(chalk.dim(" skipped (not confirmed)"));
|
|
70
|
+
skipped += 1;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
for (const name of targets) try {
|
|
74
|
+
scan.run([
|
|
75
|
+
"iam",
|
|
76
|
+
"remove-user-from-group",
|
|
77
|
+
"--group-name",
|
|
78
|
+
ADMIN_GROUP_NAME,
|
|
79
|
+
"--user-name",
|
|
80
|
+
name
|
|
81
|
+
], { expectJson: false });
|
|
82
|
+
console.log(chalk.green(` removed ${name}`));
|
|
83
|
+
removed += 1;
|
|
84
|
+
} catch (removeError) {
|
|
85
|
+
const reason = removeError instanceof Error ? removeError.message.split("\n")[0] ?? "" : String(removeError);
|
|
86
|
+
console.log(chalk.red(` failed to remove ${name}: ${reason}`));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
console.log(chalk.blue("\n==> Summary"));
|
|
90
|
+
console.log(` Profiles scanned: ${profiles.length}`);
|
|
91
|
+
console.log(` Users removed: ${removed}`);
|
|
92
|
+
console.log(` Already clean: ${cleaned}`);
|
|
93
|
+
console.log(` Skipped: ${skipped}`);
|
|
94
|
+
if (dryRun) console.log(chalk.yellow("\n[dry-run] Re-run without --dry-run to apply changes."));
|
|
95
|
+
} catch (error) {
|
|
96
|
+
if (error instanceof ZodError) {
|
|
97
|
+
console.error(chalk.red("\n❌ Invalid command options:"));
|
|
98
|
+
error.errors.forEach((err) => {
|
|
99
|
+
console.error(chalk.red(` ${err.path.join(".")}: ${err.message}`));
|
|
100
|
+
});
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
const verbose = options?.verbose || false;
|
|
104
|
+
console.error(chalk.red("\n❌ remove-admin failed:"));
|
|
105
|
+
if (error instanceof Error) {
|
|
106
|
+
console.error(chalk.red(` ${error.message}`));
|
|
107
|
+
if (verbose && error.stack) {
|
|
108
|
+
console.error(chalk.gray("\nStack trace:"));
|
|
109
|
+
console.error(chalk.gray(error.stack));
|
|
110
|
+
}
|
|
111
|
+
} else console.error(chalk.red(` ${String(error)}`));
|
|
112
|
+
console.error(chalk.yellow("\n💡 Requires the AWS CLI (and aws-vault when scanning multiple profiles) and iam:RemoveUserFromGroup.\n"));
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//#endregion
|
|
117
|
+
export { removeAdminCommand };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export { ADMIN_GROUP_NAME } from "../admin-group.js";
|
|
2
|
+
/**
|
|
3
|
+
* Zod schema for `aws iam remove-admin` options.
|
|
4
|
+
*/
|
|
5
|
+
export const removeAdminOptionsSchema: z.ZodObject<{
|
|
6
|
+
profile: z.ZodOptional<z.ZodString>;
|
|
7
|
+
all: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
8
|
+
user: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
|
|
9
|
+
yes: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
10
|
+
dryRun: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
11
|
+
verbose: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
verbose: boolean;
|
|
14
|
+
yes: boolean;
|
|
15
|
+
all: boolean;
|
|
16
|
+
user: string[];
|
|
17
|
+
dryRun: boolean;
|
|
18
|
+
profile?: string | undefined;
|
|
19
|
+
}, {
|
|
20
|
+
profile?: string | undefined;
|
|
21
|
+
verbose?: boolean | undefined;
|
|
22
|
+
yes?: boolean | undefined;
|
|
23
|
+
all?: boolean | undefined;
|
|
24
|
+
user?: string[] | undefined;
|
|
25
|
+
dryRun?: boolean | undefined;
|
|
26
|
+
}>;
|
|
27
|
+
export type RemoveAdminOptions = z.infer<typeof removeAdminOptionsSchema>;
|
|
28
|
+
import { z } from "zod";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { profileField, verboseField } from "../../schema.js";
|
|
2
|
+
import { ADMIN_GROUP_NAME } from "../admin-group.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
//#region src/commands/aws/iam/remove-admin/schema.js
|
|
5
|
+
/**
|
|
6
|
+
* Zod schema for `aws iam remove-admin` options.
|
|
7
|
+
*/
|
|
8
|
+
const removeAdminOptionsSchema = z.object({
|
|
9
|
+
profile: profileField,
|
|
10
|
+
all: z.boolean().optional().default(false).describe("Scan every aws-vault profile (default only when --profile and AWS_PROFILE are unset)"),
|
|
11
|
+
user: z.array(z.string()).optional().default([]).describe("Only remove these user(s); repeatable. Default: every user in the group"),
|
|
12
|
+
yes: z.boolean().optional().default(false).describe("Skip the per-profile confirmation prompt"),
|
|
13
|
+
dryRun: z.boolean().optional().default(false).describe("Preview removals without changing anything"),
|
|
14
|
+
verbose: verboseField
|
|
15
|
+
});
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {z.infer<typeof removeAdminOptionsSchema>} RemoveAdminOptions
|
|
18
|
+
*/
|
|
19
|
+
//#endregion
|
|
20
|
+
export { ADMIN_GROUP_NAME, removeAdminOptionsSchema };
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { promptYesNo } from "../../utils/tty.js";
|
|
2
|
+
import { getCallerIdentity, requireCommands } from "../../utils/exec-aws.js";
|
|
3
|
+
import { resolveProfile } from "../../utils/resolve-profile.js";
|
|
4
|
+
import { createUsersInteractive } from "../users/utils.js";
|
|
5
|
+
import { setupAclOptionsSchema } from "./schema.js";
|
|
6
|
+
import { ACL_GROUPS, CUSTOM_POLICIES, attach, detach, ensureGroup, printFinalState, publishPolicy } from "./utils.js";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import { ZodError } from "zod";
|
|
9
|
+
//#region src/commands/aws/iam/setup-acl/handler.js
|
|
10
|
+
/**
|
|
11
|
+
* Decide whether to attach the region restriction policy.
|
|
12
|
+
* @param {{ restrictRegions?: "yes" | "no" }} params
|
|
13
|
+
* @returns {Promise<boolean>}
|
|
14
|
+
*/
|
|
15
|
+
async function resolveRestrictRegions(params) {
|
|
16
|
+
const { restrictRegions } = params;
|
|
17
|
+
if (restrictRegions) {
|
|
18
|
+
console.log(`Region restriction: ${restrictRegions}`);
|
|
19
|
+
return restrictRegions === "yes";
|
|
20
|
+
}
|
|
21
|
+
console.log("Region restriction");
|
|
22
|
+
console.log(" The policy UserAdminsDenyRegionsList limits acl-power-users to a hard-coded");
|
|
23
|
+
console.log(" region allowlist. Most accounts should leave this OFF unless you have a strong reason.");
|
|
24
|
+
const restrict = await promptYesNo({
|
|
25
|
+
message: " Attach region restriction to acl-power-users?",
|
|
26
|
+
defaultYes: false
|
|
27
|
+
});
|
|
28
|
+
console.log(` → ${restrict ? "yes" : "no"}`);
|
|
29
|
+
console.log("");
|
|
30
|
+
return restrict;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* `aws iam setup-acl` handler: idempotently create ACL groups, publish policies,
|
|
34
|
+
* attach/detach them per group, and optionally create IAM users.
|
|
35
|
+
* @param {unknown} options
|
|
36
|
+
*/
|
|
37
|
+
async function setupAclCommand(options) {
|
|
38
|
+
try {
|
|
39
|
+
const { restrictRegions, createUsers, profile: profileOption, region, verbose } = setupAclOptionsSchema.parse(options);
|
|
40
|
+
requireCommands(["aws"]);
|
|
41
|
+
const profile = await resolveProfile({ profile: profileOption });
|
|
42
|
+
const identity = getCallerIdentity({
|
|
43
|
+
profile,
|
|
44
|
+
region,
|
|
45
|
+
verbose
|
|
46
|
+
});
|
|
47
|
+
const accountId = identity.Account;
|
|
48
|
+
console.log("Caller:");
|
|
49
|
+
console.log(` Account: ${accountId}`);
|
|
50
|
+
console.log(` Arn: ${identity.Arn}`);
|
|
51
|
+
console.log("");
|
|
52
|
+
const restrict = await resolveRestrictRegions({ restrictRegions });
|
|
53
|
+
console.log("1. Ensure groups exist...");
|
|
54
|
+
for (const group of ACL_GROUPS) ensureGroup({
|
|
55
|
+
name: group,
|
|
56
|
+
profile,
|
|
57
|
+
verbose
|
|
58
|
+
});
|
|
59
|
+
console.log("");
|
|
60
|
+
console.log("2. Publish custom policies...");
|
|
61
|
+
for (const policy of CUSTOM_POLICIES) publishPolicy({
|
|
62
|
+
name: policy.name,
|
|
63
|
+
fileName: policy.fileName,
|
|
64
|
+
accountId,
|
|
65
|
+
profile,
|
|
66
|
+
verbose
|
|
67
|
+
});
|
|
68
|
+
console.log("");
|
|
69
|
+
const ADMIN = "arn:aws:iam::aws:policy/AdministratorAccess";
|
|
70
|
+
const IAM_FULL = "arn:aws:iam::aws:policy/IAMFullAccess";
|
|
71
|
+
const READ_ONLY = "arn:aws:iam::aws:policy/ReadOnlyAccess";
|
|
72
|
+
const WRITE_LIST = `arn:aws:iam::${accountId}:policy/UserAdminsWriteList`;
|
|
73
|
+
const DENY_LIST = `arn:aws:iam::${accountId}:policy/UserAdminsDenyList`;
|
|
74
|
+
const SELF_SERVICE = `arn:aws:iam::${accountId}:policy/UserAdminsSelfServiceIAM`;
|
|
75
|
+
const DENY_REGIONS = `arn:aws:iam::${accountId}:policy/UserAdminsDenyRegionsList`;
|
|
76
|
+
const STS_FEDERATION = `arn:aws:iam::${accountId}:policy/sts-federation`;
|
|
77
|
+
const S3_RESTRICTIONS = `arn:aws:iam::${accountId}:policy/S3RestrictionsDenyNonS3Services`;
|
|
78
|
+
console.log("3. Attach policies to groups...");
|
|
79
|
+
attach({
|
|
80
|
+
group: "acl-admin-do-not-use",
|
|
81
|
+
arn: ADMIN,
|
|
82
|
+
profile,
|
|
83
|
+
verbose
|
|
84
|
+
});
|
|
85
|
+
attach({
|
|
86
|
+
group: "acl-iam-full-access",
|
|
87
|
+
arn: IAM_FULL,
|
|
88
|
+
profile,
|
|
89
|
+
verbose
|
|
90
|
+
});
|
|
91
|
+
attach({
|
|
92
|
+
group: "acl-iam-full-access",
|
|
93
|
+
arn: READ_ONLY,
|
|
94
|
+
profile,
|
|
95
|
+
verbose
|
|
96
|
+
});
|
|
97
|
+
attach({
|
|
98
|
+
group: "acl-iam-full-access",
|
|
99
|
+
arn: SELF_SERVICE,
|
|
100
|
+
profile,
|
|
101
|
+
verbose
|
|
102
|
+
});
|
|
103
|
+
attach({
|
|
104
|
+
group: "acl-iam-full-access",
|
|
105
|
+
arn: STS_FEDERATION,
|
|
106
|
+
profile,
|
|
107
|
+
verbose
|
|
108
|
+
});
|
|
109
|
+
detach({
|
|
110
|
+
group: "acl-iam-full-access",
|
|
111
|
+
arn: DENY_LIST,
|
|
112
|
+
profile,
|
|
113
|
+
verbose
|
|
114
|
+
});
|
|
115
|
+
attach({
|
|
116
|
+
group: "acl-power-users",
|
|
117
|
+
arn: READ_ONLY,
|
|
118
|
+
profile,
|
|
119
|
+
verbose
|
|
120
|
+
});
|
|
121
|
+
attach({
|
|
122
|
+
group: "acl-power-users",
|
|
123
|
+
arn: WRITE_LIST,
|
|
124
|
+
profile,
|
|
125
|
+
verbose
|
|
126
|
+
});
|
|
127
|
+
attach({
|
|
128
|
+
group: "acl-power-users",
|
|
129
|
+
arn: DENY_LIST,
|
|
130
|
+
profile,
|
|
131
|
+
verbose
|
|
132
|
+
});
|
|
133
|
+
attach({
|
|
134
|
+
group: "acl-power-users",
|
|
135
|
+
arn: SELF_SERVICE,
|
|
136
|
+
profile,
|
|
137
|
+
verbose
|
|
138
|
+
});
|
|
139
|
+
attach({
|
|
140
|
+
group: "acl-read-only",
|
|
141
|
+
arn: READ_ONLY,
|
|
142
|
+
profile,
|
|
143
|
+
verbose
|
|
144
|
+
});
|
|
145
|
+
attach({
|
|
146
|
+
group: "acl-read-only",
|
|
147
|
+
arn: STS_FEDERATION,
|
|
148
|
+
profile,
|
|
149
|
+
verbose
|
|
150
|
+
});
|
|
151
|
+
attach({
|
|
152
|
+
group: "acl-s3-restrictions",
|
|
153
|
+
arn: S3_RESTRICTIONS,
|
|
154
|
+
profile,
|
|
155
|
+
verbose
|
|
156
|
+
});
|
|
157
|
+
console.log("");
|
|
158
|
+
console.log("4. Apply region restriction to acl-power-users...");
|
|
159
|
+
if (restrict) attach({
|
|
160
|
+
group: "acl-power-users",
|
|
161
|
+
arn: DENY_REGIONS,
|
|
162
|
+
profile,
|
|
163
|
+
verbose
|
|
164
|
+
});
|
|
165
|
+
else detach({
|
|
166
|
+
group: "acl-power-users",
|
|
167
|
+
arn: DENY_REGIONS,
|
|
168
|
+
profile,
|
|
169
|
+
verbose
|
|
170
|
+
});
|
|
171
|
+
console.log("");
|
|
172
|
+
console.log("5. Detach legacy policies (if present)...");
|
|
173
|
+
const legacyArns = [
|
|
174
|
+
"arn:aws:iam::aws:policy/PowerUserAccess",
|
|
175
|
+
"arn:aws:iam::aws:policy/IAMReadOnlyAccess",
|
|
176
|
+
`arn:aws:iam::${accountId}:policy/UserAdminsAllowList`,
|
|
177
|
+
`arn:aws:iam::${accountId}:policy/UserAdminsDenyListServices`,
|
|
178
|
+
`arn:aws:iam::${accountId}:policy/UserAdminsDenyListGpu`
|
|
179
|
+
];
|
|
180
|
+
for (const group of ACL_GROUPS) for (const arn of legacyArns) detach({
|
|
181
|
+
group,
|
|
182
|
+
arn,
|
|
183
|
+
profile,
|
|
184
|
+
verbose
|
|
185
|
+
});
|
|
186
|
+
console.log("");
|
|
187
|
+
console.log("6. Final state:");
|
|
188
|
+
printFinalState({
|
|
189
|
+
profile,
|
|
190
|
+
verbose
|
|
191
|
+
});
|
|
192
|
+
console.log("");
|
|
193
|
+
if (createUsers) {
|
|
194
|
+
console.log("7. Create IAM users (optional)");
|
|
195
|
+
console.log("");
|
|
196
|
+
await createUsersInteractive({
|
|
197
|
+
profile,
|
|
198
|
+
verbose
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
console.log(chalk.green("\n✅ ACL setup complete."));
|
|
202
|
+
} catch (error) {
|
|
203
|
+
if (error instanceof ZodError) {
|
|
204
|
+
console.error(chalk.red("\n❌ Invalid command options:"));
|
|
205
|
+
error.errors.forEach((err) => {
|
|
206
|
+
console.error(chalk.red(` ${err.path.join(".")}: ${err.message}`));
|
|
207
|
+
});
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
const verbose = options?.verbose || false;
|
|
211
|
+
console.error(chalk.red("\n❌ iam setup-acl failed:"));
|
|
212
|
+
if (error instanceof Error) {
|
|
213
|
+
console.error(chalk.red(` ${error.message}`));
|
|
214
|
+
if (verbose && error.stack) {
|
|
215
|
+
console.error(chalk.gray("\nStack trace:"));
|
|
216
|
+
console.error(chalk.gray(error.stack));
|
|
217
|
+
}
|
|
218
|
+
} else console.error(chalk.red(` ${String(error)}`));
|
|
219
|
+
console.error(chalk.yellow("\n💡 Run with a profile that has IAMFullAccess (e.g. md-*-iam-admin).\n"));
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
//#endregion
|
|
224
|
+
export { setupAclCommand };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { setupAclOptionsSchema } from "./schema.js";
|
|
2
|
+
import { ACL_GROUPS, CUSTOM_POLICIES, attach, detach, ensureGroup, printFinalState, publishPolicy } from "./utils.js";
|
|
3
|
+
import { setupAclCommand } from "./handler.js";
|
|
4
|
+
export { ACL_GROUPS, CUSTOM_POLICIES, attach, detach, ensureGroup, printFinalState, publishPolicy, setupAclCommand, setupAclOptionsSchema };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schema for `aws iam setup-acl` options.
|
|
3
|
+
*/
|
|
4
|
+
export const setupAclOptionsSchema: z.ZodObject<{
|
|
5
|
+
restrictRegions: z.ZodOptional<z.ZodEnum<["yes", "no"]>>;
|
|
6
|
+
createUsers: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
7
|
+
profile: z.ZodOptional<z.ZodString>;
|
|
8
|
+
region: z.ZodOptional<z.ZodString>;
|
|
9
|
+
verbose: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
10
|
+
}, "strip", z.ZodTypeAny, {
|
|
11
|
+
verbose: boolean;
|
|
12
|
+
createUsers: boolean;
|
|
13
|
+
profile?: string | undefined;
|
|
14
|
+
region?: string | undefined;
|
|
15
|
+
restrictRegions?: "yes" | "no" | undefined;
|
|
16
|
+
}, {
|
|
17
|
+
profile?: string | undefined;
|
|
18
|
+
region?: string | undefined;
|
|
19
|
+
verbose?: boolean | undefined;
|
|
20
|
+
restrictRegions?: "yes" | "no" | undefined;
|
|
21
|
+
createUsers?: boolean | undefined;
|
|
22
|
+
}>;
|
|
23
|
+
export type SetupAclOptions = z.infer<typeof setupAclOptionsSchema>;
|
|
24
|
+
import { z } from "zod";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { profileField, regionField, verboseField } from "../../schema.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/commands/aws/iam/setup-acl/schema.js
|
|
4
|
+
/**
|
|
5
|
+
* Zod schema for `aws iam setup-acl` options.
|
|
6
|
+
*/
|
|
7
|
+
const setupAclOptionsSchema = z.object({
|
|
8
|
+
restrictRegions: z.enum(["yes", "no"]).optional().describe("Attach the region restriction to acl-power-users (skips the interactive prompt)"),
|
|
9
|
+
createUsers: z.boolean().optional().default(true).describe("Create IAM users after configuring groups (use --no-create-users to skip)"),
|
|
10
|
+
profile: profileField,
|
|
11
|
+
region: regionField,
|
|
12
|
+
verbose: verboseField
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {z.infer<typeof setupAclOptionsSchema>} SetupAclOptions
|
|
16
|
+
*/
|
|
17
|
+
//#endregion
|
|
18
|
+
export { setupAclOptionsSchema };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create an IAM group if it does not already exist.
|
|
3
|
+
* @param {{ name: string; profile?: string; verbose?: boolean }} params
|
|
4
|
+
*/
|
|
5
|
+
export function ensureGroup(params: {
|
|
6
|
+
name: string;
|
|
7
|
+
profile?: string;
|
|
8
|
+
verbose?: boolean;
|
|
9
|
+
}): void;
|
|
10
|
+
/**
|
|
11
|
+
* Create or update a customer-managed policy from a bundled JSON document.
|
|
12
|
+
* Handles the IAM five-version limit by pruning the oldest non-default version.
|
|
13
|
+
* @param {{ name: string; fileName: string; accountId: string; profile?: string; verbose?: boolean }} params
|
|
14
|
+
*/
|
|
15
|
+
export function publishPolicy(params: {
|
|
16
|
+
name: string;
|
|
17
|
+
fileName: string;
|
|
18
|
+
accountId: string;
|
|
19
|
+
profile?: string;
|
|
20
|
+
verbose?: boolean;
|
|
21
|
+
}): void;
|
|
22
|
+
/**
|
|
23
|
+
* Attach a policy to a group if not already attached.
|
|
24
|
+
* @param {{ group: string; arn: string; profile?: string; verbose?: boolean }} params
|
|
25
|
+
*/
|
|
26
|
+
export function attach(params: {
|
|
27
|
+
group: string;
|
|
28
|
+
arn: string;
|
|
29
|
+
profile?: string;
|
|
30
|
+
verbose?: boolean;
|
|
31
|
+
}): void;
|
|
32
|
+
/**
|
|
33
|
+
* Detach a (legacy) policy from a group if it is currently attached.
|
|
34
|
+
* @param {{ group: string; arn: string; profile?: string; verbose?: boolean }} params
|
|
35
|
+
*/
|
|
36
|
+
export function detach(params: {
|
|
37
|
+
group: string;
|
|
38
|
+
arn: string;
|
|
39
|
+
profile?: string;
|
|
40
|
+
verbose?: boolean;
|
|
41
|
+
}): void;
|
|
42
|
+
/**
|
|
43
|
+
* Print the attached policies for each ACL group.
|
|
44
|
+
* @param {{ profile?: string; verbose?: boolean }} params
|
|
45
|
+
*/
|
|
46
|
+
export function printFinalState(params: {
|
|
47
|
+
profile?: string;
|
|
48
|
+
verbose?: boolean;
|
|
49
|
+
}): void;
|
|
50
|
+
/**
|
|
51
|
+
* The five ACL groups managed by setup-acl.
|
|
52
|
+
*/
|
|
53
|
+
export const ACL_GROUPS: string[];
|
|
54
|
+
/**
|
|
55
|
+
* Custom managed policies published from bundled JSON documents.
|
|
56
|
+
* @type {Array<{ name: string; fileName: string }>}
|
|
57
|
+
*/
|
|
58
|
+
export const CUSTOM_POLICIES: Array<{
|
|
59
|
+
name: string;
|
|
60
|
+
fileName: string;
|
|
61
|
+
}>;
|