aws-security-mcp 0.5.2 → 0.5.3

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 CHANGED
@@ -9,7 +9,7 @@ MCP server for automated AWS security scanning — 19 modules, risk scoring, zer
9
9
 
10
10
  ## Features
11
11
 
12
- - **19 Security Scan Modules** — 15 unique scanners + 4 aggregation scanners (Security Hub, GuardDuty, Inspector, Trusted Advisor, Config Rules, Access Analyzer, Patch Compliance)
12
+ - **19 Security Scan Modules** — Security Hub, GuardDuty, Inspector, Trusted Advisor, Config Rules, Access Analyzer, Patch Compliance, and more
13
13
  - **Risk Scoring** — every finding scored 0-10 with severity (CRITICAL/HIGH/MEDIUM/LOW) and priority (P0-P3)
14
14
  - **100% Read-Only** — uses only Describe/Get/List API calls; never modifies your AWS resources
15
15
  - **Multi-Account Support** — scan all accounts in an AWS Organization via `org_mode` with cross-account role assumption
@@ -246,8 +246,6 @@ Attach this policy to the IAM user or role running the scanner. All actions are
246
246
 
247
247
  ## Scan Modules
248
248
 
249
- ### Unique Scanners (15)
250
-
251
249
  | Module | What It Checks | Risk Score Range |
252
250
  |--------|---------------|-----------------|
253
251
  | **Service Detection** | Enabled security services (Security Hub, GuardDuty, Inspector, Config, Macie, CloudTrail) and maturity level | 5.0 - 7.5 |
@@ -265,11 +263,6 @@ Attach this policy to the IAM user or role running the scanner. All actions are
265
263
  | **Patch Compliance** | SSM Patch Manager compliance status for managed instances | 3.0 - 9.5 |
266
264
  | **IMDSv2 Enforcement** | EC2 instances not enforcing IMDSv2 (HttpTokens != required) | 7.5 |
267
265
  | **WAF Coverage** | Internet-facing ALBs without WAF Web ACL protection | 7.5 |
268
-
269
- ### Aggregation Scanners (4)
270
-
271
- | Module | Source Service | Risk Score Range |
272
- |--------|---------------|-----------------|
273
266
  | **Security Hub Findings** | AWS Security Hub (FSBP, CIS, PCI DSS) | 3.0 - 9.5 |
274
267
  | **GuardDuty Findings** | Amazon GuardDuty threat detection | 3.0 - 9.5 |
275
268
  | **Inspector Findings** | Amazon Inspector vulnerability scanning | 3.0 - 9.5 |
@@ -237,7 +237,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
237
237
  import { z } from "zod";
238
238
 
239
239
  // src/version.ts
240
- var VERSION = "0.5.2";
240
+ var VERSION = "0.5.3";
241
241
 
242
242
  // src/utils/aws-client.ts
243
243
  import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
@@ -2439,7 +2439,6 @@ import {
2439
2439
  DescribeNetworkInterfacesCommand,
2440
2440
  DescribeSecurityGroupsCommand as DescribeSecurityGroupsCommand2
2441
2441
  } from "@aws-sdk/client-ec2";
2442
- var THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1e3;
2443
2442
  function makeFinding9(opts) {
2444
2443
  const severity = severityFromScore(opts.riskScore);
2445
2444
  return { ...opts, severity, priority: priorityFromSeverity(severity) };
@@ -6908,9 +6907,8 @@ var MLPS3_CHECK_MAPPING = [
6908
6907
  },
6909
6908
  {
6910
6909
  id: "L3-SMC1-09",
6911
- type: "auto",
6912
- modules: ["service_detection"],
6913
- findingPatterns: ["CloudWatch"]
6910
+ type: "manual",
6911
+ guidance: "\u9700\u914D\u7F6E CloudWatch \u96C6\u4E2D\u76D1\u63A7\u5E73\u53F0\uFF0C\u7ED3\u5408 SNS \u8FDB\u884C\u544A\u8B66\u901A\u77E5"
6914
6912
  },
6915
6913
  {
6916
6914
  id: "L3-SMC1-10",
@@ -7004,226 +7002,57 @@ function evaluateAllFullChecks(scanResults) {
7004
7002
  return evaluateFullCheck(item, mapping, allFindings, scanModules);
7005
7003
  });
7006
7004
  }
