Skip to content

Commit da3f2fd

Browse files
committed
Add an initial POC version that only works with CIDR whitelists
1 parent 3cbb27f commit da3f2fd

9 files changed

+329
-14
lines changed

README.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
1-
# lua-resty-whitelist
1+
# Lua Resty Whitelist
22

3-
Lua NGINX dynamic allowlist based on ngx_lua module and OpenResty
3+
Dynamic whitelist in Lua based on ngx_lua for NGINX and OpenResty
44

5-
:warning: under construction
5+
:warning: Under construction
6+
7+
## Publish to LuaRocks
8+
9+
```sh
10+
# Upload to LuaRocks
11+
luarocks upload lua-resty-whitelist-*.rockspec
12+
13+
# Create a source rock
14+
luarocks pack lua-resty-whitelist-*.rockspec
15+
```
16+
17+
## Running the demo
18+
19+
```sh
20+
cd demo
21+
docker-compose up # visit openresty at localhost:80
22+
# Run a local server to serve the IP lists to simulate a dynamic IP whitelist
23+
# Depending on the configuration, the server is genereally accessible inside the openrest docker container at 172.18.0.1
24+
python -m http.server 9001
25+
# Edit the IP list files to experiment with the configuration
26+
```

demo/Dockerfile.openresty

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
FROM openresty/openresty:latest
2+
3+
RUN apt-get -y update && apt-get -y install wget make unzip && \
4+
wget http://luarocks.org/releases/luarocks-2.0.13.tar.gz && \
5+
tar -xzvf luarocks-2.0.13.tar.gz && \
6+
cd luarocks-2.0.13/ && \
7+
./configure --prefix=/usr/local/openresty/luajit \
8+
--with-lua=/usr/local/openresty/luajit/ \
9+
--lua-suffix=jit \
10+
--with-lua-include=/usr/local/openresty/luajit/include/luajit-2.1 && \
11+
make && make install
12+
13+
RUN luarocks install lua-resty-iputils
14+
RUN luarocks install lua-resty-http

demo/default.conf

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
lua_package_path "/usr/local/lib/lua/?.lua;;";
2+
3+
server {
4+
listen 80;
5+
server_name localhost;
6+
7+
resolver 1.1.1.1 ipv6=off;
8+
9+
location / {
10+
lua_code_cache on;
11+
access_by_lua_block {
12+
local whitelist = require "resty.whitelist"
13+
local url = "http://172.18.0.1:9001/list-cloudfront-ips.json"
14+
whitelist.new(url)
15+
}
16+
}
17+
}

demo/docker-compose.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
version: '3.7'
2+
3+
services:
4+
openresty:
5+
restart: always
6+
build:
7+
context: .
8+
dockerfile: Dockerfile.openresty
9+
container_name: openresty
10+
volumes:
11+
- "./default.conf:/etc/nginx/conf.d/default.conf:ro"
12+
- "../lib/resty/whitelist.lua:/usr/local/lib/lua/resty/whitelist.lua:ro"
13+
ports:
14+
- "80:80"
15+
expose:
16+
- "80"

demo/list-cloudflare-ips.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
173.245.48.0/20
2+
103.21.244.0/22
3+
103.22.200.0/22
4+
103.31.4.0/22
5+
141.101.64.0/18
6+
108.162.192.0/18
7+
190.93.240.0/20
8+
188.114.96.0/20
9+
197.234.240.0/22
10+
198.41.128.0/17
11+
162.158.0.0/15
12+
104.16.0.0/13
13+
104.24.0.0/14
14+
172.64.0.0/13
15+
131.0.72.0/22

