Nginxのmapモジュールを利用して特定パスのみBasic認証を有効化する

tl;dr

えのかわです。Nginx で特定パスのみ Basic 認証を有効化したい場面に遭遇したので備忘録として残します。前提として、Nginx の Backend には php-fpm が存在するものとします。

なぜmapか

ngx_http_map_module を利用することで、シンプルに条件を記述することが可能です。パス毎に location を記載するのも一つの手段ですが、期待する挙動とならずに苦戦してしまい map モジュールを使うことにしました。(おい

nginx.org

nginx.confにmapを定義

まずは /etc/nginx/nginx.conf に map を定義します。今回は /sample/ もしくは /admin/ 配下にリクエストがあった際に Basic 認証を有効化させるものとします。

map $request_uri $auth {
  default off;
  ~^/sample/.* "Basic Authentication";
  ~^/admin/.* "Basic Authentication";
}

~正規表現の利用を宣言しています。前述のドキュメントにも下記の様に正規表現の記載があります。

A regular expression should either start from the “~” symbol for a case-sensitive matching, or from the “~*” symbols (1.0.4) for case-insensitive matching. A regular expression can contain named and positional captures that can later be used in other directives along with the resulting variable.

ハマったのが、map を定義する conf です。/etc/nginx/conf.d/ 配下の default.conf に定義しようとすると、下記の様にエラーが発生しました。

2019/11/25 15:01:35 [emerg] 1#1: "map" directive is not allowed here in /etc/nginx/conf.d/default.conf:8
nginx: [emerg] "map" directive is not allowed here in /etc/nginx/conf.d/default.conf:8

こちらも前述のドキュメントに丁寧に Directives が記載されていますね。nginx.conf というよりは、http Directive に記載しましょう。が正しいですね。ちゃんとドキュメントを読みましょう。はい。(スミマセン

Syntax:  map string $variable { ... }
Default:    —
Context:    http

default.confauth_basicを定義

下記の様に Basic 認証の設定を記載します。

location ~ \.php$ {
    root           /var/www/html/public;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    include        fastcgi_params;

+   auth_basic $auth;
+   auth_basic_user_file /etc/nginx/.htpasswd;
}

キモは auth_basic の値が $auth となっている点です。nginx.conf で定義した map の値を参照して振る舞います。ngx_http_auth_basic_module の仕様上、auth_basic の値が off の場合は Basic 認証をキャンセルします。先ほど定義した map には default off; と記載されているため、/sample/ もしくは /admin/ 配下へのリクエストがあった場合にのみ Basic 認証が有効化され、それ以外のパスへリクエストがあった場合は Basic 認証をキャンセル(off)します。

nginx.org

Enables validation of user name and password using the “HTTP Basic Authentication” protocol. The specified parameter is used as a realm. Parameter value can contain variables (1.3.10, 1.2.7). The special value off allows cancelling the effect of the auth_basic directive inherited from the previous configuration level.

余談

location Context で if を利用することが可能ですが、Nginx としては推奨していないようです。Nginx 公式が If Is Evil (if Directive は悪)と謳っていることから、信憑性は高いでしょう。Qiita やその他ブログを漁ったところ、map ではなく if で判定している内容もちらほら見られたので、気をつけようと思いました。

www.nginx.com

まとめ

ちゃんと公式ドキュメントは読みましょう。(戒め