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
package/dist/src/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
|
|
6
6
|
// src/version.ts
|
|
7
|
-
var VERSION = "0.
|
|
7
|
+
var VERSION = "0.5.1";
|
|
8
8
|
|
|
9
9
|
// src/utils/aws-client.ts
|
|
10
10
|
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
|
|
@@ -3733,6 +3733,242 @@ var PatchComplianceFindingsScanner = class {
|
|
|
3733
3733
|
}
|
|
3734
3734
|
};
|
|
3735
3735
|
|
|
3736
|
+
// src/scanners/imdsv2-enforcement.ts
|
|
3737
|
+
import {
|
|
3738
|
+
EC2Client as EC2Client6,
|
|
3739
|
+
DescribeInstancesCommand as DescribeInstancesCommand5
|
|
3740
|
+
} from "@aws-sdk/client-ec2";
|
|
3741
|
+
function makeFinding11(opts) {
|
|
3742
|
+
const severity = severityFromScore(opts.riskScore);
|
|
3743
|
+
return { ...opts, severity, priority: priorityFromSeverity(severity) };
|
|
3744
|
+
}
|
|
3745
|
+
var Imdsv2EnforcementScanner = class {
|
|
3746
|
+
moduleName = "imdsv2_enforcement";
|
|
3747
|
+
async scan(ctx) {
|
|
3748
|
+
const { region, partition, accountId } = ctx;
|
|
3749
|
+
const startMs = Date.now();
|
|
3750
|
+
const findings = [];
|
|
3751
|
+
const warnings = [];
|
|
3752
|
+
try {
|
|
3753
|
+
const client = createClient(EC2Client6, region, ctx.credentials);
|
|
3754
|
+
const instances = [];
|
|
3755
|
+
let nextToken;
|
|
3756
|
+
do {
|
|
3757
|
+
const resp = await client.send(
|
|
3758
|
+
new DescribeInstancesCommand5({
|
|
3759
|
+
Filters: [{ Name: "instance-state-name", Values: ["running"] }],
|
|
3760
|
+
NextToken: nextToken
|
|
3761
|
+
})
|
|
3762
|
+
);
|
|
3763
|
+
if (resp.Reservations) {
|
|
3764
|
+
for (const reservation of resp.Reservations) {
|
|
3765
|
+
if (reservation.Instances) {
|
|
3766
|
+
instances.push(...reservation.Instances);
|
|
3767
|
+
}
|
|
3768
|
+
}
|
|
3769
|
+
}
|
|
3770
|
+
nextToken = resp.NextToken;
|
|
3771
|
+
} while (nextToken);
|
|
3772
|
+
for (const instance of instances) {
|
|
3773
|
+
const instanceId = instance.InstanceId ?? "unknown";
|
|
3774
|
+
const instanceType = instance.InstanceType ?? "unknown";
|
|
3775
|
+
const state = instance.State?.Name ?? "unknown";
|
|
3776
|
+
const httpTokens = instance.MetadataOptions?.HttpTokens ?? "unknown";
|
|
3777
|
+
const hopLimit = instance.MetadataOptions?.HttpPutResponseHopLimit ?? 1;
|
|
3778
|
+
const instanceArn = `arn:${partition}:ec2:${region}:${accountId}:instance/${instanceId}`;
|
|
3779
|
+
if (httpTokens !== "required") {
|
|
3780
|
+
const description = [
|
|
3781
|
+
`EC2 instance ${instanceId} (type: ${instanceType}, state: ${state}) has HttpTokens set to "${httpTokens}".`,
|
|
3782
|
+
`IMDSv1 is accessible, allowing unauthenticated metadata requests.`
|
|
3783
|
+
];
|
|
3784
|
+
if (hopLimit > 1) {
|
|
3785
|
+
description.push(`HttpPutResponseHopLimit is ${hopLimit} (>1), which may allow containers to reach IMDS.`);
|
|
3786
|
+
}
|
|
3787
|
+
findings.push(
|
|
3788
|
+
makeFinding11({
|
|
3789
|
+
riskScore: 7.5,
|
|
3790
|
+
title: `EC2 instance ${instanceId} does not enforce IMDSv2`,
|
|
3791
|
+
resourceType: "AWS::EC2::Instance",
|
|
3792
|
+
resourceId: instanceId,
|
|
3793
|
+
resourceArn: instanceArn,
|
|
3794
|
+
region,
|
|
3795
|
+
description: description.join(" "),
|
|
3796
|
+
impact: "IMDSv1 allows attackers to steal IAM role credentials via SSRF attacks",
|
|
3797
|
+
remediationSteps: [
|
|
3798
|
+
"Enforce IMDSv2 by setting HttpTokens to 'required'.",
|
|
3799
|
+
"Run: aws ec2 modify-instance-metadata-options --instance-id " + instanceId + " --http-tokens required --http-endpoint enabled",
|
|
3800
|
+
"Set HttpPutResponseHopLimit to 1 unless running containers that need metadata access.",
|
|
3801
|
+
"Update launch templates and Auto Scaling groups to enforce IMDSv2 for new instances."
|
|
3802
|
+
]
|
|
3803
|
+
})
|
|
3804
|
+
);
|
|
3805
|
+
} else if (hopLimit > 1) {
|
|
3806
|
+
warnings.push(
|
|
3807
|
+
`Instance ${instanceId} enforces IMDSv2 but HttpPutResponseHopLimit is ${hopLimit} (>1). Verify this is intentional for containerized workloads.`
|
|
3808
|
+
);
|
|
3809
|
+
}
|
|
3810
|
+
}
|
|
3811
|
+
return {
|
|
3812
|
+
module: this.moduleName,
|
|
3813
|
+
status: "success",
|
|
3814
|
+
warnings: warnings.length > 0 ? warnings : void 0,
|
|
3815
|
+
resourcesScanned: instances.length,
|
|
3816
|
+
findingsCount: findings.length,
|
|
3817
|
+
scanTimeMs: Date.now() - startMs,
|
|
3818
|
+
findings
|
|
3819
|
+
};
|
|
3820
|
+
} catch (err) {
|
|
3821
|
+
return {
|
|
3822
|
+
module: this.moduleName,
|
|
3823
|
+
status: "error",
|
|
3824
|
+
error: err instanceof Error ? err.message : String(err),
|
|
3825
|
+
warnings: warnings.length > 0 ? warnings : void 0,
|
|
3826
|
+
resourcesScanned: 0,
|
|
3827
|
+
findingsCount: 0,
|
|
3828
|
+
scanTimeMs: Date.now() - startMs,
|
|
3829
|
+
findings: []
|
|
3830
|
+
};
|
|
3831
|
+
}
|
|
3832
|
+
}
|
|
3833
|
+
};
|
|
3834
|
+
|
|
3835
|
+
// src/scanners/waf-coverage.ts
|
|
3836
|
+
import {
|
|
3837
|
+
ElasticLoadBalancingV2Client,
|
|
3838
|
+
DescribeLoadBalancersCommand
|
|
3839
|
+
} from "@aws-sdk/client-elastic-load-balancing-v2";
|
|
3840
|
+
import {
|
|
3841
|
+
WAFV2Client,
|
|
3842
|
+
GetWebACLForResourceCommand
|
|
3843
|
+
} from "@aws-sdk/client-wafv2";
|
|
3844
|
+
function makeFinding12(opts) {
|
|
3845
|
+
const severity = severityFromScore(opts.riskScore);
|
|
3846
|
+
return { ...opts, severity, priority: priorityFromSeverity(severity) };
|
|
3847
|
+
}
|
|
3848
|
+
var WafCoverageScanner = class {
|
|
3849
|
+
moduleName = "waf_coverage";
|
|
3850
|
+
async scan(ctx) {
|
|
3851
|
+
const { region } = ctx;
|
|
3852
|
+
const startMs = Date.now();
|
|
3853
|
+
const findings = [];
|
|
3854
|
+
const warnings = [];
|
|
3855
|
+
try {
|
|
3856
|
+
const elbClient = createClient(ElasticLoadBalancingV2Client, region, ctx.credentials);
|
|
3857
|
+
const wafClient = createClient(WAFV2Client, region, ctx.credentials);
|
|
3858
|
+
const loadBalancers = [];
|
|
3859
|
+
let marker;
|
|
3860
|
+
do {
|
|
3861
|
+
const resp = await elbClient.send(
|
|
3862
|
+
new DescribeLoadBalancersCommand({ Marker: marker })
|
|
3863
|
+
);
|
|
3864
|
+
if (resp.LoadBalancers) {
|
|
3865
|
+
loadBalancers.push(...resp.LoadBalancers);
|
|
3866
|
+
}
|
|
3867
|
+
marker = resp.NextMarker;
|
|
3868
|
+
} while (marker);
|
|
3869
|
+
const internetFacing = loadBalancers.filter((lb) => lb.Scheme === "internet-facing");
|
|
3870
|
+
for (const lb of internetFacing) {
|
|
3871
|
+
const lbName = lb.LoadBalancerName ?? "unknown";
|
|
3872
|
+
const lbArn = lb.LoadBalancerArn ?? "unknown";
|
|
3873
|
+
const lbType = lb.Type ?? "unknown";
|
|
3874
|
+
if (lbType !== "application") {
|
|
3875
|
+
warnings.push(
|
|
3876
|
+
`Skipping ${lbType} load balancer "${lbName}" \u2014 WAF Web ACL association is only supported for ALBs.`
|
|
3877
|
+
);
|
|
3878
|
+
continue;
|
|
3879
|
+
}
|
|
3880
|
+
try {
|
|
3881
|
+
const wafResp = await wafClient.send(
|
|
3882
|
+
new GetWebACLForResourceCommand({ ResourceArn: lbArn })
|
|
3883
|
+
);
|
|
3884
|
+
if (!wafResp.WebACL) {
|
|
3885
|
+
findings.push(
|
|
3886
|
+
makeFinding12({
|
|
3887
|
+
riskScore: 7.5,
|
|
3888
|
+
title: `Internet-facing ALB ${lbName} has no WAF protection`,
|
|
3889
|
+
resourceType: "AWS::ElasticLoadBalancingV2::LoadBalancer",
|
|
3890
|
+
resourceId: lbName,
|
|
3891
|
+
resourceArn: lbArn,
|
|
3892
|
+
region,
|
|
3893
|
+
description: `Internet-facing Application Load Balancer "${lbName}" does not have a WAF Web ACL associated. Traffic is not inspected for common web exploits.`,
|
|
3894
|
+
impact: "Without WAF, the ALB is exposed to SQL injection, XSS, and other OWASP Top 10 attacks",
|
|
3895
|
+
remediationSteps: [
|
|
3896
|
+
"Create a WAFv2 Web ACL with managed rule groups (e.g., AWSManagedRulesCommonRuleSet).",
|
|
3897
|
+
"Associate the Web ACL with the ALB using the REGIONAL scope.",
|
|
3898
|
+
"Enable WAF logging for visibility into blocked requests.",
|
|
3899
|
+
"Consider adding rate-based rules to mitigate DDoS at the application layer."
|
|
3900
|
+
]
|
|
3901
|
+
})
|
|
3902
|
+
);
|
|
3903
|
+
}
|
|
3904
|
+
} catch (wafErr) {
|
|
3905
|
+
const errMsg = wafErr instanceof Error ? wafErr.message : String(wafErr);
|
|
3906
|
+
const errName = wafErr instanceof Error ? wafErr.name ?? "" : "";
|
|
3907
|
+
if (errName === "WAFNonexistentItemException") {
|
|
3908
|
+
findings.push(
|
|
3909
|
+
makeFinding12({
|
|
3910
|
+
riskScore: 7.5,
|
|
3911
|
+
title: `Internet-facing ALB ${lbName} has no WAF protection`,
|
|
3912
|
+
resourceType: "AWS::ElasticLoadBalancingV2::LoadBalancer",
|
|
3913
|
+
resourceId: lbName,
|
|
3914
|
+
resourceArn: lbArn,
|
|
3915
|
+
region,
|
|
3916
|
+
description: `Internet-facing Application Load Balancer "${lbName}" does not have a WAF Web ACL associated. Traffic is not inspected for common web exploits.`,
|
|
3917
|
+
impact: "Without WAF, the ALB is exposed to SQL injection, XSS, and other OWASP Top 10 attacks",
|
|
3918
|
+
remediationSteps: [
|
|
3919
|
+
"Create a WAFv2 Web ACL with managed rule groups (e.g., AWSManagedRulesCommonRuleSet).",
|
|
3920
|
+
"Associate the Web ACL with the ALB using the REGIONAL scope.",
|
|
3921
|
+
"Enable WAF logging for visibility into blocked requests.",
|
|
3922
|
+
"Consider adding rate-based rules to mitigate DDoS at the application layer."
|
|
3923
|
+
]
|
|
3924
|
+
})
|
|
3925
|
+
);
|
|
3926
|
+
} else if (errName === "AccessDeniedException" || errName === "WAFInvalidParameterException") {
|
|
3927
|
+
warnings.push(
|
|
3928
|
+
`Could not check WAF for ALB "${lbName}": ${errMsg}. Ensure wafv2:GetWebACLForResource permission is granted.`
|
|
3929
|
+
);
|
|
3930
|
+
} else {
|
|
3931
|
+
warnings.push(`Error checking WAF for ALB "${lbName}": ${errMsg}`);
|
|
3932
|
+
}
|
|
3933
|
+
}
|
|
3934
|
+
}
|
|
3935
|
+
return {
|
|
3936
|
+
module: this.moduleName,
|
|
3937
|
+
status: "success",
|
|
3938
|
+
warnings: warnings.length > 0 ? warnings : void 0,
|
|
3939
|
+
resourcesScanned: internetFacing.length,
|
|
3940
|
+
findingsCount: findings.length,
|
|
3941
|
+
scanTimeMs: Date.now() - startMs,
|
|
3942
|
+
findings
|
|
3943
|
+
};
|
|
3944
|
+
} catch (err) {
|
|
3945
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3946
|
+
const errName = err instanceof Error ? err.name ?? "" : "";
|
|
3947
|
+
if (errName === "AccessDeniedException" || errName === "UnrecognizedClientException") {
|
|
3948
|
+
return {
|
|
3949
|
+
module: this.moduleName,
|
|
3950
|
+
status: "success",
|
|
3951
|
+
warnings: [`WAF coverage check skipped: ${errMsg}`],
|
|
3952
|
+
resourcesScanned: 0,
|
|
3953
|
+
findingsCount: 0,
|
|
3954
|
+
scanTimeMs: Date.now() - startMs,
|
|
3955
|
+
findings: []
|
|
3956
|
+
};
|
|
3957
|
+
}
|
|
3958
|
+
return {
|
|
3959
|
+
module: this.moduleName,
|
|
3960
|
+
status: "error",
|
|
3961
|
+
error: errMsg,
|
|
3962
|
+
warnings: warnings.length > 0 ? warnings : void 0,
|
|
3963
|
+
resourcesScanned: 0,
|
|
3964
|
+
findingsCount: 0,
|
|
3965
|
+
scanTimeMs: Date.now() - startMs,
|
|
3966
|
+
findings: []
|
|
3967
|
+
};
|
|
3968
|
+
}
|
|
3969
|
+
}
|
|
3970
|
+
};
|
|
3971
|
+
|
|
3736
3972
|
// src/tools/report-tool.ts
|
|
3737
3973
|
var SEVERITY_ICON = {
|
|
3738
3974
|
CRITICAL: "\u{1F534}",
|
|
@@ -4120,6 +4356,92 @@ function scoreColor(score) {
|
|
|
4120
4356
|
if (score >= 50) return "#eab308";
|
|
4121
4357
|
return "#ef4444";
|
|
4122
4358
|
}
|
|
4359
|
+
var SERVICE_RECOMMENDATIONS = {
|
|
4360
|
+
security_hub_findings: {
|
|
4361
|
+
icon: "\u{1F534}",
|
|
4362
|
+
service: "Security Hub",
|
|
4363
|
+
impact: "\u65E0\u6CD5\u83B7\u53D6 300+ \u9879\u81EA\u52A8\u5316\u5B89\u5168\u68C0\u67E5\uFF08FSBP/CIS/PCI DSS \u6807\u51C6\uFF09",
|
|
4364
|
+
action: "\u542F\u7528 Security Hub \u83B7\u5F97\u6700\u5168\u9762\u7684\u5B89\u5168\u6001\u52BF\u8BC4\u4F30"
|
|
4365
|
+
},
|
|
4366
|
+
guardduty_findings: {
|
|
4367
|
+
icon: "\u{1F534}",
|
|
4368
|
+
service: "GuardDuty",
|
|
4369
|
+
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",
|
|
4370
|
+
action: "\u542F\u7528 GuardDuty \u83B7\u5F97\u6301\u7EED\u5A01\u80C1\u68C0\u6D4B\u80FD\u529B"
|
|
4371
|
+
},
|
|
4372
|
+
inspector_findings: {
|
|
4373
|
+
icon: "\u{1F7E1}",
|
|
4374
|
+
service: "Inspector",
|
|
4375
|
+
impact: "\u65E0\u6CD5\u626B\u63CF EC2/Lambda/\u5BB9\u5668\u7684\u8F6F\u4EF6\u6F0F\u6D1E\uFF08CVE\uFF09",
|
|
4376
|
+
action: "\u542F\u7528 Inspector \u53D1\u73B0\u5DF2\u77E5\u5B89\u5168\u6F0F\u6D1E"
|
|
4377
|
+
},
|
|
4378
|
+
trusted_advisor_findings: {
|
|
4379
|
+
icon: "\u{1F7E1}",
|
|
4380
|
+
service: "Trusted Advisor",
|
|
4381
|
+
impact: "\u65E0\u6CD5\u83B7\u53D6 AWS \u6700\u4F73\u5B9E\u8DF5\u5B89\u5168\u68C0\u67E5",
|
|
4382
|
+
action: "\u5347\u7EA7\u81F3 Business/Enterprise Support \u8BA1\u5212\u4EE5\u4F7F\u7528 Trusted Advisor \u5B89\u5168\u68C0\u67E5"
|
|
4383
|
+
},
|
|
4384
|
+
config_rules_findings: {
|
|
4385
|
+
icon: "\u{1F7E1}",
|
|
4386
|
+
service: "AWS Config",
|
|
4387
|
+
impact: "\u65E0\u6CD5\u68C0\u67E5\u8D44\u6E90\u914D\u7F6E\u5408\u89C4\u72B6\u6001",
|
|
4388
|
+
action: "\u542F\u7528 AWS Config \u5E76\u914D\u7F6E Config Rules"
|
|
4389
|
+
},
|
|
4390
|
+
access_analyzer_findings: {
|
|
4391
|
+
icon: "\u{1F7E1}",
|
|
4392
|
+
service: "IAM Access Analyzer",
|
|
4393
|
+
impact: "\u65E0\u6CD5\u68C0\u6D4B\u8D44\u6E90\u662F\u5426\u88AB\u5916\u90E8\u8D26\u53F7\u6216\u516C\u7F51\u8BBF\u95EE",
|
|
4394
|
+
action: "\u521B\u5EFA IAM Access Analyzer\uFF08\u8D26\u6237\u7EA7\u6216\u7EC4\u7EC7\u7EA7\uFF09"
|
|
4395
|
+
},
|
|
4396
|
+
patch_compliance_findings: {
|
|
4397
|
+
icon: "\u{1F7E1}",
|
|
4398
|
+
service: "SSM Patch Manager",
|
|
4399
|
+
impact: "\u65E0\u6CD5\u68C0\u67E5\u5B9E\u4F8B\u8865\u4E01\u5408\u89C4\u72B6\u6001",
|
|
4400
|
+
action: "\u5B89\u88C5 SSM Agent \u5E76\u914D\u7F6E Patch Manager"
|
|
4401
|
+
}
|
|
4402
|
+
};
|
|
4403
|
+
var SERVICE_NOT_ENABLED_PATTERNS = [
|
|
4404
|
+
"not enabled",
|
|
4405
|
+
"not found",
|
|
4406
|
+
"No IAM Access Analyzer",
|
|
4407
|
+
"No SSM-managed instances",
|
|
4408
|
+
"requires AWS Business or Enterprise Support",
|
|
4409
|
+
"not available",
|
|
4410
|
+
"is not enabled"
|
|
4411
|
+
];
|
|
4412
|
+
function getDisabledServices(modules) {
|
|
4413
|
+
const disabled = [];
|
|
4414
|
+
for (const mod of modules) {
|
|
4415
|
+
const rec = SERVICE_RECOMMENDATIONS[mod.module];
|
|
4416
|
+
if (!rec) continue;
|
|
4417
|
+
if (!mod.warnings?.length) continue;
|
|
4418
|
+
const hasNotEnabled = mod.warnings.some(
|
|
4419
|
+
(w) => SERVICE_NOT_ENABLED_PATTERNS.some((p) => w.includes(p))
|
|
4420
|
+
);
|
|
4421
|
+
if (hasNotEnabled) {
|
|
4422
|
+
disabled.push(rec);
|
|
4423
|
+
}
|
|
4424
|
+
}
|
|
4425
|
+
return disabled;
|
|
4426
|
+
}
|
|
4427
|
+
function buildServiceReminderHtml(modules) {
|
|
4428
|
+
const disabled = getDisabledServices(modules);
|
|
4429
|
+
if (disabled.length === 0) return "";
|
|
4430
|
+
const items = disabled.map((svc) => `
|
|
4431
|
+
<div style="margin-bottom:12px">
|
|
4432
|
+
<div style="font-weight:600;font-size:15px">${esc(svc.icon)} ${esc(svc.service)} \u672A\u542F\u7528</div>
|
|
4433
|
+
<div style="margin-left:28px;color:#cbd5e1;font-size:13px">\u5F71\u54CD\uFF1A${esc(svc.impact)}</div>
|
|
4434
|
+
<div style="margin-left:28px;color:#cbd5e1;font-size:13px">\u5EFA\u8BAE\uFF1A${esc(svc.action)}</div>
|
|
4435
|
+
</div>`).join("\n");
|
|
4436
|
+
return `
|
|
4437
|
+
<section>
|
|
4438
|
+
<div style="background:#2d1f00;border:1px solid #b45309;border-radius:8px;padding:20px;margin-bottom:32px">
|
|
4439
|
+
<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>
|
|
4440
|
+
${items}
|
|
4441
|
+
<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>
|
|
4442
|
+
</div>
|
|
4443
|
+
</section>`;
|
|
4444
|
+
}
|
|
4123
4445
|
function sharedCss() {
|
|
4124
4446
|
return `
|
|
4125
4447
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
@@ -4645,6 +4967,8 @@ ${trendHtml}
|
|
|
4645
4967
|
|
|
4646
4968
|
${top5Html}
|
|
4647
4969
|
|
|
4970
|
+
${buildServiceReminderHtml(modules)}
|
|
4971
|
+
|
|
4648
4972
|
<section>
|
|
4649
4973
|
<h2>Scan Statistics</h2>
|
|
4650
4974
|
<table>
|
|
@@ -4841,6 +5165,8 @@ ${unknownNote}
|
|
|
4841
5165
|
|
|
4842
5166
|
${trendHtml}
|
|
4843
5167
|
|
|
5168
|
+
${buildServiceReminderHtml(scanResults.modules)}
|
|
5169
|
+
|
|
4844
5170
|
${categorySections}
|
|
4845
5171
|
|
|
4846
5172
|
${remediationHtml}
|
|
@@ -4964,13 +5290,13 @@ var SCAN_GROUPS = {
|
|
|
4964
5290
|
mlps3_precheck: {
|
|
4965
5291
|
name: "\u7B49\u4FDD\u4E09\u7EA7\u9884\u68C0",
|
|
4966
5292
|
description: "GB/T 22239-2019 \u7B49\u4FDD\u4E09\u7EA7 AWS \u4E91\u79DF\u6237\u5C42\u914D\u7F6E\u68C0\u67E5",
|
|
4967
|
-
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"],
|
|
5293
|
+
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"],
|
|
4968
5294
|
reportType: "mlps3"
|
|
4969
5295
|
},
|
|
4970
5296
|
hw_defense: {
|
|
4971
5297
|
name: "\u62A4\u7F51\u84DD\u961F\u52A0\u56FA",
|
|
4972
5298
|
description: "\u62A4\u7F51\u524D\u5B89\u5168\u81EA\u67E5 \u2014 \u653B\u51FB\u9762+\u5F31\u70B9\u8BC4\u4F30",
|
|
4973
|
-
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"],
|
|
5299
|
+
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"],
|
|
4974
5300
|
findingsFilter: {
|
|
4975
5301
|
guardDutyTypes: ["Backdoor", "Trojan", "PenTest", "CryptoCurrency"],
|
|
4976
5302
|
minSeverity: "MEDIUM"
|
|
@@ -4979,7 +5305,7 @@ var SCAN_GROUPS = {
|
|
|
4979
5305
|
exposure: {
|
|
4980
5306
|
name: "\u516C\u7F51\u66B4\u9732\u9762\u8BC4\u4F30",
|
|
4981
5307
|
description: "\u8BC4\u4F30\u516C\u7F51\u53EF\u8FBE\u7684\u8D44\u6E90\u548C\u7AEF\u53E3",
|
|
4982
|
-
modules: ["network_reachability", "dns_dangling", "public_access_verify", "ssl_certificate", "security_hub_findings", "access_analyzer_findings"],
|
|
5308
|
+
modules: ["network_reachability", "dns_dangling", "public_access_verify", "ssl_certificate", "security_hub_findings", "access_analyzer_findings", "imdsv2_enforcement", "waf_coverage"],
|
|
4983
5309
|
findingsFilter: {
|
|
4984
5310
|
securityHubCategories: ["network", "public", "exposure", "port"]
|
|
4985
5311
|
}
|
|
@@ -5026,7 +5352,7 @@ var SCAN_GROUPS = {
|
|
|
5026
5352
|
new_account_baseline: {
|
|
5027
5353
|
name: "\u65B0\u8D26\u6237\u57FA\u7EBF\u68C0\u67E5",
|
|
5028
5354
|
description: "\u65B0 AWS \u8D26\u6237\u5B89\u5168\u57FA\u7EBF",
|
|
5029
|
-
modules: ["service_detection", "secret_exposure", "iam_privilege_escalation", "security_hub_findings", "guardduty_findings", "access_analyzer_findings"]
|
|
5355
|
+
modules: ["service_detection", "secret_exposure", "iam_privilege_escalation", "security_hub_findings", "guardduty_findings", "access_analyzer_findings", "imdsv2_enforcement"]
|
|
5030
5356
|
},
|
|
5031
5357
|
aggregation: {
|
|
5032
5358
|
name: "\u5B89\u5168\u670D\u52A1\u805A\u5408",
|
|
@@ -5036,7 +5362,7 @@ var SCAN_GROUPS = {
|
|
|
5036
5362
|
};
|
|
5037
5363
|
|
|
5038
5364
|
// src/resources/index.ts
|
|
5039
|
-
var SECURITY_RULES_CONTENT = `# AWS Security Scan Modules & Rules (
|
|
5365
|
+
var SECURITY_RULES_CONTENT = `# AWS Security Scan Modules & Rules (19 modules)
|
|
5040
5366
|
|
|
5041
5367
|
## 1. Service Detection (service_detection)
|
|
5042
5368
|
Detects which AWS security services are enabled and assesses overall security maturity.
|
|
@@ -5130,6 +5456,21 @@ Checks patch compliance status for SSM-managed instances.
|
|
|
5130
5456
|
- Missing non-security patches \u2192 MEDIUM (5.5).
|
|
5131
5457
|
- Instances without patch data flagged as LOW (3.0) for visibility.
|
|
5132
5458
|
- Includes platform info, missing/failed counts, and last scan time.
|
|
5459
|
+
|
|
5460
|
+
## 18. IMDSv2 Enforcement (imdsv2_enforcement)
|
|
5461
|
+
Checks if EC2 instances enforce IMDSv2 (Instance Metadata Service v2).
|
|
5462
|
+
- Lists all running EC2 instances and checks MetadataOptions.HttpTokens.
|
|
5463
|
+
- **HttpTokens != "required"** \u2014 Risk 7.5: IMDSv1 allows credential theft via SSRF attacks.
|
|
5464
|
+
- Also checks HttpPutResponseHopLimit \u2014 values >1 on containerized workloads noted as warning.
|
|
5465
|
+
- Remediation: Set HttpTokens to "required" via modify-instance-metadata-options.
|
|
5466
|
+
|
|
5467
|
+
## 19. WAF Coverage (waf_coverage)
|
|
5468
|
+
Checks if internet-facing ALBs have WAF Web ACL associated for protection.
|
|
5469
|
+
- Lists all ELBv2 load balancers, filters to internet-facing only.
|
|
5470
|
+
- For each internet-facing ALB, checks WAFv2 Web ACL association.
|
|
5471
|
+
- **No WAF Web ACL** \u2014 Risk 7.5: ALB exposed to SQL injection, XSS, and OWASP Top 10 attacks.
|
|
5472
|
+
- NLBs (L4) are skipped as WAF does not apply \u2014 noted in warnings.
|
|
5473
|
+
- Gracefully handles WAFv2 access denied or unavailable regions.
|
|
5133
5474
|
`;
|
|
5134
5475
|
var RISK_SCORING_CONTENT = `# Risk Scoring Model
|
|
5135
5476
|
|
|
@@ -5194,8 +5535,144 @@ var MODULE_DESCRIPTIONS = {
|
|
|
5194
5535
|
trusted_advisor_findings: "Aggregates security checks from AWS Trusted Advisor \u2014 requires Business or Enterprise Support plan.",
|
|
5195
5536
|
config_rules_findings: "Pulls non-compliant AWS Config Rule evaluation results \u2014 configuration compliance violations across all resource types.",
|
|
5196
5537
|
access_analyzer_findings: "Pulls active IAM Access Analyzer findings \u2014 resources accessible from outside the account (external principals, public access).",
|
|
5197
|
-
patch_compliance_findings: "Checks SSM Patch Manager compliance \u2014 managed instances with missing or failed security and system patches."
|
|
5538
|
+
patch_compliance_findings: "Checks SSM Patch Manager compliance \u2014 managed instances with missing or failed security and system patches.",
|
|
5539
|
+
imdsv2_enforcement: "Checks if EC2 instances enforce IMDSv2 (HttpTokens: required) \u2014 IMDSv1 allows credential theft via SSRF.",
|
|
5540
|
+
waf_coverage: "Checks if internet-facing ALBs have WAF Web ACL associated for protection against common web exploits."
|
|
5541
|
+
};
|
|
5542
|
+
var HW_DEFENSE_CHECKLIST = `
|
|
5543
|
+
\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
|
|
5544
|
+
\u{1F4CB} \u62A4\u7F51\u884C\u52A8\u8865\u5145\u63D0\u9192\uFF08\u8D85\u51FA\u81EA\u52A8\u5316\u626B\u63CF\u8303\u56F4\uFF09
|
|
5545
|
+
\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
|
|
5546
|
+
|
|
5547
|
+
\u4EE5\u4E0B\u4E8B\u9879\u9700\u8981\u4EBA\u5DE5\u786E\u8BA4\u548C\u6267\u884C\uFF1A
|
|
5548
|
+
|
|
5549
|
+
\u26A0\uFE0F \u5E94\u6025\u9694\u79BB/\u6B62\u8840\u65B9\u6848
|
|
5550
|
+
\u25A1 \u51C6\u5907\u4E13\u7528\u9694\u79BB\u5B89\u5168\u7EC4\uFF08\u65E0 Inbound/Outbound \u89C4\u5219\uFF09
|
|
5551
|
+
\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
|
|
5552
|
+
\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
|
|
5553
|
+
\u25A1 \u660E\u786E\u5404\u9879\u76EE\u8D26\u6237\u53CA\u8D44\u6E90\u7684\u8D1F\u8D23\u4EBA\u4E0E\u8054\u7CFB\u65B9\u5F0F
|
|
5554
|
+
|
|
5555
|
+
\u26A0\uFE0F \u6D4B\u8BD5/\u5F00\u53D1\u73AF\u5883\u5904\u7F6E
|
|
5556
|
+
\u25A1 \u975E\u6838\u5FC3\u7CFB\u7EDF\u5728\u62A4\u7F51\u671F\u95F4\u5173\u95ED
|
|
5557
|
+
\u25A1 \u6D4B\u8BD5/\u5F00\u53D1\u73AF\u5883\u5173\u95ED\u6216\u4E0E\u751F\u4EA7\u4FDD\u6301\u540C\u7B49\u5B89\u5168\u57FA\u7EBF
|
|
5558
|
+
\u25A1 \u786E\u8BA4\u54EA\u4E9B\u73AF\u5883\u53EF\u4EE5\u7D27\u6025\u5173\u505C\uFF0C\u907F\u514D\u653B\u51FB\u6269\u6563
|
|
5559
|
+
|
|
5560
|
+
\u26A0\uFE0F \u503C\u5B88\u56E2\u961F\u7EC4\u5EFA
|
|
5561
|
+
\u25A1 7\xD724 \u76D1\u63A7\u5FEB\u901F\u54CD\u5E94\u56E2\u961F
|
|
5562
|
+
\u25A1 \u6280\u672F\u4E0E\u98CE\u9669\u5206\u6790\u7EC4
|
|
5563
|
+
\u25A1 \u5B89\u5168\u7B56\u7565\u4E0B\u53D1\u7EC4
|
|
5564
|
+
\u25A1 \u4E1A\u52A1\u54CD\u5E94\u7EC4
|
|
5565
|
+
\u25A1 \u660E\u786E AWS TAM/Support \u8054\u7CFB\u65B9\u5F0F\uFF08ES/EOP \u5BA2\u6237\uFF09
|
|
5566
|
+
|
|
5567
|
+
\u26A0\uFE0F \u51FA\u5165\u7AD9\u8DEF\u5F84\u67B6\u6784\u56FE
|
|
5568
|
+
\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
|
|
5569
|
+
\u25A1 \u660E\u786E\u5404 ELB/Public EC2/S3/DX \u7684\u6570\u636E\u6D41\u5411
|
|
5570
|
+
\u25A1 \u8BC6\u522B\u6240\u6709\u9762\u5411\u4E92\u8054\u7F51\u7684\u6570\u636E\u4EA4\u4E92\u63A5\u53E3
|
|
5571
|
+
|
|
5572
|
+
\u26A0\uFE0F \u4E3B\u52A8\u5F0F\u6E17\u900F\u6D4B\u8BD5
|
|
5573
|
+
\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
|
|
5574
|
+
\u25A1 \u57FA\u4E8E\u6E17\u900F\u6D4B\u8BD5\u62A5\u544A\u8FDB\u884C\u6B63\u5F0F\u62A4\u7F51\u524D\u7684\u5B89\u5168\u52A0\u56FA
|
|
5575
|
+
\u25A1 \u5173\u6CE8 AWS \u5B89\u5168\u516C\u544A\uFF08\u5DF2\u77E5\u6F0F\u6D1E\u4E0E\u8865\u4E01\uFF09
|
|
5576
|
+
|
|
5577
|
+
\u26A0\uFE0F WAR-ROOM \u5B9E\u65F6\u6C9F\u901A
|
|
5578
|
+
\u25A1 \u521B\u5EFA\u62A4\u7F51\u671F\u95F4\u4E13\u7528\u6C9F\u901A\u6E20\u9053\uFF08\u4F01\u5FAE/\u9489\u9489/\u98DE\u4E66/Chime\uFF09
|
|
5579
|
+
\u25A1 \u4E0E AWS TAM \u5EFA\u7ACB WAR-ROOM \u8054\u7CFB\uFF08\u4F01\u4E1A\u7EA7\u652F\u6301\u5BA2\u6237\uFF09
|
|
5580
|
+
\u25A1 \u7EDF\u4E00\u6848\u4F8B\u6807\u9898\u683C\u5F0F\uFF1A"\u3010\u62A4\u7F51\u3011+ \u95EE\u9898\u63CF\u8FF0"
|
|
5581
|
+
|
|
5582
|
+
\u26A0\uFE0F \u5BC6\u7801\u4E0E\u51ED\u8BC1\u7BA1\u7406
|
|
5583
|
+
\u25A1 \u6240\u6709 IAM \u7528\u6237\u7ED1\u5B9A MFA
|
|
5584
|
+
\u25A1 AKSK \u8F6E\u8F6C\u5468\u671F \u2264 90 \u5929
|
|
5585
|
+
\u25A1 \u907F\u514D\u5171\u4EAB\u8D26\u6237\u4F7F\u7528
|
|
5586
|
+
\u25A1 S3/Lambda/\u5E94\u7528\u4EE3\u7801\u4E2D\u65E0\u660E\u6587\u5BC6\u7801
|
|
5587
|
+
|
|
5588
|
+
\u26A0\uFE0F \u62A4\u7F51\u540E\u4F18\u5316
|
|
5589
|
+
\u25A1 \u9488\u5BF9\u653B\u51FB\u62A5\u544A\u9010\u9879\u5E94\u7B54\u4E0E\u4FEE\u590D
|
|
5590
|
+
\u25A1 \u4E0E\u5B89\u5168\u56E2\u961F\u5EFA\u7ACB\u5468\u671F\u6027\u5B89\u5168\u7EF4\u62A4\u6D41\u7A0B
|
|
5591
|
+
\u25A1 \u6301\u7EED\u8865\u5168\u5B89\u5168\u98CE\u9669
|
|
5592
|
+
|
|
5593
|
+
\u53C2\u8003\uFF1AAWS \u62A4\u7F51\u884C\u52A8 Standard Operation Procedure (Compliance IEM)
|
|
5594
|
+
`;
|
|
5595
|
+
var SERVICE_RECOMMENDATIONS2 = {
|
|
5596
|
+
security_hub_findings: {
|
|
5597
|
+
icon: "\u{1F534}",
|
|
5598
|
+
service: "Security Hub",
|
|
5599
|
+
impact: "\u65E0\u6CD5\u83B7\u53D6 300+ \u9879\u81EA\u52A8\u5316\u5B89\u5168\u68C0\u67E5\uFF08FSBP/CIS/PCI DSS \u6807\u51C6\uFF09",
|
|
5600
|
+
action: "\u542F\u7528 Security Hub \u83B7\u5F97\u6700\u5168\u9762\u7684\u5B89\u5168\u6001\u52BF\u8BC4\u4F30"
|
|
5601
|
+
},
|
|
5602
|
+
guardduty_findings: {
|
|
5603
|
+
icon: "\u{1F534}",
|
|
5604
|
+
service: "GuardDuty",
|
|
5605
|
+
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",
|
|
5606
|
+
action: "\u542F\u7528 GuardDuty \u83B7\u5F97\u6301\u7EED\u5A01\u80C1\u68C0\u6D4B\u80FD\u529B"
|
|
5607
|
+
},
|
|
5608
|
+
inspector_findings: {
|
|
5609
|
+
icon: "\u{1F7E1}",
|
|
5610
|
+
service: "Inspector",
|
|
5611
|
+
impact: "\u65E0\u6CD5\u626B\u63CF EC2/Lambda/\u5BB9\u5668\u7684\u8F6F\u4EF6\u6F0F\u6D1E\uFF08CVE\uFF09",
|
|
5612
|
+
action: "\u542F\u7528 Inspector \u53D1\u73B0\u5DF2\u77E5\u5B89\u5168\u6F0F\u6D1E"
|
|
5613
|
+
},
|
|
5614
|
+
trusted_advisor_findings: {
|
|
5615
|
+
icon: "\u{1F7E1}",
|
|
5616
|
+
service: "Trusted Advisor",
|
|
5617
|
+
impact: "\u65E0\u6CD5\u83B7\u53D6 AWS \u6700\u4F73\u5B9E\u8DF5\u5B89\u5168\u68C0\u67E5",
|
|
5618
|
+
action: "\u5347\u7EA7\u81F3 Business/Enterprise Support \u8BA1\u5212\u4EE5\u4F7F\u7528 Trusted Advisor \u5B89\u5168\u68C0\u67E5"
|
|
5619
|
+
},
|
|
5620
|
+
config_rules_findings: {
|
|
5621
|
+
icon: "\u{1F7E1}",
|
|
5622
|
+
service: "AWS Config",
|
|
5623
|
+
impact: "\u65E0\u6CD5\u68C0\u67E5\u8D44\u6E90\u914D\u7F6E\u5408\u89C4\u72B6\u6001",
|
|
5624
|
+
action: "\u542F\u7528 AWS Config \u5E76\u914D\u7F6E Config Rules"
|
|
5625
|
+
},
|
|
5626
|
+
access_analyzer_findings: {
|
|
5627
|
+
icon: "\u{1F7E1}",
|
|
5628
|
+
service: "IAM Access Analyzer",
|
|
5629
|
+
impact: "\u65E0\u6CD5\u68C0\u6D4B\u8D44\u6E90\u662F\u5426\u88AB\u5916\u90E8\u8D26\u53F7\u6216\u516C\u7F51\u8BBF\u95EE",
|
|
5630
|
+
action: "\u521B\u5EFA IAM Access Analyzer\uFF08\u8D26\u6237\u7EA7\u6216\u7EC4\u7EC7\u7EA7\uFF09"
|
|
5631
|
+
},
|
|
5632
|
+
patch_compliance_findings: {
|
|
5633
|
+
icon: "\u{1F7E1}",
|
|
5634
|
+
service: "SSM Patch Manager",
|
|
5635
|
+
impact: "\u65E0\u6CD5\u68C0\u67E5\u5B9E\u4F8B\u8865\u4E01\u5408\u89C4\u72B6\u6001",
|
|
5636
|
+
action: "\u5B89\u88C5 SSM Agent \u5E76\u914D\u7F6E Patch Manager"
|
|
5637
|
+
}
|
|
5198
5638
|
};
|
|
5639
|
+
var SERVICE_NOT_ENABLED_PATTERNS2 = [
|
|
5640
|
+
"not enabled",
|
|
5641
|
+
"not found",
|
|
5642
|
+
"No IAM Access Analyzer",
|
|
5643
|
+
"No SSM-managed instances",
|
|
5644
|
+
"requires AWS Business or Enterprise Support",
|
|
5645
|
+
"not available",
|
|
5646
|
+
"is not enabled"
|
|
5647
|
+
];
|
|
5648
|
+
function buildServiceReminder(modules) {
|
|
5649
|
+
const disabledServices = [];
|
|
5650
|
+
for (const mod of modules) {
|
|
5651
|
+
const rec = SERVICE_RECOMMENDATIONS2[mod.module];
|
|
5652
|
+
if (!rec) continue;
|
|
5653
|
+
if (!mod.warnings?.length) continue;
|
|
5654
|
+
const hasNotEnabled = mod.warnings.some(
|
|
5655
|
+
(w) => SERVICE_NOT_ENABLED_PATTERNS2.some((p) => w.includes(p))
|
|
5656
|
+
);
|
|
5657
|
+
if (hasNotEnabled) {
|
|
5658
|
+
disabledServices.push(rec);
|
|
5659
|
+
}
|
|
5660
|
+
}
|
|
5661
|
+
if (disabledServices.length === 0) return "";
|
|
5662
|
+
const lines = [
|
|
5663
|
+
"",
|
|
5664
|
+
"\u26A1 \u4EE5\u4E0B\u5B89\u5168\u670D\u52A1\u672A\u542F\u7528\uFF0C\u90E8\u5206\u68C0\u67E5\u65E0\u6CD5\u6267\u884C\uFF1A",
|
|
5665
|
+
""
|
|
5666
|
+
];
|
|
5667
|
+
for (const svc of disabledServices) {
|
|
5668
|
+
lines.push(`${svc.icon} ${svc.service} \u672A\u542F\u7528`);
|
|
5669
|
+
lines.push(` \u5F71\u54CD\uFF1A${svc.impact}`);
|
|
5670
|
+
lines.push(` \u5EFA\u8BAE\uFF1A${svc.action}`);
|
|
5671
|
+
lines.push("");
|
|
5672
|
+
}
|
|
5673
|
+
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");
|
|
5674
|
+
return lines.join("\n");
|
|
5675
|
+
}
|
|
5199
5676
|
function summarizeResult(result) {
|
|
5200
5677
|
const { summary } = result;
|
|
5201
5678
|
const lines = [
|
|
@@ -5203,6 +5680,10 @@ function summarizeResult(result) {
|
|
|
5203
5680
|
`Total findings: ${summary.totalFindings} (${summary.critical} Critical, ${summary.high} High, ${summary.medium} Medium, ${summary.low} Low)`,
|
|
5204
5681
|
`Modules: ${summary.modulesSuccess} succeeded, ${summary.modulesError} errored`
|
|
5205
5682
|
];
|
|
5683
|
+
const reminder = buildServiceReminder(result.modules);
|
|
5684
|
+
if (reminder) {
|
|
5685
|
+
lines.push(reminder);
|
|
5686
|
+
}
|
|
5206
5687
|
return lines.join("\n");
|
|
5207
5688
|
}
|
|
5208
5689
|
function summarizeScanResult(result) {
|
|
@@ -5246,7 +5727,9 @@ function createServer(defaultRegion) {
|
|
|
5246
5727
|
new TrustedAdvisorFindingsScanner(),
|
|
5247
5728
|
new ConfigRulesFindingsScanner(),
|
|
5248
5729
|
new AccessAnalyzerFindingsScanner(),
|
|
5249
|
-
new PatchComplianceFindingsScanner()
|
|
5730
|
+
new PatchComplianceFindingsScanner(),
|
|
5731
|
+
new Imdsv2EnforcementScanner(),
|
|
5732
|
+
new WafCoverageScanner()
|
|
5250
5733
|
];
|
|
5251
5734
|
const scannerMap = /* @__PURE__ */ new Map();
|
|
5252
5735
|
for (const s of allScanners) {
|
|
@@ -5302,7 +5785,9 @@ function createServer(defaultRegion) {
|
|
|
5302
5785
|
{ toolName: "scan_trusted_advisor_findings", moduleName: "trusted_advisor_findings", label: "Trusted Advisor Findings" },
|
|
5303
5786
|
{ toolName: "scan_config_rules_findings", moduleName: "config_rules_findings", label: "Config Rules Findings" },
|
|
5304
5787
|
{ toolName: "scan_access_analyzer_findings", moduleName: "access_analyzer_findings", label: "Access Analyzer Findings" },
|
|
5305
|
-
{ toolName: "scan_patch_compliance_findings", moduleName: "patch_compliance_findings", label: "Patch Compliance Findings" }
|
|
5788
|
+
{ toolName: "scan_patch_compliance_findings", moduleName: "patch_compliance_findings", label: "Patch Compliance Findings" },
|
|
5789
|
+
{ toolName: "scan_imdsv2_enforcement", moduleName: "imdsv2_enforcement", label: "IMDSv2 Enforcement" },
|
|
5790
|
+
{ toolName: "scan_waf_coverage", moduleName: "waf_coverage", label: "WAF Coverage" }
|
|
5306
5791
|
];
|
|
5307
5792
|
for (const { toolName, moduleName, label } of individualScanners) {
|
|
5308
5793
|
server.tool(
|
|
@@ -5425,12 +5910,17 @@ function createServer(defaultRegion) {
|
|
|
5425
5910
|
lines.push("");
|
|
5426
5911
|
lines.push(`Warning: ${missingModules.length} requested module(s) not available: ${missingModules.join(", ")}`);
|
|
5427
5912
|
}
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5913
|
+
const content = [
|
|
5914
|
+
{ type: "text", text: lines.join("\n") },
|
|
5915
|
+
{ type: "text", text: JSON.stringify(result, null, 2) }
|
|
5916
|
+
];
|
|
5917
|
+
if (group === "hw_defense") {
|
|
5918
|
+
const summaryContent = content[0];
|
|
5919
|
+
if (summaryContent && summaryContent.type === "text") {
|
|
5920
|
+
summaryContent.text += "\n\n" + HW_DEFENSE_CHECKLIST;
|
|
5921
|
+
}
|
|
5922
|
+
}
|
|
5923
|
+
return { content };
|
|
5434
5924
|
} catch (err) {
|
|
5435
5925
|
return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
5436
5926
|
}
|
|
@@ -5734,7 +6224,7 @@ Deploy this as a StackSet from your Management Account to all member accounts.`
|
|
|
5734
6224
|
server.resource(
|
|
5735
6225
|
"security-rules",
|
|
5736
6226
|
"security://rules",
|
|
5737
|
-
{ description: "Describes all
|
|
6227
|
+
{ description: "Describes all 19 scan modules and their check rules", mimeType: "text/markdown" },
|
|
5738
6228
|
async () => ({
|
|
5739
6229
|
contents: [{ uri: "security://rules", text: SECURITY_RULES_CONTENT, mimeType: "text/markdown" }]
|
|
5740
6230
|
})
|
|
@@ -5781,6 +6271,25 @@ ${finding}`
|
|
|
5781
6271
|
]
|
|
5782
6272
|
})
|
|
5783
6273
|
);
|
|
6274
|
+
server.prompt(
|
|
6275
|
+
"hw_defense_checklist",
|
|
6276
|
+
"\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",
|
|
6277
|
+
async () => ({
|
|
6278
|
+
messages: [
|
|
6279
|
+
{
|
|
6280
|
+
role: "user",
|
|
6281
|
+
content: {
|
|
6282
|
+
type: "text",
|
|
6283
|
+
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
|
|
6284
|
+
|
|
6285
|
+
${HW_DEFENSE_CHECKLIST}
|
|
6286
|
+
|
|
6287
|
+
\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`
|
|
6288
|
+
}
|
|
6289
|
+
}
|
|
6290
|
+
]
|
|
6291
|
+
})
|
|
6292
|
+
);
|
|
5784
6293
|
return server;
|
|
5785
6294
|
}
|
|
5786
6295
|
async function startServer(defaultRegion) {
|