開発環境用LDAPサーバーをSambaで作成する

Webアプリケーション作成中に動作確認用として利用するLDAPサーバーをできるだけ手軽に用意したかったのでまとめました。

LDAPサーバーの構築にはSambaの持っているActive Directoryドメインコントローラー機能を利用します。かつてOpenLDAPに挑戦して挫折した身としてはSambaは扱いやすく感じました。

情報
あくまで開発時に利用することを目的としているため、実際の運用には適さないセキュリティレベルの設定をしています。

実行環境

WSL上のdockerを使用します。

コンテナー定義ファイルの作成

空のディレクトリを作成し、その中に以下のファイルとディレクトリを作成します。

  • build (ディレクトリ)
    • Dockerfile
    • docker-entrypoint.sh
  • compose.yaml

各ファイルの内容は以下の通りです。

build/Dockerfile

FROM alpine:latest
RUN  apk add --no-cache samba-dc krb5 py3-cryptography && \
     rm -f /etc/samba/smb.conf
COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]

build/docker-entrypoint.sh

#!/bin/sh

if [ ! -f /samba/etc/smb.conf ]; then
  mkdir -p /samba/etc /samba/lib /samba/log
  echo "samba dc configure start: ${SAMBA_DC_DOMAIN}"
  samba-tool domain provision --use-rfc2307 --realm="${SAMBA_DC_REALM}" --domain="${SAMBA_DC_DOMAIN}" --dns-backend=SAMB
A_INTERNAL --server-role=dc --adminpass="${SAMBA_DC_ADMINPASS}"
  sed -i '/^\[global\]$/a \\tldap server require strong auth = no' /etc/samba/smb.conf
  echo "samba dc configure end: ${SAMBA_DC_DOMAIN}"
fi

if [ ! -f /etc/krb5.conf ]; then
  ln -sf /var/lib/samba/private/krb5.conf /etc/krb5.conf
fi

if [ -z "$1" ]; then
  exec /usr/sbin/samba -i
else
  exec "$@"
fi

compose.yaml

services:
  samba:
    build:
      context: ./build
    cap_add:
      - SYS_ADMIN
    hostname: devdc
    environment:
      TZ: Asia/Tokyo
      SAMBA_DC_DOMAIN: progress-ng
      SAMBA_DC_REALM: progress-ng.com
      SAMBA_DC_ADMINPASS: Administratorのパスワードを設定
    ports:
      - 389:389/tcp
      - 636:636/tcp
      - 3268:3268/tcp
      - 3269:3269/tcp
    volumes:
      - ./samba/etc:/etc/samba/
      - ./samba/lib:/var/lib/samba
      - ./samba/log:/var/log/samba

hostnameはコンテナに対する任意のホスト名を設定する(Samba AD DCの名称として使用される)

以下環境変数には自環境に合わせた値を設定する

  • SAMBA_DC_DOMAIN
  • SAMBA_DC_REALM
  • SAMBA_DC_ADMINPASS

コンテナーのビルド

以下のコマンドでビルドします。

docker compose build

起動と終了

起動コマンド

docker compose up -d

終了コマンド

docker compose down

ユーザーとグループの作成

以下コマンドを実行してコンテナ内に入ります。

docker compose exec samba ash

ユーザーの作成

samba-tool user add ユーザー名 パスワード

グループの作成

samba-tool group add グループ名

グループにユーザーを追加

samba-tool group addmembers グループ名 ユーザー名[,ユーザー名2...]

その他ユーザー操作コマンド

# samba-tool user --help
samba-tool user: missing subcommand

Usage: samba-tool user <subcommand>

User management.

Options:
  -h, --help            show this help message and exit
  --color=always|never|auto
                        use colour if available (default: auto)

Available subcommands:
  add                  - Add a new user.
  addunixattrs         - Add RFC2307 attributes to a user.
  auth                 - Manage authentication policies and silos on a user.
  create               - Add a new user.
  delete               - Delete a user.
  disable              - Disable a user.
  edit                 - Modify User AD object.
  enable               - Enable a user.
  get-kerberos-ticket  - Get a Kerberos Ticket Granting Ticket as a user
  getgroups            - Get the direct group memberships of a user account.
  getpassword          - Get the password fields of a user/computer account.
  list                 - List all users.
  move                 - Move a user to an organizational unit/container.
  password             - Change password for a user account (the one provided in authentication).
  rename               - Rename a user and related attributes.
  sensitive            - Set/unset or show UF_NOT_DELEGATED for an account.
  setexpiry            - Set the expiration of a user account.
  setpassword          - Set or reset the password of a user account.
  setprimarygroup      - Set the primary group a user account.
  show                 - Display a user AD object.
  syncpasswords        - Sync the password of user accounts.
  unlock               - Unlock a user account.

For more help on a specific subcommand, please type: samba-tool user <subcommand> (-h|--help)

その他グループ操作コマンド

# samba-tool group --help
samba-tool group: missing subcommand

Usage: samba-tool group <subcommand>

Group management.

Options:
  -h, --help            show this help message and exit
  --color=always|never|auto
                        use colour if available (default: auto)

Available subcommands:
  add            - Creates a new AD group.
  addmembers     - Add members to an AD group.
  addunixattrs   - Add RFC2307 attributes to a group.
  create         - Creates a new AD group.
  delete         - Deletes an AD group.
  edit           - Modify Group AD object.
  list           - List all groups.
  listmembers    - List all members of an AD group.
  move           - Move a group to an organizational unit/container.
  removemembers  - Remove members from an AD group.
  rename         - Rename a group and related attributes.
  show           - Display a group AD object.
  stats          - Summary statistics about group memberships.

For more help on a specific subcommand, please type: samba-tool group <subcommand> (-h|--help)

動作確認

dockerホストマシンのRubyでSamba ADからユーザーを照会してみる。

暗号化無し版

require 'net/ldap'

ldap = Net::LDAP.new(
  host: "127.0.0.1",
  port: 389,
  base: "DC=progress-ng,DC=com",
  auth: {
    username: "CN=Administrator,CN=Users,DC=progress-ng,DC=com",
    password: "compose.yamlで設定したパスワード",
    method: :simple
  }
)

raise 'bind failed' unless ldap.bind

ldap.open do |conn|
  filter1 = Net::LDAP::Filter.eq('sAMAccountName', '照会するユーザー名')
  filter2 = Net::LDAP::Filter.eq('objectClass', '*')
  conn.search(filter: filter1 & filter2) do |entry|
    pp entry
  end
end

暗号化有り版(証明書チェック無し)

require 'net/ldap'

ldap = Net::LDAP.new(
  host: "127.0.0.1",
  port: 636,
  encryption: {
    method: :simple_tls,
    tls_options: {
      verify_mode: OpenSSL::SSL::VERIFY_NONE    # 証明書をチェックしない
    }
  },
  base: "DC=progress-ng,DC=com",
  auth: {
    username: "CN=Administrator,CN=Users,DC=progress-ng,DC=com",
    password: "compose.yamlで設定したパスワード",
    method: :simple
  }
)

raise 'bind failed' unless ldap.bind

ldap.open do |conn|
  filter1 = Net::LDAP::Filter.eq('sAMAccountName', '照会したいユーザー名')
  filter2 = Net::LDAP::Filter.eq('objectClass', '*')
  conn.search(filter: filter1 & filter2) do |entry|
    pp entry
  end
end

参考

<<開発コンテナー(Dev Containers)でRails開発環境を準備する