OpenResty(nginx-luaフレームワーク)とRedisでアクセス制限システムの試作


この記事は リクルートライフスタイルアドベントカレンダー2016 の11日目です。
ホットペッパービューティーでゆるふわエンジニアをしています。しゃぜです。
割りと最近入社したばっかりです。

さて、今回は前から試そうと思って暇がなくてサボっていた、OpenRestyで少し遊んでみました。

はじめに

  • OpenRestyとredisを利用して、簡易的なアクセス制御システムを試作してみます。
  • 同じIPアドレスから一定回数のアクセスが合った場合にBANするというものです。
    • 今回は雑に、30秒以内に10アクセス以上あった場合「アクセスしすぎですよ」というメッセージを表示してみます。
    • お仕事の場合だと、404を返すとか、そういう感じになるかとは思います。
  • 今回は同じEC2インスタンス(ubuntu)上で、nginxとredis-serverを動かしています。
    • そのEC2にEIPを付与して、そのまま外からアクセスできるような状態です。

redisの導入と起動

sudo apt-get install redis-server -y
sudo service redis-server start

Ubuntu 16.04.1 LTS に OpenRestyの導入(nginx含む)

sudo apt-get install libreadline-dev libncurses5-dev libpcre3-dev libssl-dev perl make wget gcc -y
cd /usr/local
wget https://openresty.org/download/openresty-1.11.2.2.tar.gz
tar xvfz openresty-1.11.2.2.tar.gz
cd openresty-1.11.2.2
./configure --prefix=/usr/local
make
sudo make install

nginxの操作

  • 起動
    • sudo /usr/local/nginx/sbin/nginx
  • 再読込
    • sudo /usr/local/nginx/sbin/nginx -s reload
  • 停止
    • sudo /usr/local/nginx/sbin/nginx -s stop

nginxの設定

  • location /のところを、sample.luaを見るようにしています。

/usr/local/nginx/conf/nginx.conf

worker_processes  1;

events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;

        location / {
                default_type 'text/html';
                content_by_lua_file /usr/local/luafiles/sample.lua;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

    }

}

luaスクリプト配置用のディレクトリをつくります。

sudo mkdir /usr/local/luafiles

アクセス制御用のlua scriptの実装

では、実際に、lua scriptを配置してみます。
実装イメージはこんな感じです。
/usr/local/luafiles/sample.lua

local redis = require "resty.redis"
local redisObject = redis:new()
redisObject:set_timeout(3000)

local ok, err = redisObject:connect("127.0.0.1",6379)
if not ok then
  ngx.say("connection error",err)
  return
end

redisObject:incr(ngx.var.remote_addr)
redisObject:expire(ngx.var.remote_addr,30)

local counter = redisObject:get(ngx.var.remote_addr)
if tonumber(counter) > 10 then
  ngx.say("アクセスしすぎですよ")
else
  ngx.say("ようこそ")
end

動作

nginxに対して、同一IPアドレスから、30秒以内に10回アクセスすると、「アクセスしすぎですよ」というメッセージがでるようになりました。

まとめ

  • 今回は手抜きでパッケージ入れましたが、お仕事で使う時は、nginxや、redisの最新版を使うようにしたいですね。
  • luaのエラーハンドリングなどは雑なので、あくまでもサンプルということでご容赦を。
    • redisのexpireの仕組みからすると厳密な30sになっていないとかいろいろありますが。。。
  • お仕事で使う際はいろいろ要件とかありそうですが、導入の敷居は低いなぁと感じました。気軽に活用できるのではないでしょうか。

ではではーε≡≡ヘ( ´Д`)ノ