案例
前置需求
总所周知hdfs默认是没有鉴权的操作,而用户通过调用httpfs对hdfs进行操作时,可以随便填写上传用户名,这样对hdfs本身而言存在着较大的风险性。由于没有开启Kerberos安全认证,故需要借助第三方的方式来实现此安全性。 于是就有了通过nginx简单的auth basic认证,强制用户提交的user.name等于认证header的user,也就是$remote_user。
简单实现
upstream hdfs-httpfs {
server xxxxx:21400;
}
server {
listen 80;
server_name hdfs.xx.xx.xxx;
auth_basic auth;
auth_basic_user_file /etc/nginx/htpasswd/hdfs.xxx.xxx.xx.passwd;
location / {
if ( $arg_user.name = "") {
set $args '$args&user.name=$remote_user';
}
if ( $arg_user.name != "$remote_user" ){
return 401;
}
proxy_pass http://hdfs-httpfs/webhdfs/v1/;
}
}
踩坑
这里有个比较坑的点,原本以为通过简单修改 arg_user.name的值就可以实现此需求了,如下
set $arg_user.name $remote_user;
但是发现修改后并不生效,后来才知道除了变量$args可以被修改以外,其对应的子变量值都只能被查看而不能进行修改。
附录
自定义变量与内置预定义变量
自定义变量
可以在sever,http,location等标签中使用set命令(非唯一)声明变量,语法如下
set $变量名 变量值
nginx的内置变量是全局可见的,在不同层级的标签中声明的变量性的可见性规则如下:
- location标签中声明的变量中对这个location块可见
- server标签中声明的变量对server块以及server块中的所有子块可见
- http标签中声明的变量对http块以及http块中的所有子块可见
内置常用变量列表
变量名 | 定义 |
---|---|
$arg_PARAMETER | GET请求中变量名PARAMETER参数的值。 |
$args | 这个变量等于GET请求中的参数。例如,foo=123&bar=blahblah;这个变量可以被修改 |
$content_length | 请求头中的Content-length字段。 |
$content_type | 请求头中的Content-Type字段。 |
$cookie_COOKIE cookie | COOKIE的值。 |
$host | 请求中的主机头(Host)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称(处理请求的server的server_name指令的值)。值为小写,不包含端口。 |
$hostname | 机器名使用 gethostname系统调用的值 |
$http_HEADER | HTTP请求头中的内容,HEADER为HTTP请求中的内容转为小写,-变为_(破折号变为下划线),例如:$http_user_agent ( User-Agent的值 ) |
$sent_http_HEADER | HTTP响应头中的内容,HEADER为HTTP响应中的内容转为小写,-变为_(破折号变为下划线),例如: $sent_http_cache_control( Cache-Control的值 ) |
$is_args | 如果$args设置,值为"?",否则为""。 |
$limit_rate | 这个变量可以限制连接速率。 |
$query_string | 与$args相同。 |
$remote_addr | 客户端的IP地址。 |
$remote_port | 客户端的端口。 |
$remote_user | 已经经过Auth Basic Module验证的用户名。 |
$request_filename | 当前连接请求的文件路径,由root或alias指令与URI请求生成。 |
$request_uri | 这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI。 |
$scheme | 所用的协议,比如http或者是https,比如rewrite ^(.+)scheme://example.com$1 redirect; |
$server_addr | 服务器地址,在完成一次系统调用后可以确定这个值,如果要绕开系统调用,则必须在listen中指定地址并且使用bind参数。 |
$server_name | 服务器名称。 |
$server_port | 请求到达服务器的端口号。 |
$server_protocol | 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。 |
$uri | 请求中的当前URI(不带请求参数,参数位于args),不同于浏览器传递的args,不同于浏览器传递的request_uri的值,它可以通过内部重定向,或者使用index指令进行修改。不包括协议和主机名,例如/foo/bar.html |