aws-security-mcp 0.4.3 → 0.5.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/README.md +18 -9
- package/dist/bin/aws-security-mcp.js +525 -16
- package/dist/bin/aws-security-mcp.js.map +1 -1
- package/dist/src/index.js +525 -16
- package/dist/src/index.js.map +1 -1
- package/package.json +3 -1
|
@@ -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.
|
|
240
|
+
var VERSION = "0.5.1";
|
|
241
241
|
|
|
242
242
|
// src/utils/aws-client.ts
|
|
243
243
|
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
|
|
@@ -3961,6 +3961,242 @@ var PatchComplianceFindingsScanner = class {
|
|
|
3961
3961
|
}
|
|
3962
3962
|
};
|
|
3963
3963
|
|
|
3964
|
+
// src/scanners/imdsv2-enforcement.ts
|
|
3965
|
+
import {
|
|
3966
|
+
EC2Client as EC2Client6,
|
|
3967
|
+
DescribeInstancesCommand as DescribeInstancesCommand5
|
|
3968
|
+
} from "@aws-sdk/client-ec2";
|
|
3969
|
+
function makeFinding11(opts) {
|
|
3970
|
+
const severity = severityFromScore(opts.riskScore);
|
|
3971
|
+
return { ...opts, severity, priority: priorityFromSeverity(severity) };
|
|
3972
|
+
}
|
|
3973
|
+
var Imdsv2EnforcementScanner = class {
|
|
3974
|
+
moduleName = "imdsv2_enforcement";
|
|
3975
|
+
async scan(ctx) {
|
|
3976
|
+
const { region, partition, accountId } = ctx;
|
|
3977
|
+
const startMs = Date.now();
|
|
3978
|
+
const findings = [];
|
|
3979
|
+
const warnings = [];
|
|
3980
|
+
try {
|
|
3981
|
+
const client = createClient(EC2Client6, region, ctx.credentials);
|
|
3982
|
+
const instances = [];
|
|
3983
|
+
let nextToken;
|
|
3984
|
+
do {
|
|
3985
|
+
const resp = await client.send(
|
|
3986
|
+
new DescribeInstancesCommand5({
|
|
3987
|
+
Filters: [{ Name: "instance-state-name", Values: ["running"] }],
|
|
3988
|
+
NextToken: nextToken
|
|
3989
|
+
})
|
|
3990
|
+
);
|
|
3991
|
+
if (resp.Reservations) {
|
|
3992
|
+
for (const reservation of resp.Reservations) {
|
|
3993
|
+
if (reservation.Instances) {
|
|
3994
|
+
instances.push(...reservation.Instances);
|
|
3995
|
+
}
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
nextToken = resp.NextToken;
|
|
3999
|
+
} while (nextToken);
|
|
4000
|
+
for (const instance of instances) {
|
|
4001
|
+
const instanceId = instance.InstanceId ?? "unknown";
|
|
4002
|
+
const instanceType = instance.InstanceType ?? "unknown";
|
|
4003
|
+
const state = instance.State?.Name ?? "unknown";
|
|
4004
|
+
const httpTokens = instance.MetadataOptions?.HttpTokens ?? "unknown";
|
|
4005
|
+
const hopLimit = instance.MetadataOptions?.HttpPutResponseHopLimit ?? 1;
|
|
4006
|
+
const instanceArn = `arn:${partition}:ec2:${region}:${accountId}:instance/${instanceId}`;
|
|
4007
|
+
if (httpTokens !== "required") {
|
|
4008
|
+
const description = [
|
|
4009
|
+
`EC2 instance ${instanceId} (type: ${instanceType}, state: ${state}) has HttpTokens set to "${httpTokens}".`,
|
|
4010
|
+
`IMDSv1 is accessible, allowing unauthenticated metadata requests.`
|
|
4011
|
+
];
|
|
4012
|
+
if (hopLimit > 1) {
|
|
4013
|
+
description.push(`HttpPutResponseHopLimit is ${hopLimit} (>1), which may allow containers to reach IMDS.`);
|
|
4014
|
+
}
|
|
4015
|
+
findings.push(
|
|
4016
|
+
makeFinding11({
|
|
4017
|
+
riskScore: 7.5,
|
|
4018
|
+
title: `EC2 instance ${instanceId} does not enforce IMDSv2`,
|
|
4019
|
+
resourceType: "AWS::EC2::Instance",
|
|
4020
|
+
resourceId: instanceId,
|
|
4021
|
+
resourceArn: instanceArn,
|
|
4022
|
+
region,
|
|
4023
|
+
description: description.join(" "),
|
|
4024
|
+
impact: "IMDSv1 allows attackers to steal IAM role credentials via SSRF attacks",
|
|
4025
|
+
remediationSteps: [
|
|
4026
|
+
"Enforce IMDSv2 by setting HttpTokens to 'required'.",
|
|
4027
|
+
"Run: aws ec2 modify-instance-metadata-options --instance-id " + instanceId + " --http-tokens required --http-endpoint enabled",
|
|
4028
|
+
"Set HttpPutResponseHopLimit to 1 unless running containers that need metadata access.",
|
|
4029
|
+
"Update launch templates and Auto Scaling groups to enforce IMDSv2 for new instances."
|
|
4030
|
+
]
|
|
4031
|
+
})
|
|
4032
|
+
);
|
|
4033
|
+
} else if (hopLimit > 1) {
|
|
4034
|
+
warnings.push(
|
|
4035
|
+
`Instance ${instanceId} enforces IMDSv2 but HttpPutResponseHopLimit is ${hopLimit} (>1). Verify this is intentional for containerized workloads.`
|
|
4036
|
+
);
|
|
4037
|
+
}
|
|
4038
|
+
}
|
|
4039
|
+
return {
|
|
4040
|
+
module: this.moduleName,
|
|
4041
|
+
status: "success",
|
|
4042
|
+
warnings: warnings.length > 0 ? warnings : void 0,
|
|
4043
|
+
resourcesScanned: instances.length,
|
|
4044
|
+
findingsCount: findings.length,
|
|
4045
|
+
scanTimeMs: Date.now() - startMs,
|
|
4046
|
+
findings
|
|
4047
|
+
};
|
|
4048
|
+
} catch (err) {
|
|
4049
|
+
return {
|
|
4050
|
+
module: this.moduleName,
|
|
4051
|
+
status: "error",
|
|
4052
|
+
error: err instanceof Error ? err.message : String(err),
|
|
4053
|
+
warnings: warnings.length > 0 ? warnings : void 0,
|
|
4054
|
+
resourcesScanned: 0,
|
|
4055
|
+
findingsCount: 0,
|
|
4056
|
+
scanTimeMs: Date.now() - startMs,
|
|
4057
|
+
findings: []
|
|
4058
|
+
};
|
|
4059
|
+
}
|
|
4060
|
+
}
|
|
4061
|
+
};
|
|
4062
|
+
|
|
4063
|
+
// src/scanners/waf-coverage.ts
|
|
4064
|
+
import {
|
|
4065
|
+
ElasticLoadBalancingV2Client,
|
|
4066
|
+
DescribeLoadBalancersCommand
|
|
4067
|
+
} from "@aws-sdk/client-elastic-load-balancing-v2";
|
|
4068
|
+
import {
|
|
4069
|
+
WAFV2Client,
|
|
4070
|
+
GetWebACLForResourceCommand
|
|
4071
|
+
} from "@aws-sdk/client-wafv2";
|
|
4072
|
+
function makeFinding12(opts) {
|
|
4073
|
+
const severity = severityFromScore(opts.riskScore);
|
|
4074
|
+
return { ...opts, severity, priority: priorityFromSeverity(severity) };
|
|
4075
|
+
}
|
|
4076
|
+
var WafCoverageScanner = class {
|
|
4077
|
+
moduleName = "waf_coverage";
|
|
4078
|
+
async scan(ctx) {
|
|
4079
|
+
const { region } = ctx;
|
|
4080
|
+
const startMs = Date.now();
|
|
4081
|
+
const findings = [];
|
|
4082
|
+
const warnings = [];
|
|
4083
|
+
try {
|
|
4084
|
+
const elbClient = createClient(ElasticLoadBalancingV2Client, region, ctx.credentials);
|
|
4085
|
+
const wafClient = createClient(WAFV2Client, region, ctx.credentials);
|
|
4086
|
+
const loadBalancers = [];
|
|
4087
|
+
let marker;
|
|
4088
|
+
do {
|
|
4089
|
+
const resp = await elbClient.send(
|
|
4090
|
+
new DescribeLoadBalancersCommand({ Marker: marker })
|
|
4091
|
+
);
|
|
4092
|
+
if (resp.LoadBalancers) {
|
|
4093
|
+
loadBalancers.push(...resp.LoadBalancers);
|
|
4094
|
+
}
|
|
4095
|
+
marker = resp.NextMarker;
|
|
4096
|
+
} while (marker);
|
|
4097
|
+
const internetFacing = loadBalancers.filter((lb) => lb.Scheme === "internet-facing");
|
|
4098
|
+
for (const lb of internetFacing) {
|
|
4099
|
+
const lbName = lb.LoadBalancerName ?? "unknown";
|
|
4100
|
+
const lbArn = lb.LoadBalancerArn ?? "unknown";
|
|
4101
|
+
const lbType = lb.Type ?? "unknown";
|
|
4102
|
+
if (lbType !== "application") {
|
|
4103
|
+
warnings.push(
|
|
4104
|
+
`Skipping ${lbType} load balancer "${lbName}" \u2014 WAF Web ACL association is only supported for ALBs.`
|
|
4105
|
+
);
|
|
4106
|
+
continue;
|
|
4107
|
+
}
|
|
4108
|
+
try {
|
|
4109
|
+
const wafResp = await wafClient.send(
|
|
4110
|
+
new GetWebACLForResourceCommand({ ResourceArn: lbArn })
|
|
4111
|
+
);
|
|
4112
|
+
if (!wafResp.WebACL) {
|
|
4113
|
+
findings.push(
|
|
4114
|
+
makeFinding12({
|
|
4115
|
+
riskScore: 7.5,
|
|
4116
|
+
title: `Internet-facing ALB ${lbName} has no WAF protection`,
|
|
4117
|
+
resourceType: "AWS::ElasticLoadBalancingV2::LoadBalancer",
|
|
4118
|
+
resourceId: lbName,
|
|
4119
|
+
resourceArn: lbArn,
|
|
4120
|
+
region,
|
|
4121
|
+
description: `Internet-facing Application Load Balancer "${lbName}" does not have a WAF Web ACL associated. Traffic is not inspected for common web exploits.`,
|
|
4122
|
+
impact: "Without WAF, the ALB is exposed to SQL injection, XSS, and other OWASP Top 10 attacks",
|
|
4123
|
+
remediationSteps: [
|
|
4124
|
+
"Create a WAFv2 Web ACL with managed rule groups (e.g., AWSManagedRulesCommonRuleSet).",
|
|
4125
|
+
"Associate the Web ACL with the ALB using the REGIONAL scope.",
|
|
4126
|
+
"Enable WAF logging for visibility into blocked requests.",
|
|
4127
|
+
"Consider adding rate-based rules to mitigate DDoS at the application layer."
|
|
4128
|
+
]
|
|
4129
|
+
})
|
|
4130
|
+
);
|
|
4131
|
+
}
|
|
4132
|
+
} catch (wafErr) {
|
|
4133
|
+
const errMsg = wafErr instanceof Error ? wafErr.message : String(wafErr);
|
|
4134
|
+
const errName = wafErr instanceof Error ? wafErr.name ?? "" : "";
|
|
4135
|
+
if (errName === "WAFNonexistentItemException") {
|
|
4136
|
+
findings.push(
|
|
4137
|
+
makeFinding12({
|
|
4138
|
+
riskScore: 7.5,
|
|
4139
|
+
title: `Internet-facing ALB ${lbName} has no WAF protection`,
|
|
4140
|
+
resourceType: "AWS::ElasticLoadBalancingV2::LoadBalancer",
|
|
4141
|
+
resourceId: lbName,
|
|
4142
|
+
resourceArn: lbArn,
|
|
4143
|
+
region,
|
|
4144
|
+
description: `Internet-facing Application Load Balancer "${lbName}" does not have a WAF Web ACL associated. Traffic is not inspected for common web exploits.`,
|
|
4145
|
+
impact: "Without WAF, the ALB is exposed to SQL injection, XSS, and other OWASP Top 10 attacks",
|
|
4146
|
+
remediationSteps: [
|
|
4147
|
+
"Create a WAFv2 Web ACL with managed rule groups (e.g., AWSManagedRulesCommonRuleSet).",
|
|
4148
|
+
"Associate the Web ACL with the ALB using the REGIONAL scope.",
|
|
4149
|
+
"Enable WAF logging for visibility into blocked requests.",
|
|
4150
|
+
"Consider adding rate-based rules to mitigate DDoS at the application layer."
|
|
4151
|
+
]
|
|
4152
|
+
})
|
|
4153
|
+
);
|
|
4154
|
+
} else if (errName === "AccessDeniedException" || errName === "WAFInvalidParameterException") {
|
|
4155
|
+
warnings.push(
|
|
4156
|
+
`Could not check WAF for ALB "${lbName}": ${errMsg}. Ensure wafv2:GetWebACLForResource permission is granted.`
|
|
4157
|
+
);
|
|
4158
|
+
} else {
|
|
4159
|
+
warnings.push(`Error checking WAF for ALB "${lbName}": ${errMsg}`);
|
|
4160
|
+
}
|
|
4161
|
+
}
|
|
4162
|
+
}
|
|
4163
|
+
return {
|
|
4164
|
+
module: this.moduleName,
|
|
4165
|
+
status: "success",
|
|
4166
|
+
warnings: warnings.length > 0 ? warnings : void 0,
|
|
4167
|
+
resourcesScanned: internetFacing.length,
|
|
4168
|
+
findingsCount: findings.length,
|
|
4169
|
+
scanTimeMs: Date.now() - startMs,
|
|
4170
|
+
findings
|
|
4171
|
+
};
|
|
4172
|
+
} catch (err) {
|
|
4173
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
4174
|
+
const errName = err instanceof Error ? err.name ?? "" : "";
|
|
4175
|
+
if (errName === "AccessDeniedException" || errName === "UnrecognizedClientException") {
|
|
4176
|
+
return {
|
|
4177
|
+
module: this.moduleName,
|
|
4178
|
+
status: "success",
|
|
4179
|
+
warnings: [`WAF coverage check skipped: ${errMsg}`],
|
|
4180
|
+
resourcesScanned: 0,
|
|
4181
|
+
findingsCount: 0,
|
|
4182
|
+
scanTimeMs: Date.now() - startMs,
|
|
4183
|
+
findings: []
|
|
4184
|
+
};
|
|
4185
|
+
}
|
|
4186
|
+
return {
|
|
4187
|
+
module: this.moduleName,
|
|
4188
|
+
status: "error",
|
|
4189
|
+
error: errMsg,
|
|
4190
|
+
warnings: warnings.length > 0 ? warnings : void 0,
|
|
4191
|
+
resourcesScanned: 0,
|
|
4192
|
+
findingsCount: 0,
|
|
4193
|
+
scanTimeMs: Date.now() - startMs,
|
|
4194
|
+
findings: []
|
|
4195
|
+
};
|
|
4196
|
+
}
|
|
4197
|
+
}
|
|
4198
|
+
};
|
|
4199
|
+
|
|
3964
4200
|
// src/tools/report-tool.ts
|
|
3965
4201
|
var SEVERITY_ICON = {
|
|
3966
4202
|
CRITICAL: "\u{1F534}",
|
|
@@ -4348,6 +4584,92 @@ function scoreColor(score) {
|
|
|
4348
4584
|
if (score >= 50) return "#eab308";
|
|
4349
4585
|
return "#ef4444";
|
|
4350
4586
|
}
|
|
4587
|
+
var SERVICE_RECOMMENDATIONS = {
|
|
4588
|
+
security_hub_findings: {
|
|
4589
|
+
icon: "\u{1F534}",
|
|
4590
|
+
service: "Security Hub",
|
|
4591
|
+
impact: "\u65E0\u6CD5\u83B7\u53D6 300+ \u9879\u81EA\u52A8\u5316\u5B89\u5168\u68C0\u67E5\uFF08FSBP/CIS/PCI DSS \u6807\u51C6\uFF09",
|
|
4592
|
+
action: "\u542F\u7528 Security Hub \u83B7\u5F97\u6700\u5168\u9762\u7684\u5B89\u5168\u6001\u52BF\u8BC4\u4F30"
|
|
4593
|
+
},
|
|
4594
|
+
guardduty_findings: {
|
|
4595
|
+
icon: "\u{1F534}",
|
|
4596
|
+
service: "GuardDuty",
|
|
4597
|
+
impact: "\u65E0\u6CD5\u68C0\u6D4B\u5A01\u80C1\u6D3B\u52A8\uFF08\u6076\u610F IP\u3001\u5F02\u5E38 API \u8C03\u7528\u3001\u52A0\u5BC6\u8D27\u5E01\u6316\u77FF\u7B49\uFF09",
|
|
4598
|
+
action: "\u542F\u7528 GuardDuty \u83B7\u5F97\u6301\u7EED\u5A01\u80C1\u68C0\u6D4B\u80FD\u529B"
|
|
4599
|
+
},
|
|
4600
|
+
inspector_findings: {
|
|
4601
|
+
icon: "\u{1F7E1}",
|
|
4602
|
+
service: "Inspector",
|
|
4603
|
+
impact: "\u65E0\u6CD5\u626B\u63CF EC2/Lambda/\u5BB9\u5668\u7684\u8F6F\u4EF6\u6F0F\u6D1E\uFF08CVE\uFF09",
|
|
4604
|
+
action: "\u542F\u7528 Inspector \u53D1\u73B0\u5DF2\u77E5\u5B89\u5168\u6F0F\u6D1E"
|
|
4605
|
+
},
|
|
4606
|
+
trusted_advisor_findings: {
|
|
4607
|
+
icon: "\u{1F7E1}",
|
|
4608
|
+
service: "Trusted Advisor",
|
|
4609
|
+
impact: "\u65E0\u6CD5\u83B7\u53D6 AWS \u6700\u4F73\u5B9E\u8DF5\u5B89\u5168\u68C0\u67E5",
|
|
4610
|
+
action: "\u5347\u7EA7\u81F3 Business/Enterprise Support \u8BA1\u5212\u4EE5\u4F7F\u7528 Trusted Advisor \u5B89\u5168\u68C0\u67E5"
|
|
4611
|
+
},
|
|
4612
|
+
config_rules_findings: {
|
|
4613
|
+
icon: "\u{1F7E1}",
|
|
4614
|
+
service: "AWS Config",
|
|
4615
|
+
impact: "\u65E0\u6CD5\u68C0\u67E5\u8D44\u6E90\u914D\u7F6E\u5408\u89C4\u72B6\u6001",
|
|
4616
|
+
action: "\u542F\u7528 AWS Config \u5E76\u914D\u7F6E Config Rules"
|
|
4617
|
+
},
|
|
4618
|
+
access_analyzer_findings: {
|
|
4619
|
+
icon: "\u{1F7E1}",
|
|
4620
|
+
service: "IAM Access Analyzer",
|
|
4621
|
+
impact: "\u65E0\u6CD5\u68C0\u6D4B\u8D44\u6E90\u662F\u5426\u88AB\u5916\u90E8\u8D26\u53F7\u6216\u516C\u7F51\u8BBF\u95EE",
|
|
4622
|
+
action: "\u521B\u5EFA IAM Access Analyzer\uFF08\u8D26\u6237\u7EA7\u6216\u7EC4\u7EC7\u7EA7\uFF09"
|
|
4623
|
+
},
|
|
4624
|
+
patch_compliance_findings: {
|
|
4625
|
+
icon: "\u{1F7E1}",
|
|
4626
|
+
service: "SSM Patch Manager",
|
|
4627
|
+
impact: "\u65E0\u6CD5\u68C0\u67E5\u5B9E\u4F8B\u8865\u4E01\u5408\u89C4\u72B6\u6001",
|
|
4628
|
+
action: "\u5B89\u88C5 SSM Agent \u5E76\u914D\u7F6E Patch Manager"
|
|
4629
|
+
}
|
|
4630
|
+
};
|
|
4631
|
+
var SERVICE_NOT_ENABLED_PATTERNS = [
|
|
4632
|
+
"not enabled",
|
|
4633
|
+
"not found",
|
|
4634
|
+
"No IAM Access Analyzer",
|
|
4635
|
+
"No SSM-managed instances",
|
|
4636
|
+
"requires AWS Business or Enterprise Support",
|
|
4637
|
+
"not available",
|
|
4638
|
+
"is not enabled"
|
|
4639
|
+
];
|
|
4640
|
+
function getDisabledServices(modules) {
|
|
4641
|
+
const disabled = [];
|
|
4642
|
+
for (const mod of modules) {
|
|
4643
|
+
const rec = SERVICE_RECOMMENDATIONS[mod.module];
|
|
4644
|
+
if (!rec) continue;
|
|
4645
|
+
if (!mod.warnings?.length) continue;
|
|
4646
|
+
const hasNotEnabled = mod.warnings.some(
|
|
4647
|
+
(w) => SERVICE_NOT_ENABLED_PATTERNS.some((p) => w.includes(p))
|
|
4648
|
+
);
|
|
4649
|
+
if (hasNotEnabled) {
|
|
4650
|
+
disabled.push(rec);
|
|
4651
|
+
}
|
|
4652
|
+
}
|
|
4653
|
+
return disabled;
|
|
4654
|
+
}
|
|
4655
|
+
function buildServiceReminderHtml(modules) {
|
|
4656
|
+
const disabled = getDisabledServices(modules);
|
|
4657
|
+
if (disabled.length === 0) return "";
|
|
4658
|
+
const items = disabled.map((svc) => `
|
|
4659
|
+
<div style="margin-bottom:12px">
|
|
4660
|
+
<div style="font-weight:600;font-size:15px">${esc(svc.icon)} ${esc(svc.service)} \u672A\u542F\u7528</div>
|
|
4661
|
+
<div style="margin-left:28px;color:#cbd5e1;font-size:13px">\u5F71\u54CD\uFF1A${esc(svc.impact)}</div>
|
|
4662
|
+
<div style="margin-left:28px;color:#cbd5e1;font-size:13px">\u5EFA\u8BAE\uFF1A${esc(svc.action)}</div>
|
|
4663
|
+
</div>`).join("\n");
|
|
4664
|
+
return `
|
|
4665
|
+
<section>
|
|
4666
|
+
<div style="background:#2d1f00;border:1px solid #b45309;border-radius:8px;padding:20px;margin-bottom:32px">
|
|
4667
|
+
<div style="font-size:17px;font-weight:700;margin-bottom:12px">⚡ \u4EE5\u4E0B\u5B89\u5168\u670D\u52A1\u672A\u542F\u7528\uFF0C\u90E8\u5206\u68C0\u67E5\u65E0\u6CD5\u6267\u884C\uFF1A</div>
|
|
4668
|
+
${items}
|
|
4669
|
+
<div style="margin-top:12px;font-size:13px;color:#fbbf24;font-weight:500">\u542F\u7528\u4EE5\u4E0A\u670D\u52A1\u540E\u91CD\u65B0\u626B\u63CF\u53EF\u83B7\u5F97\u66F4\u5B8C\u6574\u7684\u5B89\u5168\u8BC4\u4F30\u3002</div>
|
|
4670
|
+
</div>
|
|
4671
|
+
</section>`;
|
|
4672
|
+
}
|
|
4351
4673
|
function sharedCss() {
|
|
4352
4674
|
return `
|
|
4353
4675
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
@@ -4873,6 +5195,8 @@ ${trendHtml}
|
|
|
4873
5195
|
|
|
4874
5196
|
${top5Html}
|
|
4875
5197
|
|
|
5198
|
+
${buildServiceReminderHtml(modules)}
|
|
5199
|
+
|
|
4876
5200
|
<section>
|
|
4877
5201
|
<h2>Scan Statistics</h2>
|
|
4878
5202
|
<table>
|
|
@@ -5069,6 +5393,8 @@ ${unknownNote}
|
|
|
5069
5393
|
|
|
5070
5394
|
${trendHtml}
|
|
5071
5395
|
|
|
5396
|
+
${buildServiceReminderHtml(scanResults.modules)}
|
|
5397
|
+
|
|
5072
5398
|
${categorySections}
|
|
5073
5399
|
|
|
5074
5400
|
${remediationHtml}
|
|
@@ -5192,13 +5518,13 @@ var SCAN_GROUPS = {
|
|
|
5192
5518
|
mlps3_precheck: {
|
|
5193
5519
|
name: "\u7B49\u4FDD\u4E09\u7EA7\u9884\u68C0",
|
|
5194
5520
|
description: "GB/T 22239-2019 \u7B49\u4FDD\u4E09\u7EA7 AWS \u4E91\u79DF\u6237\u5C42\u914D\u7F6E\u68C0\u67E5",
|
|
5195
|
-
modules: ["service_detection", "secret_exposure", "ssl_certificate", "dns_dangling", "network_reachability", "iam_privilege_escalation", "tag_compliance", "disaster_recovery", "security_hub_findings", "guardduty_findings", "inspector_findings", "trusted_advisor_findings", "config_rules_findings", "access_analyzer_findings", "patch_compliance_findings"],
|
|
5521
|
+
modules: ["service_detection", "secret_exposure", "ssl_certificate", "dns_dangling", "network_reachability", "iam_privilege_escalation", "tag_compliance", "disaster_recovery", "security_hub_findings", "guardduty_findings", "inspector_findings", "trusted_advisor_findings", "config_rules_findings", "access_analyzer_findings", "patch_compliance_findings", "imdsv2_enforcement", "waf_coverage"],
|
|
5196
5522
|
reportType: "mlps3"
|
|
5197
5523
|
},
|
|
5198
5524
|
hw_defense: {
|
|
5199
5525
|
name: "\u62A4\u7F51\u84DD\u961F\u52A0\u56FA",
|
|
5200
5526
|
description: "\u62A4\u7F51\u524D\u5B89\u5168\u81EA\u67E5 \u2014 \u653B\u51FB\u9762+\u5F31\u70B9\u8BC4\u4F30",
|
|
5201
|
-
modules: ["service_detection", "secret_exposure", "network_reachability", "dns_dangling", "ssl_certificate", "iam_privilege_escalation", "security_hub_findings", "guardduty_findings", "inspector_findings", "config_rules_findings", "access_analyzer_findings", "patch_compliance_findings"],
|
|
5527
|
+
modules: ["service_detection", "secret_exposure", "network_reachability", "dns_dangling", "ssl_certificate", "iam_privilege_escalation", "security_hub_findings", "guardduty_findings", "inspector_findings", "config_rules_findings", "access_analyzer_findings", "patch_compliance_findings", "imdsv2_enforcement", "waf_coverage"],
|
|
5202
5528
|
findingsFilter: {
|
|
5203
5529
|
guardDutyTypes: ["Backdoor", "Trojan", "PenTest", "CryptoCurrency"],
|
|
5204
5530
|
minSeverity: "MEDIUM"
|
|
@@ -5207,7 +5533,7 @@ var SCAN_GROUPS = {
|
|
|
5207
5533
|
exposure: {
|
|
5208
5534
|
name: "\u516C\u7F51\u66B4\u9732\u9762\u8BC4\u4F30",
|
|
5209
5535
|
description: "\u8BC4\u4F30\u516C\u7F51\u53EF\u8FBE\u7684\u8D44\u6E90\u548C\u7AEF\u53E3",
|
|
5210
|
-
modules: ["network_reachability", "dns_dangling", "public_access_verify", "ssl_certificate", "security_hub_findings", "access_analyzer_findings"],
|
|
5536
|
+
modules: ["network_reachability", "dns_dangling", "public_access_verify", "ssl_certificate", "security_hub_findings", "access_analyzer_findings", "imdsv2_enforcement", "waf_coverage"],
|
|
5211
5537
|
findingsFilter: {
|
|
5212
5538
|
securityHubCategories: ["network", "public", "exposure", "port"]
|
|
5213
5539
|
}
|
|
@@ -5254,7 +5580,7 @@ var SCAN_GROUPS = {
|
|
|
5254
5580
|
new_account_baseline: {
|
|
5255
5581
|
name: "\u65B0\u8D26\u6237\u57FA\u7EBF\u68C0\u67E5",
|
|
5256
5582
|
description: "\u65B0 AWS \u8D26\u6237\u5B89\u5168\u57FA\u7EBF",
|
|
5257
|
-
modules: ["service_detection", "secret_exposure", "iam_privilege_escalation", "security_hub_findings", "guardduty_findings", "access_analyzer_findings"]
|
|
5583
|
+
modules: ["service_detection", "secret_exposure", "iam_privilege_escalation", "security_hub_findings", "guardduty_findings", "access_analyzer_findings", "imdsv2_enforcement"]
|
|
5258
5584
|
},
|
|
5259
5585
|
aggregation: {
|
|
5260
5586
|
name: "\u5B89\u5168\u670D\u52A1\u805A\u5408",
|
|
@@ -5264,7 +5590,7 @@ var SCAN_GROUPS = {
|
|
|
5264
5590
|
};
|
|
5265
5591
|
|
|
5266
5592
|
// src/resources/index.ts
|
|
5267
|
-
var SECURITY_RULES_CONTENT = `# AWS Security Scan Modules & Rules (
|
|
5593
|
+
var SECURITY_RULES_CONTENT = `# AWS Security Scan Modules & Rules (19 modules)
|
|
5268
5594
|
|
|
5269
5595
|
## 1. Service Detection (service_detection)
|
|
5270
5596
|
Detects which AWS security services are enabled and assesses overall security maturity.
|
|
@@ -5358,6 +5684,21 @@ Checks patch compliance status for SSM-managed instances.
|
|
|
5358
5684
|
- Missing non-security patches \u2192 MEDIUM (5.5).
|
|
5359
5685
|
- Instances without patch data flagged as LOW (3.0) for visibility.
|
|
5360
5686
|
- Includes platform info, missing/failed counts, and last scan time.
|
|
5687
|
+
|
|
5688
|
+
## 18. IMDSv2 Enforcement (imdsv2_enforcement)
|
|
5689
|
+
Checks if EC2 instances enforce IMDSv2 (Instance Metadata Service v2).
|
|
5690
|
+
- Lists all running EC2 instances and checks MetadataOptions.HttpTokens.
|
|
5691
|
+
- **HttpTokens != "required"** \u2014 Risk 7.5: IMDSv1 allows credential theft via SSRF attacks.
|
|
5692
|
+
- Also checks HttpPutResponseHopLimit \u2014 values >1 on containerized workloads noted as warning.
|
|
5693
|
+
- Remediation: Set HttpTokens to "required" via modify-instance-metadata-options.
|
|
5694
|
+
|
|
5695
|
+
## 19. WAF Coverage (waf_coverage)
|
|
5696
|
+
Checks if internet-facing ALBs have WAF Web ACL associated for protection.
|
|
5697
|
+
- Lists all ELBv2 load balancers, filters to internet-facing only.
|
|
5698
|
+
- For each internet-facing ALB, checks WAFv2 Web ACL association.
|
|
5699
|
+
- **No WAF Web ACL** \u2014 Risk 7.5: ALB exposed to SQL injection, XSS, and OWASP Top 10 attacks.
|
|
5700
|
+
- NLBs (L4) are skipped as WAF does not apply \u2014 noted in warnings.
|
|
5701
|
+
- Gracefully handles WAFv2 access denied or unavailable regions.
|
|
5361
5702
|
`;
|
|
5362
5703
|
var RISK_SCORING_CONTENT = `# Risk Scoring Model
|
|
5363
5704
|
|
|
@@ -5422,8 +5763,144 @@ var MODULE_DESCRIPTIONS = {
|
|
|
5422
5763
|
trusted_advisor_findings: "Aggregates security checks from AWS Trusted Advisor \u2014 requires Business or Enterprise Support plan.",
|
|
5423
5764
|
config_rules_findings: "Pulls non-compliant AWS Config Rule evaluation results \u2014 configuration compliance violations across all resource types.",
|
|
5424
5765
|
access_analyzer_findings: "Pulls active IAM Access Analyzer findings \u2014 resources accessible from outside the account (external principals, public access).",
|
|
5425
|
-
patch_compliance_findings: "Checks SSM Patch Manager compliance \u2014 managed instances with missing or failed security and system patches."
|
|
5766
|
+
patch_compliance_findings: "Checks SSM Patch Manager compliance \u2014 managed instances with missing or failed security and system patches.",
|
|
5767
|
+
imdsv2_enforcement: "Checks if EC2 instances enforce IMDSv2 (HttpTokens: required) \u2014 IMDSv1 allows credential theft via SSRF.",
|
|
5768
|
+
waf_coverage: "Checks if internet-facing ALBs have WAF Web ACL associated for protection against common web exploits."
|
|
5769
|
+
};
|
|
5770
|
+
var HW_DEFENSE_CHECKLIST = `
|
|
5771
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
5772
|
+
\u{1F4CB} \u62A4\u7F51\u884C\u52A8\u8865\u5145\u63D0\u9192\uFF08\u8D85\u51FA\u81EA\u52A8\u5316\u626B\u63CF\u8303\u56F4\uFF09
|
|
5773
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
5774
|
+
|
|
5775
|
+
\u4EE5\u4E0B\u4E8B\u9879\u9700\u8981\u4EBA\u5DE5\u786E\u8BA4\u548C\u6267\u884C\uFF1A
|
|
5776
|
+
|
|
5777
|
+
\u26A0\uFE0F \u5E94\u6025\u9694\u79BB/\u6B62\u8840\u65B9\u6848
|
|
5778
|
+
\u25A1 \u51C6\u5907\u4E13\u7528\u9694\u79BB\u5B89\u5168\u7EC4\uFF08\u65E0 Inbound/Outbound \u89C4\u5219\uFF09
|
|
5779
|
+
\u25A1 \u5236\u5B9A\u5B9E\u4F8B\u9694\u79BB SOP\uFF1A\u544A\u8B66 \u2192 \u6392\u67E5 \u2192 \u5C01\u9501\u653B\u51FBIP \u2192 \u7F51\u7EDC\u9694\u79BB \u2192 \u5B89\u5168\u5904\u7F6E \u2192 \u8BB0\u5F55\u653B\u51FB\u9879
|
|
5780
|
+
\u25A1 \u660E\u786E\u5404\u7CFB\u7EDF\uFF08\u751F\u4EA7\u6838\u5FC3/\u751F\u4EA7\u975E\u6838\u5FC3/\u6D4B\u8BD5/\u5F00\u53D1\uFF09\u7684\u5E94\u6025\u5904\u7F6E\u65B9\u5F0F
|
|
5781
|
+
\u25A1 \u660E\u786E\u5404\u9879\u76EE\u8D26\u6237\u53CA\u8D44\u6E90\u7684\u8D1F\u8D23\u4EBA\u4E0E\u8054\u7CFB\u65B9\u5F0F
|
|
5782
|
+
|
|
5783
|
+
\u26A0\uFE0F \u6D4B\u8BD5/\u5F00\u53D1\u73AF\u5883\u5904\u7F6E
|
|
5784
|
+
\u25A1 \u975E\u6838\u5FC3\u7CFB\u7EDF\u5728\u62A4\u7F51\u671F\u95F4\u5173\u95ED
|
|
5785
|
+
\u25A1 \u6D4B\u8BD5/\u5F00\u53D1\u73AF\u5883\u5173\u95ED\u6216\u4E0E\u751F\u4EA7\u4FDD\u6301\u540C\u7B49\u5B89\u5168\u57FA\u7EBF
|
|
5786
|
+
\u25A1 \u786E\u8BA4\u54EA\u4E9B\u73AF\u5883\u53EF\u4EE5\u7D27\u6025\u5173\u505C\uFF0C\u907F\u514D\u653B\u51FB\u6269\u6563
|
|
5787
|
+
|
|
5788
|
+
\u26A0\uFE0F \u503C\u5B88\u56E2\u961F\u7EC4\u5EFA
|
|
5789
|
+
\u25A1 7\xD724 \u76D1\u63A7\u5FEB\u901F\u54CD\u5E94\u56E2\u961F
|
|
5790
|
+
\u25A1 \u6280\u672F\u4E0E\u98CE\u9669\u5206\u6790\u7EC4
|
|
5791
|
+
\u25A1 \u5B89\u5168\u7B56\u7565\u4E0B\u53D1\u7EC4
|
|
5792
|
+
\u25A1 \u4E1A\u52A1\u54CD\u5E94\u7EC4
|
|
5793
|
+
\u25A1 \u660E\u786E AWS TAM/Support \u8054\u7CFB\u65B9\u5F0F\uFF08ES/EOP \u5BA2\u6237\uFF09
|
|
5794
|
+
|
|
5795
|
+
\u26A0\uFE0F \u51FA\u5165\u7AD9\u8DEF\u5F84\u67B6\u6784\u56FE
|
|
5796
|
+
\u25A1 \u786E\u4FDD\u6240\u6709\u4E92\u8054\u7F51/DX \u4E13\u7EBF\u51FA\u5165\u7AD9\u8DEF\u5F84\u5728\u67B6\u6784\u56FE\u4E2D\u6E05\u6670\u6807\u6CE8
|
|
5797
|
+
\u25A1 \u660E\u786E\u5404 ELB/Public EC2/S3/DX \u7684\u6570\u636E\u6D41\u5411
|
|
5798
|
+
\u25A1 \u8BC6\u522B\u6240\u6709\u9762\u5411\u4E92\u8054\u7F51\u7684\u6570\u636E\u4EA4\u4E92\u63A5\u53E3
|
|
5799
|
+
|
|
5800
|
+
\u26A0\uFE0F \u4E3B\u52A8\u5F0F\u6E17\u900F\u6D4B\u8BD5
|
|
5801
|
+
\u25A1 \u62A4\u7F51\u524D\u8054\u7CFB\u5B89\u5168\u5382\u5546\uFF08\u9752\u85E4/\u957F\u4EAD/\u5FAE\u6B65\u7B49\uFF09\u8FDB\u884C\u6A21\u62DF\u653B\u51FB\u6F14\u7EC3
|
|
5802
|
+
\u25A1 \u57FA\u4E8E\u6E17\u900F\u6D4B\u8BD5\u62A5\u544A\u8FDB\u884C\u6B63\u5F0F\u62A4\u7F51\u524D\u7684\u5B89\u5168\u52A0\u56FA
|
|
5803
|
+
\u25A1 \u5173\u6CE8 AWS \u5B89\u5168\u516C\u544A\uFF08\u5DF2\u77E5\u6F0F\u6D1E\u4E0E\u8865\u4E01\uFF09
|
|
5804
|
+
|
|
5805
|
+
\u26A0\uFE0F WAR-ROOM \u5B9E\u65F6\u6C9F\u901A
|
|
5806
|
+
\u25A1 \u521B\u5EFA\u62A4\u7F51\u671F\u95F4\u4E13\u7528\u6C9F\u901A\u6E20\u9053\uFF08\u4F01\u5FAE/\u9489\u9489/\u98DE\u4E66/Chime\uFF09
|
|
5807
|
+
\u25A1 \u4E0E AWS TAM \u5EFA\u7ACB WAR-ROOM \u8054\u7CFB\uFF08\u4F01\u4E1A\u7EA7\u652F\u6301\u5BA2\u6237\uFF09
|
|
5808
|
+
\u25A1 \u7EDF\u4E00\u6848\u4F8B\u6807\u9898\u683C\u5F0F\uFF1A"\u3010\u62A4\u7F51\u3011+ \u95EE\u9898\u63CF\u8FF0"
|
|
5809
|
+
|
|
5810
|
+
\u26A0\uFE0F \u5BC6\u7801\u4E0E\u51ED\u8BC1\u7BA1\u7406
|
|
5811
|
+
\u25A1 \u6240\u6709 IAM \u7528\u6237\u7ED1\u5B9A MFA
|
|
5812
|
+
\u25A1 AKSK \u8F6E\u8F6C\u5468\u671F \u2264 90 \u5929
|
|
5813
|
+
\u25A1 \u907F\u514D\u5171\u4EAB\u8D26\u6237\u4F7F\u7528
|
|
5814
|
+
\u25A1 S3/Lambda/\u5E94\u7528\u4EE3\u7801\u4E2D\u65E0\u660E\u6587\u5BC6\u7801
|
|
5815
|
+
|
|
5816
|
+
\u26A0\uFE0F \u62A4\u7F51\u540E\u4F18\u5316
|
|
5817
|
+
\u25A1 \u9488\u5BF9\u653B\u51FB\u62A5\u544A\u9010\u9879\u5E94\u7B54\u4E0E\u4FEE\u590D
|
|
5818
|
+
\u25A1 \u4E0E\u5B89\u5168\u56E2\u961F\u5EFA\u7ACB\u5468\u671F\u6027\u5B89\u5168\u7EF4\u62A4\u6D41\u7A0B
|
|
5819
|
+
\u25A1 \u6301\u7EED\u8865\u5168\u5B89\u5168\u98CE\u9669
|
|
5820
|
+
|
|
5821
|
+
\u53C2\u8003\uFF1AAWS \u62A4\u7F51\u884C\u52A8 Standard Operation Procedure (Compliance IEM)
|
|
5822
|
+
`;
|
|
5823
|
+
var SERVICE_RECOMMENDATIONS2 = {
|
|
5824
|
+
security_hub_findings: {
|
|
5825
|
+
icon: "\u{1F534}",
|
|
5826
|
+
service: "Security Hub",
|
|
5827
|
+
impact: "\u65E0\u6CD5\u83B7\u53D6 300+ \u9879\u81EA\u52A8\u5316\u5B89\u5168\u68C0\u67E5\uFF08FSBP/CIS/PCI DSS \u6807\u51C6\uFF09",
|
|
5828
|
+
action: "\u542F\u7528 Security Hub \u83B7\u5F97\u6700\u5168\u9762\u7684\u5B89\u5168\u6001\u52BF\u8BC4\u4F30"
|
|
5829
|
+
},
|
|
5830
|
+
guardduty_findings: {
|
|
5831
|
+
icon: "\u{1F534}",
|
|
5832
|
+
service: "GuardDuty",
|
|
5833
|
+
impact: "\u65E0\u6CD5\u68C0\u6D4B\u5A01\u80C1\u6D3B\u52A8\uFF08\u6076\u610F IP\u3001\u5F02\u5E38 API \u8C03\u7528\u3001\u52A0\u5BC6\u8D27\u5E01\u6316\u77FF\u7B49\uFF09",
|
|
5834
|
+
action: "\u542F\u7528 GuardDuty \u83B7\u5F97\u6301\u7EED\u5A01\u80C1\u68C0\u6D4B\u80FD\u529B"
|
|
5835
|
+
},
|
|
5836
|
+
inspector_findings: {
|
|
5837
|
+
icon: "\u{1F7E1}",
|
|
5838
|
+
service: "Inspector",
|
|
5839
|
+
impact: "\u65E0\u6CD5\u626B\u63CF EC2/Lambda/\u5BB9\u5668\u7684\u8F6F\u4EF6\u6F0F\u6D1E\uFF08CVE\uFF09",
|
|
5840
|
+
action: "\u542F\u7528 Inspector \u53D1\u73B0\u5DF2\u77E5\u5B89\u5168\u6F0F\u6D1E"
|
|
5841
|
+
},
|
|
5842
|
+
trusted_advisor_findings: {
|
|
5843
|
+
icon: "\u{1F7E1}",
|
|
5844
|
+
service: "Trusted Advisor",
|
|
5845
|
+
impact: "\u65E0\u6CD5\u83B7\u53D6 AWS \u6700\u4F73\u5B9E\u8DF5\u5B89\u5168\u68C0\u67E5",
|
|
5846
|
+
action: "\u5347\u7EA7\u81F3 Business/Enterprise Support \u8BA1\u5212\u4EE5\u4F7F\u7528 Trusted Advisor \u5B89\u5168\u68C0\u67E5"
|
|
5847
|
+
},
|
|
5848
|
+
config_rules_findings: {
|
|
5849
|
+
icon: "\u{1F7E1}",
|
|
5850
|
+
service: "AWS Config",
|
|
5851
|
+
impact: "\u65E0\u6CD5\u68C0\u67E5\u8D44\u6E90\u914D\u7F6E\u5408\u89C4\u72B6\u6001",
|
|
5852
|
+
action: "\u542F\u7528 AWS Config \u5E76\u914D\u7F6E Config Rules"
|
|
5853
|
+
},
|
|
5854
|
+
access_analyzer_findings: {
|
|
5855
|
+
icon: "\u{1F7E1}",
|
|
5856
|
+
service: "IAM Access Analyzer",
|
|
5857
|
+
impact: "\u65E0\u6CD5\u68C0\u6D4B\u8D44\u6E90\u662F\u5426\u88AB\u5916\u90E8\u8D26\u53F7\u6216\u516C\u7F51\u8BBF\u95EE",
|
|
5858
|
+
action: "\u521B\u5EFA IAM Access Analyzer\uFF08\u8D26\u6237\u7EA7\u6216\u7EC4\u7EC7\u7EA7\uFF09"
|
|
5859
|
+
},
|
|
5860
|
+
patch_compliance_findings: {
|
|
5861
|
+
icon: "\u{1F7E1}",
|
|
5862
|
+
service: "SSM Patch Manager",
|
|
5863
|
+
impact: "\u65E0\u6CD5\u68C0\u67E5\u5B9E\u4F8B\u8865\u4E01\u5408\u89C4\u72B6\u6001",
|
|
5864
|
+
action: "\u5B89\u88C5 SSM Agent \u5E76\u914D\u7F6E Patch Manager"
|
|
5865
|
+
}
|
|
5426
5866
|
};
|
|
5867
|
+
var SERVICE_NOT_ENABLED_PATTERNS2 = [
|
|
5868
|
+
"not enabled",
|
|
5869
|
+
"not found",
|
|
5870
|
+
"No IAM Access Analyzer",
|
|
5871
|
+
"No SSM-managed instances",
|
|
5872
|
+
"requires AWS Business or Enterprise Support",
|
|
5873
|
+
"not available",
|
|
5874
|
+
"is not enabled"
|
|
5875
|
+
];
|
|
5876
|
+
function buildServiceReminder(modules) {
|
|
5877
|
+
const disabledServices = [];
|
|
5878
|
+
for (const mod of modules) {
|
|
5879
|
+
const rec = SERVICE_RECOMMENDATIONS2[mod.module];
|
|
5880
|
+
if (!rec) continue;
|
|
5881
|
+
if (!mod.warnings?.length) continue;
|
|
5882
|
+
const hasNotEnabled = mod.warnings.some(
|
|
5883
|
+
(w) => SERVICE_NOT_ENABLED_PATTERNS2.some((p) => w.includes(p))
|
|
5884
|
+
);
|
|
5885
|
+
if (hasNotEnabled) {
|
|
5886
|
+
disabledServices.push(rec);
|
|
5887
|
+
}
|
|
5888
|
+
}
|
|
5889
|
+
if (disabledServices.length === 0) return "";
|
|
5890
|
+
const lines = [
|
|
5891
|
+
"",
|
|
5892
|
+
"\u26A1 \u4EE5\u4E0B\u5B89\u5168\u670D\u52A1\u672A\u542F\u7528\uFF0C\u90E8\u5206\u68C0\u67E5\u65E0\u6CD5\u6267\u884C\uFF1A",
|
|
5893
|
+
""
|
|
5894
|
+
];
|
|
5895
|
+
for (const svc of disabledServices) {
|
|
5896
|
+
lines.push(`${svc.icon} ${svc.service} \u672A\u542F\u7528`);
|
|
5897
|
+
lines.push(` \u5F71\u54CD\uFF1A${svc.impact}`);
|
|
5898
|
+
lines.push(` \u5EFA\u8BAE\uFF1A${svc.action}`);
|
|
5899
|
+
lines.push("");
|
|
5900
|
+
}
|
|
5901
|
+
lines.push("\u542F\u7528\u4EE5\u4E0A\u670D\u52A1\u540E\u91CD\u65B0\u626B\u63CF\u53EF\u83B7\u5F97\u66F4\u5B8C\u6574\u7684\u5B89\u5168\u8BC4\u4F30\u3002");
|
|
5902
|
+
return lines.join("\n");
|
|
5903
|
+
}
|
|
5427
5904
|
function summarizeResult(result) {
|
|
5428
5905
|
const { summary } = result;
|
|
5429
5906
|
const lines = [
|
|
@@ -5431,6 +5908,10 @@ function summarizeResult(result) {
|
|
|
5431
5908
|
`Total findings: ${summary.totalFindings} (${summary.critical} Critical, ${summary.high} High, ${summary.medium} Medium, ${summary.low} Low)`,
|
|
5432
5909
|
`Modules: ${summary.modulesSuccess} succeeded, ${summary.modulesError} errored`
|
|
5433
5910
|
];
|
|
5911
|
+
const reminder = buildServiceReminder(result.modules);
|
|
5912
|
+
if (reminder) {
|
|
5913
|
+
lines.push(reminder);
|
|
5914
|
+
}
|
|
5434
5915
|
return lines.join("\n");
|
|
5435
5916
|
}
|
|
5436
5917
|
function summarizeScanResult(result) {
|
|
@@ -5474,7 +5955,9 @@ function createServer(defaultRegion) {
|
|
|
5474
5955
|
new TrustedAdvisorFindingsScanner(),
|
|
5475
5956
|
new ConfigRulesFindingsScanner(),
|
|
5476
5957
|
new AccessAnalyzerFindingsScanner(),
|
|
5477
|
-
new PatchComplianceFindingsScanner()
|
|
5958
|
+
new PatchComplianceFindingsScanner(),
|
|
5959
|
+
new Imdsv2EnforcementScanner(),
|
|
5960
|
+
new WafCoverageScanner()
|
|
5478
5961
|
];
|
|
5479
5962
|
const scannerMap = /* @__PURE__ */ new Map();
|
|
5480
5963
|
for (const s of allScanners) {
|
|
@@ -5530,7 +6013,9 @@ function createServer(defaultRegion) {
|
|
|
5530
6013
|
{ toolName: "scan_trusted_advisor_findings", moduleName: "trusted_advisor_findings", label: "Trusted Advisor Findings" },
|
|
5531
6014
|
{ toolName: "scan_config_rules_findings", moduleName: "config_rules_findings", label: "Config Rules Findings" },
|
|
5532
6015
|
{ toolName: "scan_access_analyzer_findings", moduleName: "access_analyzer_findings", label: "Access Analyzer Findings" },
|
|
5533
|
-
{ toolName: "scan_patch_compliance_findings", moduleName: "patch_compliance_findings", label: "Patch Compliance Findings" }
|
|
6016
|
+
{ toolName: "scan_patch_compliance_findings", moduleName: "patch_compliance_findings", label: "Patch Compliance Findings" },
|
|
6017
|
+
{ toolName: "scan_imdsv2_enforcement", moduleName: "imdsv2_enforcement", label: "IMDSv2 Enforcement" },
|
|
6018
|
+
{ toolName: "scan_waf_coverage", moduleName: "waf_coverage", label: "WAF Coverage" }
|
|
5534
6019
|
];
|
|
5535
6020
|
for (const { toolName, moduleName, label } of individualScanners) {
|
|
5536
6021
|
server.tool(
|
|
@@ -5653,12 +6138,17 @@ function createServer(defaultRegion) {
|
|
|
5653
6138
|
lines.push("");
|
|
5654
6139
|
lines.push(`Warning: ${missingModules.length} requested module(s) not available: ${missingModules.join(", ")}`);
|
|
5655
6140
|
}
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
6141
|
+
const content = [
|
|
6142
|
+
{ type: "text", text: lines.join("\n") },
|
|
6143
|
+
{ type: "text", text: JSON.stringify(result, null, 2) }
|
|
6144
|
+
];
|
|
6145
|
+
if (group === "hw_defense") {
|
|
6146
|
+
const summaryContent = content[0];
|
|
6147
|
+
if (summaryContent && summaryContent.type === "text") {
|
|
6148
|
+
summaryContent.text += "\n\n" + HW_DEFENSE_CHECKLIST;
|
|
6149
|
+
}
|
|
6150
|
+
}
|
|
6151
|
+
return { content };
|
|
5662
6152
|
} catch (err) {
|
|
5663
6153
|
return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
5664
6154
|
}
|
|
@@ -5962,7 +6452,7 @@ Deploy this as a StackSet from your Management Account to all member accounts.`
|
|
|
5962
6452
|
server.resource(
|
|
5963
6453
|
"security-rules",
|
|
5964
6454
|
"security://rules",
|
|
5965
|
-
{ description: "Describes all
|
|
6455
|
+
{ description: "Describes all 19 scan modules and their check rules", mimeType: "text/markdown" },
|
|
5966
6456
|
async () => ({
|
|
5967
6457
|
contents: [{ uri: "security://rules", text: SECURITY_RULES_CONTENT, mimeType: "text/markdown" }]
|
|
5968
6458
|
})
|
|
@@ -6009,6 +6499,25 @@ ${finding}`
|
|
|
6009
6499
|
]
|
|
6010
6500
|
})
|
|
6011
6501
|
);
|
|
6502
|
+
server.prompt(
|
|
6503
|
+
"hw_defense_checklist",
|
|
6504
|
+
"\u62A4\u7F51\u884C\u52A8\u5B8C\u6574\u68C0\u67E5\u6E05\u5355 \u2014 \u5305\u542B\u81EA\u52A8\u5316\u626B\u63CF\u9879\u548C\u4EBA\u5DE5\u68C0\u67E5\u9879",
|
|
6505
|
+
async () => ({
|
|
6506
|
+
messages: [
|
|
6507
|
+
{
|
|
6508
|
+
role: "user",
|
|
6509
|
+
content: {
|
|
6510
|
+
type: "text",
|
|
6511
|
+
text: `\u8BF7\u57FA\u4E8E\u4EE5\u4E0B\u62A4\u7F51\u884C\u52A8\u68C0\u67E5\u6E05\u5355\uFF0C\u5E2E\u52A9\u6211\u5236\u5B9A\u62A4\u7F51\u51C6\u5907\u8BA1\u5212\uFF1A
|
|
6512
|
+
|
|
6513
|
+
${HW_DEFENSE_CHECKLIST}
|
|
6514
|
+
|
|
6515
|
+
\u81EA\u52A8\u5316\u626B\u63CF\u90E8\u5206\u8BF7\u4F7F\u7528 scan_group hw_defense \u6267\u884C\u3002\u4EE5\u4E0A\u4EBA\u5DE5\u68C0\u67E5\u9879\u8BF7\u9010\u9879\u786E\u8BA4\u5E76\u63D0\u4F9B\u5177\u4F53\u5EFA\u8BAE\u3002`
|
|
6516
|
+
}
|
|
6517
|
+
}
|
|
6518
|
+
]
|
|
6519
|
+
})
|
|
6520
|
+
);
|
|
6012
6521
|
return server;
|
|
6013
6522
|
}
|
|
6014
6523
|
async function startServer(defaultRegion) {
|