为 Caddy v2 配置访问控制,例如 IP 的黑白名单、路径黑白名单和 basicauth 等。
Nginx 配置
在使用 Nginx 的时候,可以很方便的通过 allow
和deny
设置黑白名单,例如:
白名单:
1
2
3
4
5
6
server {
listen:80;
server_name localhost;
allow 192 .168.1.0/24;
deny all;
}
黑名单:
1
2
3
4
5
server {
listen:80;
server_name localhost;
deny 192 .168.1.0/24;
}
Caddy 配置
到了 Caddy,为了实现对应的目的,去查了一下文档,找到了这两个相关内容:
Request matchers (Caddyfile) — Caddy Documentation
respond (Caddyfile directive) — Caddy Documentation
指定响应的语法是这样的:
1
2
3
4
respond [<matcher>] <status>|<body> [<status>] {
body <text>
close
}
简单来说,就是设定一个 matcher,对符合 matcher 的请求返回 403 状态码就可以了。
对于指定的 IP 进行过滤,使用的是 remote-ip ,语法相当简单:
1
remote_ip 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 123.45.67.89
IP 黑白名单
对于 IP 过滤,组合起来就是:
白名单:
1
2
3
4
5
6
7
8
9
10
11
test.example.com {
@ip_whitelist {
remote_ip 192 .168.1.9 172 .16.0.0/12
}
route @ip_whitelist {
file_server browse
}
respond "Blocked" 403
}
黑名单:
1
2
3
4
5
6
7
8
9
10
11
test.example.com {
@ip_blacklist {
remote_ip 192 .168.1.9 172 .16.0.0/12
}
route @ip_blacklist {
respond "Blocked" 403
}
file_server browse
}
结合多个匹配器
有时候我们只允许指定 IP 访问指定路径,可以加上 Matchers 里的 path 或者 path_regexp。
需要注意的是,在 Caddy 的一个 matcher block 中定义多个 matchers,那么他们是 AND 的关系;在同一个 matcher 中定义多个条件(比如路径或 IP),他们是 OR 的关系。例如:
1
2
3
4
@matcher {
remote_ip 192 .168.1.9
path /test1 /test2
}
效果是:IP 地址为 192.168.1.9
的客户端访问 /test1
/test2
路径时满足该 matcher block。
其他的 matcher 语法可以查看文档 Request matchers (Caddyfile) — Caddy Documentation ,只需要配置好 matcher,并为每个 matcher 指定对应的 route,即可实现各种访问控制。
多个指令的顺序问题
在加入 basicauth 后,遇到了一点小问题:
1
2
3
4
5
6
7
8
9
10
11
12
@ip_blacklist {
remote_ip 192 .168.1.9 172 .16.0.0/12
}
route @ip_blacklist {
respond "Blocked" 403
}
basicauth * {
Bob JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX
}
file_server browse
配置文件像上面一样写,测试发现:当黑名单内的客户端访问时,不是直接返回 403,而是弹出了 basicauth,在 basicauth 通过后才会返回 403。查了文档之后发现,不同指令(Directive)之间是存在优先级的,basicauth
的优先级高于route
,因此被首先执行。
参考文档Directive order ,指令的优先级是这样的:
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
tracing
map
vars
root
header
request_body
redir
# incoming request manipulation
method
rewrite
uri
try_files
# middleware handlers; some wrap responses
basicauth
request_header
encode
push
templates
# special routing & dispatching directives
handle
handle_path
route
# handlers that typically respond to requests
abort
error
respond
metrics
reverse_proxy
php_fastcgi
file_server
acme_server
为了让 basicauth
在黑名单后面执行,我们可以将指令都放到 route
中,这样便不会对指令进行重排序,会按照定义的顺序执行,配置文件应当修改为:
1
2
3
4
5
6
7
8
9
10
11
@ip_blacklist {
remote_ip 192 .168.1.9 172 .16.0.0/12
}
route {
respond @ip_blacklist "Blocked" 403
basicauth * {
BobJDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkDhX
}
file_server browse
}
放到 route
中后要尤其注意,basicauth
要写在提供服务的指令之前。不在 route
中时由于 Caddy 会自动重排序,因此 basicauth
即使在最后也能正确触发验证。而在 route 中 Caddy 会严格按照书写顺序执行指令,因此一定要把 basicauth
放到前面,以免验证失效。