cloud-sre
Polygon Erigon 归档节点:为什么要收口 8545
一次把 Polygon Erigon archive node 从 allow-all 安全组收口到最小公网入口的实践记录。
一个区块链归档节点经常会被误配置成“所有端口对公网开放”。这在节点刚启动、同步压力还很高时尤其危险:公网扫描器会持续探测 JSON-RPC,日志里会出现无意义的 eth_accounts、eth_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。
安全组决策
最终安全组只开放下面三个入站规则:
| 端口 | 协议 | 来源 | 用途 |
|---|---|---|---|
30303 | TCP | 0.0.0.0/0 | Erigon P2P peering |
30303 | UDP | 0.0.0.0/0 | Erigon P2P peering |
42069 | UDP | 0.0.0.0/0 | Erigon torrent / snapshot peer |
关闭下面这些公网入口:
| 端口 | 原因 |
|---|---|
8545/tcp | JSON-RPC。业务没有要求公开提供 RPC,所以不应暴露到公网。 |
6060/tcp | metrics / pprof 类观测端口。只应给内部监控或本机调试使用。 |
9090/tcp | Erigon private API。Erigon 示例也把 private.api.addr 放在 127.0.0.1:9090。 |
8546/tcp | WebSocket RPC。没有公网业务需求时不开放。 |
8551/tcp | Engine API / JWT auth。不是外部用户入口。 |
22/tcp | SSH。运维访问走 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"]
}
8545 和 6060 不写死开放,而是留成显式变量:
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 plan 和 terraform 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