7007
- var MLPS_CHECKS = [
7008
- // 一、身份鉴别
7009
- {
7010
- id: "8.1.4.1a",
7011
- category: "\u8EAB\u4EFD\u9274\u522B",
7012
- name: "\u5BC6\u7801\u7B56\u7565",
7013
- modules: ["security_hub_findings"],
7014
- findingPatterns: ["password policy", "password length", "complexity", "password expiry", "reuse prevention", "IAM.7", "IAM.10"]
7015
- },
7016
- {
7017
- id: "8.1.4.1a",
7018
- category: "\u8EAB\u4EFD\u9274\u522B",
7019
- name: "\u5BC6\u94A5\u8F6E\u6362",
7020
- modules: ["security_hub_findings"],
7021
- findingPatterns: ["access key older", "access key rotated", "IAM.3", "IAM.4"]
7022
- },
7023
- {
7024
- id: "8.1.4.1d",
7025
- category: "\u8EAB\u4EFD\u9274\u522B",
7026
- name: "\u53CC\u56E0\u7D20\u8BA4\u8BC1",
7027
- modules: ["security_hub_findings"],
7028
- findingPatterns: ["MFA", "IAM.5", "IAM.6"]
7029
- },
7030
- // 二、访问控制
7031
- {
7032
- id: "8.1.4.2c",
7033
- category: "\u8BBF\u95EE\u63A7\u5236",
7034
- name: "\u6700\u5C0F\u6743\u9650",
7035
- modules: ["iam_privilege_escalation", "security_hub_findings"],
7036
- findingPatterns: [
7037
- "AdministratorAccess",
7038
- "PowerUserAccess",
7039
- "IAMFullAccess",
7040
- "over-permissive",
7041
- "privilege escalation",
7042
- "self-grant",
7043
- "iam:*",
7044
- "create admin",
7045
- "Lambda role passing",
7046
- "CreateAccessKey",
7047
- "AssumeRole"
7048
- ]
7049
- },
7050
- {
7051
- id: "8.1.4.2",
7052
- category: "\u8BBF\u95EE\u63A7\u5236",
7053
- name: "\u5B89\u5168\u7EC4",
7054
- modules: ["network_reachability", "security_hub_findings"],
7055
- findingPatterns: ["allows all ports", "allows SSH", "allows RDP", "MySQL", "PostgreSQL", "MongoDB", "Redis", "high-risk port", "security group", "EC2.18", "EC2.19"]
7056
- },
7057
- // 三、安全审计
7058
- {
7059
- id: "8.1.4.3a",
7060
- category: "\u5B89\u5168\u5BA1\u8BA1",
7061
- name: "\u5BA1\u8BA1\u529F\u80FD",
7062
- modules: ["security_hub_findings"],
7063
- findingPatterns: ["CloudTrail", "not enabled", "multi-region", "not logging", "CloudTrail.1"]
7064
- },
7065
- {
7066
- id: "8.1.4.3b",
7067
- category: "\u5B89\u5168\u5BA1\u8BA1",
7068
- name: "\u5BA1\u8BA1\u5B8C\u6574\u6027",
7069
- modules: ["security_hub_findings"],
7070
- findingPatterns: ["log file validation", "log integrity", "log validation", "CloudTrail.4", "CloudTrail.5"]
7071
- },
7072
- {
7073
- id: "8.1.4.3c",
7074
- category: "\u5B89\u5168\u5BA1\u8BA1",
7075
- name: "\u5BA1\u8BA1\u4FDD\u62A4",
7076
- modules: ["security_hub_findings"],
7077
- findingPatterns: ["CloudTrail", "S3 bucket", "encryption", "versioning", "Block Public Access", "CloudTrail.6", "CloudTrail.7"]
7078
- },
7079
- // 四、入侵防范
7080
- {
7081
- id: "8.1.4.4a",
7082
- category: "\u5165\u4FB5\u9632\u8303",
7083
- name: "GuardDuty \u5A01\u80C1\u68C0\u6D4B",
7084
- modules: ["service_detection", "guardduty_findings"],
7085
- findingPatterns: ["GuardDuty"]
7086
- },
7087
- {
7088
- id: "8.1.4.4a",
7089
- category: "\u5165\u4FB5\u9632\u8303",
7090
- name: "Inspector \u6F0F\u6D1E\u626B\u63CF",
7091
- modules: ["service_detection", "inspector_findings"],
7092
- findingPatterns: ["Inspector", "CVE-"]
7093
- },
7094
- // 五、数据安全
7095
- {
7096
- id: "8.1.4.5a",
7097
- category: "\u6570\u636E\u5B89\u5168",
7098
- name: "\u4F20\u8F93\u52A0\u5BC6",
7099
- modules: ["ssl_certificate", "security_hub_findings"],
7100
- findingPatterns: ["HTTPS", "TLS", "HTTP listener", "certificate", "ELB.1"]
7101
- },
7102
- {
7103
- id: "8.1.4.5b",
7104
- category: "\u6570\u636E\u5B89\u5168",
7105
- name: "S3 \u5B58\u50A8\u52A0\u5BC6",
7106
- modules: ["security_hub_findings"],
7107
- findingPatterns: ["no default encryption", "not encrypted", "S3.4"]
7108
- },
7109
- {
7110
- id: "8.1.4.5b",
7111
- category: "\u6570\u636E\u5B89\u5168",
7112
- name: "EBS \u9ED8\u8BA4\u52A0\u5BC6",
7113
- modules: ["security_hub_findings"],
7114
- findingPatterns: ["EBS default encryption", "EC2.7"]
7115
- },
7116
- {
7117
- id: "8.1.4.5b",
7118
- category: "\u6570\u636E\u5B89\u5168",
7119
- name: "RDS \u5B58\u50A8\u52A0\u5BC6",
7120
- modules: ["security_hub_findings"],
7121
- findingPatterns: ["storage is not encrypted", "RDS.3"]
7122
- },
7123
- // 六、网络安全
7124
- {
7125
- id: "8.1.3.1a",
7126
- category: "\u7F51\u7EDC\u5B89\u5168",
7127
- name: "\u7F51\u7EDC\u67B6\u6784",
7128
- modules: ["security_hub_findings"],
7129
- findingPatterns: ["default VPC", "EC2.2"]
7130
- },
7131
- {
7132
- id: "8.1.3.2a",
7133
- category: "\u7F51\u7EDC\u5B89\u5168",
7134
- name: "\u8FB9\u754C\u9632\u62A4",
7135
- modules: ["network_reachability", "security_hub_findings"],
7136
- findingPatterns: ["allows all ports", "allows SSH", "allows RDP", "security group", "EC2.18", "EC2.19"]
7137
- }
7138
- ];
7139
- var CATEGORY_ORDER = [
7140
- "\u8EAB\u4EFD\u9274\u522B",
7141
- "\u8BBF\u95EE\u63A7\u5236",
7142
- "\u5B89\u5168\u5BA1\u8BA1",
7143
- "\u5165\u4FB5\u9632\u8303",
7144
- "\u6570\u636E\u5B89\u5168",
7145
- "\u7F51\u7EDC\u5B89\u5168"
7146
- ];
7147
- var CATEGORY_SECTION = {
7148
- "\u8EAB\u4EFD\u9274\u522B": "\u4E00\u3001\u8EAB\u4EFD\u9274\u522B",
7149
- "\u8BBF\u95EE\u63A7\u5236": "\u4E8C\u3001\u8BBF\u95EE\u63A7\u5236",
7150
- "\u5B89\u5168\u5BA1\u8BA1": "\u4E09\u3001\u5B89\u5168\u5BA1\u8BA1",
7151
- "\u5165\u4FB5\u9632\u8303": "\u56DB\u3001\u5165\u4FB5\u9632\u8303",
7152
- "\u6570\u636E\u5B89\u5168": "\u4E94\u3001\u6570\u636E\u5B89\u5168",
7153
- "\u7F51\u7EDC\u5B89\u5168": "\u516D\u3001\u7F51\u7EDC\u5B89\u5168"
7154
- };
7155
- function evaluateCheck(check, allFindings, scanModules) {
7156
- const allModulesPresent = check.modules.every(
7157
- (mod) => scanModules.some((m) => m.module === mod && m.status === "success")
7158
- );
7159
- if (!allModulesPresent) {
7160
- return { check, status: "unknown", relatedFindings: [] };
7161
- }
7162
- const relatedFindings = allFindings.filter((f) => {
7163
- const moduleMatch = check.modules.some((mod) => f.module === mod);
7164
- if (!moduleMatch) return false;
7165
- const text = `${f.title} ${f.description}`.toLowerCase();
7166
- return check.findingPatterns.some(
7167
- (pattern) => text.includes(pattern.toLowerCase())
7168
- );
7169
- });
7170
- return {
7171
- check,
7172
- status: relatedFindings.length === 0 ? "clean" : "issues",
7173
- relatedFindings
7174
- };
7175
- }
7176
7005
  function generateMlps3Report(scanResults) {
7177
7006
  const { accountId, region, scanStart } = scanResults;
7178
7007
  const scanTime = scanStart.replace("T", " ").replace(/\.\d+Z$/, " UTC");
7179
- const allFindings = scanResults.modules.flatMap(
7180
- (m) => m.findings.map((f) => ({ ...f, module: f.module ?? m.module }))
7181
- );
7182
- const scanModules = scanResults.modules.map((m) => ({
7183
- module: m.module,
7184
- status: m.status
7185
- }));
7186
- const results = MLPS_CHECKS.map(
7187
- (check) => evaluateCheck(check, allFindings, scanModules)
7188
- );
7189
- const cleanCount = results.filter((r) => r.status === "clean").length;
7190
- const issuesCount = results.filter((r) => r.status === "issues").length;
7191
- const unknownCount = results.filter((r) => r.status === "unknown").length;
7192
- const checkedTotal = cleanCount + issuesCount;
7193
- const total = results.length;
7008
+ const results = evaluateAllFullChecks(scanResults);
7009
+ const autoResults = results.filter((r) => r.mapping.type === "auto");
7010
+ const autoClean = autoResults.filter((r) => r.status === "clean").length;
7011
+ const autoIssues = autoResults.filter((r) => r.status === "issues").length;
7012
+ const autoUnknown = autoResults.filter((r) => r.status === "unknown").length;
7013
+ const checkedTotal = autoClean + autoIssues;
7014
+ const cloudCount = results.filter((r) => r.status === "cloud_provider").length;
7015
+ const manualCount = results.filter((r) => r.status === "manual").length;
7016
+ const naCount = results.filter((r) => r.status === "not_applicable").length;
7194
7017
  const lines = [];
7195
7018
  lines.push("# \u7B49\u4FDD\u4E09\u7EA7\u9884\u68C0\u62A5\u544A");
7196
7019
  lines.push("> **\u672C\u62A5\u544A\u4E3A\u7B49\u4FDD\u4E09\u7EA7\u9884\u68C0\u53C2\u8003\uFF0C\u63D0\u4F9B\u4E91\u5E73\u53F0\u914D\u7F6E\u68C0\u67E5\u6570\u636E\u4E0E\u5EFA\u8BAE\u3002\u5408\u89C4\u5224\u5B9A\uFF08\u7B26\u5408/\u90E8\u5206\u7B26\u5408/\u4E0D\u7B26\u5408\uFF09\u9700\u7531\u6301\u8BC1\u6D4B\u8BC4\u673A\u6784\u6839\u636E\u5B9E\u9645\u60C5\u51B5\u786E\u8BA4\u3002**");
7020
+ lines.push("> **\uFF08GB/T 22239-2019 \u5B8C\u6574\u68C0\u67E5\u6E05\u5355 184 \u9879\uFF09**");
7197
7021
  lines.push("");
7198
7022
  lines.push("## \u8D26\u6237\u4FE1\u606F");
7199
7023
  lines.push(`- Account: ${accountId} | Region: ${region} | \u626B\u63CF\u65F6\u95F4: ${scanTime}`);
7200
7024
  lines.push("");
7201
7025
  lines.push("## \u9884\u68C0\u603B\u89C8");
7202
- lines.push(`- \u5DF2\u68C0\u67E5 ${checkedTotal} \u9879 / \u5171 ${total} \u9879`);
7203
- lines.push(` - \u672A\u53D1\u73B0\u95EE\u9898: ${cleanCount} \u9879`);
7204
- lines.push(` - \u53D1\u73B0\u95EE\u9898: ${issuesCount} \u9879`);
7205
- if (unknownCount > 0) {
7206
- lines.push(` - \u672A\u68C0\u67E5: ${unknownCount} \u9879`);
7026
+ lines.push(`- \u5DF2\u68C0\u67E5: ${checkedTotal} \u9879\uFF08\u672A\u53D1\u73B0\u95EE\u9898: ${autoClean} \u9879 | \u53D1\u73B0\u95EE\u9898: ${autoIssues} \u9879\uFF09`);
7027
+ if (autoUnknown > 0) {
7028
+ lines.push(`- \u672A\u68C0\u67E5: ${autoUnknown} \u9879\uFF08\u5BF9\u5E94\u626B\u63CF\u6A21\u5757\u672A\u8FD0\u884C\uFF09`);
7029
+ }
7030
+ lines.push(`- \u4E91\u5E73\u53F0\u8D1F\u8D23: ${cloudCount} \u9879`);
7031
+ lines.push(`- \u9700\u4EBA\u5DE5\u8BC4\u4F30: ${manualCount} \u9879`);
7032
+ if (naCount > 0) {
7033
+ lines.push(`- \u4E0D\u9002\u7528: ${naCount} \u9879`);
7207
7034
  }
7208
7035
  lines.push("");
7209
- for (const category of CATEGORY_ORDER) {
7210
- const sectionTitle = CATEGORY_SECTION[category];
7211
- const categoryResults = results.filter((r) => r.check.category === category);
7212
- if (categoryResults.length === 0) continue;
7036
+ for (const category of MLPS3_CATEGORY_ORDER) {
7037
+ const sectionTitle = MLPS3_CATEGORY_SECTION[category];
7038
+ const catResults = results.filter(
7039
+ (r) => r.item.categoryCn === category && r.status !== "not_applicable"
7040
+ );
7041
+ if (catResults.length === 0) continue;
7213
7042
  lines.push(`## ${sectionTitle}`);
7214
7043
  lines.push("");
7215
- const byId = /* @__PURE__ */ new Map();
7216
- for (const r of categoryResults) {
7217
- const existing = byId.get(r.check.id) ?? [];
7218
- existing.push(r);
7219
- byId.set(r.check.id, existing);
7044
+ const controlMap = /* @__PURE__ */ new Map();
7045
+ for (const r of catResults) {
7046
+ const key = r.item.controlCn;
7047
+ if (!controlMap.has(key)) controlMap.set(key, []);
7048
+ controlMap.get(key).push(r);
7220
7049
  }
7221
- for (const [checkId, checkResults] of byId) {
7222
- lines.push(`### ${checkId} ${checkResults[0].check.name}`);
7223
- for (const r of checkResults) {
7224
- const icon = r.status === "clean" ? "\u2705" : r.status === "issues" ? "\u274C" : "\u26A0\uFE0F";
7225
- const label = r.status === "unknown" ? " \u672A\u68C0\u67E5" : r.status === "clean" ? " \u672A\u53D1\u73B0\u95EE\u9898" : r.status === "issues" ? " \u53D1\u73B0\u95EE\u9898" : "";
7226
- lines.push(`- [${icon}] ${r.check.name}${label}`);
7050
+ for (const [controlName, controlResults] of controlMap) {
7051
+ lines.push(`### ${controlName}`);
7052
+ for (const r of controlResults) {
7053
+ const icon = r.status === "clean" ? "\u2705" : r.status === "issues" ? "\u274C" : r.status === "unknown" ? "\u26A0\uFE0F" : r.status === "manual" ? "\u{1F4CB}" : "\u{1F3E2}";
7054
+ const suffix = r.status === "unknown" ? " \u2014 \u672A\u68C0\u67E5" : r.status === "manual" ? ` \u2014 ${r.mapping.guidance ?? "\u9700\u4EBA\u5DE5\u8BC4\u4F30"}` : r.status === "cloud_provider" ? ` \u2014 ${r.mapping.note ?? "\u4E91\u5E73\u53F0\u8D1F\u8D23"}` : r.status === "clean" ? " \u672A\u53D1\u73B0\u95EE\u9898" : " \u53D1\u73B0\u95EE\u9898";
7055
+ lines.push(`- [${icon}] ${r.item.id} ${r.item.requirementCn.slice(0, 60)}${r.item.requirementCn.length > 60 ? "\u2026" : ""}${suffix}`);
7227
7056
  if (r.status === "issues" && r.relatedFindings.length > 0) {
7228
7057
  for (const f of r.relatedFindings.slice(0, 3)) {
7229
7058
  lines.push(` - ${f.severity}: ${f.title}`);
@@ -7260,6 +7089,10 @@ function generateMlps3Report(scanResults) {
7260
7089
  }
7261
7090
  lines.push("");
7262
7091
  }
7092
+ if (naCount > 0) {
7093
+ lines.push(`> \u4E0D\u9002\u7528\u9879: ${naCount} \u9879\uFF08\u7269\u8054\u7F51/\u65E0\u7EBF\u7F51\u7EDC/\u79FB\u52A8\u7EC8\u7AEF/\u5DE5\u63A7\u7CFB\u7EDF/\u53EF\u4FE1\u9A8C\u8BC1\u7B49\uFF09`);
7094
+ lines.push("");
7095
+ }
7263
7096
  return lines.join("\n");
7264
7097
  }
7265
7098