demo/list-cloudfront-ips.json

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
{
2+
"CLOUDFRONT_GLOBAL_IP_LIST": [
3+
"120.52.22.96/27",
4+
"205.251.249.0/24",
5+
"180.163.57.128/26",
6+
"204.246.168.0/22",
7+
"18.160.0.0/15",
8+
"205.251.252.0/23",
9+
"54.192.0.0/16",
10+
"204.246.173.0/24",
11+
"54.230.200.0/21",
12+
"120.253.240.192/26",
13+
"116.129.226.128/26",
14+
"130.176.0.0/17",
15+
"108.156.0.0/14",
16+
"99.86.0.0/16",
17+
"205.251.200.0/21",
18+
"223.71.71.128/25",
19+
"13.32.0.0/15",
20+
"120.253.245.128/26",
21+
"13.224.0.0/14",
22+
"70.132.0.0/18",
23+
"15.158.0.0/16",
24+
"13.249.0.0/16",
25+
"18.238.0.0/15",
26+
"18.244.0.0/15",
27+
"205.251.208.0/20",
28+
"65.9.128.0/18",
29+
"130.176.128.0/18",
30+
"58.254.138.0/25",
31+
"54.230.208.0/20",
32+
"116.129.226.0/25",
33+
"52.222.128.0/17",
34+
"18.164.0.0/15",
35+
"64.252.128.0/18",
36+
"205.251.254.0/24",
37+
"54.230.224.0/19",
38+
"71.152.0.0/17",
39+
"216.137.32.0/19",
40+
"204.246.172.0/24",
41+
"18.172.0.0/15",
42+
"120.52.39.128/27",
43+
"118.193.97.64/26",
44+
"223.71.71.96/27",
45+
"18.154.0.0/15",
46+
"54.240.128.0/18",
47+
"205.251.250.0/23",
48+
"180.163.57.0/25",
49+
"52.46.0.0/18",
50+
"223.71.11.0/27",
51+
"52.82.128.0/19",
52+
"54.230.0.0/17",
53+
"54.230.128.0/18",
54+
"54.239.128.0/18",
55+
"130.176.224.0/20",
56+
"36.103.232.128/26",
57+
"52.84.0.0/15",
58+
"143.204.0.0/16",
59+
"144.220.0.0/16",
60+
"120.52.153.192/26",
61+
"119.147.182.0/25",
62+
"120.232.236.0/25",
63+
"54.182.0.0/16",
64+
"58.254.138.128/26",
65+
"120.253.245.192/27",
66+
"54.239.192.0/19",
67+
"18.68.0.0/16",
68+
"18.64.0.0/14",
69+
"120.52.12.64/26",
70+
"99.84.0.0/16",
71+
"130.176.192.0/19",
72+
"52.124.128.0/17",
73+
"204.246.164.0/22",
74+
"13.35.0.0/16",
75+
"204.246.174.0/23",
76+
"36.103.232.0/25",
77+
"119.147.182.128/26",
78+
"118.193.97.128/25",
79+
"120.232.236.128/26",
80+
"204.246.176.0/20",
81+
"65.8.0.0/16",
82+
"65.9.0.0/17",
83+
"108.138.0.0/15",
84+
"120.253.241.160/27",
85+
"64.252.64.0/18"
86+
],
87+
"CLOUDFRONT_REGIONAL_EDGE_IP_LIST": [
88+
"13.113.196.64/26",
89+
"13.113.203.0/24",
90+
"52.199.127.192/26",
91+
"13.124.199.0/24",
92+
"3.35.130.128/25",
93+
"52.78.247.128/26",
94+
"13.233.177.192/26",
95+
"15.207.13.128/25",
96+
"15.207.213.128/25",
97+
"52.66.194.128/26",
98+
"13.228.69.0/24",
99+
"52.220.191.0/26",
100+
"13.210.67.128/26",
101+
"13.54.63.128/26",
102+
"99.79.169.0/24",
103+
"18.192.142.0/23",
104+
"35.158.136.0/24",
105+
"52.57.254.0/24",
106+
"13.48.32.0/24",
107+
"18.200.212.0/23",
108+
"52.212.248.0/26",
109+
"3.10.17.128/25",
110+
"3.11.53.0/24",
111+
"52.56.127.0/25",
112+
"15.188.184.0/24",
113+
"52.47.139.0/24",
114+
"18.229.220.192/26",
115+
"54.233.255.128/26",
116+
"3.231.2.0/25",
117+
"3.234.232.224/27",
118+
"3.236.169.192/26",
119+
"3.236.48.0/23",
120+
"34.195.252.0/24",
121+
"34.226.14.0/24",
122+
"13.59.250.0/26",
123+
"18.216.170.128/25",
124+
"3.128.93.0/24",
125+
"3.134.215.0/24",
126+
"52.15.127.128/26",
127+
"3.101.158.0/23",
128+
"52.52.191.128/26",
129+
"34.216.51.0/25",
130+
"34.223.12.224/27",
131+
"34.223.80.192/26",
132+
"35.162.63.192/26",
133+
"35.167.191.128/26",
134+
"44.227.178.0/24",
135+
"44.234.108.128/25",
136+
"44.234.90.252/30"
137+
]
138+
}

dist.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=lua-resty-whitelist
2-
abstract=Lua NGINX dynamic allowlist based on ngx_lua module and OpenResty
2+
abstract=Dynamic whitelist in Lua based on ngx_lua for NGINX and OpenResty
33
author=El Mahdi Sidate
44
is_original=yes
55
license=mit

