tornado+nginx+IP白名单

背景

实现白名单,只允许可信用户访问我的服务
考虑采用iptables或者nginx

如果用nginx,那么可以建立一个allow_ip.conf,然后把这个配置文件include到nginx的配置中
用户可以主动添加他们的IP到我这,打算玩玩tornado,用户输入他的IP,然后存入到我的文件中,最后定时合并到allow_ip.conf

分析一下需求

  • 一个input,一个button,点button就把input的内容追加到某个文件中,暂时不考虑input是否合法
  • tornado 写一个handler
  • 定时把最新的IP合并到allow_ip.con

tornado

安装

1
2
3
4
5
wget https://pypi.python.org/packages/source/t/tornado/tornado-4.2.1.tar.gz
tar zxvf tornado-4.2.1.tar.gz
cd tornado-4.2.1
python setup.py build
sudo python setup.py install

开搞

demos

先试用一下tornado源码里的demos,找到最简单的helloworld,运行

1
python helloworld.py

在另一台机器上访问,总是载入不了网页。于是开始排查

  • 本机上查看端口netstat -tulpn | grep :8888
  • 在本机上curl,可以打开
  • 猜测可能是防火墙的问题,iptables -I INPUT -p TCP --dport 8888 -j ACCEPT
    再次访问,就OK啦

一个输入页面

login.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<form action="{{ request.path }}" method="post">
<div>{{ _("你的IP") }} <input type="text" name="username"/></div>
<!--<div>{{ _("Password") }} <input type="password" name="password"/></div> -->
<div><input type="submit" value="{{ _("输入") }}"/></div>
{% module xsrf_form_html() %}
</form>
</body>
</html>

test.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
def get(self):
#self.write("Hello, world")
items = ["Item 1", "Item 2", "Item 3"]
self.render("temp.html", title="My title", items=items)

# LoginHandler
class LoginHandler(tornado.web.RequestHandler):
def get(self):
# template from login.html
self.render("login.html", title="login")
def post(self):
usr=self.get_argument("username", "")
#pwd=self.get_argument("password", "")
self.write(usr)
#self.write(pwd)

application = tornado.web.Application([
(r"/", MainHandler),

# login时通过LoginHandler处理
(r"/login", LoginHandler),
])

if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.current().start()

运行效果

输入

结果

保存用户的IP到白名单

先写入到一个临时文件,然后定时同步到nginx的配置里include白名单文件allow_ips.conf

写入文件

先实现一个最简单的,不考虑锁啊,共享之类的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
def get(self):
#self.write("Hello, world")
items = ["Item 1", "Item 2", "Item 3"]
self.render("temp.html", title="My title", items=items)

class LoginHandler(tornado.web.RequestHandler):
file_name = "ip.txt"
FILE = None

def get(self):
self.render("login.html", title="login")

def post(self):
usr=self.get_argument("username", "")

# 把用户输入的IP写入到文件
self.WriteIP(usr)
self.write("Your IP have been added to the white list\n"+usr)

# 增加一个writeIP的方法不考虑共享等问题
def WriteIP(self,ip):
self.FILE = open(self.file_name, "w")
self.FILE.writelines(ip)

application = tornado.web.Application([
(r"/", MainHandler),
(r"/login", LoginHandler),
])

if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.current().start()

nginx

下载安装

源码编译

1
2
3
4
wget http://nginx.org/download/nginx-1.9.4.tar.gz
tar zxvf nginx-1.9.4.tar.gz
cd nginx-1.9.4
./configure

提示缺少C编译器,于是yum install gcc
提示缺少pcre library,于是yum -y install pcre-devel
接着又提示缺少zlib。。算了,还是换别的方式吧,不从源码编了

yum安装

1
2
3
wget http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
sudo rpm -ivh nginx-release-centos-7-0.el7.ngx.noarch.rpm
sudo yum install nginx

配置nginx.conf

1
2
3
4
5
6
7
server {
listen 8777;

location / {
proxy_pass http://192.168.151.55:8888/;
}
}
1
2
# 测试配置是否正确
sudo nginx -t -c /etc/nginx/nginx.conf

iptables

我们只是需要一个白名单而已,用nginx是不是太重型化了?
iptables热插拔,即使生效,也支持可信ip,而且用起来比较简单。

导入导出

1
2
3
4
5
# export the rules of iptable
iptables-save > /some/file

# restore
iptables-restore </some/file

即时生效

Is a reboot required after edit/saving linux iptables?

iptables rules take effect immediately.
Changes to iptables take effect immediately when they are run.However, your language of “edit and save” makes me think you are editing a conf file or script of some kind rather than actually running the iptables commands.If you are making your changes in a script, you must make sure that script gets run in order for the changes to take affect.

使用

生产环境的使用

最终还是采用了nginx

  1. 用户注册,将IP保存到数据库
  2. 定时从数据库中取IP,并生成allow_ips.conf
  3. nginx reload -s
1
2
3
4
5
6
7
8
9
10
# nginx 配置
server {
listen 8777;
location / {
include allow_ips.conf
deny all;
errorpage 403 http://register_server:port;
proxy_pass http://192.168.151.55:8888/;
}
}

本博客欢迎转发,但请保留原作者信息
github:codejuan
博客地址:http://blog.decbug.com/