cloud-sre

Polygon Erigon 归档节点:为什么要收口 8545

一次把 Polygon Erigon archive node 从 allow-all 安全组收口到最小公网入口的实践记录。

Jun 16, 2026
AWSPolygonErigonsecurity-grouparchive-node

一个区块链归档节点经常会被误配置成“所有端口对公网开放”。这在节点刚启动、同步压力还很高时尤其危险:公网扫描器会持续探测 JSON-RPC,日志里会出现无意义的 eth_accountseth_sendRawTransaction 等请求,既增加噪音,也扩大攻击面。

这篇文章记录一次 Polygon Erigon archive node 的安全组收口:保留节点参与 P2P 网络所需的公网端口,关闭公网 JSON-RPC、metrics、private API 和 SSH。

背景

这台节点运行的是 Polygon Mainnet archive node。Polygon 官方文档对 archive node 的基线要求包括 16-core CPU、64GB RAM,以及 mainnet archive node 约 15TB 存储;存储侧建议 io1 或更高、20k+ IOPS、RAID-0 结构,并使用 SSD 或 NVMe [1]

节点启动参数里启用了 HTTP JSON-RPC:

--http
--ws
--http.addr=0.0.0.0
--http.port=8545
--http.api=web3,net,eth,trace

这表示容器内服务监听所有地址。如果 EC2 安全组也允许公网访问 8545/tcp,这个 RPC 就会直接暴露到互联网。

这次暴露了什么问题

节点日志里出现了外部 IP 访问 RPC 的记录,例如调用已经废弃的 eth_accounts。这类请求通常不是业务流量,而是公网扫描或探测。

Erigon README 对 Public RPC 的建议很明确:不要把 admin 加进 --http.api,不要使用过宽的 CORS,并用 RPC batch 参数降低 DoS 风险 [2]

更直接的处理是:如果这个节点不是公共 RPC 服务,就不要在安全组层面开放 8545

安全组决策

最终安全组只开放下面三个入站规则:

端口协议来源用途
30303TCP0.0.0.0/0Erigon P2P peering
30303UDP0.0.0.0/0Erigon P2P peering
42069UDP0.0.0.0/0Erigon torrent / snapshot peer

关闭下面这些公网入口:

端口原因
8545/tcpJSON-RPC。业务没有要求公开提供 RPC,所以不应暴露到公网。
6060/tcpmetrics / pprof 类观测端口。只应给内部监控或本机调试使用。
9090/tcpErigon private API。Erigon 示例也把 private.api.addr 放在 127.0.0.1:9090
8546/tcpWebSocket RPC。没有公网业务需求时不开放。
8551/tcpEngine API / JWT auth。不是外部用户入口。
22/tcpSSH。运维访问走 SSM Session Manager,不需要公网 SSH。

Erigon README 的默认端口表也支持这个边界:30303/30304 是公开 peering 端口,42069 是 snap sync,8545 是 RPC,6060/metrics、9090 private API、8551 Engine API 都不应该作为普通公网入口开放 [3]

为什么出站仍然放行

这次只收口入站,不收紧出站。原因是 Polygon Erigon 仍需要主动访问外部依赖:

  • 连接 P2P peers
  • 访问远端 Heimdall API
  • 下载或交换 snapshot/torrent 数据
  • 系统维护、镜像拉取、包管理等出站 HTTPS

Polygon 官方文档说明,如果不运行本地 Heimdall,可以通过 --bor.heimdall=<your heimdall url> 指向远端 Heimdall;PoS mainnet 的远端地址是 https://heimdall-api.polygon.technology [1]

因此,出站保持 0.0.0.0/0,入站按最小需要开放,是这次的折中。

AWS Security Group 本身是有状态防火墙:它控制关联资源允许进入和离开的流量;如果安全组没有入站规则,默认不允许入站流量;新建安全组默认带有允许所有出站流量的规则 [4][5]

Terraform 表达方式

Terraform 里把 Polygon 节点从共享的 allow-all 安全组切到专用安全组:

security_group_ids = [aws_security_group.polygon_node_sg.id]

专用安全组只保留 P2P 和 torrent 入站:

ingress {
  description = "Polygon P2P TCP"
  from_port   = 30303
  to_port     = 30303
  protocol    = "tcp"
  cidr_blocks = ["0.0.0.0/0"]
}

ingress {
  description = "Polygon P2P UDP"
  from_port   = 30303
  to_port     = 30303
  protocol    = "udp"
  cidr_blocks = ["0.0.0.0/0"]
}

