ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Serverless Framework AppSync WAF 配置指南:为 GraphQL API 接入 AWS Web Application Firewall

Serverless Framework AppSync WAF 配置指南:为 GraphQL API 接入 AWS Web Application Firewall Serverless Framework AppSync WAF 配置指南为 GraphQL API 接入 AWS Web Application Firewall【免费下载链接】serverless⚡ Serverless Framework – Effortlessly build apps that auto-scale, incur zero costs when idle, and require minimal maintenance using AWS Lambda and other managed cloud services.项目地址: https://gitcode.com/GitHub_Trending/se/serverless本文聚焦 Serverless Framework 对 AWS AppSync 的 WAFWeb Application FirewallWeb 应用防火墙集成能力讲解如何在serverless.yml中通过appSync.waf配置节定义 Web ACL、启用预置防护规则、编写自定义规则并按 API Key 差异化放行。读完你将掌握从“快速接入”到“限流、禁止 introspection、Geo 封禁、API Key 豁免”等完整防护方案的写法并了解这些配置如何被插件翻译成 CloudFormation 的AWS::WAFv2::WebACL资源。本指南对应的主文档位于 docs/sf/providers/aws/guide/appsync/WAF.md属于仓库中 AppSync 使用指南 系列的一篇相关实现代码位于 Waf.js入口插件为 index.js。一、为什么需要为 AppSync 配置 WAFAppSync 是面向 GraphQL 的托管服务其端点直接暴露在公网。除业务层的鉴权API Key、IAM、Cognito、OIDC 等见 authentication.md之外运维层仍需要防护常见 Web 攻击例如同一 IP 的突发高频请求CC 攻击、爬虫未受信任的客户端通过 introspection 探测整个 GraphQL Schema 结构非目标地区的非法流量、已知漏洞签名流量等。AWS WAF 正是这类“应用防火墙”它基于Web ACLWeb Access Control List工作Web ACL 中包含一组带Priority的规则每条规则由Statement匹配条件ActionAllow/Block 等动作构成。AppSync 官方支持 WAF而 Serverless Framework 的 AppSync 集成在此基础上又封装了若干“开箱即用”的预置规则让开发者只需几行配置即可完成防护。需要特别说明的是实现层面的工作方式从 Waf.js 的源码看框架会把appSync.waf编译为两类 CloudFormation 资源AWS::WAFv2::WebACL——定义 Web ACL 本体新建场景且固定使用Scope: REGIONALAppSync 是区域性服务区别于 CloudFront 的全局 Web ACLAWS::WAFv2::WebACLAssociation——把该 Web ACL 与 AppSync GraphQL API通过Fn::GetAtt取 API 的Arn自动关联。也就是说你在 YAML 里写 WAF 规则实际部署后落地为 CloudFormation 中的 WAFv2 资源及关联关系。二、快速开始两种接入形态WAF 配置统一放在顶层appSync.waf属性下。接入方式有两种。形态一让框架创建 Web ACL 并预置规则appSync: name: my-api waf: enabled: true defaultAction: Allow rules: - throttle - disableIntrospection上面配置的含义创建一个名为my-api的 AppSync API并为它新建一个 Web ACL当请求不命中任何规则时默认Allow随后按顺序评估两条预置规则——先是 IP 限流throttle再是禁止 introspectiondisableIntrospection。两条规则的具体行为见下文“预置规则”章节。形态二直接关联一个已有的 Web ACL如果你希望复用团队中已经通过其他途径如独立 WAF 模板、AWS Console、第三方 IaC 工具创建好的 Web ACL只需提供其 ARNappSync: name: my-api waf: enabled: true arn: arn:aws:wafv2:us-east-1:123456789012:regional/webacl/my-Waf/d7b694d2-4f7d-4dd6-a9a9-843dd1931330对照 Waf.js 的实现可知当配置了arn时框架只生成AWS::WAFv2::WebACLAssociation资源WebACLArn直接取你给定的 ARNResourceArn指向 AppSync API此时不再创建 Web ACL 本体因此也无需再提供rules配置校验中rules与arn互斥见后文。三、appSync.waf配置项总览配置项类型必填默认值说明enabledBoolean否只要定义了appSync.waf即视为true是否启用 WAF。置为false时Waf.js 的compile()直接返回空对象不生成任何 WAF 资源arnString否与rules二选一无已有 Web ACL 的 ARN。提供时框架只做关联不创建 ACLnameString否AppSync API 名 Waf后缀新建 Web ACL 的名称。源码中为${appSync.name}WafdefaultActionString否Allow请求未命中任何规则时执行的动作Allow或BlockdescriptionString否ACL rules for AppSync ${name}Web ACL 描述visibilityConfigObject否两个开关默认均开启Web ACL 级的指标与采样配置详情见下文rulesArray是使用arn时可不填无规则数组元素可以是预置规则的简写、对象写法或自定义规则其中visibilityConfig的三个子字段为nameCloudWatch 指标名MetricNamecloudWatchMetricsEnabled布尔值是否把该 Web ACL 的指标发送到 CloudWatchsampledRequestsEnabled布尔值是否让 WAF 采样并保留命中的 Web 请求样本。需要留意源码中的继承式默认逻辑getWafVisibilityConfig()见 Waf.js会优先取规则/ACL 自己的visibilityConfig其次回退到 Web ACL 顶层visibilityConfig最后cloudWatchMetricsEnabled与sampledRequestsEnabled都回退为trueMetricName回退为 Web ACL/规则名。关于rules与arn的互斥关系可在 validation.js 看到精确描述waf校验使用了if/then/else——若提供arn则只校验arn的类型否则必须提供rules且name/defaultAction/description均有各自类型与取值约束defaultAction仅允许Allow/Block。四、预置规则一Throttling 限流throttle规则会记录来自同一 IP 的请求当5 分钟窗口内的请求量超过阈值时拒绝后续请求。它在底层对应 CloudFormation 中 WAF 规则的RateBasedStatement。它支持三种书写形态从简到繁waf: enabled: true rules: - throttle # 默认5 分钟内最多 100 次 - throttle: 200 # 5 分钟内最多 200 次数字简写即 limit - throttle: # 完整自定义形态 limit: 200 priority: 10 aggregateKeyType: FORWARDED_IP forwardedIPConfig: headerName: X-Forwarded-For fallbackBehavior: MATCH结合 Waf.js 的buildThrottleRule()可以看到它的详细默认值与行为动作恒为Block命中即拦截默认规则名Throttle默认limit100数字简写会直接覆盖该值默认aggregateKeyTypeIP即按来源 IP 聚合统计只有显式指定aggregateKeyType: FORWARDED_IP时才生成ForwardedIPConfig且其内部默认值为HeaderName: X-Forwarded-For、FallbackBehavior: MATCH适用于经过了 CDN / 负载均衡转发的场景需要从转发头中还原真实客户端 IP可通过scopeDownStatement限定限流作用的范围即“仅当命中某个更细的匹配条件时才参与计数限流”。Throttle 对象的可配置字段如下字段类型取值/默认说明nameString默认Throttle规则名limitInteger默认 100校验要求最小 100同一 IP 在 5 分钟窗口内的请求上限aggregateKeyTypeStringIP/FORWARDED_IP聚合统计的键类型forwardedIPConfigObject见上仅FORWARDED_IP时生效headerName需匹配^[a-zA-Z0-9-]$fallbackBehavior为MATCH/NO_MATCHscopeDownStatementObject无额外的范围收窄 StatementpriorityInteger自动分配见“规则优先级”章节规则优先级这些约束都在 validation.js 中有对应 schema 定义throttle对象形态下limit的最小值为 100aggregateKeyType限定IP/FORWARDED_IPforwardedIPConfig要求headerName与fallbackBehavior同时给出。五、预置规则二Disable IntrospectionGraphQL 的 introspection 查询允许客户端拿到完整的 Schema。在面向不可信消费方的场景例如公开 API 但只希望特定方访问中你可能想整体禁用 introspection防止调用方探测 API 内部结构。该预置规则写法如下waf: enabled: true rules: - disableIntrospection # 对所有请求禁用 introspection - disableIntrospection: # 自定义命名与优先级 name: Disable introspection priority: 200从实现看Waf.js 的buildDisableIntrospectionRule()这条规则的“动作恒为Block”底层用一个OR 组合的 Statement去识别 introspection 特征请求超大请求体SizeConstraintStatement匹配Body大于 8 KB8 * 1024比较运算符GT的请求——完整 introspection 查询会一次性请求全量 Schema包体通常远大于 8 KB含__schema关键字ByteMatchStatement在Body中匹配字符串__schemaCONTAINS并先做COMPRESS_WHITE_SPACE文本归一化——GraphQL introspection 的标准入口字段就是__schema/__type。两条子条件取“或”即只要命中其一请求体超大或包含__schema即判定为 introspection 探测并拦截。这正是 WAF 规则能“无侵入”禁用 introspection 的原理它不依赖 AppSync 层开关而是在流量进入 API 之前直接丢弃匹配请求。六、自定义规则把任意 WAF Statement 落到配置里内置规则无法覆盖所有场景因此框架允许你书写任意符合 CloudFormation WAF Rule 语义的自定义规则。此时配置项与 WAF 原生 Rule 字段一一对应name、priority、statement以及action或overrideAction后者主要用于ManagedRuleGroupStatement这类托管规则组。例一基于 GeoMatchStatement 只放行美国用户waf: enabled: true defaultAction: Block # 默认拦截所有 rules: # 只允许来自美国的请求 - action: Allow name: UsOnly statement: GeoMatchStatement: CountryCodes: - US例二使用 AWS 托管规则组waf: enabled: true defaultAction: Block rules: # 使用 AWSManagedRulesCommonRuleSet 托管规则组 - name: AWSManagedRulesCommonRuleSet priority: 20 overrideAction: None: {} statement: ManagedRuleGroupStatement: VendorName: AWS Name: AWSManagedRulesCommonRuleSet实现细节Waf.js自定义规则的action默认是Allow一旦提供overrideAction框架会优先用OverrideAction通过toCfnKeys把下划线键转换为 CFN 的大驼峰键否则把 action 包装成{ action: {} }形式写进ActionvisibilityConfig可逐条覆盖逻辑与 Web ACL 层一致配置校验validation.js要求自定义规则必须提供name和statementaction可取值包括Allow、Block、Count、Captcha。七、按 API Key 差异化应用规则有时你并不想对所有客户端一刀切而是希望某条规则只对特定 API Key 生效。此时可在appSync.apiKeys数组里为某个 Key 追加wafRulesapiKeys: - name: MyApiKey expiresAfter: 365d wafRules: - throttle # 该 Key 单独限流 - disableIntrospection # 该 Key 禁用 introspectionexpiresAfter等 API Key 生命周期配置的完整说明可参考 API-keys.md。实现原理Header 精确匹配 Statement 合并框架如何做到“规则只对某一个 Key 生效”答案在 Waf.js 的buildApiKeyRules()API Key 鉴权的 GraphQL 请求会携带X-Api-Key请求头。框架因此为每条规则自动生成一个ByteMatchStatement——用Fn::GetAtt从 CloudFormation 拿到该 API Key 资源的真实密钥值然后与请求头X-Api-Key做EXACTLY完全相等匹配并做LOWERCASE文本归一化处理。随后该“Key 匹配条件”与原规则的关系按类型区分原规则是RateBasedStatementthrottleKey 匹配条件会被并进ScopeDownStatement——即“只有该 Key 的请求才参与限流计数”原规则带其他 Statement用AndStatement把原条件与 Key 匹配条件合并——请求必须同时命中原条件且来自该 Key原规则没有任何 statement整个规则就是“该 Key 匹配”本身也就是下文的 match-all 规则。关键技巧用无 statement 的规则把某个 Key 从全局规则中“豁免”注意一个容易被忽略但非常实用的行为给 API Key 添加一条没有任何statement的规则等于为这个 Key 建立一条 match-all 规则该 Key 的所有请求都会命中这条规则。典型用途是把某些 API Key 从全局规则中排除——例如某个信任的内部客户端希望绕开“仅美国可访问”的限制。此时务必给这条豁免规则分配更高优先级数值更小确保它先于全局规则被评估。官方给出的经典场景如下默认拦截所有请求但放行美国流量同时希望WorldWideApiKey这个内部 Key 完全不受“仅美国”限制。appSync: waf: enabled: true defaultAction: Block # 默认全部拦截 rules: # 放行美国请求优先级 5数值越小越先评估 - action: Allow name: UsOnly priority: 5 statement: geoMatchStatement: countryCodes: - US apiKeys: - name: Key1 # 未配 wafRules走全局规则仅美国可访问 - name: WorldWideApiKey # 希望它不受地区限制 wafRules: - name: WorldWideApiKeyRule action: Allow priority: 1 # 优先级高于 5先被评估 → 该 Key 的所有请求都被 Allow对照上文原理WorldWideApiKeyRule没有 statement因此它退化为一个纯粹的“X-Api-Key 等于该 Key 值即命中”的 match-all 规则又因为priority: 1小于全局UsOnly规则的priority: 5WAF 会先评估它于是来自该 Key 的全部请求先被放行根本走不到后面的地区限制规则。八、规则优先级Rules PriorityWAF 按Priority数值从小到大依次评估规则数值不必连续但必须各不相同。优先级语义对最终效果影响很大框架为此提供了一套“不写也行”的自动分配策略。优先级是可选的但强烈建议显式设置。若不设置框架会按下述规则自动分配、顺序递增 先处理appSync.waf.rules下的全局规则按书写顺序再处理各 API Key 的规则按 API Key 顺序及 Key 内规则顺序。 自动分配的起始优先级为100从而为 0–99 区间留出空间方便你后续插入真正需要“更高优先级”数值更小的规则。对照 Waf.jsbuildWafRules()以let defaultPriority 100起步把全局规则与所有 API Key 规则串联后统一map只有rule.Priority为空未显式设置时才递增占用一个自动值。因此下面示例中的注释结论完全可由代码推导appSync: waf: enabled: true rules: - name: Rule1 # 未设置Priority 100 - name: Rule2 priority: 5 # Priority 5 - name: Rule3 # 未设置Priority 101 apiKeys: - name: Key1 wafRules: - name: Rule4 # 未设置Priority 102 - name: Rule5 # 未设置Priority 103 - name: Key2 wafRules: - name: Rule6 priority: 1 # Priority 1 - name: Rule7 # 未设置Priority 104注意一个易踩坑的细节自动编号不会“补位”。示例中Rule2占用了 5但它消耗的并不是自动计数器的 100因此后续Rule3依然拿到 101而不是 6——自动编号永远从 100 起步且顺序递增。规则实际执行顺序上Rule6(1)→Rule2(5)→Rule1(100)→Rule3(101)→Rule4(102)→Rule5(103)→Rule7(104)。九、编译链路与测试覆盖从 YAML 到 CloudFormation为了在排查问题时心里有数这里把整条链路串起来sls deploy等生命周期触发 AppSync 插件index.js的buildAndAppendResources()loadConfig()先调用validateConfig(appSync)validation.js不符合 schema 的 WAF 配置会报出类似must be a valid WAF rule的精确错误Api.compile()汇总各资源其中 WAF 部分委托给Waf类resources/Waf.js输出AWS::WAFv2::WebACL可选与AWS::WAFv2::WebACLAssociation逻辑资源名由 Naming 统一生成Web ACL 为GraphQlWaf、关联资源为GraphQlWafAssoc见 resources/Naming.js编译结果最终合并进 Serverless 生成的 CloudFormation 模板并部署。另外仓库自带了针对该功能的单元测试 waf.test.js含对应快照文件__snapshots__/waf.test.js.snap。测试覆盖了“生成 WAF 基础资源”“无 Tags 场景”“enabled: false时不生成任何 WAF 资源”等关键路径是验证你配置预期与实际产物的可靠参照——如果你不确定某种写法最终会编译成什么模板直接查阅该测试与快照是最高效的途径。十、实操建议小结先默认 Allow、最小规则集起步defaultAction: Allowthrottle通常是最安全的开场配置可先观察线上指标再收紧introspection 开关要区分对内/对外公开 API 建议配合disableIntrospection只有可信客户端时用“无 statement 的 API Key 规则 更高优先级”精确放行其余流量保持禁用显式声明priority尤其是存在 API Key 豁免、托管规则组叠加时不要依赖自动编号避免“规则顺序与你想象的不一致”用了arn就别再写rules两者互斥schema 校验会在部署前拦截错误组合转发场景必须处理真实 IPWeb 请求若经 CDN / ALB记得用aggregateKeyType: FORWARDED_IP并配置可信的forwardedIPConfig否则限流会误伤同一出口 IP 后的所有用户关于规则评估顺序、Statement 组合语义的官方细节AWS 文档中以“Web ACL 处理流程”与各 Statement 类型RateBasedStatement、GeoMatchStatement、ManagedRuleGroupStatement、ByteMatchStatement、SizeConstraintStatement等分别说明配合本文源码分析可对照理解框架自动生成的部分与需要你手写的部分。【免费下载链接】serverless⚡ Serverless Framework – Effortlessly build apps that auto-scale, incur zero costs when idle, and require minimal maintenance using AWS Lambda and other managed cloud services.项目地址: https://gitcode.com/GitHub_Trending/se/serverless创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表