aws ec2 describe-vpc-endpoint-services 会把一个区里能建 endpoint 的服务名都列出来,每条带一个 ServiceTypeCLI 文档里这个字段的取值只有三个,InterfaceGatewayGatewayLoadBalancer,它同时也能当过滤条件用:

aws ec2 describe-vpc-endpoint-services --region ap-northeast-1 \
  --filters Name=service-type,Values=Gateway \
  --query 'ServiceDetails[].ServiceName' --output text

这条命令能在自己的区里核一遍。gateway endpoint 文档开篇就把范围写死了:

Gateway VPC endpoints provide reliable connectivity to Amazon S3 and DynamoDB without requiring an internet gateway or a NAT device for your VPC. Gateway endpoints do not use AWS PrivateLink, unlike other types of VPC endpoints.

价格那一半在 NAT Gateway 那篇里按东京区算过:gateway endpoint 不收钱,interface endpoint 有小时费和每 GB 费,月流量到 600 GB 上下才开始省。这篇整理的是价格之外那几条分界,它们通常在算钱之前就把选择定死了。

gateway endpoint 是路由表里的一条 prefix list 记录#

建 gateway endpoint 的时候要选路由表,AWS 会往每一张选中的表里自动写一条路由,destination 是这个服务的 AWS 托管 prefix list,target 是 endpoint 本身。这条记录在控制台里看得见,改不了也删不掉,解除路由表关联或者删掉 endpoint 时它自己消失。

生效范围是路由表,不是实例。文档里的说法是:

All instances in the subnets associated with a route table associated with a gateway endpoint automatically use the gateway endpoint to access the service. Instances in subnets that aren’t associated with these route tables use the public service endpoint, not the gateway endpoint.

所以漏勾一张表,挂在它下面的子网就照旧走 NAT,而且没有任何报错。同一张路由表里,同一个服务只能有一条 endpoint 路由,但同一个服务的 endpoint 路由可以出现在多张表里。

还有一点容易忘:包发出去时的目的地址仍然是 S3 或 DynamoDB 的公网 IP,gateway endpoint 改的只是这个包往哪条路走。安全组因此仍然要放行,出站规则可以直接引用 prefix list 的 id;network ACL 引用不了 prefix list,只能把 prefix list 里的 CIDR 抄进规则。

跨区是这套机制绕不过去的地方。路由靠最长前缀匹配决定,而 prefix list 按区划分:

Traffic that’s destined for the service (Amazon S3 or DynamoDB) in a different Region goes to the internet gateway because prefix lists are specific to a Region

发往东京区 S3 的包命中那条 endpoint 路由,发往首尔区同一个服务的包不命中,落回 0.0.0.0/0,也就是回到 NAT 或者 IGW,每 GB 那笔钱照收。

interface endpoint 是子网里的一张 ENI 加一条私有 DNS 记录#

interface endpoint 在你指定的每个子网里建一张 endpoint 网卡,从子网地址段里分一个私有 IP。这张网卡是 requester-managed 的,账号里看得见但改不了,IP 在 endpoint 的生命周期内不变。一个可用区只能选一个子网。

安全组挂在这张 ENI 上,这是两种 endpoint 在访问控制上最容易看出来的差别。gateway endpoint 那边你能收紧的是实例侧的安全组、network ACL 和 endpoint policy,interface endpoint 这边多一层,可以按来源安全组限制 VPC 里谁能用这个 endpoint。endpoint policy 两种 endpoint 都能挂,不过不是每个服务都支持,不支持的那些 AWS 一律放行。它是挂在 endpoint 上的资源策略,不替代 IAM 身份策略,也不替代桶策略那类资源策略;不挂就用默认那份全开的,上限 20480 字符,改完要过几分钟才生效。

打开 private DNS 之后,AWS 建一个隐藏的托管 private hosted zone,把服务原本的公网区域域名解析成这些 ENI 的私有 IP,应用侧不用动代码。铺了多个 AZ 时,走公网域名的请求会在几张健康 ENI 之间 round robin;想固定打到同 AZ 那张,用 endpoint 的 zonal 域名或者直接用 IP。

方向也是固定的,文档写得很干脆:

AWS services accept connection requests automatically. The service can’t initiate requests to resources through the VPC endpoint.

配额上,interface endpoint 和 Gateway Load Balancer endpoint 合起来每个 VPC 默认 50 个(可调),gateway endpoint 是每区 20 个、每 VPC 最多 255 个。

两种机制的分岔点落在不同的层,一个由路由表决定,一个在 DNS 解析时就决定了。

