亲手跑一遍安全组和 NACL
目标
这两种机制的差别只有一个:是否记住状态,其余所有差别都源于此。本实验无需云账号:亲手写规则表,再亲手写一个读取规则表的评估器,用眼睛看清这个差别。
条件
- VPC 为
10.42.0.0/16,有 web · app · db 三层。 - 互联网只能通过 web 的 443 端口进入。
- web 调用 app 的 8080,app 调用 db 的 5432。
- app 对外访问 HTTPS(443)。db 不对外出站。
规则表格式
安全组有五列。在对端位置可以写另一个安全组的名称。
그룹,방향,프로토콜,포트,상대
sg-db,inbound,tcp,5432,sg-app
网络 ACL 有六列。从编号小的开始看,在第一条匹配的规则处结束。
번호,방향,동작,프로토콜,포트범위,상대
100,outbound,allow,tcp,443,0.0.0.0/0
32767,outbound,deny,all,all,0.0.0.0/0
포트범위(韩文,意为“端口范围”)可以像 443 这样只写一个端口,也可以像 1024-65535 这样写成范围。프로토콜(韩文,意为“协议”)和 포트범위(韩文,意为“端口范围”)中可以使用 all。
要创建的内容
| 文件 | 内容 |
|---|---|
/root/sgnacl/sg.csv |
三层的安全组规则 |
/root/sgnacl/nacl.csv |
app 子网的 NACL |
/root/sgnacl/nacl-ssh.csv · 03-order.md |
顺序陷阱及其说明 |
/root/sgnacl/nacl_eval.py |
读取规则表的评估器 |
/root/sgnacl/05-return.md |
响应要经过的关卡 |
/root/sgnacl/nacl-db.csv |
db 子网的护栏 |
/root/sgnacl/07-notes.md |
总结 |
参考
第 4 步的评估器,评分器会用藏起来的规则表来测试。 其中有一张表把宽泛的允许放在靠前的编号、把精确的拒绝放在靠后, 如果沿用安全组的习惯让拒绝优先,就会在这里出错。
用组引用把三层连起来
把三层的安全组规则按 그룹,방향,프로토콜,포트,상대(韩文,意为“组,方向,协议,端口,对端”)五列写入 /root/sgnacl/sg.csv。互联网只能进入 sg-web 的 443,web 调用 sg-app 的 8080,app 调用 sg-db 的 5432。
sg-app 和 sg-db 的对端不要写 IP。可以直接写另一个安全组的名称——这就是组引用。
无论应用服务器有多少台,也无论是否因自动扩缩容而增减,都不需要修改规则。用 IP 来写的话,服务器每增加一台规则就增加一条,服务器消失后规则却还留着。
不要创建向 0.0.0.0/0 开放 22 端口的规则行。评分器也会检查这一点。
同时开放出去的路和回来的路
把 app 子网的网络 ACL 按 번호,방향,동작,프로토콜,포트범위,상대(韩文,意为“编号,方向,动作,协议,端口范围,对端”)六列写入 /root/sgnacl/nacl.csv。要能对外访问 HTTPS(443)并让其响应返回,同时来自外部的入站 22 和出站 3306 必须被拦住。
NACL 不会记住状态。即使开放了出站 443,响应也必须另外通过规则,而响应会返回到我方的临时端口(1024–65535)。
最后用一个大编号放一条全部拒绝的规则,没有写出的流量就会自动被拦住。这样 22 和 3306 就不必单独拦截了。
编号要像 100、200 这样拉开间隔。如果按 1、2、3 紧挨着排,以后就没有位置可以插入,只能全部重新编号。
在第一条匹配的规则处结束
在 100 전체 허용(韩文,意为“100 全部允许”)之后放 200 tcp 22 거부(韩文,意为“200 tcp 22 拒绝”)的规则表,拦不住 22 端口。把只拦 22、其余全部放行的入站规则写入 /root/sgnacl/nacl-ssh.csv,并把原来的表为什么不行写入 /root/sgnacl/03-order.md。
NACL 从编号小的开始看,在第一条匹配的规则处结束。并不像安全组那样拒绝优先。
所以要把精确的拒绝放在小编号,把宽泛的允许放在大编号。只需调换顺序,同样的两行就能按预期工作。
说明中必须包含 번호、처음 和 22(前两项为韩文,依次意为“编号”“第一条”)。
亲手写评估器
创建 /root/sgnacl/nacl_eval.py。用 python3 /root/sgnacl/nacl_eval.py <규칙파일> <방향> <포트> <상대IP>(占位符依次为规则文件、方向、端口与对端 IP)调用时,第一行只能输出 allow 或 deny。
规则有三行。只看同一方向的规则,按编号升序逐条扫描,把协议、端口和对端全部匹配的第一条规则的动作原样输出。什么都不匹配则输出 deny。
地址是否落在网段内,用 ipaddress.ip_address(x) in ipaddress.ip_network(cidr) 判断。端口范围只需处理 443、1024-65535 和 all 三种。
评分器会用藏起来的规则表来测试。其中有一张表把宽泛的允许放在靠前的编号、把精确的拒绝放在靠后,如果让拒绝优先,就会在这里出错。
数一数响应要经过的关卡
对从互联网进入 sg-web 的 443 的请求,在它的响应发出时,分别说明安全组和网络 ACL 还需要什么,并在 /root/sgnacl/05-return.md 中至少写四行。
安全组会记住进入的连接,所以不需要为响应另外写规则。
NACL 不会记住。响应也必须通过规则,而响应的去向是对方的临时端口。用数字写出该范围。
就因为这一点差别,人们会为“入站明明开了,响应却收不到”耗掉半天。
在整个子网上设置护栏
用 NACL 彻底封锁 db 子网通往互联网的出口,但要保留 VPC(10.42.0.0/16)内部的通信。规则写入 /root/sgnacl/nacl-db.csv。
安全组附加在每个实例上,而 NACL 附加在整个子网上。因此它适合用作“这个子网不访问互联网”这类宽泛的护栏。
把允许 VPC 网段的规则放在小编号,把拒绝 0.0.0.0/0 的规则放在大编号。顺序反过来,允许就永远不会生效。
还必须保证 app 通过 5432 进入,以及它的响应通过临时端口发出。
总结三件事
在 /root/sgnacl/07-notes.md 中至少写三行:两种机制对状态的处理有何不同、NACL 的编号决定什么、用 IP 来写安全组规则会发生什么。
正文中必须包含 상태、번호 和 그룹 참조(均为韩文,依次意为“状态”“编号”“组引用”)。