資料簡介:如果你有以下痛苦:
1、使用默認docker0橋接方式;
2、修改防火墻規則的話,使用手動修改配置;
3、并且修改時候還得計算來源端口,防止重復端口使用戶登陸錯誤容器;
4、并當容器意外重啟,內網ip變化后還得修改規則
那么你可以看看本文了,對你這些痛處都有解決方法。
目前docker容器設置訪問規則的話,就2個方法
1、在docker容器創建的時候,使用-p來設置
2、在容器運行中,獲取容器的ip,然后在宿主機的iptables力通過nat鏈做dnat設置
我之前一直使用第2個方法,但隨著我docker項目的增加(目前我這里研發使用docker的容器做測試機),防火墻的訪問規則設置起來十分麻煩,并且之前規劃沒有弄好,容器的網絡還是默認的docker0橋接方式,這樣容器一掛或者異常問題、docker daemon重啟,都會導致容器的ip變更,變更后就得修改防火墻策略,十分的麻煩。
為了解決這個問題,我開發了2個程序,1個是持久化固定容器ip,另外一個是智能防火墻,下面是關于智能防火墻功能的介紹。
一、介紹
1、編寫語言
python
2、運行環境
容器需要使用我之前寫的持久化固定ip方式來創建
需要額外安裝的python模塊
etcd
docker
nmap
3、基本宿主機防火墻(包含filter鏈與nat鏈)
默認在/root/firewall里有個基礎的宿主機防火墻,里面包含filter鏈與nat鏈,我的防火墻程序先獲取這個文件,然后在從etcd里獲取各容器的防火墻結合后是新的規則,如下面是我的
[root@docker-test3 firewall]# cat /root/firewall/iptables_base.txt*filter:INPUT DROP [0:0]:FORWARD ACCEPT [0:0]:OUTPUT ACCEPT [1:83]-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT-A INPUT -p icmp -j ACCEPT-A INPUT -i lo -j ACCEPT-A INPUT -i em1 -j ACCEPT-A INPUT -i ovs1 -j ACCEPT#forllow is room network-A INPUT -s 117.121.x.0/24 -p tcp -m multiport --dports 50020 -j ACCEPT-A INPUT -p tcp -j REJECT --reject-with tcp-reset-A FORWARD -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK RST -m limit --limit 1/sec -j ACCEPTCOMMIT# Completed on Fri Dec 6 10:59:13 2013*nat:PREROUTING ACCEPT [2:269]:POSTROUTING ACCEPT [1739:127286]:OUTPUT ACCEPT [1739:127286]:DOCKER - [0:0]-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER-A POSTROUTING -s 172.16.0.0/16 ! -d 172.16.0.0/16 -j MASQUERADE-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKERCOMMIT
其中50020是ssh端口,117.121.x.0/24是允許的網段,x的意思保密,不讓你們看我的網絡。
4、代碼
#!/usr/bin/env python#-*- coding: utf-8 -*-#author:Deng Lei#email: dl528888@gmail.comimport osimport sysimport argparseimport etcdimport timeimport socket, struct, fcntlfrom docker import Clientimport subprocessimport shutilimport nmapdef get_local_ip(iface = 'em1'):sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sockfd = sock.fileno()SIOCGIFADDR = 0x8915ifreq = struct.pack('16sH14s', iface, socket.AF_INET, 'x00'*14)try:res = fcntl.ioctl(sockfd, SIOCGIFADDR, ifreq)except:return Noneip = struct.unpack('16sH2x4s8x', res)[2]return socket.inet_ntoa(ip)def docker_container_all():docker_container=docker_client.containers(all=True)container_name=[]container_stop_name=[]for i in docker_container:container_name.append(i['Names'])for b in container_name:for c in b:container_stop_name.append(c)return container_stop_namedef docker_container_run():docker_container=docker_client.containers()container_name=[]container_stop_name=[]for i in docker_container:container_name.append(i['Names'])for b in container_name:for c in b:container_stop_name.append(c[1::])return container_stop_nameif __name__ == "__main__":#follow is help infop = argparse.ArgumentParser(description='It is userful tool to modify docker container firewall')p.add_argument("container_name",help="list local docker container name")p.add_argument("-l","--list",help="show container firewall rules",action="store_true")p.add_argument("-a","--add",help="add container firewall rules",action="store_true")p.add_argument("-r","--rm",help="rm container firewall rules")p.add_argument("-m","--mode",choices=["internal","external"],help="set container firewall mode")p.add_argument("-s","--source",help="source ip view container firewall rules")p.add_argument("-sp","--sport",help="source port view container firewall rules")p.add_argument("-d","--dest",help="destination ip container firewall rules")p.add_argument("-dp","--dport",help="destination port view container firewall rules")p.add_argument("-pm","--portmode",choices=["dynamic","manual"],help="set container port mode")p.add_argument("-e","--effect",help="effect container firewall rules",action="store_true")p.add_argument("-ap","--addip",help="add external ip to container")p.add_argument("-rp","--rmip",help="rm external ip to container")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=''#get container ipr = etcd_client.read('%s%s'%(docker_etcd_key,local_ip), recursive=True, sorted=True)for child in r.children:if child.dir is not True and args.container_name in child.key and 'firewall' not in child.key:container_ip=eval(child.value)['Container_ip']if len(container_ip) == 0 and args.container_name != "all":print 'This container:%s info is not in etcd!'%args.container_namesys.exit(1)if '/'+args.container_name not in docker_container_all_name and args.container_name != "all":print 'local host docker is not container:%s!'%args.container_namesys.exit(1)if args.list:try:now_firewall_rule=etcd_client.read('%s%s/firewall/nat-%s'%(docker_etcd_key,local_ip,args.container_name)).valueexcept KeyError:print 'This container:%s is not firewall rule!'%args.container_namesys.exit(1)if len(now_firewall_rule) >0:now_firewall_rule=eval(now_firewall_rule)print 'Follow is container:%s firewall rule!'%args.container_namefor i in now_firewall_rule:print ielse:print 'This container:%s is not firewall rule!'%args.container_namesys.exit(1)if args.portmode=="dynamic":try:now_port=etcd_client.read('%s%s/firewall/now_port'%(docker_etcd_key,local_ip)).valueexcept KeyError:now_port='40000'now_port=int(now_port) + 1key='%s%s/firewall/now_port'%(docker_etcd_key,local_ip)etcd_client.write(key,now_port)portmode=args.portmodeelif args.portmode=="manual":if len(args.sport)>0:now_port=args.sportelse:print 'no input source port'key='%s%s/firewall/now_port'%(docker_etcd_key,local_ip)etcd_client.write(key,now_port)#add docker container firewall ruleif args.add:if args.mode:if args.source:if args.source == "all":source_ip='0.0.0.0/0.0.0.0'else:source_ip=args.sourceif args.portmode=="dynamic":sport=now_portelse:sport=args.sportif args.dport:dport=args.dportelse:print 'please input dest port!This port is container local port!'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))except KeyError:now_id='0'except SyntaxError:now_id='0'now_id = int(now_id) + 1if args.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:if args.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 'please input destination ip'sys.exit(1)#add rule to iptablestry:now_firewall_rule=etcd_client.read('%s%s/firewall/nat-%s'%(docker_etcd_key,local_ip,args.container_name)).valuenow_firewall_rule=eval(now_firewall_rule)except KeyError:now_firewall_rule=[]except SyntaxError:now_firewall_rule=[]for i in now_firewall_rule:if msg['Local_port'] == i['Local_port'] and msg['Source_ip'] == i['Source_ip'] and msg['Mode'] == i['Mode'] and msg['Container_name'] == i['Container_name'] and msg['Source_port'] == i['Source_port']:print 'This rule had exist!'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)for i in now_firewall_rule:print i#del exist firewall ruleif args.rm:try:now_info=eval(etcd_client.read('%s%s/firewall/nat-%s'%(docker_etcd_key,local_ip,args.container_name)).value)except KeyError:print 'This Container:%s is not firewall rule!'%args.container_namesys.exit(1)except SyntaxError:print 'This container:%s is not firewall rule!'%args.container_namesys.exit(1)old_id=[i['Id'] for i in now_info]if args.rm != 'all':if int(args.rm) not in old_id:print 'you input rule id %s is not exit!'%args.rmsys.exit(1)for i in now_info:if int(args.rm) == i['Id']:now_info.remove(i)print 'Follow is container_name:%s new firewall rule!'%args.container_namefor i in now_info:print ikey='%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 'This container_name:%s is not firewall rule!'%args.container_namesys.exit(0)#effect container firewall ruleif args.effect:#check firewall filter existconfig_dir='/root/firewall'iptables_config='iptables_base.txt'if os.path.exists(config_dir) is False:os.mkdir(config_dir)if os.path.isfile('%s/%s'%(config_dir,iptables_config)) is False:print 'no found base iptables config in %s/%s!'%(config_dir,iptables_config)sys.exit(1)docker_container_run=docker_container_run()etcd_exist_firewall=[]if args.container_name != "all":container_name=args.container_nametry:now_info=eval(etcd_client.read('%s%s/firewall/nat-%s'%(docker_etcd_key,local_ip,args.container_name)).value)msg=[]msg.append('#follow is container:%s firewall rulen'%args.container_name)for i in now_info:if 'Destination_ip' not in i:text='-A DOCKER -s %s ! -i ovs2 -p tcp -m tcp --dport %s -j DNAT --to-destination %s:%s'%(i['Source_ip'],i['Source_port'],i['Container_ip'].split('/')[0],i['Local_port'])msg.append('%sn'%text)else:text='-A DOCKER -s %s -d %s ! -i ovs2 -p tcp -m tcp --dport %s -j DNAT --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)except SyntaxError:msg=''#wirte container firewall ruleiptables_new_config='iptables_nat_%s.txt'%args.container_namef=open('%s/%s'%(config_dir,iptables_new_config),'w')for i in msg:f.write(i)f.close()else:r = etcd_client.read('%s%s/firewall'%(docker_etcd_key,local_ip), recursive=True, sorted=True)for child in r.children:if child.dir is not True and 'nat' in child.key and child.key.split('/')[-1].split('nat-')[-1] in docker_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('#follow is container:%s firewall rulen'%child.key.split('/')[-1].split('nat-')[-1])for i in now_info:if 'Destination_ip' not in i:text='-A DOCKER -s %s ! -i ovs2 -p tcp -m tcp --dport %s -j DNAT --to-destination %s:%s'%(i['Source_ip'],i['Source_port'],i['Container_ip'].split('/')[0],i['Local_port'])msg.append('%sn'%text)else:text='-A DOCKER -s %s -d %s ! -i ovs2 -p tcp -m tcp --dport %s -j DNAT --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)except SyntaxError:msg=''#wirte container firewall ruleiptables_new_config='iptables_nat_%s.txt'%child.key.split('/')[-1].split('nat-')[-1]f=open('%s/%s'%(config_dir,iptables_new_config),'w')for i in msg:f.write(i)f.close()#get now all container firewall ruleall_firewall_file=[]for parent,dirnames,filenames in os.walk(config_dir):for filename in filenames:if 'iptables_nat' in filename:all_firewall_file.append(os.path.join(parent,filename))#get iptables base file linecount = len(open('%s/%s'%(config_dir,iptables_config),'rU').readlines())modify_post=int(count)-1f=open('%s/%s'%(config_dir,iptables_config),'r+')flist=f.readlines()flist[modify_post]=''f=openfor i in all_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')for i in flist:f.write(i)f.close()#apply new firewall ruleshutil.copy('%s/temp_iptables.txt'%config_dir,'/etc/sysconfig/iptables')#restart firewallfirewall_status=((subprocess.Popen("systemctl restart iptables &>>/dev/null && echo 0 || echo 1",shell=True,stdout=subprocess.PIPE)).stdout.readlines()[0]).strip('n')if firewall_status != "0":print 'firewall rule has problem!'sys.exit(1)else:print 'config firewall rule is success!'sys.exit(0)if args.addip:if '/' not in args.addip:print 'please input ip:netmask!'sys.exit(1)external_ip=args.addip.split('/')[0]external_ip_netmask=args.addip.split('/')[1]#nmap ip exist!nm = nmap.PortScanner()nmap_result=nm.scan(external_ip,'60020')['nmap']['scanstats']['uphosts']if int(nmap_result) == 1:print 'you input ip:%s is online!'%external_ipsys.exit(1)try:now_ip=eval(etcd_client.read('%s%s/external_ip/%s'%(docker_etcd_key,local_ip,external_ip)).value)if now_ip['Container_name'] != args.container_name:print 'this is external ip:%s is has used by container:%s.if you want to use it again,please delete this key:%s.'%(args.addip,now_ip['Container_name'],'%s%s/external_ip/%s'%(docker_etcd_key,local_ip,external_ip))sys.exit(1)except KeyError:pass
新聞熱點
疑難解答