摆弄摆弄iptables

作为一名运维人员,安全是第一任务,那么某些高机密web网页限制IP访问是必做的环节,当然如果使用阿里云的“安全组”可以让这一切变的简单和直观。不过有时候,一个安全组里面有多个服务,不同的服务使用同一个端口(比如都是443),有些443要对所有人开放,有的443只能对公司的IP开放,那么如果不想重新收拾安全组的话,就干脆用iptables。

普通的iptables

常用的iptables规则如下:

1
2
3
4
5
6
7
iptables -nvL	#详细查看当前iptables情况
iptables -I INPUT -p tcp --dport 8701 -j DROP #所有来访问8701端口的请求都作废
iptables -I INPUT -s 60.191.94.118 -p tcp --dport 8070 -j ACCEPT #只准许60.191.94.118这个IP访问8070端口
iptables -t nat -I PREROUTING 1 -s 120.92.136.159/32 -p tcp -m tcp --dport 6379 -j DNAT --to-destination 100.99.231.81:6379 #准许120.92.136.159的6379信息转发到100.99.231.81的6379里
iptables -A OUTPUT -p tcp -m tcp --dport 61616 -j DROP #将61616端口的报文抛弃
iptables -D INPUT 1 #删除INPUT表里的第一规则
iptables -L FORWARD --line-numbers #展现规则序号,-D删除的行号就是这里的序号

如果不小心配错的规则比较多,不愿意一个一个删除,可以执行service iptables restart直接恢复。

容器的iptables

现在容器化横行,但是我们也要限制IP来访问容器的端口,但是如果像上面那样的话,是无法成功的。对于容器,为了避免您的规则被docker破坏,请使用DOCKER-USER链,比如有个容器已经做了3306端口与宿主机的3306端口互通,那么配置如下规则:

1
2
3
iptables -A DOCKER-USER -i eth0 -s 1.1.1.1 -p tcp -m conntrack --ctorigdstport 3306 -j ACCEPT
iptables -A DOCKER-USER -i eth0 -s 2.2.2.2 -p tcp -m conntrack --ctorigdstport 3306 -j ACCEPT
iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 3306 -j DROP

执行的效果就是只能1.1.1.1和2.2.2.2来访问该服务器的3306端口,其余IP一律drop掉。这里也要注意输入的顺序,因为iptables执行是从上往下的。

RETURN的问题

如果上面的规则如果变成了这样:

1
2
3
4
iptables -A DOCKER-USER -p all -j RETURN
iptables -A DOCKER-USER -i eth0 -s 1.1.1.1 -p tcp -m conntrack --ctorigdstport 3306 -j ACCEPT
iptables -A DOCKER-USER -i eth0 -s 2.2.2.2 -p tcp -m conntrack --ctorigdstport 3306 -j ACCEPT
iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 3306 -j DROP

会不会达不到预期的要求?答曰不一定,在我这个例子里结果就是任何人都可以访问容器的3306端口。因为return退出的是当前CHIAN:如果当前CHIAN是别的CHAIN调用的子CHIAN(从一个CHAIN里可以jump到另一个CHAIN, jump到的那个CHAIN是子CHAIN),那么返回到调用点下一条规则处开始执行,如果当前CHIAN不是子CHAIN,那么就以默认策略执行。iptables -nvL看一下当前iptables的情况:
akb48

可以看出DOCKER-USER这个链是1 references,即它被一个默认链调用,被哪个默认链呢?FORWARD,当DOCKER-USER RETURN的时候回返回到FORWARD链里然后走下一个规则,而下一个规则是什么呢?是

1
7893K 5610M ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED

所以所有人都可以访问这个3306了。

没有DOCKER-USER?

DOCKER-USER这个链是Docker比较新的版本加上的,例子里的docker版本是version 18.06.1-ce, build e68fc7a。但是如果docker比较老的话,是不会默认生成这个链的,比如:
akb48

这种情况要么乖乖的升级docker,要么可以自定义创建iptables链。比如我们创建一个链,链名叫GITLAB,只让公司内部网络(115.200.239.106)访问GITLAB。

首先先iptables -N GITLAB,创建该链。然后iptables -I GITLAB -p tcp --dport 443 -j DROPiptables -I GITLAB -s 115.200.239.106 -j ACCEPT创建给GITLAB链里添加两个访问规则达到只有指定IP访问443端口的目的。但是此时这个GITLAB链没有被任何任何默认链引用,所以即使配了规则也是无法匹配到任何报文的,所以我们要把它与FORWARD链链接起来,准许443端口可以转发,命令是iptables -I FORWARD -p https --dport 443 -j GITLAB,如图:
akb48

去浏览器里或者curl一下验证,的确只能指定IP才能访问GITLAB主页。不过,你以为现在就完事了么?非也,因为gitlab默认是通过https的形式拉取代码的,所以你还要把所有的代码服务器IP也要写进iptables里。

参考资料

https://docs.docker.com/network/iptables/
https://www.frozentux.net/iptables-tutorial/cn/iptables-tutorial-cn-1.1.19.html
http://kuntsung.blogspot.com/2012/10/iptables.html
https://www.zsythink.net/archives/1625

感谢您请我喝咖啡~O(∩_∩)O,如果要联系请直接发我邮箱chenx1242@163.com,我会回复你的
-------------本文结束感谢您的阅读-------------