OpenRestyとは
OpenRestyとは、NginxをベースにLuaJITを搭載したWebサーバーです。Luaのライブラリなどが利用できます。
環境
- Ubuntu 20.04
- Docker version 20.10.14
- Docker Compose version v2.4.1
- nginx version: openresty/1.21.4.1
なぜNginxを使わなかったのか?
今回やりたいことは、Basic認証と認可を実装することです。Nginx単体でも認証は簡単に実装できますが、認可の仕組みは意外と骨が折れます。
OpenRestyを利用することで、LuaからNginxの変数にアクセスできます。ログインしてきたユーザー名などを取得できれば、Luaスクリプト内の認可ロジックでそのユーザーを許可するかどうか判定できるようになります。
検証ソース
ディレクトリ構成
ソースの配置は以下を想定しています。
.
├── docker-compose.yaml
└── nginx
├── conf.d
│ └── default.conf
├── lua
│ └── auth.lua
└── nginx.conf
Docker Compose
version: "3"
services:
openresty:
image: openresty/openresty:latest
hostname: openresty
container_name: openresty
volumes:
- ./nginx/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf
- ./nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf
- ./nginx/lua/auth.lua:/etc/nginx/lua/auth.lua
- ./nginx/.htpasswd:/etc/nginx/.htpasswd
ports:
- "80:80"
restart: always
OpenRestyの設定
nginx.conf
はデフォルトのまま変更していません。
# nginx.conf -- docker-openresty
#
# This file is installed to:
# `/usr/local/openresty/nginx/conf/nginx.conf`
# and is the file loaded by nginx at startup,
# unless the user specifies otherwise.
#
# It tracks the upstream OpenResty's `nginx.conf`, but removes the `server`
# section and adds this directive:
# `include /etc/nginx/conf.d/*.conf;`
#
# The `docker-openresty` file `nginx.vh.default.conf` is copied to
# `/etc/nginx/conf.d/default.conf`. It contains the `server section
# of the upstream `nginx.conf`.
#
# See https://github.com/openresty/docker-openresty/blob/master/README.md#nginx-config-files
#
#user nobody;
#worker_processes 1;
# Enables the use of JIT for regular expressions to speed-up their processing.
pcre_jit on;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
# Enables or disables the use of underscores in client request header fields.
# When the use of underscores is disabled, request header fields whose names contain underscores are marked as invalid and become subject to the ignore_invalid_headers directive.
# underscores_in_headers off;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
# Log in JSON Format
# log_format nginxlog_json escape=json '{ "timestamp": "$time_iso8601", '
# '"remote_addr": "$remote_addr", '
# '"body_bytes_sent": $body_bytes_sent, '
# '"request_time": $request_time, '
# '"response_status": $status, '
# '"request": "$request", '
# '"request_method": "$request_method", '
# '"host": "$host",'
# '"upstream_addr": "$upstream_addr",'
# '"http_x_forwarded_for": "$http_x_forwarded_for",'
# '"http_referrer": "$http_referer", '
# '"http_user_agent": "$http_user_agent", '
# '"http_version": "$server_protocol", '
# '"nginx_access": true }';
# access_log /dev/stdout nginxlog_json;
# See Move default writable paths to a dedicated directory (#119)
# https://github.com/openresty/docker-openresty/issues/119
client_body_temp_path /var/run/openresty/nginx-client-body;
proxy_temp_path /var/run/openresty/nginx-proxy;
fastcgi_temp_path /var/run/openresty/nginx-fastcgi;
uwsgi_temp_path /var/run/openresty/nginx-uwsgi;
scgi_temp_path /var/run/openresty/nginx-scgi;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
# Don't reveal OpenResty version to clients.
# server_tokens off;
}
基本認証の設定とluaスクリプトの設定を追記しています。
# nginx.vh.default.conf -- docker-openresty
#
# This file is installed to:
# `/etc/nginx/conf.d/default.conf`
#
# It tracks the `server` section of the upstream OpenResty's `nginx.conf`.
#
# This config (and any other configs in `etc/nginx/conf.d/`) is loaded by
# default by the `include` directive in `/usr/local/openresty/nginx/conf/nginx.conf`.
#
# See https://github.com/openresty/docker-openresty/blob/master/README.md#nginx-config-files
#
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/local/openresty/nginx/html;
index index.html index.htm;
+ auth_basic "basic auth";
+ auth_basic_user_file /etc/nginx/.htpasswd;
+ access_by_lua_file /etc/nginx/lua/auth.lua;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/openresty/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root /usr/local/openresty/nginx/html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
以下が基本認証の設定です。コンテナ内の/etc/nginx/.htpasswd
にユーザーとパスワードの情報を持たせています。
auth_basic "basic auth";
auth_basic_user_file /etc/nginx/.htpasswd;
今回はadmin
とtest
の2つユーザーを用意します。パスワードはそれぞれ、admin
、test
としています。
admin:$apr1$83K7MhNj$OTxCQTTH8eCkfLY94DdG41
test:$apr1$0jX4sM1.$wgnHDKX3u2dyALc7.uEYF/
ちなみにパスワードの生成するときは以下のコマンドを実行します。
こちらの記事を参考にしました。
htpasswd
コマンドの-c
オプションは、新規にファイルを作成するオプションであるため、2つ目以降のユーザーを保存したい場合は-c
オプションなしで実行すると追記になるようです。
htpasswd -c ./nginx/.htpasswd admin
htpasswd ./nginx/.htpasswd test
htpasswd
コマンドが無い場合は、以下のようにインストールします。
apt-get -y install apache2-utils
Luaスクリプト(認可用)
default.conf
内の以下の設定は、認可用のLuaスクリプトを定義しています。
access_by_lua_file /etc/nginx/lua/auth.lua;
-- remote user名を取得
local remote_user = ngx.var.remote_user
if remote_user ~= "admin" then
-- adminユーザーでなければ403
ngx.header.content_type = "text/plain"
ngx.log(ngx.STDERR, remote_user.." にはアクセス権がありません")
ngx.status = ngx.HTTP_FORBIDDEN
return ngx.exit(403)
end
-
ngx.var.remote_user
- ngx.var.XXXでNginxの変数にアクセスできます。
remote_user
にはユーザー名が入っています。
- ngx.var.XXXでNginxの変数にアクセスできます。
if分以降は、remote_user
がadmin
ユーザーでなければ403でアクセスできないようにしています。今回のケースだと、admin
ユーザーはOpenRestyのデフォルトページにアクセスできるが、test
ユーザーはアクセスできない状況を作っています。
コンテナ起動
docker-compose up -d
アクセス確認
admin
ユーザーでログインする場合
OpenRestyのデフォルトページが表示されます。
test
ユーザーでログインする場合
403が表示されます。
OpenRestyのログを確認
docker logs openresty
test
ユーザーが403になっていることが確認できます。
2023/03/19 09:08:50 [] 7#7: *2 [lua] auth.lua:7: test にはアクセス権がありません, client: 172.24.0.1, server: localhost, request: "GET / HTTP/1.1", host: "localhost"
172.24.0.1 - test [19/Mar/2023:09:08:50 +0000] "GET / HTTP/1.1" 403 561 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.44"
OpenRestyでよく使うコマンド
設定ファイルが有効かチェック(-t
)
docker exec -it openresty bash -c 'openresty -t'
実行結果の例。
nginx: the configuration file /usr/local/openresty/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/openresty/nginx/conf/nginx.conf test is successful
OpenRestyのリロード(-s reload
)
docker exec -it openresty bash -c 'openresty -s reload'
実行結果の例。
2023/03/19 09:16:43 [notice] 15#15: signal process started
まとめ
OpenRestyを利用することで、Basic認証に認可の仕組みを実装することができました。Luaスクリプトをもう少し工夫すれば複雑な認証・認可の仕組みを実装できそうです。
以下の記事で、Ldap認証で同様のことを試してみました。