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集群与平台方面知识,希望大家多提意见。