2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

OpenResty(Nginx)+Lua+OpenLDAP+ngx_auth_modでLdap認証と認可を実装する

Posted at

はじめに

以下の記事で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言語のベースイメージを使っても良かったかもしれません。

Dockerfile
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を指定してもコンテナの外からアクセスできません。

auth-ldap.conf
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以外はデフォルトのままです。

default.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)

auth.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認証を試すことができました。

2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?