ingress {
  description = "Polygon torrent UDP"
  from_port   = 42069
  to_port     = 42069
  protocol    = "udp"
  cidr_blocks = ["0.0.0.0/0"]
}

85456060 不写死开放,而是留成显式变量:

variable "polygon_rpc_allowed_cidr_blocks" {
  description = "CIDR blocks allowed to access Polygon JSON-RPC on TCP 8545. Empty closes public RPC access."
  type        = list(string)
  default     = []
}

variable "polygon_metrics_allowed_cidr_blocks" {
  description = "CIDR blocks allowed to access Polygon Erigon metrics on TCP 6060. Empty closes public metrics access."
  type        = list(string)
  default     = []
}

这样默认状态是关闭。如果以后确实需要让某个固定办公出口、监控 VPC 或反向代理访问 RPC,再显式填入 CIDR,而不是重新回到 0.0.0.0/0

线上临时收口

在 Terraform provider 本地异常、暂时无法稳定 apply 的情况下,可以先用 AWS CLI 做等价的在线变更:

aws ec2 create-security-group \
  --region ap-northeast-1 \
  --group-name polygon-node-sg \
  --description "Polygon Erigon node security group" \
  --vpc-id <vpc-id>

然后只授权必要入口:

aws ec2 authorize-security-group-ingress \
  --region ap-northeast-1 \
  --group-id <polygon-node-sg-id> \
  --ip-permissions \
  'IpProtocol=tcp,FromPort=30303,ToPort=30303,IpRanges=[{CidrIp=0.0.0.0/0,Description="Polygon P2P TCP"}]' \
  'IpProtocol=udp,FromPort=30303,ToPort=30303,IpRanges=[{CidrIp=0.0.0.0/0,Description="Polygon P2P UDP"}]' \
  'IpProtocol=udp,FromPort=42069,ToPort=42069,IpRanges=[{CidrIp=0.0.0.0/0,Description="Polygon torrent UDP"}]'

最后把实例切到新安全组:

aws ec2 modify-instance-attribute \
  --region ap-northeast-1 \
  --instance-id <instance-id> \
  --groups <polygon-node-sg-id>

这个操作不会重启 EC2,也不会重启容器;它只改变 ENI 关联的安全组规则。

验证

外部验证 8545 应该失败:

curl -sS --connect-timeout 5 -m 8 \
  -H 'Content-Type: application/json' \
  --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
  http://<public-ip>:8545

预期结果是连接超时或被拒绝。

实例内部仍然可以访问本地 RPC:

curl -sS -H 'Content-Type: application/json' \
  --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
  http://127.0.0.1:8545 | jq

这说明 RPC 服务没有被关掉,只是公网入口被安全组挡住了。

还要确认同步没有被误伤:

curl -sS -H 'Content-Type: application/json' \
  --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' \
  http://127.0.0.1:8545 | jq

如果 currentBlock 持续增长,日志中也能看到 Execution 阶段推进,说明 P2P、Heimdall 和本地 RPC 都仍然工作。

后续治理

手工创建的安全组需要回收到 Terraform state:

terraform import aws_security_group.polygon_node_sg <polygon-node-sg-id>

之后再执行正常的 terraform planterraform apply,确保 Terraform 不会尝试重复创建同名安全组。

更完整的下一步不是重新开放 RPC,而是把 RPC 放到明确边界后面:

  • 只允许内网调用
  • 或只允许固定办公出口 IP
  • 或放到带认证、限流和访问日志的反向代理后面
  • 或单独部署只读 RPC 服务,而不是直接暴露 archive node 本体

归档节点最重要的是稳定追块和服务内部查询。除非它本身就是一项公开 RPC 产品,否则 8545 不应该暴露在公网。

参考文献

[1] Polygon Labs. “Run an Erigon archive node.” Polygon Docs. https://docs.polygon.technology/pos/how-to/erigon-archive-node

[2] Erigon Contributors. “Public RPC.” Erigon README. https://github.com/erigontech/erigon#public-rpc

[3] Erigon Contributors. “Default Ports and Firewalls.” Erigon README. https://github.com/erigontech/erigon#default-ports-and-firewalls

[4] Amazon Web Services. “Control traffic to AWS resources using security groups.” Amazon VPC User Guide. https://docs.aws.amazon.com/vpc/latest/userguide/vpc-security-groups.html

[5] Amazon Web Services. “Security group rules.” Amazon VPC User Guide. https://docs.aws.amazon.com/vpc/latest/userguide/security-group-rules.html