Docker高级教程之智能添加与修改防火墙规则
资料简介:如果你有以下痛苦:
1、使用默认docker0桥接方式;
2、修改防火墙规则的话,使用手动修改配置;
3、并且修改时候还得计算来源端口,防止重复端口使用户登陆错误容器;
4、并当容器意外重启,内网ip变化后还得修改规则
那么你可以看看本文了,对你这些痛处都有解决方法。
目前docker容器设置访问规则的话,就2个方法
1、在docker容器创建的时候,使用-p来设置
2、在容器运行中,获取容器的ip,然后在宿主机的iptables力通过nat链做dnat设置
我之前一直使用第2个方法,但随着我docker项目的增加(目前我这里研发使用docker的容器做测试机),防火墙的访问规则设置起来十分麻烦,并且之前规划没有弄好,容器的网络还是默认的docker0桥接方式,这样容器一挂或者异常问题、dockerdaemon重启,都会导致容器的ip变更,变更后就得修改防火墙策略,十分的麻烦。
为了解决这个问题,我开发了2个程序,1个是持久化固定容器ip,另外一个是智能防火墙,下面是关于智能防火墙功能的介绍。
一、介绍
1、编写语言
python
2、运行环境
容器需要使用我之前写的持久化固定ip方式来创建
需要额外安装的python模块
etcd
docker
nmap
3、基本宿主机防火墙(包含filter链与nat链)
默认在/root/firewall里有个基础的宿主机防火墙,里面包含filter链与nat链,我的防火墙程序先获取这个文件,然后在从etcd里获取各容器的防火墙结合后是新的规则,如下面是我的
[root@docker-test3firewall]#cat/root/firewall/iptables_base.txt *filter :INPUTDROP[0:0] :FORWARDACCEPT[0:0] :OUTPUTACCEPT[1:83] -AINPUT-mstate--stateRELATED,ESTABLISHED-jACCEPT -AINPUT-picmp-jACCEPT -AINPUT-ilo-jACCEPT -AINPUT-iem1-jACCEPT -AINPUT-iovs1-jACCEPT #forllowisroomnetwork -AINPUT-s117.121.x.0/24-ptcp-mmultiport--dports50020-jACCEPT -AINPUT-ptcp-jREJECT--reject-withtcp-reset -AFORWARD-ptcp-mtcp--tcp-flagsFIN,SYN,RST,ACKRST-mlimit--limit1/sec-jACCEPT COMMIT #CompletedonFriDec610:59:132013 *nat :PREROUTINGACCEPT[2:269] :POSTROUTINGACCEPT[1739:127286] :OUTPUTACCEPT[1739:127286] :DOCKER-[0:0] -APREROUTING-maddrtype--dst-typeLOCAL-jDOCKER -APOSTROUTING-s172.16.0.0/16!-d172.16.0.0/16-jMASQUERADE -AOUTPUT!-d127.0.0.0/8-maddrtype--dst-typeLOCAL-jDOCKER COMMIT
其中50020是ssh端口,117.121.x.0/24是允许的网段,x的意思保密,不让你们看我的网络。
4、代码
#!/usr/bin/envpython #-*-coding:utf-8-*- #author:DengLei #email:dl528888@gmail.com importos importsys importargparse importetcd importtime importsocket,struct,fcntl fromdockerimportClient importsubprocess importshutil importnmap defget_local_ip(iface='em1'): sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) sockfd=sock.fileno() SIOCGIFADDR=0x8915 ifreq=struct.pack('16sH14s',iface,socket.AF_INET,'x00'*14) try: res=fcntl.ioctl(sockfd,SIOCGIFADDR,ifreq) except: returnNone ip=struct.unpack('16sH2x4s8x',res)[2] returnsocket.inet_ntoa(ip) defdocker_container_all(): docker_container=docker_client.containers(all=True) container_name=[] container_stop_name=[] foriindocker_container: container_name.append(i['Names']) forbincontainer_name: forcinb: container_stop_name.append(c) returncontainer_stop_name defdocker_container_run(): docker_container=docker_client.containers() container_name=[] container_stop_name=[] foriindocker_container: container_name.append(i['Names']) forbincontainer_name: forcinb: container_stop_name.append(c[1::]) returncontainer_stop_name if__name__=="__main__": #followishelpinfo p=argparse.ArgumentParser(description='Itisuserfultooltomodifydockercontainerfirewall') p.add_argument("container_name",help="listlocaldockercontainername") p.add_argument("-l","--list",help="showcontainerfirewallrules",action="store_true") p.add_argument("-a","--add",help="addcontainerfirewallrules",action="store_true") p.add_argument("-r","--rm",help="rmcontainerfirewallrules") p.add_argument("-m","--mode",choices=["internal","external"],help="setcontainerfirewallmode") p.add_argument("-s","--source",help="sourceipviewcontainerfirewallrules") p.add_argument("-sp","--sport",help="sourceportviewcontainerfirewallrules") p.add_argument("-d","--dest",help="destinationipcontainerfirewallrules") p.add_argument("-dp","--dport",help="destinationportviewcontainerfirewallrules") p.add_argument("-pm","--portmode",choices=["dynamic","manual"],help="setcontainerportmode") p.add_argument("-e","--effect",help="effectcontainerfirewallrules",action="store_true") p.add_argument("-ap","--addip",help="addexternaliptocontainer") p.add_argument("-rp","--rmip",help="rmexternaliptocontainer") args=p.parse_args() local_ip=get_local_ip('ovs1') docker_etcd_key='/app/docker/' etcd_client=etcd.Client(host='127.0.0.1',port=4001) docker_client=Client(base_url='unix://var/run/docker.sock',version='1.15',timeout=10) docker_container_all_name=docker_container_all() portmode='manual' container_ip='' #getcontainerip r=etcd_client.read('%s%s'%(docker_etcd_key,local_ip),recursive=True,sorted=True) forchildinr.children: ifchild.dirisnotTrueandargs.container_nameinchild.keyand'firewall'notinchild.key: container_ip=eval(child.value)['Container_ip'] iflen(container_ip)==0andargs.container_name!="all": print'Thiscontainer:%sinfoisnotinetcd!'%args.container_name sys.exit(1) if'/'+args.container_namenotindocker_container_all_nameandargs.container_name!="all": print'localhostdockerisnotcontainer:%s!'%args.container_name sys.exit(1) ifargs.list: try: now_firewall_rule=etcd_client.read('%s%s/firewall/nat-%s'%(docker_etcd_key,local_ip,args.container_name)).value exceptKeyError: print'Thiscontainer:%sisnotfirewallrule!'%args.container_name sys.exit(1) iflen(now_firewall_rule)>0: now_firewall_rule=eval(now_firewall_rule) print'Followiscontainer:%sfirewallrule!'%args.container_name foriinnow_firewall_rule: printi else: print'Thiscontainer:%sisnotfirewallrule!'%args.container_name sys.exit(1) ifargs.portmode=="dynamic": try: now_port=etcd_client.read('%s%s/firewall/now_port'%(docker_etcd_key,local_ip)).value exceptKeyError: now_port='40000' now_port=int(now_port)+1 key='%s%s/firewall/now_port'%(docker_etcd_key,local_ip) etcd_client.write(key,now_port) portmode=args.portmode elifargs.portmode=="manual": iflen(args.sport)>0: now_port=args.sport else: print'noinputsourceport' key='%s%s/firewall/now_port'%(docker_etcd_key,local_ip) etcd_client.write(key,now_port) #adddockercontainerfirewallrule ifargs.add: ifargs.mode: ifargs.source: ifargs.source=="all": source_ip='0.0.0.0/0.0.0.0' else: source_ip=args.source ifargs.portmode=="dynamic": sport=now_port else: sport=args.sport ifargs.dport: dport=args.dport else: print'pleaseinputdestport!Thisportiscontainerlocalport!' sys.exit(1) try: now_id=len(eval(etcd_client.read('%s%s/firewall/nat-%s'%(docker_etcd_key,local_ip,args.container_name)).value)) exceptKeyError: now_id='0' exceptSyntaxError: now_id='0' now_id=int(now_id)+1 ifargs.mode=="internal": msg={'Id':now_id,'Mode':args.mode,'Container_name':args.container_name,'Source_ip':source_ip,'Port_mode':portmode,'Source_port':'%s'%sport,'Local_port':dport,'Container_ip':container_ip} else: ifargs.dest: msg={'Id':now_id,'Mode':args.mode,'Container_name':args.container_name,'Source_ip':source_ip,'Destination_ip':args.dest,'Port_mode':portmode,'Source_port':'%s'%sport,'Local_port':dport,'Container_ip':container_ip} else: print'pleaseinputdestinationip' sys.exit(1) #addruletoiptables try: now_firewall_rule=etcd_client.read('%s%s/firewall/nat-%s'%(docker_etcd_key,local_ip,args.container_name)).value now_firewall_rule=eval(now_firewall_rule) exceptKeyError: now_firewall_rule=[] exceptSyntaxError: now_firewall_rule=[] foriinnow_firewall_rule: ifmsg['Local_port']==i['Local_port']andmsg['Source_ip']==i['Source_ip']andmsg['Mode']==i['Mode']andmsg['Container_name']==i['Container_name']andmsg['Source_port']==i['Source_port']: print'Thisrulehadexist!' sys.exit(1) now_firewall_rule.append(msg) key='%s%s/firewall/nat-%s'%(docker_etcd_key,local_ip,args.container_name) etcd_client.write(key,now_firewall_rule) foriinnow_firewall_rule: printi #delexistfirewallrule ifargs.rm: try: now_info=eval(etcd_client.read('%s%s/firewall/nat-%s'%(docker_etcd_key,local_ip,args.container_name)).value) exceptKeyError: print'ThisContainer:%sisnotfirewallrule!'%args.container_name sys.exit(1) exceptSyntaxError: print'Thiscontainer:%sisnotfirewallrule!'%args.container_name sys.exit(1) old_id=[i['Id']foriinnow_info] ifargs.rm!='all': ifint(args.rm)notinold_id: print'youinputruleid%sisnotexit!'%args.rm sys.exit(1) foriinnow_info: ifint(args.rm)==i['Id']: now_info.remove(i) print'Followiscontainer_name:%snewfirewallrule!'%args.container_name foriinnow_info: printi key='%s%s/firewall/nat-%s'%(docker_etcd_key,local_ip,args.container_name) etcd_client.write(key,now_info) sys.exit(0) else: now_info='' key='%s%s/firewall/nat-%s'%(docker_etcd_key,local_ip,args.container_name) etcd_client.write(key,now_info) print'Thiscontainer_name:%sisnotfirewallrule!'%args.container_name sys.exit(0) #effectcontainerfirewallrule ifargs.effect: #checkfirewallfilterexist config_dir='/root/firewall' iptables_config='iptables_base.txt' ifos.path.exists(config_dir)isFalse: os.mkdir(config_dir) ifos.path.isfile('%s/%s'%(config_dir,iptables_config))isFalse: print'nofoundbaseiptablesconfigin%s/%s!'%(config_dir,iptables_config) sys.exit(1) docker_container_run=docker_container_run() etcd_exist_firewall=[] ifargs.container_name!="all": container_name=args.container_name try: now_info=eval(etcd_client.read('%s%s/firewall/nat-%s'%(docker_etcd_key,local_ip,args.container_name)).value) msg=[] msg.append('#followiscontainer:%sfirewallrulen'%args.container_name) foriinnow_info: if'Destination_ip'notini: text='-ADOCKER-s%s!-iovs2-ptcp-mtcp--dport%s-jDNAT--to-destination%s:%s'%(i['Source_ip'],i['Source_port'],i['Container_ip'].split('/')[0],i['Local_port']) msg.append('%sn'%text) else: text='-ADOCKER-s%s-d%s!-iovs2-ptcp-mtcp--dport%s-jDNAT--to-destination%s:%s'%(i['Source_ip'],i['Destination_ip'],i['Source_port'],i['Container_ip'].split('/')[0],i['Local_port']) msg.append('%sn'%text) exceptSyntaxError: msg='' #wirtecontainerfirewallrule iptables_new_config='iptables_nat_%s.txt'%args.container_name f=open('%s/%s'%(config_dir,iptables_new_config),'w') foriinmsg: f.write(i) f.close() else: r=etcd_client.read('%s%s/firewall'%(docker_etcd_key,local_ip),recursive=True,sorted=True) forchildinr.children: ifchild.dirisnotTrueand'nat'inchild.keyandchild.key.split('/')[-1].split('nat-')[-1]indocker_container_run: #etcd_exist_firewall.append(child.key.split('/')[-1].split('nat-')[-1]) try: now_info=eval(etcd_client.read(child.key).value) msg=[] msg.append('#followiscontainer:%sfirewallrulen'%child.key.split('/')[-1].split('nat-')[-1]) foriinnow_info: if'Destination_ip'notini: text='-ADOCKER-s%s!-iovs2-ptcp-mtcp--dport%s-jDNAT--to-destination%s:%s'%(i['Source_ip'],i['Source_port'],i['Container_ip'].split('/')[0],i['Local_port']) msg.append('%sn'%text) else: text='-ADOCKER-s%s-d%s!-iovs2-ptcp-mtcp--dport%s-jDNAT--to-destination%s:%s'%(i['Source_ip'],i['Destination_ip'],i['Source_port'],i['Container_ip'].split('/')[0],i['Local_port']) msg.append('%sn'%text) exceptSyntaxError: msg='' #wirtecontainerfirewallrule iptables_new_config='iptables_nat_%s.txt'%child.key.split('/')[-1].split('nat-')[-1] f=open('%s/%s'%(config_dir,iptables_new_config),'w') foriinmsg: f.write(i) f.close() #getnowallcontainerfirewallrule all_firewall_file=[] forparent,dirnames,filenamesinos.walk(config_dir): forfilenameinfilenames: if'iptables_nat'infilename: all_firewall_file.append(os.path.join(parent,filename)) #getiptablesbasefileline count=len(open('%s/%s'%(config_dir,iptables_config),'rU').readlines()) modify_post=int(count)-1 f=open('%s/%s'%(config_dir,iptables_config),'r+') flist=f.readlines() flist[modify_post]='' f=open foriinall_firewall_file: f=open(i) try: container_text=f.read() finally: f.close() flist.append(container_text) flist.append('COMMITn') f=open('%s/temp_iptables.txt'%config_dir,'w') foriinflist: f.write(i) f.close() #applynewfirewallrule shutil.copy('%s/temp_iptables.txt'%config_dir,'/etc/sysconfig/iptables') #restartfirewall firewall_status=((subprocess.Popen("systemctlrestartiptables&>>/dev/null&&echo0||echo1",shell=True,stdout=subprocess.PIPE)).stdout.readlines()[0]).strip('n') iffirewall_status!="0": print'firewallrulehasproblem!' sys.exit(1) else: print'configfirewallruleissuccess!' sys.exit(0) ifargs.addip: if'/'notinargs.addip: print'pleaseinputip:netmask!' sys.exit(1) external_ip=args.addip.split('/')[0] external_ip_netmask=args.addip.split('/')[1] #nmapipexist! nm=nmap.PortScanner() nmap_result=nm.scan(external_ip,'60020')['nmap']['scanstats']['uphosts'] ifint(nmap_result)==1: print'youinputip:%sisonline!'%external_ip sys.exit(1) try: now_ip=eval(etcd_client.read('%s%s/external_ip/%s'%(docker_etcd_key,local_ip,external_ip)).value) ifnow_ip['Container_name']!=args.container_name: print'thisisexternalip:%sishasusedbycontainer:%s.ifyouwanttouseitagain,pleasedeletethiskey:%s.'%(args.addip,now_ip['Container_name'],'%s%s/external_ip/%s'%(docker_etcd_key,local_ip,external_ip)) sys.exit(1) exceptKeyError: pass
#getdeviceinfo try: now_device=etcd_client.read('%s%s/external_ip/device'%(docker_etcd_key,local_ip)).value exceptKeyError: now_device='em2:0' new_device=now_device.split(':')[0]+':'+str(int(now_device.split(':')[1])+1) key='%s%s/external_ip/device'%(docker_etcd_key,local_ip) etcd_client.write(key,new_device) #addnewexternalipinlocalhost ifint(external_ip_netmask)==8: external_ip_netmask='255.0.0.0' elifint(external_ip_netmask)==16: external_ip_netmask='255.255.0.0' elifint(external_ip_netmask)==24: external_ip_netmask='255.255.255.0' elifint(external_ip_netmask)==32: external_ip_netmask='255.255.255.255' else: print'youinputnetmask%sicannotcalculate'%external_ip_netmask sys.exit(1) add_external_ip_status=((subprocess.Popen("/sbin/ifconfig%s%snetmask%sup&>>/dev/null&&echo0||echo1"%(new_device,external_ip,external_ip_netmask),shell=True,stdout=subprocess.PIPE)).stdout.readlines()[0]).strip('n') ifadd_external_ip_status!="0": print'addexternalip:%sisfail!'%args.addip sys.exit(1) else: print'addexternalip:%sissuccess!'%args.addip key='%s%s/external_ip/%s'%(docker_etcd_key,local_ip,external_ip) info={'Ip':external_ip,'Netmask':external_ip_netmask,'Container_name':args.container_name,'Device':new_device,'Date':time.strftime('%Y.%m.%d-%T')} etcd_client.write(key,info) sys.exit(0) ifargs.rmip: try: now_ip=eval(etcd_client.read('%s%s/external_ip/%s'%(docker_etcd_key,local_ip,args.rmip)).value) exceptKeyError: print'Thisexternalip:%sisnotuseinetcd!'%args.rmip sys.exit(1) ifnow_ip['Container_name']!=args.container_name: print'thisisexternalip:%sishasusedbycontainer:%s.ifyouwanttodeleteit,pleaseinputcorrectcontainer:%sandexternalip:%s.'%(args.rmip,now_ip['Container_name'],now_ip['Container_name'],now_ip['Ip']) sys.exit(1) #deleteuseexternalipinlocalhost delete_external_ip_status=((subprocess.Popen("/sbin/ifconfig%sdown&>>/dev/null&&echo0||echo1"%(now_ip['Device']),shell=True,stdout=subprocess.PIPE)).stdout.readlines()[0]).strip('n') ifdelete_external_ip_status!="0": print'deleteexternalip:%sisfail!'%args.rmip sys.exit(1) else: print'deleteexternalip:%sissuccess!'%args.rmip key='%s%s/external_ip/%s'%(docker_etcd_key,local_ip,args.rmip) etcd_client.delete(key) sys.exit(0) sys.exit(1)
建议根据自己实际环境来修改上面代码,我这个仅是让大家参考我的运行方式,以及可以使用这个东东来解决自己的问题,大家如果有其他的方法也可以使用。
二、运行
1、使用帮助
[root@docker-test3code]#pythonmodify_docker_container_firewall.py-h usage:modify_docker_container_firewall.py[-h][-l][-a][-rRM] [-m{internal,external}] [-sSOURCE][-spSPORT][-dDEST] [-dpDPORT][-pm{dynamic,manual}] [-e][-apADDIP][-rpRMIP] container_name
Itisuserfultooltomodifydockercontainerfirewall positionalarguments: container_namelistlocaldockercontainername optionalarguments: -h,--helpshowthishelpmessageandexit -l,--listshowcontainerfirewallrules -a,--addaddcontainerfirewallrules -rRM,--rmRMrmcontainerfirewallrules -m{internal,external},--mode{internal,external} setcontainerfirewallmode -sSOURCE,--sourceSOURCE sourceipviewcontainerfirewallrules -spSPORT,--sportSPORT sourceportviewcontainerfirewallrules -dDEST,--destDESTdestinationipcontainerfirewallrules -dpDPORT,--dportDPORT destinationportviewcontainerfirewallrules -pm{dynamic,manual},--portmode{dynamic,manual} setcontainerportmode -e,--effecteffectcontainerfirewallrules -apADDIP,--addipADDIP addexternaliptocontainer -rpRMIP,--rmipRMIP rmexternaliptocontainer
说明:
-l是展示当前容器的所有防火墙规则,后面不加值
-a是进行增加容器防火墙规则,后面不加值
-r是删除容器规则,后面是防火墙的id值
-m是防火墙规则的模式,有internal(内部模式)与external(外部模式),如果你使用跟宿主机一样出口ip的话,选择
internal,如果使用独立的外网ip,就选择external
-s是来源ip,后面是ip/netmask模式
-sp是来源访问端口,后面需要输入允许外边访问进来的端口
-d是指定独立的外网ip,后面需要输入ip值
-dp是指定访问容器的端口,后面是属于端口值
-pm是指定来源端口的模式,有dynamic与manual模式,如果选择dynamic就不需要你指定来源端口值,会自动生成一个值,使
用manual的话,就需要你手动输入一个来源端口值
-e是设置好防火墙后,应用此防火墙策略,也就是在iptables里生效,后面不加值
-ap是在本机增加独立的外网ip,后面是ip/netmask模式
-rp是删除本机独立外网ip,后面是ip模式
2、查看test1的规则
目前我本机有test1-3这3个容器
[root@docker-test3code]#dockerps-a CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES c07b67c2382adocker.ops-chukong.com:5000/centos6-http:new"/usr/bin/supervisor40hoursagoUp40hourstest2 7c31bbfe0091docker.ops-chukong.com:5000/centos6-http:new"/usr/bin/supervisor3daysagoUp15hourstest1 5eede798f189docker.ops-chukong.com:5000/centos6-http:new"/usr/bin/supervisor3daysagoExited(0)24hoursagotest3
其中test1与test2都使用持久化固定ip了,test3没有
现在使用智能防火墙查看test1的防火墙
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest1-l Thiscontainer:test1isnotfirewallrule! [root@docker-test3code]#pythonmodify_docker_container_firewall.pytest2-l Thiscontainer:test2isnotfirewallrule! [root@docker-test3code]#pythonmodify_docker_container_firewall.pytest3-l Thiscontainer:test3infoisnotinetcd!
可以看到test1与test2都是没有规则的,而test3每一使用持久化固定ip,所以没办法查看数据
3、添加规则
先给test1添加内部模式规则-minternal,这样能使用docker宿主机的外网ip+port访问
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest1-a-minternal-s1.1.1.1/24-pmdynamic-dp22 {'Mode':'internal','Container_name':'test1','Source_port':'40030','Port_mode':'dynamic','Local_port':'22','Source_ip':'1.1.1.1/24','Id':1,'Container_ip':'172.16.1.2/24'}
这样是给与test1容器设置,允许1.1.1.1/24通过40030(使用动态模式自动生成访问端口),访问test1的22端口
其中test1的容器ip自动查看,不需要收到查找与手动输入
说明
Mode是运行的模式
Container_name是对应容器名
Source_port是来源端口
Port_mode是指端口模式为动态获取
Local_port是目的端口
Source_ip是来源ip
Id是指防火墙规则的id,后面可以通过指定id来删除规则
Container_ip是容器的ip
以上数据均是在使用持久化故障ip脚本生成容器的时候,程序自动把数据写入到etcd里,然后只能防火墙也通过etcd获取数据
在给test1添加一个使用手动模式设置来源端口
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest1-a-minternal-s1.1.1.1/24-pmmanual-sp400031-dp22 {'Mode':'internal','Container_name':'test1','Source_port':'40030','Source_ip':'1.1.1.1/24','Local_port':'22','Port_mode':'dynamic','Id':1,'Container_ip':'172.16.1.2/24'} {'Mode':'internal','Container_name':'test1','Source_port':'400031','Port_mode':'manual','Local_port':'22','Source_ip':'1.1.1.1/24','Id':2,'Container_ip':'172.16.1.2/24'}
如果指定的来源端口相同,并且来源ip也相同会报错
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest1-a-minternal-s1.1.1.1/24-pmmanual-sp40031-dp22 Thisrulehadexist!
现在通过-l参数来查看当前test1的规则
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest1-l Followiscontainer:test1firewallrule! {'Mode':'internal','Container_name':'test1','Source_port':'40030','Port_mode':'dynamic','Local_port':'22','Source_ip':'1.1.1.1/24','Id':1,'Container_ip':'172.16.1.2/24'} {'Mode':'internal','Container_name':'test1','Source_port':'40031','Source_ip':'1.1.1.1/24','Local_port':'22','Port_mode':'manual','Id':2,'Container_ip':'172.16.1.2/24'}
可以看到有2个刚才输入的规则
4、防火墙规则生效
先查看当前宿主机防火墙
[root@docker-test3code]#iptables-tnat-L-nv ChainPREROUTING(policyACCEPT117Kpackets,11Mbytes) pktsbytestargetprotoptinoutsourcedestination 15431914KDOCKERall--**0.0.0.0/00.0.0.0/0ADDRTYPEmatchdst-typeLOCAL ChainINPUT(policyACCEPT11906packets,716Kbytes) pktsbytestargetprotoptinoutsourcedestination ChainOUTPUT(policyACCEPT1462packets,86817bytes) pktsbytestargetprotoptinoutsourcedestination 241424DOCKERall--**0.0.0.0/0!127.0.0.0/8ADDRTYPEmatchdst-typeLOCAL ChainPOSTROUTING(policyACCEPT4994packets,234Kbytes) pktsbytestargetprotoptinoutsourcedestination 00MASQUERADEall--**172.16.0.0/16!172.16.0.0/16 ChainDOCKER(2references) pktsbytestargetprotoptinoutsourcedestination
可以看到只有默认的nat规则,其他的没有
现在使用-e参数来生效
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest1-e configfirewallruleissuccess!
可以看到运行成功
[root@docker-test3code]#iptables-tnat-L-nv ChainPREROUTING(policyACCEPT53packets,5242bytes) pktsbytestargetprotoptinoutsourcedestination 5300DOCKERall--**0.0.0.0/00.0.0.0/0ADDRTYPEmatchdst-typeLOCAL ChainINPUT(policyACCEPT5packets,300bytes) pktsbytestargetprotoptinoutsourcedestination ChainOUTPUT(policyACCEPT0packets,0bytes) pktsbytestargetprotoptinoutsourcedestination 00DOCKERall--**0.0.0.0/0!127.0.0.0/8ADDRTYPEmatchdst-typeLOCAL ChainPOSTROUTING(policyACCEPT0packets,0bytes) pktsbytestargetprotoptinoutsourcedestination 00MASQUERADEall--**172.16.0.0/16!172.16.0.0/16 ChainDOCKER(2references) pktsbytestargetprotoptinoutsourcedestination 00DNATtcp--!ovs2*1.1.1.0/240.0.0.0/0tcpdpt:40030to:172.16.1.2:22 00DNATtcp--!ovs2*1.1.1.0/240.0.0.0/0tcpdpt:40031to:172.16.1.2:22
规则已经运行了
在去配置文件里看看
[root@docker-test3code]#tail-n12/etc/sysconfig/iptables *nat :PREROUTINGACCEPT[2:269] :POSTROUTINGACCEPT[1739:127286] :OUTPUTACCEPT[1739:127286] :DOCKER-[0:0] -APREROUTING-maddrtype--dst-typeLOCAL-jDOCKER -APOSTROUTING-s172.16.0.0/16!-d172.16.0.0/16-jMASQUERADE -AOUTPUT!-d127.0.0.0/8-maddrtype--dst-typeLOCAL-jDOCKER #followiscontainer:test1firewallrule -ADOCKER-s1.1.1.1/24!-iovs2-ptcp-mtcp--dport40030-jDNAT--to-destination172.16.1.2:22 -ADOCKER-s1.1.1.1/24!-iovs2-ptcp-mtcp--dport40031-jDNAT--to-destination172.16.1.2:22 COMMIT
也是跟我们之前配置的一样,并且每个容器规则上面都有标示下面规则是属于哪个容器的,方便查看
5、删除防火墙规则
当前test1的规则
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest1-l Followiscontainer:test1firewallrule! {'Mode':'internal','Container_name':'test1','Source_port':'40030','Port_mode':'dynamic','Local_port':'22','Source_ip':'1.1.1.1/24','Id':1,'Container_ip':'172.16.1.2/24'} {'Mode':'internal','Container_name':'test1','Source_port':'40031','Source_ip':'1.1.1.1/24','Local_port':'22','Port_mode':'manual','Id':2,'Container_ip':'172.16.1.2/24'}
使用-r来删除,-r后面输入id
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest1-r2 Followiscontainer_name:test1newfirewallrule! {'Mode':'internal','Container_name':'test1','Source_port':'40030','Port_mode':'dynamic','Local_port':'22','Source_ip':'1.1.1.1/24','Id':1,'Container_ip':'172.16.1.2/24'}
然后-e生效
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest1-e configfirewallruleissuccess! [root@docker-test3code]#iptables-tnat-L-nv ChainPREROUTING(policyACCEPT4packets,200bytes) pktsbytestargetprotoptinoutsourcedestination 3168DOCKERall--**0.0.0.0/00.0.0.0/0ADDRTYPEmatchdst-typeLOCAL ChainINPUT(policyACCEPT2packets,120bytes) pktsbytestargetprotoptinoutsourcedestination ChainOUTPUT(policyACCEPT0packets,0bytes) pktsbytestargetprotoptinoutsourcedestination 00DOCKERall--**0.0.0.0/0!127.0.0.0/8ADDRTYPEmatchdst-typeLOCAL ChainPOSTROUTING(policyACCEPT1packets,40bytes) pktsbytestargetprotoptinoutsourcedestination 00MASQUERADEall--**172.16.0.0/16!172.16.0.0/16 ChainDOCKER(2references) pktsbytestargetprotoptinoutsourcedestination 00DNATtcp--!ovs2*1.1.1.0/240.0.0.0/0tcpdpt:40030to:172.16.1.2:22 [root@docker-test3code]#tail-n12/etc/sysconfig/iptables #CompletedonFriDec610:59:132013 *nat :PREROUTINGACCEPT[2:269] :POSTROUTINGACCEPT[1739:127286] :OUTPUTACCEPT[1739:127286] :DOCKER-[0:0] -APREROUTING-maddrtype--dst-typeLOCAL-jDOCKER -APOSTROUTING-s172.16.0.0/16!-d172.16.0.0/16-jMASQUERADE -AOUTPUT!-d127.0.0.0/8-maddrtype--dst-typeLOCAL-jDOCKER #followiscontainer:test1firewallrule -ADOCKER-s1.1.1.1/24!-iovs2-ptcp-mtcp--dport40030-jDNAT--to-destination172.16.1.2:22 COMMIT
可以看到已经智能自动修改了
6、添加额外的外网ip
使用-ap来添加
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest1-ap117.121.x.99/24 addexternalip:117.121.x.99/24issuccess! [root@docker-test3code]#ping117.121.x.99-c2 PING117.121.x.99(117.121.x.99)56(84)bytesofdata. 64bytesfrom117.121.x.99:icmp_seq=1ttl=64time=0.039ms 64bytesfrom117.121.x.99:icmp_seq=2ttl=64time=0.032ms ---117.121.x.99pingstatistics--- 2packetstransmitted,2received,0%packetloss,time999ms rttmin/avg/max/mdev=0.032/0.035/0.039/0.006ms
可以看到已经添加成功,并且能ping通,安全起见,我把额外的外网ip第三位添加个x,防止坏人扫描。
在通过修改防火墙来设置外部模式策略
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest1-a-mexternal-pmdynamic-sall-d117.121.x.99-dp22 {'Mode':'internal','Container_name':'test1','Source_port':'40030','Source_ip':'1.1.1.1/24','Local_port':'22','Port_mode':'dynamic','Id':1,'Container_ip':'172.16.1.2/24'} {'Destination_ip':'117.121.x.99','Mode':'external','Container_name':'test1','Source_port':'40033','Port_mode':'dynamic','Local_port':'22','Source_ip':'0.0.0.0/0.0.0.0','Id':2,'Container_ip':'172.16.1.2/24'}
备注:其中-sall是允许所有公网ip访问
然后生效
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest1-e configfirewallruleissuccess! [root@docker-test3code]#iptables-tnat-L-nv ChainPREROUTING(policyACCEPT16packets,1308bytes) pktsbytestargetprotoptinoutsourcedestination 160DOCKERall--**0.0.0.0/00.0.0.0/0ADDRTYPEmatchdst-typeLOCAL ChainINPUT(policyACCEPT1packets,60bytes) pktsbytestargetprotoptinoutsourcedestination ChainOUTPUT(policyACCEPT0packets,0bytes) pktsbytestargetprotoptinoutsourcedestination 00DOCKERall--**0.0.0.0/0!127.0.0.0/8ADDRTYPEmatchdst-typeLOCAL ChainPOSTROUTING(policyACCEPT0packets,0bytes) pktsbytestargetprotoptinoutsourcedestination 00MASQUERADEall--**172.16.0.0/16!172.16.0.0/16 ChainDOCKER(2references) pktsbytestargetprotoptinoutsourcedestination 00DNATtcp--!ovs2*1.1.1.0/240.0.0.0/0tcpdpt:40030to:172.16.1.2:22 00DNATtcp--!ovs2*0.0.0.0/0117.121.x.99tcpdpt:40033to:172.16.1.2:22
然后ssh登陆试试
[root@docker-test3code]#ssh117.121.x.99-lroot-p40033 Theauthenticityofhost'[117.121.x.99]:40033([117.121.x.99]:40033)'can'tbeestablished. RSAkeyfingerprintis39:7c:13:9f:d4:b0:d7:63:fc:ff:ae:e3:46:a4:bf:6b. Areyousureyouwanttocontinueconnecting(yes/no)?yes Warning:Permanentlyadded'[117.121.x.99]:40033'(RSA)tothelistofknownhosts. root@117.121.x.99'spassword: Lastlogin:ThuMar1211:04:042015from211.151.20.221 root@7c31bbfe0091:~ 11:04:57#ifconfig eth1Linkencap:EthernetHWaddr66:17:20:C3:4E:21 inetaddr:172.16.1.2Bcast:0.0.0.0Mask:255.255.255.0 inet6addr:fe80::6417:20ff:fec3:4e21/64Scope:Link UPBROADCASTRUNNINGMULTICASTMTU:1500Metric:1 RXpackets:606errors:0dropped:2overruns:0frame:0 TXpackets:411errors:0dropped:0overruns:0carrier:0 collisions:0txqueuelen:1000 RXbytes:52692(51.4KiB)TXbytes:45451(44.3KiB) loLinkencap:LocalLoopback inetaddr:127.0.0.1Mask:255.0.0.0 inet6addr:::1/128Scope:Host UPLOOPBACKRUNNINGMTU:65536Metric:1 RXpackets:0errors:0dropped:0overruns:0frame:0 TXpackets:0errors:0dropped:0overruns:0carrier:0 collisions:0txqueuelen:0 RXbytes:0(0.0b)TXbytes:0(0.0b)
可以设置的外网ip可以正常登陆到test1的容器里
7、测试批量生效防火墙策略
目前仅有test1有防火墙测试了,现在给test2也设置
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest2-a-minternal-s1.1.1.1/24-pmdynamic-dp22 {'Mode':'internal','Container_name':'test2','Source_port':'40034','Port_mode':'dynamic','Local_port':'22','Source_ip':'0.0.0.0/0.0.0.0','Id':1,'Container_ip':'172.16.1.4/24'} {'Mode':'internal','Container_name':'test2','Source_port':'40035','Source_ip':'0.0.0.0/0.0.0.0','Local_port':'22','Port_mode':'dynamic','Id':2,'Container_ip':'172.16.1.4/24'} {'Mode':'internal','Container_name':'test2','Source_port':'40036','Port_mode':'dynamic','Local_port':'22','Source_ip':'1.1.1.1/24','Id':3,'Container_ip':'172.16.1.4/24'}
然后我在修改一下test1的
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest1-a-minternal-s2.2.2.2/24-pmdynamic-dp22 {'Mode':'internal','Container_name':'test1','Source_port':'40030','Port_mode':'dynamic','Local_port':'22','Source_ip':'1.1.1.1/24','Id':1,'Container_ip':'172.16.1.2/24'} {'Destination_ip':'117.121.x.99','Mode':'external','Container_name':'test1','Source_port':'40033','Source_ip':'0.0.0.0','Local_port':'22','Port_mode':'dynamic','Id':2,'Container_ip':'172.16.1.2/24'} {'Mode':'internal','Container_name':'test1','Source_port':'40037','Port_mode':'dynamic','Local_port':'22','Source_ip':'2.2.2.2/24','Id':3,'Container_ip':'172.16.1.2/24'}
之前如果想动态生效需要知道容器名,下面可以把容器名那里输入all,就可以生效所有已经设置的规则
[root@docker-test3code]#pythonmodify_docker_container_firewall.pyall-e configfirewallruleissuccess! [root@docker-test3code]#iptables-tnat-L-nv ChainPREROUTING(policyACCEPT20packets,1914bytes) pktsbytestargetprotoptinoutsourcedestination 160DOCKERall--**0.0.0.0/00.0.0.0/0ADDRTYPEmatchdst-typeLOCAL ChainINPUT(policyACCEPT1packets,60bytes) pktsbytestargetprotoptinoutsourcedestination ChainOUTPUT(policyACCEPT0packets,0bytes) pktsbytestargetprotoptinoutsourcedestination 00DOCKERall--**0.0.0.0/0!127.0.0.0/8ADDRTYPEmatchdst-typeLOCAL ChainPOSTROUTING(policyACCEPT0packets,0bytes) pktsbytestargetprotoptinoutsourcedestination 00MASQUERADEall--**172.16.0.0/16!172.16.0.0/16 ChainDOCKER(2references) pktsbytestargetprotoptinoutsourcedestination 00DNATtcp--!ovs2*1.1.1.0/240.0.0.0/0tcpdpt:40030to:172.16.1.2:22 00DNATtcp--!ovs2*0.0.0.0117.121.x.99tcpdpt:40033to:172.16.1.2:22 00DNATtcp--!ovs2*2.2.2.0/240.0.0.0/0tcpdpt:40037to:172.16.1.2:22 00DNATtcp--!ovs2*0.0.0.0/00.0.0.0/0tcpdpt:40034to:172.16.1.4:22 00DNATtcp--!ovs2*0.0.0.0/00.0.0.0/0tcpdpt:40035to:172.16.1.4:22 00DNATtcp--!ovs2*1.1.1.0/240.0.0.0/0tcpdpt:40036to:172.16.1.4:22 [root@docker-test3code]#tail-n15/etc/sysconfig/iptables :POSTROUTINGACCEPT[1739:127286] :OUTPUTACCEPT[1739:127286] :DOCKER-[0:0] -APREROUTING-maddrtype--dst-typeLOCAL-jDOCKER -APOSTROUTING-s172.16.0.0/16!-d172.16.0.0/16-jMASQUERADE -AOUTPUT!-d127.0.0.0/8-maddrtype--dst-typeLOCAL-jDOCKER #followiscontainer:test1firewallrule -ADOCKER-s1.1.1.1/24!-iovs2-ptcp-mtcp--dport40030-jDNAT--to-destination172.16.1.2:22 -ADOCKER-s0.0.0.0-d117.121.x.99!-iovs2-ptcp-mtcp--dport40033-jDNAT--to-destination172.16.1.2:22 -ADOCKER-s2.2.2.2/24!-iovs2-ptcp-mtcp--dport40037-jDNAT--to-destination172.16.1.2:22 #followiscontainer:test2firewallrule -ADOCKER-s0.0.0.0/0.0.0.0!-iovs2-ptcp-mtcp--dport40034-jDNAT--to-destination172.16.1.4:22 -ADOCKER-s0.0.0.0/0.0.0.0!-iovs2-ptcp-mtcp--dport40035-jDNAT--to-destination172.16.1.4:22 -ADOCKER-s1.1.1.1/24!-iovs2-ptcp-mtcp--dport40036-jDNAT--to-destination172.16.1.4:22 COMMIT
很简单吧,比以前需要找到容器的ip,然后收到去防火墙里修改,并且修改的时候,还得计算给予的来源端口,现在是否舒服很多,以后有平台想使用的话,直接调用就可以。
8、删除额外的外网ip
使用rp参数
[root@docker-test3code]#pythonmodify_docker_container_firewall.pytest2-rp117.121.x.99 thisisexternalip:117.121.x.99ishasusedbycontainer:test1.ifyouwanttodeleteit,pleaseinputcorrectcontainer:test1andexternalip:117.121.x.99. [root@docker-test3code]#pythonmodify_docker_container_firewall.pytest1-rp117.121.x.99 deleteexternalip:117.121.x.99issuccess!
删除的时候,还必须制定对应的容器与额外外网ip,否则删除失败,但提供对于的容器与ip
[root@docker-test3code]#ping-c2117.121.x.99 PING117.121.x.99(117.121.x.99)56(84)bytesofdata. From117.121.x.3icmp_seq=1DestinationHostUnreachable From117.121.x.3icmp_seq=2DestinationHostUnreachable ---117.121.x.99pingstatistics--- 2packetstransmitted,0received,+2errors,100%packetloss,time1000ms pipe2
可以看到已经删除完成,ping不通了。
目前docker方面的文章,已经完成了:
1、安装docker
2、动态扩容docker容器的空间
3、动态绑定volume
4、docker多主机网络互联
5、docker持久化固定ip
6、docker智能添加与修改防火墙
以后有空给大家分享Docker集群与平台方面知识,希望大家多提意见。