lib/resty/whitelist.lua

Lines changed: 99 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,102 @@
1-
local _M = {
2-
_VERSION = '0.0.1'
3-
}
1+
local iputils = require "resty.iputils"
2+
local http = require "resty.http"
3+
4+
local ngx = ngx
45

5-
local mt = {
6-
__index = _M
6+
local whitelist_m = {
7+
_VERSION = '0.1-0'
78
}
89

9-
return _M
10+
whitelist_m.__index = whitelist_m
11+
12+
local validation_message =
13+
"[lua-resty-whitelist] whitelist URL must be either a non-empty string or table of non-empty strings."
14+
15+
local function istable(t)
16+
return type(t) == 'table'
17+
end
18+
19+
local function is_empty(s)
20+
return s == nil or s == ''
21+
end
22+
23+
local function fetch_whitelist(url)
24+
iputils.enable_lrucache()
25+
26+
local httpc = http.new()
27+
local res, err = httpc:request_uri(url, {
28+
method = "GET",
29+
ssl_verify = false,
30+
headers = {
31+
["Content-Type"] = "application/x-www-form-urlencoded"
32+
}
33+
})
34+
35+
local status = res and res.status or nil
36+
local body = res and res.body or nil
37+
38+
if (not res) or (not body) or (status and (status < 200 or status >= 300)) or err then
39+
ngx.log(ngx.ERR, "[lua-resty-whitelist] failed to fetch whitelist => url: " .. url .. ", status: " .. status ..
40+
", body: " .. body, err)
41+
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
42+
end
43+
44+
local whitelist = body .. " "
45+
local whitelist_array = {}
46+
47+
-- Extract CIRDs
48+
for ip in string.gmatch(whitelist, "((%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)/(%d%d?))") do
49+
table.insert(whitelist_array, ip)
50+
end
51+
52+
-- local whitelist_concat = table.concat(whitelist_array, ", ")
53+
-- ngx.log(ngx.ERR, "[lua-resty-whitelist] CIRDs: " .. whitelist_concat)
54+
55+
-- TODO: Extract normal IPs as well
56+
57+
-- -- Extract IPs
58+
-- for ip in string.gmatch(whitelist, "((%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)$)") do
59+
-- table.insert(whitelist_array, string.sub(ip, 1, -2))
60+
-- end
61+
62+
-- whitelist_concat = table.concat(whitelist_array, ", ")
63+
-- ngx.log(ngx.ERR, "[lua-resty-whitelist] whitelist_concat: " .. whitelist_concat)
64+
65+
return whitelist_array
66+
end
67+
68+
local function match_ip_whitelist(ip, whitelist_array)
69+
local whitelist = iputils.parse_cidrs(whitelist_array)
70+
if not iputils.ip_in_cidrs(ip, whitelist) then
71+
return ngx.exit(ngx.HTTP_FORBIDDEN)
72+
end
73+
end
74+
75+
function whitelist_m.new(url)
76+
77+
if is_empty(url) then
78+
ngx.log(ngx.ERR, validation_message)
79+
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
80+
end
81+
82+
local whitelist_array = {}
83+
84+
if istable(url) then
85+
for _, u in ipairs(url) do
86+
if is_empty(u) then
87+
ngx.log(ngx.ERR, validation_message)
88+
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
89+
end
90+
91+
for _, v in ipairs(fetch_whitelist(u)) do
92+
table.insert(whitelist_array, v)
93+
end
94+
end
95+
else
96+
whitelist_array = fetch_whitelist(url)
97+
end
98+
99+
match_ip_whitelist(ngx.var.remote_addr, whitelist_array)
100+
end
101+
102+
return whitelist_m

lua-resty-whitelist-0.0.1.rockspec renamed to lua-resty-whitelist-0.1-0.rockspec

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
package = "lua-resty-whitelist"
2-
version = "0.0.0"
2+
version = "0.1-0"
33

44
source = {
55
url = "git+https://github.com/esidate/lua-resty-whitelist",
6-
tag = "v0.0.0",
6+
tag = "v0.1-0",
77
}
88

99
description = {
10-
summary = "Lua NGINX dynamic allowlist based on ngx_lua module and OpenResty",
10+
summary = "Dynamic whitelist in Lua based on ngx_lua for NGINX and OpenResty",
1111
license = "MIT",
1212
}
1313

1414
dependencies = {
1515
"lua >= 5.1",
16-
"resty.iputils => 0.3.0"
16+
"resty.iputils >= 0.3",
17+
"resty.http >= 0.15",
1718
}
1819

1920
build = {

0 commit comments

Comments
 (0)