はじめに
以下の記事でOpenResryとLuaを用いて、Basic認証と認可を実装しました。
今回の記事では、応用してLdap認証をできるようにしてみます。
ngx auth mod
NginxでLdap認証をするためのツールとして、
を利用します。
IIJがGithubに公開しているものです。公開の経緯などは以下に分かりやすくまとめられています。
OpenLDAP
OpenLDAP ソフトウェアは、 Lightweight Directory Access Protocolのオープン ソース 実装です 。
引用:OpenLDAP
ディレクトリサービスへアクセスるためのLdapプロトコルの機能を実装しています。
Dockerコンテナで簡単に構築ができるため採用しました。イメージは以下を利用します。
ソース
構築方法などはGithubのREADMEに書いています。必要なソースは以下からクローンして利用してください。
セットアップ
# ソースクローン
git clone https://github.com/v1tam1nb2/openresty-ldap-auth.git
# ディレクトリ移動
cd openresty-ldap-auth
# ビルド
docker-compose build
# コンテナ起動
docker-compose up -d
# テストユーザー投入(test001~test005)
docker exec ldap-server ldapadd -x -D "cn=admin,dc=my-company,dc=com" -w admin -f /openldap/testuser.ldif -ZZ
アクセス確認
-
http://localhost:8080
- phpLDAPadminにアクセスできます。ブラウザからLdapのユーザー追加などができるサービスです
以下の情報でログインできます。
Login DN: cn=admin,dc=my-company,dc=com
Password: admin
-
http://localhost
- OpenRestyのデフォルトページにアクセスします。認証を問われます。
test001ユーザーのパスワードはtest001というように、test001~test005の5つのテストユーザーを投入しています。
Luaの認可スクリプトでtest001ユーザーのみアクセスを許可しています。
ngx auth modをコンテナで利用する方法
Ubuntu 20.04のベースイメージにGo言語をインストールして、ngx_auth_modをビルドしました。
Go言語のベースイメージを使っても良かったかもしれません。
FROM ubuntu:20.04
ARG GO_VERSION="1.20.2"
ENV DEBIAN_FRONTEND="noninteractive"
# 最低限のコマンドインストール
# golangのセットアップ
RUN apt-get update && apt-get upgrade -y && \
apt-get install -y wget curl vim openssl git zip jq gettext-base && \
# クリーニング
rm -rf /root/.cache && rm -rf /tmp/*\
apt-get autoremove && apt-get autoclean && apt-get clean && rm -fr /var/lib/apt/lists/*
# golang install
RUN wget https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz && \
tar -xzf go${GO_VERSION}.linux-amd64.tar.gz -C /usr/local/ && \
echo 'export PATH=$PATH:/usr/local/go/bin' >> /root/.profile && \
rm go${GO_VERSION}.linux-amd64.tar.gz && \
rm -rf /root/.cache && rm -rf /tmp/*
# nginx auth mod build
RUN cd /usr/local && \
git clone https://github.com/iij/ngx_auth_mod.git -b master --depth 1 && \
. /root/.profile && \
cd ngx_auth_mod && ./build.sh && \
mv bin/* /usr/local/bin/
COPY ./src/ngx_auth_mod/auth-ldap.conf /ngx_auth_mod/auth-ldap.conf
ENV DEBIAN_FRONTEND=""
# コンテナ起動時の実行コマンド設定
ENTRYPOINT [ "/usr/local/bin/ngx_ldap_auth","/ngx_auth_mod/auth-ldap.conf"]
設定は以下を参考にしました。
コンテナで利用する際の注意点として、socket_path
のIPを127.0.0.1
ではなく、0.0.0.0
にする必要がありました。今回はコンテナとして利用するので、コンテナ内で127.0.0.1
を指定してもコンテナの外からアクセスできません。
socket_type = "tcp"
socket_path = "0.0.0.0:9200"
#cache_seconds = 0
#use_etag = true
auth_realm = "TEST Authentication"
host_url = "ldaps://ldap-server"
start_tls = 0
skip_cert_verify = 1
# root_ca_files = [
# "/etc/ssl/certs/Local-CA-Chain.cer",
# ]
base_dn = "DC=my-company,DC=com"
bind_dn = "CN=%s,DC=my-company,DC=com"
#uniq_filter = "(memberOf=CN=%s,DC=my-company,DC=com)"
timeout = 5000
OpenLDAP
my-company.com
というドメインにしています。
ldap-server:
image: osixia/openldap:latest
restart: always
container_name: ldap-server
environment:
LDAP_ORGANISATION: "My Company"
LDAP_DOMAIN: "my-company.com"
LDAP_ADMIN_PASSWORD: "admin"
LDAP_READONLY_USER: "true"
LDAP_READONLY_USER_USERNAME: "readonly"
LDAP_READONLY_USER_PASSWORD: "readonly_password"
LDAP_TLS_VERIFY_CLIENT: "never"
ports:
- "389:389"
volumes:
- ./src/openldap/testuser.ldif:/openldap/testuser.ldif
ldap-admin:
image: osixia/phpldapadmin:latest
container_name: ldap-admin
restart: always
environment:
PHPLDAPADMIN_LDAP_HOSTS: "ldap"
PHPLDAPADMIN_HTTPS: "false"
ports:
- "8080:80"
links:
- "ldap-server:ldap"
OpenRestyの設定
defalut.conf
以外はデフォルトのままです。
# 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
#
# ngx_ldap_auth service
upstream auth_req {
server ngx_ldap_auth:9200;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
# Authentication URL path
auth_request /auth;
proxy_set_header Authorization "";
location = /auth {
proxy_set_header X-Forwarded-User $remote_user; # Required if using modules other than ngx_ldap_auth.
proxy_set_header Context-Length "";
proxy_pass_request_body off;
proxy_pass http://auth_req;
}
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;
#}
}
認可スクリプト(Lua)
-- remote user名を取得
local remote_user = ngx.var.remote_user
if remote_user ~= "test001" then
-- test001ユーザーでなければ401
ngx.header.content_type = "text/plain"
ngx.log(ngx.STDERR, remote_user.." にはアクセス権がありません")
ngx.status = ngx.HTTP_UNAUTHORIZED
return ngx.exit(ngx.status)
end
まとめ
簡単な記事になってしまいましたが、無事ngx_auth_modを利用してLdap認証と認可が実装できました。
OpenLDAPを利用することで、ローカル環境でも気軽にLdap認証を試すことができました。