flowchart TB APP["私有子网里的应用
连服务的区域域名"] APP --> DNS["Route 53 Resolver"] DNS -- "只有 gateway endpoint
解析出服务的公网 IP" --> RT{"子网路由表
最长前缀匹配"} DNS -- "有 interface endpoint 且开了 private DNS
解析出 ENI 的私有 IP" --> ENI["endpoint ENI
安全组挂在这一层"] RT -- "命中本区 prefix list" --> GW["gateway endpoint"] RT -- "跨区,或没勾这张路由表
落到 0.0.0.0/0" --> NAT["NAT Gateway 或 IGW"] ENI --> SVC[("AWS 服务")] GW --> SVC NAT --> SVC

服务清单、请求来源、DNS 名字#

上面两套机制的差别落到选型上是三处,每一处都能单独把结果定死。三处的判断有先后:服务本身有没有得选,请求从哪儿发起,客户端连的名字要不要改。

只有 S3 和 DynamoDB 两种都能建#

AWS 有一份 PrivateLink 集成服务清单,2026-09-14 抓下来数了一遍:

curl -s https://docs.aws.amazon.com/vpc/latest/privatelink/aws-services-privatelink-support.md \
  | grep '^- \*\*' | grep -vc 'com\.amazonaws\|aws\.api\.'
235

清单上 235 个服务。页面开头交代过,Service name 那列给的就是你建 interface endpoint 时要填的名字,少数几个由服务自己托管 endpoint。能建 gateway endpoint 的仍然只有 S3 和 DynamoDB。

所以「选哪种」这个问题只在这两个服务上成立。Secrets Manager、SSM、ECR API、Kinesis Data Streams 这些要走私有路径就只有 interface endpoint 一条路,回本点算不过来也只能在「建」和「继续走 NAT」之间选。

请求从 VPC 外面发起时 gateway endpoint 接不住#

S3DynamoDB 的文档里各有一张同构的对比表,措辞几乎一样,最后一行才是价格(Not billedBilled)。前面两行直接给了结论:gateway endpoint 那列写着 Do not allow access from on premisesDo not allow access from another AWS Region,interface endpoint 那列两条都是 allow。

机制上说得通。gateway endpoint 是一条路由,只对关联了这张路由表的子网有效,从 Direct Connect 或者 Site-to-Site VPN 进来的包不经过你 VPC 的子网路由表;再加上 prefix list 只含本区,跨区那条同样落空。peering 那边 AWS 把这类限制归在 edge to edge routing 底下,VPC peering 文档的说法是:

If VPC A has a gateway endpoint that provides connectivity to Amazon S3 to private subnets in VPC A, resources in VPC B can’t use the gateway endpoint to access Amazon S3.

interface endpoint 给出的是你 VPC 里的私有 IP,本地机房走 DX 或 VPN、别的区走 peering 或 Transit Gateway,都能连到这个地址。

另外还有一类 cross-region interface endpoint,创建时勾上 Enable cross Region endpoint 再选服务所在的区。支持它的服务另有一份清单,截至 2026-09-14 上面是 9 个,动手之前去那页确认自己要的服务在不在。

从 gateway 换到 interface,客户端连的名字可能要跟着改#

S3 和 DynamoDB 都支持两种 endpoint,在 DNS 这一处的行为却差得很远。DynamoDB 的 PrivateLink 页把 private DNS 明确列进了不支持的清单,还专门警告不要自己建 private hosted zone 去盖:

Do not create private hosted zones to override DynamoDB endpoint DNS names (such as dynamodb.region.amazonaws.com or *.region.amazonaws.com) to route traffic to your interface endpoints. DynamoDB DNS configurations might change over time.

DynamoDB 从 gateway endpoint 换到 interface endpoint,客户端就得改成 https://vpce-xxxx.dynamodb.<region>.vpce.amazonaws.com 这种 endpoint 专属 URL,SDK 那层要动配置。

S3 支持 private DNS,但默认值本身带着一个前提。CLI 里那个 PrivateDnsOnlyForInboundResolverEndpoint 参数不给就是 true,而它要求 VPC 里已经有一个 S3 gateway endpoint,没有的话建 endpoint 这一步直接报错:

To set PrivateDnsOnlyForInboundResolverEndpoint to true, the VPC vpce_id must have a gateway endpoint for the service.

这个默认值等于 AWS 自己给的分工建议:VPC 里的 S3 请求继续走免费的 gateway endpoint,本地机房经 inbound Resolver endpoint 进来的请求走 interface endpoint。两种共存不冲突,文档原话是 Interface endpoints are compatible with gateway endpoints。要让所有 S3 请求都走 interface endpoint,把这个参数显式设成 false

第三方 SaaS 只能给 interface endpoint#

第三方账号里的服务想让你私有访问,它能做的只有一件事:建一个 endpoint service。AWS 的文档写着这件事的硬性前提。

Endpoint services require either a Network Load Balancer or a Gateway Load Balancer.

然后由你这个消费者在自己 VPC 里建 interface endpoint 连过去。gateway endpoint 没有对应的提供方形态,S3 和 DynamoDB 那两条 prefix list 是 AWS 自己维护的,第三方拿不到这条路。方向仍然是单向的,请求只能从你的 VPC 发起。

Confluent Cloud 和 MongoDB Atlas 都是这个模型,两边也都有档位限制。Confluent 的 AWS PrivateLink 文档里写的是 AWS PrivateLink allows for one-way secure connection access from your VPC to Confluent Cloud,适用范围限定在 Dedicated 集群,Enterprise 集群走另一套 serverless 的文档;它给出的步骤里,第三步是在 AWS 里建 endpoint,第四步是在 AWS 里配 DNS 记录,这段 DNS 是消费者侧的活。MongoDB Atlas 的 private endpoint 文档同样限定在 dedicated 集群,Free 和 Flex 明确不支持。

至少在上一篇查的那个账号里,SaaS 这条路还停在公网域名上,peering 只服务于按私有 IP 直连的那部分调用。

小结#

  • 「选哪种」只在 S3 和 DynamoDB 上是真问题。清单上另外 233 个服务底下没有 gateway endpoint 这个选项,讨论到价格之前就定了。
  • S3 和 DynamoDB 上先建 gateway endpoint。它不要钱,不占子网 IP,也不吃 interface endpoint 那 50 个的配额,代价是只对勾中的路由表生效、只覆盖本区。
  • 需要本地机房或者跨区访问时再叠 interface endpoint,两种可以共存。S3 那个 PrivateDnsOnlyForInboundResolverEndpoint 的默认值就是这个分工。
  • 换 interface endpoint 之前先确认客户端连的名字。DynamoDB 必须改成 endpoint 专属 URL,S3 可以靠 private DNS 不动应用。
  • 第三方 SaaS 那边你能建的只有 interface endpoint,DNS 一般要自己配,能不能用还取决于对方的集群档位。

参考资料#