如果你有以下痛苦:
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(地址http://dl528888.blog.51cto.com/2382721/1616527),另外一个是智能防火墙,下面是关于智能防火墙功能的介绍。
一、介绍
1、编写语言
python
2、运行环境
容器需要使用我之前写的持久化固定ip方式来创建
需要额外安装的python模块
etcd
docker
nmap
3、代码
#!/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_port':'%s'%sport,'Local_port':dport,'Container_ip':container_ip} else: print 'please input destination ip' sys.exit(1) #add rule to iptables 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) 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生产环境-linux-网站被挂木马攻防经历 阅读原文»
生产环境-linux-网站被挂木马攻防经历 安全与方便始终是对立的,然而运维人员忽视系统安全方面的建设,带来的后果将是非常严重的,以下是一台未上线服务器入侵后的攻防经历。
一、出现异常,排查原因
发现异常是通过远端监控脚本发现访问网站时断时续,使用ssh工具连接会经常断掉连接,无法开展工作。
使用其他服务器对另一个网卡ip进行ssh连接,可以登录服务器,初步怀疑网卡异常或者流量异常。
分别使用ifstat、iftop、nethogs查看连接异常网卡流量信息(对几个流量分析工具进行对比,各有千秋):
1使用ifstat
wget http://distfiles.macports.org/ifstat/ifstat-1.1.tar.gz
cdifstat-1.1 ./configuremake make install 都是老套路
ifstat -a加入监控lo
2使用iftop监控那个端口流量
p 可以显示连接端口
3使用nethogs监控每个进程流量
yum换rpel源
wgethttp://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
yum install nethogs
nethogs eth0
效果展示ifstat:
可以看到服务器流量异常时,流量的变化情况。
效果展示iftop:
可以看到哪个PID进程导致流量过高
效果展示nethogs:
二、查找真凶
通过上面分析,造成网站打不开的原因就是有进程大量发送数据包到某个ip(其实是阿里的服务器)的80端口,导致服务器网络阻塞,但是通过以上的工具,发现此木马相当的狡猾,无法发使用的那个进程。
在使用netstat、ss通过端口获取木马进程失败后(后面才知道netstat、ps等命令已经被木马感染)
可以使用top工具,此木马在大量发包时肯定会造成资源的消耗
通过锁定发现了两个进程有大量的嫌疑:
通过ps命令找到进程执行的目录:
/usr/bin/sshupdate-bootsystem-insserv /tmp/GuiBger
通过持续观察发现时有agent进程一闪而逝,在使用find / -name agent 后
# ll /usr/bin/bsd-port/ 总用量 1120 -rwxr-xr-x. 1 root root 1135000 12月 25 11:20agent -rwxr-xr-x. 1 root root 4 12月 25 11:20 agent.conf -rw-r--r--. 1 root root 69 12月 25 11:50 conf.n -rw-r--r--. 1 root root 0 10月 9 19:36 getty
此时,相关的可以进程都找到了,通过测试,在网络阻塞时,删除sshupdate-bootsystem-insserv、GuiBger两个进程后,网络流量立即正常。而agent则怀疑是与黑客的通信进程,用于接收命令(瞎猜的)或者监控上面连个进程。
三、解决真凶
找到这3个进程并不意味结束,因为他们很可以是开机自启动程序,所以要在找到他们的开机自起的配置文件,我通过一个脚本实现这个功能:
#!/bin/sh echo > /tmp/find_init.log function ergodic(){ forfile in `ls $1` do if[ -d $1"/"$file ] #如果 file存在且是一个目录则为真 then ergodic$1"/"$file else localpath=$1"/"$file #得到文件的完整的目录 localname=$file #得到文件的名字 #做自己的工作. echo $path rootkit_init=`cat$path | grep sshupdate | head -n 1` if[ -z $rootkit_init ];then echo "sed -i 's#$rootkit_init##g' $path">> /tmp/find_init.log fi fi done } INIT_PATH="/etc/init.d" ergodic $INIT_PATH cat /tmp/find_init.log 这个脚本功能很简单,通过遍历/etc/init.d目录所有文件,使用grep搜索进程名关键词,将含有这几个进程的文件找出来。
结果如下:
sed -i's#/usr/bin/sshupdate-bootsystem-insserv##g' /etc/init.d/DbSecurityMdt sed -i's#/usr/bin/sshupdate-bootsystem-insserv##g' /etc/init.d/insserv
还真有自启动配置,迅速删除之
在删除这个木马命令时会遇到无法删除的问题,这个很简单:
lsattr /usr/bin/sshupdate-bootsystem-insserv 查看文件的隐藏权限 -------i------e- sshupdate-bootsystem-insserv 发现被限制删除操作了 chattr -i /usr/bin/sshupdate-bootsystem-insserv 取消影藏权限,然后再删除,完成。
通过查看数据的表结构,发现木马是从数据库渗透进服务器的,因为没有上线,方便开发测试在密码强度上使用了弱密码,所以被黑客破解了mysql的root账户密码,在mysql注入了木马,一步一步渗透到服务器。数据库方面处理就不详细介绍了:
-
检查生产库的表结构,删除多余表。
-
然后备份所有生产库。
-
停止mysql
-
删除datadir目录所有文件
-
重启mysql
-
导入此前备份数据库
订阅:
博文评论 (Atom)
没有评论:
发表评论