关于NGINX实现IP校验结合二选一认证方式的配置困境咨询
老哥,看你这配置里的注释,明显是踩了Nginx satisfy any 和 access阶段规则的坑了对吧?现在只要请求来自xxxxx/24这个IP段,直接就绕开了所有Basic Auth和Authentik的认证逻辑,完全没达到你想要的「IP校验和认证二选一」的效果,我来给你拆解下问题,再给你对应需求的解决方案。
问题根源拆解
你现在的配置里,allow xxxxx/24; deny all;属于Nginx的access阶段规则,而auth_basic、auth_request这些认证逻辑属于auth阶段规则。satisfy any的运行逻辑是:只要access阶段的规则通过,就直接跳过后面所有的auth阶段检查。所以来自信任IP段的请求,在access阶段就被allow规则直接放行,后面的Basic Auth、Authentik认证根本不会触发,这就是你现在困境的核心原因。
先明确你的核心需求
不同的需求对应不同的配置方案,你得先搞清楚你要的是哪种效果:
- 情况1:信任IP直接放行,非信任IP必须走认证(Basic Auth或Authentik)
- 情况2:不管IP是否在信任段,用户都可以选择「用IP放行」或者「用认证放行」(两种方式并行,满足其一即可)
针对情况1的配置方案(信任IP免认证,非信任IP强制认证)
这种需求下,我们可以用geo模块定义一个信任IP标识变量,然后根据这个变量来控制认证规则是否生效:
# 记得把这段放到http块里,全局生效 geo $trusted_ip { default 0; # 默认是0,表示非信任IP xxxxx/24 1; # 把你的信任IP段填在这里,匹配到的话变量值为1 } server { # 这里放你的server块原有配置,比如监听端口、域名等 location / { proxy_pass $forward_auth_target; # 只有非信任IP才触发认证逻辑 if ($trusted_ip = 0) { auth_basic "内部系统请认证"; # 这里替换成你的认证提示语 auth_basic_user_file "/etc/nginx/basic_auth/$forward_auth_bypass"; auth_request /outpost.goauthentik.io/auth/nginx; error_page 401 = @goauthentik_proxy_signin; } # 以下保持你原有的Authentik头部传递配置,不用改 auth_request_set $auth_cookie $upstream_http_set_cookie; add_header Set-Cookie $auth_cookie; auth_request_set $authentik_username $upstream_http_x_authentik_username; proxy_set_header X-authentik-username $authentik_username; auth_request_set $authentik_groups $upstream_http_x_authentik_groups; proxy_set_header X-authentik-groups $authentik_groups; auth_request_set $authentik_email $upstream_http_x_authentik_email; proxy_set_header X-authentik-email $authentik_email; # 把你没写完的auth_request相关配置补在这里就行 } }
这个方案逻辑很直白:信任IP直接跳过所有认证,非信任IP必须走Basic Auth或Authentik认证才能访问。
针对情况2的配置方案(IP校验和认证二选一,两种方式都可用)
如果想要不管IP是否信任,用户都可以自主选择用IP放行或者用认证放行,那得把IP校验的逻辑也放到auth阶段,避免access阶段的规则直接跳过认证。我们可以写一个内部的专用location来做IP校验,然后用satisfy any把IP校验、Basic Auth、Authentik认证这几个规则绑定起来:
server { # 这里放你的server块原有配置,比如监听端口、域名等 # 内部专用location,用来做IP校验,注意这个location只能被Nginx内部调用 location /_check_trusted_ip { internal; access_by_lua_block { # 这里替换成你的信任IP段正则,比如"^192.168.1.0/24$" if ngx.var.remote_addr:match("^xxxxx/24$") then ngx.exit(200) # IP合法,返回200表示校验通过 else ngx.exit(403) # IP不合法,返回403 end } } location / { proxy_pass $forward_auth_target; satisfy any; # 满足以下任一条件即可放行 # 条件1:通过IP校验 auth_request /_check_trusted_ip; # 条件2:通过Basic Auth auth_basic "内部系统请认证"; auth_basic_user_file "/etc/nginx/basic_auth/$forward_auth_bypass"; # 条件3:通过Authentik认证 auth_request /outpost.goauthentik.io/auth/nginx; # 不管是IP校验失败还是认证失败,都跳转到登录页 error_page 401 403 = @goauthentik_proxy_signin; # 以下保持你原有的Authentik头部传递配置,不用改 auth_request_set $auth_cookie $upstream_http_set_cookie; add_header Set-Cookie $auth_cookie; auth_request_set $authentik_username $upstream_http_x_authentik_username; proxy_set_header X-authentik-username $authentik_username; auth_request_set $authentik_groups $upstream_http_x_authentik_groups; proxy_set_header X-authentik-groups $authentik_groups; auth_request_set $authentik_email $upstream_http_x_authentik_email; proxy_set_header X-authentik-email $authentik_email; # 把你没写完的auth_request相关配置补在这里就行 } }
这个方案里,satisfy any会同时检查三个条件,只要满足其中一个(IP信任、Basic Auth通过、Authentik认证通过)就会放行请求,完美实现了「二选一/三选一」的认证效果。
备注:内容来源于stack exchange,提问作者user1955545




