资料简介:如果你有以下痛苦:
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 ACCEPT COMMIT # 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 DOCKER COMMIT
其中50020是ssh端口,117.121.x.0/24是允许的网段,x的意思保密,不让你们看我的网络。
4、代码
#!/usr/bin/env python
#-*- coding: utf-8 -*-
#author:Deng Lei
#email: dl528888@gmail.com
import os
import sys
import argparse
import etcd
import time
import socket, struct, fcntl
from docker import Client
import subprocess
import shutil
import nmap
def get_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:
return None
ip = 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_name
def 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_name
if __name__ == "__main__":
#follow is help info
p = 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 ip
r = 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_name
sys.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_name
sys.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)).value
except KeyError:
print 'This container:%s is not firewall rule!'%args.container_name
sys.exit(1)
if len(now_firewall_rule) >0:
now_firewall_rule=eval(now_firewall_rule)
print 'Follow is container:%s firewall rule!'%args.container_name
for i in now_firewall_rule:
print i
else:
print 'This container:%s is not firewall rule!'%args.container_name
sys.exit(1)
if args.portmode=="dynamic":
try:
now_port=etcd_client.read('%s%s/firewall/now_port'%(docker_etcd_key,local_ip)).value
except KeyError:
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
elif args.portmode=="manual":
if len(args.sport)>0:
now_port=args.sport
else:
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 rule
if 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.source
if args.portmode=="dynamic":
sport=now_port
else:
sport=args.sport
if args.dport:
dport=args.dport
else:
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) + 1
if 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_

