旧バージョンのページ。
[追記 2022/10/08]
この記事に掲載しているファイルをダウンロードできるようにした(設定を簡単にするため一部を改変している)。
目指す構成
公式のDockerイメージを探してみたけれど、見つからなかった。
とても勉強になるDockerのイメージがあり、これを参考に色々とやっていく。
GitHub - Fmstrat/samba-domain: Samba Active Directory Domain Controller for Docker
実際にSamba ad dcを動かすにあたっては、過去にやったSamba ad dcのインストール手順を確認しながら進める。
Dockerのインストール自体は、以前整理した手順を使う。
まずはプライマリーDCを構成して、色々動くようにする。
もしもセカンダリーDCが作りたくなったら、後から追加する。
DCが壊れたら、リストアドDCを立ち上げて復旧する。
| ホスト | コンテナのホスト名 | IP Address | 説明 |
|---|---|---|---|
| mirror | - | 192.168.110.4 | ネットワークに向けてプライマリーDCとして振る舞うように設定する。 addcを動かすホスト。 Ubuntu 20.04と22.04のリポジトリ(ミラーサーバー)。 |
| mirror | addc | 172.26.0.101 | mirrorで動くSamba ad dc(プライマリーDC)。 |
| nanashi | - | 192.168.110.34 | ネットワークに向けてセカンダリーDCとして振る舞うように設定する。 addc2を動かすホスト。 |
| nanashi | addc2 | 172.26.0.102 | nanasiで動くSamba ad dc(セカンダリーDC)。 |
| work | - | 192.168.110.3 | Ubuntu 20.04のサーバー。ドメインに参加するテスト用。 |
| WinTemp | - | 192.168.110.21 | Windows 10。ドメインに参加するテスト用。 |
| router | - | 192.168.110.1 | プロバイダーから貸与されているルーター。 プロバイダーが用意してくれているDNSで名前解決する。 |
| classc | - | 192.168.110.10 | ネットワークに向けてリストアドDCとして振る舞うように設定する。 addcrを動かすホスト。 |
| classc | addcr | 172.26.0.103 | classcで動くSamba ad dc(リストアドDC)。 |
コンテナのIPアドレスは同じネットワークにいるように見えて、別のホストなのでつながってはいない。
Samba ad dc同士が接続したときに、コンテナのIPアドレスを伝えたりするので、問題を防止するために明示的に別のIPアドレスを割り振った。
現在、ホームラボで稼働中のSamba ad dcをバージョンアップするにあたり、セカンダリーDCを作って、プライマリーDCを削除…とDCが新しくなるシナリオなの?と思っていたので、セカンダリーDCについて真面目に整理してみた。
もちろんこの方法も可能だったが、リストアドDCを立てるやり方もある。
構成するサービスと共に図にしてみると、このようなイメージ。
┌───┐
│router│
└─┬─┘
│
└┬───────────┬──────┬──────┬───────────┬────────┬───────────┬─… work, WinTemp, etc.
┌──┼───────────┼──────┼──┐┌──┼───────────┼────┐┌──┼───────────┼────┐
│┌─┴──┐ │ │ ││┌─┴──┐ │ ││┌─┴──┐ │ │
││Apache2 ├─┐ │ │ │││Apache2 ├─┐ │ │││Apache2 ├─┐ │ │
│└────┘ │ │ │ ││└────┘ │ │ ││└────┘ │ │ │
│ │ - Docker - │ │ ││ │ - Docker - │ ││ │ - Docker - │ │
│ ┌─┴──┐┌──┴───┐┌─┴─┐││ ┌─┴──┐┌──┴───┐││ ┌─┴──┐┌──┴───┐│
│ │Apache2 ││Samba ad dc ││rsync │││ │Apache2 ││Samba ad dc │││ │Apache2 ││Samba ad dc ││
│ └─┬──┘└──────┘└───┘││ └─┬──┘└──────┘││ └─┬──┘└──────┘│
│ ┌────┴─────┐ ││ ┌────┴─────┐ ││ ┌────┴─────┐ │
│ │LDAP Account Manager│ ││ │LDAP Account Manager│ ││ │LDAP Account Manager│ │
│ └──────────┘ ││ └──────────┘ ││ └──────────┘ │
│ mirror.hogeserver.hogeddns.jp ││ nanasi.hogeserver.hogeddns.jp ││ classc.hogeserver.hogeddns.jp │
│ addc.hogeserver.hogeddns.jp ││ addc2.hogeserver.hogeddns.jp ││ addcr.hogeserver.hogeddns.jp │
└────────────────────────┘└───────────────────┘└───────────────────┘
[Primary DC] [Secondary DC] [Restored DC]
プライマリーDC
DockerでSamba ad dcが動くイメージを作る。
- Ubuntu 22.04をベースイメージとして、用意されているパッケージを使用する。
- DNSはSamba内蔵のものとBIND9を選択可能。
- コンテナの中でphpLDAPadminとLDAP Account Managerを動作させる。
phpLDAPadminは1.2.3(古いバージョン)となっている。
作業のベースとなるイメージの作成
何度も試行錯誤することになったので、ベースとなるイメージを作り、自作のスクリプトだけを差し替えられるようにした。
~/samba/baseimage/Dockerfile
FROM ubuntu:jammy
USER root
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && \
apt upgrade -y && \
apt install -y \
apache2 \
bind9 \
dnsutils \
iproute2 \
iputils-ping \
krb5-user \
ldap-account-manager \
ldap-utils \
ldb-tools \
libnss-winbind \
libpam-winbind \
locales \
phpldapadmin \
rsync \
samba \
smbclient \
tzdata \
vim \
winbind && \
echo "deb https://ppa.launchpadcontent.net/ondrej/php/ubuntu/ jammy main" > /etc/apt/sources.list.d/ondrej-ubuntu-php-jammy.list && \
echo "# deb-src https://ppa.launchpadcontent.net/ondrej/php/ubuntu/ jammy main" >> /etc/apt/sources.list.d/ondrej-ubuntu-php-jammy.list && \
gpg --keyserver hkps://keyserver.ubuntu.com --recv-key 4F4EA0AAE5267A6C && \
gpg -a --export 4F4EA0AAE5267A6C | gpg --dearmour -o /etc/apt/trusted.gpg.d/ondrej.gpg && \
apt update && \
apt install -y \
php7.3 php7.3-ldap php7.3-xml php7.3-imagick php7.3-mbstring php7.3-gmp php7.3-zip && \
locale-gen en_US.UTF-8
ベースとなるイメージを作る。
$ sudo docker build -t custom/samba:0.0.1 -f ~/samba/baseimage/Dockerfile .
ファイル構成
ファイル構成は以下の通り。
~/samba/
├ docker-compose.yml
├ Dockerfile
├ entrypoint.sh ← 実行権限を付ける
└ packages/
├ config-primary.sh ← 実行権限を付ける
├ phpLDAPadmin-1.2.3.tar.gz ← あればphpLDAPadminが使えるようにする
└ cert ← あればLDAPSを使えるようにする
├ ca.crt
├ server.crt
├ server.key ← アクセス権限 0600
└ ca.crl
phpLDAPadminについては、現在のメンテナーさんが持っている一番古い1.2.3を使わせていただいている。
この後のバージョン(1.2.4)からは、ログイン情報を入れてもanonymousになってしまう問題が解消できず、上手く使える状態にならなかったため。
こちらのリンクから1.2.3のtar.gzをダウンロードしている。
Github / leenooks / phpLDAPadmin - tags
docker-compose.yml
架空のレルム HOGESERVER.HOGEDDNS.JP (HOGEDOMAIN) を運営する。
環境に合わせて変更するのはこのファイル。
後のファイルは、この設定に合わせて動作するようになっている。
SMB_HOSTIPでは、このコンテナを動かすホストのIPアドレスを指定しており、プロビジョン時に使う。
コンテナで動作させる=NAT配下にいるようなもの なので、この指定が必要。
SMB_PRIMARYでは、このコンテナがプライマリーDCであることを指定している。
セカンダリーDCやリストアドDCについては後述。
hostname: addcとしている、このaddcがこのサーバーの名前になる。
→ addc.hogeserver.hogeddns.jp
運用上、付けたい名前があれば、ここに設定しておく。
~/samba/docker-compose.yml
version: "3.9"
services:
samba:
build: ./
image: custom/samba:1.0.0
container_name: samba
restart: unless-stopped
environment:
TZ: Asia/Tokyo
SMB_REALM: HOGESERVER.HOGEDDNS.JP
SMB_DOMAIN: HOGEDOMAIN
SMB_ADMINPASS: p@ssword123
SMB_HOSTIP: 192.168.110.4
SMB_RPC_PORTS: 49152-49200
SMB_PURPOSE: "primary"
SMB_USEBIND9: "false"
# RSY_SECONDARY: 192.168.110.34
# RSY_PASS: p@ssword234
volumes:
- samba_etc:/etc/samba
- samba_lib:/var/lib/samba
- bind_etc:/etc/bind
- bind_lib:/var/lib/bind
- lam:/var/lib/ldap-account-manager
networks:
samba:
ipv4_address: 172.26.0.101
ports:
- 192.168.110.4:53:53 #DNS
- 192.168.110.4:53:53/udp #DNS
- 192.168.110.4:135:135 #End Point Mapper(WINS)
- 192.168.110.4:137:137/udp #NetBIOS Name Service
- 192.168.110.4:138:138/udp #NetBIOS Datagram
- 192.168.110.4:139:139 #NetBIOS Session
- 192.168.110.4:445:445 #SMB over TCP
- 192.168.110.4:389:389 #LDAP
- 192.168.110.4:389:389/udp #LDAP
- 192.168.110.4:636:636 #LDAPS
- 192.168.110.4:88:88 #Kerberos
- 192.168.110.4:88:88/udp #Kerberos
- 192.168.110.4:464:464 #Kerberos kpasswd
- 192.168.110.4:464:464/udp #Kerberos kpasswd
- 192.168.110.4:3268:3268 #Global Catalog
- 192.168.110.4:3269:3269 #Global Catalog SSL
#RPC The same value as SMB_RPC_PORTS.
- 192.168.110.4:49152-49200:49152-49200
- 873:873 #rsync
- 8081:80 #phpLDAPadmin & LDAP Account Manager
hostname: addc
dns:
- 192.168.110.1
dns_search:
- hogeserver.hogeddns.jp
privileged: true
devices:
- /dev/net/tun
cap_add:
- NET_ADMIN
networks:
samba:
ipam:
config:
- subnet: 172.26.0.0/16
gateway: 172.26.0.1
volumes:
samba_etc:
samba_lib:
bind_etc:
bind_lib:
lam:
Dockerfile
最初に作ったベースイメージに、今回使用するいくつかのファイルを追加する。
~/samba/Dockerfile
FROM custom/samba:0.0.1
USER root
ENV LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8
ADD entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]
COPY ./packages /root/packages
entrypoint.sh
コンテナが起動したときに呼び出され、各サービスを起動して無限ループに入る。
終了のシグナルを受け取ったら、各サービスを止める。
supervisorを使ったプロセス管理が格好良さそうだけれど、実際に動かしてみるとこの無限ループ、たいした負荷ではない。
何らかの理由でSamba ad dcが落ちていても、調査のためにログインできる良さもあるので、割り切りとしている。
~/entrypoint.sh
#!/bin/bash
echo "Start Samba container with parameter : $@"
trap sig_term SIGTERM
sig_term() {
echo "CATCH SIGTERM"
pkill -SIGTERM ^samba$
/usr/sbin/apachectl stop
case $SMB_PURPOSE in
"primary")
pkill -SIGTERM ^rsync$
;;
"secondary")
pkill -SIGTERM ^cron$
;;
esac
if [ $SMB_USEBIND9 = "true" ]; then
/usr/sbin/rndc stop
fi
wait
exit 0
}
# Make configuration
case $SMB_PURPOSE in
"primary") /root/packages/config-primary.sh;;
"secondary") /root/packages/config-secondary.sh;;
"restore") /root/packages/config-restore.sh;;
*) echo "Purporse do not match. : "$SMB_PURPOSE
esac
# Execute paramater.
exec "$@"
# Start services.
/usr/sbin/samba --interactive --no-process-group &
/usr/sbin/apachectl start
case $SMB_PURPOSE in
"primary")
/usr/bin/rsync --daemon --no-detach &
;;
"secondary")
/usr/sbin/cron
;;
esac
if [ $SMB_USEBIND9 = "true" ]; then
/usr/sbin/named -u bind
fi
# Infinity roop.
while : ; do sleep 1 ; done
ファイルを作ったら、実行権を付けておく。
$ chmod +x ~/entrypoint.sh
config-primary.sh
コンテナが起動したときに呼び出されるスクリプトで、コンテナとボリュームの状況に合わせて、必要な初期設定を実行する。
| フェーズ | ボリューム | コンテナ | 動作 |
|---|---|---|---|
| 1 | なし | なし | Samba ad dcドメインの初期設定を実行する。 /etc/samba/smb.conf はここで生成されたものを永続化している。 続けて、フェーズ2を実行する。 |
| 2 | あり | なし | 認証設定(Winbindを追加)、Kerberos設定、rsync設定、phpLDAPadminの設定を実行する。 これらは永続化していないので、コンテナが作られる度に再設定をする。 続けて、フェーズ3を実行する。 |
| 3 | あり | あり | コンテナ内部のリゾルバを127.0.0.11→127.0.0.1に向ける。 これはコンテナを実行する度に設定が必要。 結果として、Samba ad dcが名前解決をするようになる。 |
Provisionの際のパラメーターは、スクリプトの最初の方で作っているので、必要に応じて修正する。
とはいえ、/etc/sambaディレクトリを永続化しているので、致命的な問題でなければ「後からどうにでもできる」想定。
名前解決は、通常
コンテナの中のプログラム → 127.0.0.11 → docker-compose.ymlで指定したDNS
で行われる。
Samba ad dcを運用する場合、これでは具合が悪いので、
コンテナの中のプログラム → 127.0.0.1(=Samba ad dc) → 127.0.0.11 → docker-compose.ymlで指定したDNS
という名前解決順序になるよう、コンテナを起動する度に/etc/resolv.confを書き換えている。
なお、外部からの問い合わせには、
他のホスト → 192.168.110.4 → 127.0.0.1 → Samba ad dc → …
という順序で名前を解決する。
~/samba/packages/config-primary.sh
#!/bin/bash
echo "Primary domain controller settings."
#----------------------------------------------------------------------
# New volumes.
#----------------------------------------------------------------------
if [ -z "$(ls /var/lib/samba/private)" ]; then
echo "New volumes."
# Make provision parameters.
SMB_TMP_PARAM="
--use-rfc2307
--realm=$SMB_REALM
--domain=$SMB_DOMAIN
--server-role=dc
--adminpass=$SMB_ADMINPASS
--option=\"dns forwarder = 127.0.0.11\"
--option=\"dns update command = /usr/sbin/samba_dnsupdate --current-ip $SMB_HOSTIP\"
--option=\"template homedir = /home/%D/%U\"
--option=\"template shell = /bin/bash\"
--option=\"winbind enum users = yes\"
--option=\"winbind enum groups = yes\"
--option=\"idmap config $SMB_DOMAIN:unix_nss_info = yes\"
--option=\"idmap config $SMB_DOMAIN:unix_primary_group = yes\"
--option=\"rpc server dynamic port range = $SMB_RPC_PORTS\"
--host-ip=$SMB_HOSTIP
"
if [ $SMB_USEBIND9 = "true" ]; then
SMB_TMP_PARAM+=" --dns-backend=BIND9_DLZ"
else
SMB_TMP_PARAM+=" --dns-backend=SAMBA_INTERNAL"
fi
# LDAPS settings.
mkdir /var/lib/samba/private/tls/
TMP_LDAPS=0
cp -a /root/packages/cert/ca.crt /usr/local/share/ca-certificates/ && \
update-ca-certificates && \
TMP_LDAPS=$(($TMP_LDAPS | 0x01)) && \
SMB_TMP_PARAM+=" --option=\"tls cafile = /usr/local/share/ca-certificates/ca.crt\""
cp -a /root/packages/cert/server.crt /var/lib/samba/private/tls/ && \
TMP_LDAPS=$(($TMP_LDAPS | 0x02)) && \
SMB_TMP_PARAM+=" --option=\"tls certfile = /var/lib/samba/private/tls/server.crt\""
cp -a /root/packages/cert/server.key /var/lib/samba/private/tls/ && \
TMP_LDAPS=$(($TMP_LDAPS | 0x04)) && \
chmod 600 /var/lib/samba/private/tls/server.key && \
SMB_TMP_PARAM+=" --option=\"tls keyfile = /var/lib/samba/private/tls/server.key\""
cp -a /root/packages/cert/ca.crl /var/lib/samba/private/tls/ && \
TMP_LDAPS=$(($TMP_LDAPS | 0x08)) && \
SMB_TMP_PARAM+=" --option=\"tls crlfile = /var/lib/samba/private/tls/ca.crl\""
if [ $(($TMP_LDAPS & 0x07)) -eq 7 ]; then
echo "Enable LDAPS."
SMB_TMP_PARAM+=" --option=\"tls enabled = true\"
--option=\"tls verify peer = as_strict_as_possible\"
"
else
echo "Disable Strong Auth."
SMB_TMP_PARAM+="
--option=\"ldap server require strong auth = no\"
"
fi
set -f
SMB_TMP_PARAM=$(echo $SMB_TMP_PARAM)
#echo "provision parameters: $SMB_TMP_PARAM"
set +f
# Domain service settings.
mv --backup=numbered /etc/samba/smb.conf /etc/samba/smb.conf.bak
eval samba-tool domain provision "$SMB_TMP_PARAM"
if [ $? -ne 0 ]; then exit 0; fi
# Stop needlessly complicated passwords.
samba-tool domain passwordsettings set \
--complexity=off \
--history-length=0 \
--min-pwd-length=8 \
--min-pwd-age=0 \
--max-pwd-age=0
fi
#----------------------------------------------------------------------
# Volumes is left.
#----------------------------------------------------------------------
if [ ! -e /root/packages/configured ]; then
echo "New container."
# Register CA certificates.
cp -a /root/packages/cert/ca.crt /usr/local/share/ca-certificates/ && \
update-ca-certificates
# Authentication sttings.
sed -i "s/^\(passwd: \+\)[a-z ]\+$/\1compat winbind/" /etc/nsswitch.conf
sed -i "s/^\(group: \+\)[a-z ]\+$/\1compat winbind/" /etc/nsswitch.conf
# Copy krb5.conf
mv --backup=numbered /etc/krb5.conf /etc/krb5.conf.bak
cp /var/lib/samba/private/krb5.conf /etc/
# Make rsync configuration.
cat <<EOF > /etc/rsyncd.conf
[SysVol]
path = /var/lib/samba/sysvol/
comment = Samba Sysvol Share
uid = root
gid = root
hosts allow = $RSY_SECONDARY
hosts deny = *
read only = yes
auth users = sysvol-replication
secrets file = /etc/rsyncd.secret
EOF
cat <<EOF > /etc/rsyncd.secret
sysvol-replication:$RSY_PASS
EOF
chmod 600 /etc/rsyncd.secret
# Suppress apache warning.
echo "ServerName localhost" | tee /etc/apache2/conf-available/fqdn.conf
a2enconf fqdn
# Setup phpLdapAdmin.
if [ -e /root/packages/phpLDAPadmin-1.2.3.tar.gz ]; then
a2dismod php8.1
a2enmod php7.3
tar zxf /root/packages/phpLDAPadmin-1.2.3.tar.gz -C /var/www/
mv /var/www/phpLDAPadmin-1.2.3 /var/www/phpldapadmin
cp /etc/phpldapadmin/apache.conf /etc/phpldapadmin/apache.conf.bak
sed -i "s@/usr/share/phpldapadmin/htdocs@/var/www/phpldapadmin@g" /etc/phpldapadmin/apache.conf
cp /var/www/phpldapadmin/config/config.php.example /var/www/phpldapadmin//config/config.php
if [ $(grep "tls verify peer = as_strict_as_possible" /etc/samba/smb.conf -c) -ne 0 ]; then
sed -i "$ i\$servers->setValue('server','host','ldaps://$(hostname).${SMB_REALM,,}');" /var/www/phpldapadmin/config/config.php
else
sed -i "$ i\$servers->setValue('server','host','ldap://$(hostname).${SMB_REALM,,}');" /var/www/phpldapadmin/config/config.php
fi
sed -i "$ i\$servers->setValue('login','bind_id','administrator@${SMB_REALM,,}');" /var/www/phpldapadmin/config/config.php
sed -i "$ i\$config->custom->appearance['hide_template_warning'] = true;" /var/www/phpldapadmin/config/config.php
sed -i "s/\$servers->setValue('server','name','My LDAP Server');/\$servers->setValue('server','name','$SMB_DOMAIN');/" /var/www/phpldapadmin/config/config.php
# Customize phpLDAPadmin
# for PHP7.0
sed -i "s/password_hash/password_hash_custom/g" /var/www/phpldapadmin/lib/*
sed -i '2567d; 2568d; 2569i \\t\tforeach ($dn as $key => $rdn) {\n\t\t\t$a[$key] = preg_replace_callback('\''/\\\\\\([0-9A-Fa-f]{2})/'\'', function ($m) { return '\'\''.chr(hexdec('\''\\\\1'\'')).'\'\''; }, $rdn\'');\n\t\t}' /var/www/phpldapadmin/lib/functions.php
sed -i '2574c \\t\treturn preg_replace_callback('\''/\\\\\\([0-9A-Fa-f]{2})/'\'', function ($m) { return'\'\''.chr(hexdec('\''\\\\1'\'')).'\'\''; }, $dn);' /var/www/phpldapadmin/lib/functions.php
sed -i '1119d; 1120d; 1121i \\t\t\tforeach ($dn as $key => $rdn) {\n\t\t\t\t$a[$key] = preg_replace_callback('\''/\\\\\\([0-9A-Fa-f]{2})/'\'', function ($m) { return '\'\''.chr(hexdec('\''\\\\1'\'')).'\'\''; }, $rdn\'');\n\t\t\t}' /var/www/phpldapadmin/lib/ds_ldap.php
sed -i '1126c \\t\t\treturn preg_replace_callback('\''/\\\\\\([0-9A-Fa-f]{2})/'\'', function ($m) { return'\'\''.chr(hexdec('\''\\\\1'\'')).'\'\''; }, $dn);' /var/www/phpldapadmin/lib/ds_ldap.php
# for PHP7.3
sed -i '54c function my_autoload($className) {' /var/www/phpldapadmin/lib/functions.php
sed -i '777c spl_autoload_register("my_autoload");' /var/www/phpldapadmin/lib/functions.php
sed -i '1083c \\t\t$CACHE[$sortby] = __create_function('\''$a, $b'\'',$code);' /var/www/phpldapadmin/lib/functions.php
sed -i '1091a function __create_function($arg, $body) {\n\tstatic $cache = array();\n\tstatic $maxCacheSize = 64;\n\tstatic $sorter;\n\n\tif ($sorter === NULL) {\n\t\t$sorter = function($a, $b) {\n\t\t\tif ($a->hits == $b->hits) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn ($a->hits < $b->hits) ? 1 : -1;\n\t\t};\n\t}\n\n\t$crc = crc32($arg . "\\\\x00" . $body);\n\n\tif (isset($cache[$crc])) {\n\t\t++$cache[$crc][1];\n\t\treturn $cache[$crc][0];\n\t}\n\n\tif (sizeof($cache) >= $maxCacheSize) {\n\t\tuasort($cache, $sorter);\n\t\tarray_pop($cache);\n\t}\n\n\t$cache[$crc] = array($cb = eval('\''return function('\''.$arg.'\''){'\''.$body.'\''};'\''), 0);\n\treturn $cb;\n}\n' /var/www/phpldapadmin/lib/functions.php
fi
# Mark as configured.
touch /root/packages/configured
fi
#----------------------------------------------------------------------
# Container and Volumes is left.
#----------------------------------------------------------------------
echo "Setting to do every time"
# Resolver settings.
cp /etc/resolv.conf /root/packages/resolv.conf
sed -i "s/nameserver 127.0.0.11/nameserver 127.0.0.1/" /root/packages/resolv.conf
cat /root/packages/resolv.conf > /etc/resolv.conf
# Switch DNS backend.
if [ $SMB_USEBIND9 = "true" ]; then
if [ ! -e /var/lib/samba/bind-dns/named.conf ]; then
samba_upgradedns --dns-backend=BIND9_DLZ
fi
# Make bind9 configuration.
if [ $(grep "bind-dns" /etc/bind/named.conf -c) -eq 0 ]; then
cp -a /etc/bind/named.conf /etc/bind/named.conf.bak
sed -i "\$a include \"/var/lib/samba/bind-dns/named.conf\";" /etc/bind/named.conf
cp -a /etc/bind/named.conf.options /etc/bind/named.conf.options.bak
sed -i "/listen-on-v6/a\\\n\tforwarders { 127.0.0.11; };\n\tallow-query { any; };\n\tallow-transfer { none; };\n\ttkey-gssapi-keytab \"/var/lib/samba/bind-dns/dns.keytab\";\n\tminimal-responses yes;" /etc/bind/named.conf.options
cp -a /etc/bind/named.conf.local /etc/bind/named.conf.local.bak
sed -i "s@^//include@include@" /etc/bind/named.conf.local
fi
if [[ $(grep -c "server services" /etc/samba/smb.conf) -eq 0 ]]; then
sed -i "9a\\\tserver services = -dns" /etc/samba/smb.conf
fi
else
if [ -e /var/lib/samba/bind-dns/named.conf ]; then
samba_upgradedns --dns-backend=SAMBA_INTERNAL
sed -i "/server services/d" /etc/samba/smb.conf
fi
fi
ファイルを作ったら、実行権を付けておく。
$ chmod +x ~/samba/packages/config-primary.sh
証明書類
証明書類は、なければないでLDAPが使えるように動作する。
用意しておけばLDAPSが使えるようになる。
証明書類は、以下の固定した名前で ~/samba/packages/certに入れる。
スクリプトは固定のファイル名で処理をしているので、ファイル名を変更したければ、証明書類の名前と一緒にスクリプトを修正する。
| ファイル | 内容 |
|---|---|
| ca.crt | 認証局の証明書。 |
| server.crt | Samba ad dcの証明書。ca.crtの認証局が署名したものを想定。 |
| server.key | Samba ad dcの秘密鍵。パスワードは外しておく。 |
| ca.crl | ca.crtの認証局が発行するcertificate revocation list(CRL)。 |
ホームラボでは、いわゆるオレオレ認証局を運営しており、架空サイト hogeserver.hogeddns.jp と *.hogeserver.hogeddns.jp に向けたワイルドカード証明書を発行した。
スクリプトでは、ca.crt、server.crt、server.keyの3ファイルがあるとLDAPSが有効になるようにしてある。
ca.crlは無効にした証明書ができたら更新するべきものではあるが、なくても動作する。
もし更新するなら、docker cp等で放り込めば良い。
起動と確認
ファイルの準備ができたら、ファイアウォールを設定する。
Samba ad dcの機能のなかに、IPアドレスで接続してくるものがあるため。
$ sudo ufw allow from 172.26.0.101 to 192.168.110.4 comment "From container"
コンテナを起動する。
$ sudo docker compose up --build
別のターミナルを開き、様子を見ながら進める。
まずは、sambaとapacheが起動していることを確認。
$ sudo docker exec -it samba /bin/bash --login
# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 7360 3788 ? Ss 08:37 0:00 /bin/bash /entrypoint.sh root 1609 0.1 1.0 132160 42348 ? S 08:37 0:00 samba: root process root 1615 0.0 0.7 224100 28404 ? Ss 08:37 0:00 /usr/sbin/apache2 -k start …
※大量のプロセスが動いているが、上から3つを確認。
共有の一覧表示。
# smbclient -L localhost -N
Anonymous login successful
Sharename Type Comment
--------- ---- -------
sysvol Disk
netlogon Disk
IPC$ IPC IPC Service (Samba 4.15.9-Ubuntu)
SMB1 disabled -- no workgroup available
共有への接続。
# smbclient //localhost/netlogon -U administrator -c 'ls'
Password for [HOGEDOMAIN\administrator]: ユーザーadministratorのパスワード[Enter]
. D 0 Thu Aug 11 10:09:29 2022
.. D 0 Thu Aug 11 10:09:33 2022
19948144 blocks of size 1024. 8855556 blocks available
チケットの発行。
# kinit administrator
Password for administrator@HOGESERVER.HOGEDDNS.JP: ユーザーadministratorのパスワード[Enter]
# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: administrator@HOGESERVER.HOGEDDNS.JP
Valid starting Expires Service principal
08/11/2022 08:41:30 08/11/2022 18:41:30 krbtgt/HOGESERVER.HOGEDDNS.JP@HOGESERVER.HOGEDDNS.JP
renew until 08/12/2022 08:41:22
# kdestroy
名前解決。
# dig @127.0.0.1 addc.hogeserver.hogeddns.jp +short 192.168.110.4 # dig @192.168.110.4 addc.hogeserver.hogeddns.jp +norec … ;; ANSWER SECTION: addc.hogeserver.hogeddns.jp. 900 IN A 192.168.110.4 ;; AUTHORITY SECTION: hogeserver.hogeddns.jp. 3600 IN SOA addc.hogeserver.hogeddns.jp. hostmaster.hogeserver.hogeddns.jp. 1 900 600 86400 3600 ;; Query time: 0 msec ;; SERVER: 192.168.110.4#53(192.168.110.4) (UDP) ;; WHEN: Thu Aug 11 08:55:50 JST 2022 ;; MSG SIZE rcvd: 108
ただし、ホスト名で問い合わせると、コンテナ内部のIPアドレスが表示される。
workから名前解決を試みた結果がこちら。
# dig addc … ;; ANSWER SECTION: addc. 600 IN A 172.26.0.101 ;; Query time: 4 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP) ;; WHEN: Sun Aug 14 17:39:58 JST 2022 ;; MSG SIZE rcvd: 38
/etc/hostsも変えてみたけれども、問い合わせの結果は変わらない。
この情報が表示される理由は明確にできなかったので、ドメイン名を付けることで問題を回避することにした。
ゾーン情報。
# samba-tool dns query localhost hogeserver.hogeddns.jp @ ALL -U administrator
Password for [HOGEDOMAIN\administrator]: ユーザーadministratorのパスワード[Enter]
Name=, Records=3, Children=0
SOA: serial=1, refresh=900, retry=600, expire=86400, minttl=3600, ns=addc.hogeserver.hogeddns.jp., email=hostmaster.hogeserver.hogeddns.jp. (flags=600000f0, serial=1, ttl=3600)
NS: addc.hogeserver.hogeddns.jp. (flags=600000f0, serial=1, ttl=900)
A: 192.168.110.4 (flags=600000f0, serial=1, ttl=900)
Name=_msdcs, Records=0, Children=0
Name=_sites, Records=0, Children=1
Name=_tcp, Records=0, Children=4
Name=_udp, Records=0, Children=2
Name=addc, Records=1, Children=0
A: 192.168.110.4 (flags=f0, serial=1, ttl=900)
Name=DomainDnsZones, Records=0, Children=2
Name=ForestDnsZones, Records=0, Children=2
問題なく起動できたようだ。
ユーザーとグループの追加
ユーザーをいくつか追加してみる。
# samba-tool user add rohhie --given-name=Rohhie --surname=Puyopuyo --mail-address=rohhie@hogeserver.hogeddns.jp New Password: ユーザーrohhieのパスワード[Enter] Retype Password: パスワード確認入力[Enter] User 'rohhie' added successfully # samba-tool user add ssoauth p@ssword123 --given-name=Authentication --surname=SystemUser --mail-address=ssoauth@hogeserver.hogeddns.jp # samba-tool user add hoge p@ssword123 --given-name=User --surname=Hoge --mail-address=hoge@hogeserver.hogeddns.jp # samba-tool user add hogewife p@ssword123 --given-name=User --surname=Wife --mail-address=hogewife@hogeserver.hogeddns.jp
グループを作ってみる。
# samba-tool group add parent --mail-address=parent@hogeserver.hogeddns.jp Added group parent
グループにユーザーを追加する。
# samba-tool group addmembers parent hoge,hogewife Added members to group parent
rohhieを管理者グループに、ssoauthをDNS管理者グループに入れる。
# samba-tool group addmembers Administrators rohhie Added members to group Administrators # samba-tool group addmembers "Domain Admins" rohhie Added members to group Domain Admins # samba-tool group addmembers DnsAdmins ssoauth Added members to group DnsAdmins
※Windowsにログインして確認してみたら、AdministratorsにはDomain Adminsが含まれている。ここに入れないと、Windowsクライアントでは管理者にならない。
※ssoauthは認証のときにLDAPを参照するだけの人なので、DnsAdminsはやり過ぎかもしれない…
Samba ad dcでプライマリーDCを稼働させることができた。
ドメイン参加と離脱(Ubuntu)
ホームラボにあるUbuntuをドメインに参加させてみる。
元々考えていたよりはだいぶ手間取った印象。
操作自体が難しいわけではなくて、その結果がどうなるのか、というところの確認に時間が掛かっている。
ドメインへの参加
以前作っていたUbuntu 20.04サーバー(work.example.jp)をドメインに参加させてみることにした。
DNSとしてSamba ad dcを参照し、ドメイン指定がなければhoserver.hogeddns.jpを探すようにネットワーク設定を変更する。
/etc/netplan/00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
ethernets:
ens33:
addresses:
- 192.168.110.3/24
routes:
- to: default
via: 192.168.110.1
nameservers:
addresses:
- 192.168.110.4
search:
- hogeserver.hogeddns.jp
dhcp6: false
accept-ra: false
link-local: [ ]
version: 2
反映。
$ sudo netplan apply
これで、DCとドメインに参加したホストの名前解決ができるようになる。
hostsファイルを修正。
/etc/hosts
127.0.0.1 localhost #127.0.1.1 work 192.168.110.3 work.hogeserver.hogeddns.jp work …
※登録順はFQDN → ホスト名としている。この順序でないと、ドメイン参加時のDNS更新に失敗する。
続いて、必要なアプリをインストールして設定していく。
$ sudo apt install samba smbclient libpam-winbind libnss-winbind krb5-user ■途中の質問 ・Configuring Kerberos Authentication ユーザがKerberosを使おうとして、プリンシパルやユーザ名を指定したときに、 そのプリンシパルがどの管理Kerberosレルムに属しているかを指定しない場合、 システムはデフォルトレルムを追加する。デフォルトのレルムは、ローカル マシン上で動作しているKerberosサービスのレルムとして使用されることもある。 多くの場合、デフォルトのレルムは、ローカルDNSドメインの大文字版である。 デフォルトの Kerberos バージョン 5 レルム: → 今動かそうとしている HOGESERVER.HOGEDDNS.JP を入力しておいた。
※DeepL先生の翻訳
Sambaの設定。
/etc/samba/smb.conf
[global]
realm = HOGESERVER.HOGEDDNS.JP
server role = member server
workgroup = HOGEDOMAIN
winbind enum users = Yes
winbind enum groups = Yes
idmap config hogedomain : backend = rid
idmap config hogedomain : range = 1000000-1999999
idmap config * : range = 3000000-4999999
idmap config * : backend = tdb
server string = %h server (Samba, Ubuntu)
template homedir = /home/%D/%U
template shell = /bin/bash
bind interfaces only = yes
interfaces = 192.168.110.3 127.0.0.1
log file = /var/log/samba/log.%m
max log size = 1000
logging = file
panic action = /usr/share/samba/panic-action %d
[homes]
root preexec = /usr/local/bin/samba_create_home_directory "%H" "%g" "%u"
path = %H
read only = No
browseable = No
※workにはDockerがインストールしてあり、work内部でしか使えないIPアドレスを持っている。これを除外するために、bind interfacesを指定している。
ユーザーがSamba共有にアクセスしてきたら、ホームディレクトリを作成するスクリプトを作成。
/usr/local/bin/samba_create_home_directory ※新規作成
#!/bin/bash
if [ ! -d $1 ]; then
BASEDIR=$(dirname $1)
if [ ! -d $BASEDIR ]; then
mkdir $BASEDIR
chmod 755 $BASEDIR
fi
mkdir $1
cp /etc/skel/.[^.]* $1
chgrp -R "$2" $1
chown -R "$3" $1
chmod 700 $1
fi
スクリプトに実行権を付ける。
$ sudo chmod +x /usr/local/bin/samba_create_home_directory
設定を反映。
$ sudo systemctl restart smbd
ドメインに参加。
$ sudo net ads join -U administrator
Enter administrator's password: ユーザーadministratorのパスワード[Enter]
Using short domain name -- HOGEDOMAIN
Joined 'WORK' to dns domain 'hogeserver.hogeddns.jp'
今度は問題なく参加ができた。
Samba ad dcの認証が使えるようになったので、winbindの設定を変更する。
/etc/nsswitch.conf
… passwd: files systemd winbind group: files systemd winbind shadow: files …
※赤文字を追記。
SSHでログインしたり、suコマンドでユーザーを変更したときに、ホームディレクトリを作成するように、PAMの設定を追加する。
先程のスクリプトはsmbdに接続があった場合に動作するが、これはwinbindで認証されたときに動作する。
$ sudo pam-auth-update
---- PAM configuration ---- [*] Unix authentication [*] Winbind NT/Active Directory authentication [*] Register user sessions in the systemd control group hierarchy [*] Create home directory on login [*] Inheritable Capabilities Management
※Winbindは最初から追加されていると思われるが、一応確認。
※Create home directory on loginにチェックを入れると、ホームディレクトリが作成されるようになる。
これにより、以下に設定が書き込まれる。
/etc/pam.d/common-session
… # and here are more per-package modules (the "Additional" block) session required pam_unix.so session optional pam_winbind.so session optional pam_systemd.so session optional pam_mkhomedir.so # end of pam-auth-update config
さて、チケットの発行には、krb5.confファイルが必要。
$ sudo mv /etc/krb5.conf /etc/krb5.conf.bak
/etc/krb5.conf ※新規作成
[libdefaults]
dns_lookup_realm = false
dns_lookup_kdc = true
default_realm = HOGESERVER.HOGEDDNS.JP
※作成するだけでOK。
最後に、DNSへの登録状況を確かめてみる。
$ dig @hogeserver.hogeddns.jp work.hogeserver.hogeddns.jp … ;; ANSWER SECTION: work.hogeserver.hogeddns.jp. 3600 IN A 192.168.110.3
これで、参加に関わる手続きは完了。
ドメイン参加後の動作確認
このSamba ad dcにしか登録されていないaddcの名前解決ができるか。
$ dig addc.hogeserver.hogeddns.jp … ;; ANSWER SECTION: addc.hogeserver.hogeddns.jp. 334 IN A 192.168.110.4 ;; Query time: 0 msec ;; SERVER: 127.0.0.53#53(127.0.0.53) ;; WHEN: Thu Aug 11 11:19:34 JST 2022 ;; MSG SIZE rcvd: 72
ドメイン参加したworkで、ユーザーやグループの一覧が見られるか。
$ getent passwd … HOGEDOMAIN\hoge:*:1001105:1000513:User Hoge:/home/HOGEDOMAIN/hoge:/bin/bash HOGEDOMAIN\ssoauth:*:1001104:1000513::/home/HOGEDOMAIN/ssoauth:/bin/bash $ getent group … HOGEDOMAIN\domain computers:x:1000515: HOGEDOMAIN\domain users:x:1000513:
チケットを発行。
$ kinit rohhie
Password for rohhie@HOGESERVER.HOGEDDNS.JP: ユーザーrohhieのパスワード[Enter]
$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: rohhie@HOGESERVER.HOGEDDNS.JP
Valid starting Expires Service principal
08/11/2022 10:27:36 08/11/2022 20:27:36 krbtgt/HOGESERVER.HOGEDDNS.JP@HOGESERVER.HOGEDDNS.JP
renew until 08/12/2022 10:27:30
$ kdestroy
ユーザーを切り替える。
$ sudo su - hogedomain\\hoge Creating directory '/home/HOGEDOMAIN/hoge'. HOGEDOMAIN\hoge@work:~$ ll total 20 drwxr-xr-x 2 HOGEDOMAIN\hoge HOGEDOMAIN\domain users 4096 Sep 18 23:37 ./ drwxr-xr-x 3 root root 4096 Sep 18 23:37 ../ -rw-r--r-- 1 HOGEDOMAIN\hoge HOGEDOMAIN\domain users 220 Sep 18 23:37 .bash_logout -rw-r--r-- 1 HOGEDOMAIN\hoge HOGEDOMAIN\domain users 3771 Sep 18 23:37 .bashrc -rw-r--r-- 1 HOGEDOMAIN\hoge HOGEDOMAIN\domain users 807 Sep 18 23:37 .profile
共有にアクセスしてみる。(ユーザー切り替えで作られたディレクトリをいったん消して確かめている)
$ sudo rm -r /home/HOGEDOMAIN/
$ smbclient //localhost/hoge -U hoge -c 'ls'
Password for [HOGEDOMAIN\hoge]:
. D 0 Sun Sep 18 23:40:25 2022
.. D 0 Sun Sep 18 23:40:25 2022
.bash_logout H 220 Sun Sep 18 23:40:25 2022
.profile H 807 Sun Sep 18 23:40:25 2022
.bashrc H 3771 Sun Sep 18 23:40:25 2022
39887136 blocks of size 1024. 30589196 blocks available
上手く動作しているようだ。
ドメインからの離脱
Samba ad dcからの離脱自体はコマンドで簡単にできる。
このコマンドで行われるのは、コンピューターの削除処理だった。
$ sudo net ads leave -U administrator
Enter administrator's password: ユーザーadministratorのパスワード[Enter]
Deleted account for 'WORK' in realm 'HOGESERVER.HOGEDDNS.JP'
コマンド実行後、参照するDNSと、ドメイン名を付けなかった場合に検索対象となるドメインを元に戻す。
/etc/netplan/00-installer-config.yaml
…
nameservers:
addresses:
- 192.168.110.1
search:
- example.jp
dhcp6: false
accept-ra: false
link-local: [ ]
version: 2
反映。
$ sudo netplan apply
認証に追加したwinbindを外す。
/etc/nsswitch.conf
… passwd: files systemd #winbind group: files systemd #winbind shadow: files …
※赤文字を追記。この変更をするだけで、サービスの再起動は必要なし。
これだけで終わりかと思いきや…DNSのレコードが残っていた。
Samba ad dcで、DNSからworkを削除する。
# samba-tool dns delete localhost hogeserver.hogeddns.jp work A 192.168.110.3 -U administrator
Password for [HOGEDOMAIN\administrator]: ユーザーadministratorのパスワード[Enter]
Record deleted successfully
以上で離脱完了。
ドメインからの強制削除
何らかの事情で、ドメインからの離脱操作ができない場合は、Samba ad dcでコンピューターを削除する。
# samba-tool computer delete work
この場合は、DNSからもエントリーが消える。…はずだけれども、一応確認して、残っていたら消す。
ドメインへの参加(プライマリーのホスト)
結論からすると、無理。
Samba ad dcを動かしているホストな訳で、Samba clientをインストールすれば、使用するポートが重なってしまうため。
一応、よそからも名前解決だけはできるように、DNSに登録しておいてみる。
$ sudo docker exec -it samba samba-tool dns add localhost hogeserver.hogeddns.jp mirror A 192.168.110.4 -U administrator
Password for [HOGEDOMAIN\administrator]: ユーザーadministratorのパスワード[Enter]
Record added successfully
同じホストだから、これで良いかなーとも思ったが、一応、CNAMEでの指定も試してみた。
$ sudo docker exec -it samba samba-tool dns add localhost hogeserver.hogeddns.jp mirror cname addc.hogeserver.hogeddns.jp -U administrator
※FQDNでの指定が必要だった。
ドメイン参加と離脱(Windows)
Windows 10の試用版を使って試してみる。
元々、MYHOMELABドメインに入っていたので、そこから離脱して、HOGEDOMAINに参加する。
ドメインへの参加
ちょっと面倒だけれども、IPアドレスをDHCPから手動設定に変更した。
目的は、Samba ad dcで名前解決をすること。
実際に参加してみる。






これでドメインに参加することができた。
DNSには、いつ頃にこのコンピューターが登録されるのか見ていたら、 Windowsでようこそ画面が出たところだった。
なお、PowerShellによるドメイン参加は、試してみたけれども
- 離脱はできた
- 参加はできなかった
参加後の動作確認
再起動後に、ドメインに登録したユーザーでログインして、名前解決を試したところ。
DNSは手で設定しているので、名前解決自体はできて当然だが、ドメイン名がなくてもいけた。
C:\Users\rohhie.HOGEDOMAIN>nslookup work サーバー: UnKnown Address: 192.168.110.4 名前: work.hogeserver.hogeddns.jp Addresses: 192.168.110.3
チケットを確認してみる。
C:\Users\rohhie.HOGEDOMAIN>klist
現在のログオン ID: 0:0xc84ba
キャッシュされたチケット: (6)
#0> クライアント: rohhie @ HOGESERVER.HOGEDDNS.JP
サーバー: krbtgt/HOGESERVER.HOGEDDNS.JP @ HOGESERVER.HOGEDDNS.JP
Kerberos チケットの暗号化の種類: AES-256-CTS-HMAC-SHA1-96
チケットのフラグ 0x60ac0000 -> forwardable forwarded renewable pre_authent ok_as_delegate 0x80000
開始時刻: 8/11/2022 11:52:08 (ローカル)
終了時刻: 8/11/2022 21:52:08 (ローカル)
更新期限: 8/18/2022 11:52:08 (ローカル)
セッション キーの種類: AES-256-CTS-HMAC-SHA1-96
キャッシュ フラグ: 0x2 -> DELEGATION
呼び出された Kdc: addc.hogeserver.hogeddns.jp
…
Windowsの管理ツールをインストールする
管理ツールをインストールすることについて、こちらで教えてくれた。
Samba Wiki / Installing RSAT
Windows 10 version 21H2の場合で、以下をインストールすると、管理がGUIからできる。
- RSAT: Active Directory Domain Service およびライトウェイト ディレクトリ サービス ツール
- RSAT: DNS サーバー ツール
- RSAT: グループ ポリシー管理ツール
- RSAT: リモート デスクトップ サービス ツール
グループポリシーは、グループポリシーの管理アプリで、
フォレスト: hogeserver.hogeddns.jp
ドメイン
hogeserver.hogeddns.jp
Default Domain Policy(これはリンク)
とたどって、Default Domain Policyを右クリックし、表示されたポップアップで編集を選択すると、編集を開始できる。
テストのために、スタートアップスクリプトをユーザーに設定してみた。
\\hogeserver.hogeddns.jp\netlogon\test.bat
msg %username% このメッセージが表示されているということは、^ スタートアップスクリプトが実行されているということ。
これらの設定は、対象がコンピューターなのかユーザーなのか、というところを見極めて設定していく必要があるようだ。
簡単な動作確認を実施して、この件は終了とした。
ドメインからの離脱
ドメイン参加と反対の手順。所属するグループをhogeserver.hogeddns.jpからワークグループに変更する。






ドメインからの離脱は、PowerShellでも実行できた。
ドメインを抜けて、ワークグループに移動させてみる。
Microsoft / PowerShell / Remove-Computer
> Remove-Computer -ComputerName localhost -UnjoinDomainCredential HOGEDOMAIN\Administrator -WorkgroupName "WORKGROUP" -Force -Restart
認証情報を入力する画面が表示されたので、Administratorのパスワードを入力したところ、しばらくして再起動しはじめ、ドメインから抜けていた。
さて、ドメイン離脱後に確認してみたところ、DNSのレコードは残されていた。
以下のコマンドで削除ができる。
$ sudo docker exec -it samba samba-tool dns query localhost hogeserver.hogeddns.jp wintemp ALL -U administrator
Password for [HOGEDOMAIN\administrator]:
Name=, Records=1, Children=0
A: 192.168.110.21 (flags=f0, serial=110, ttl=1200)
$ sudo docker exec -it samba samba-tool dns delete localhost hogeserver.hogeddns.jp wintemp A 192.168.110.21 -U administrator
Password for [HOGEDOMAIN\administrator]:
Record deleted successfully
なお、再度ドメイン参加したときには、DNSレコードが作られた。
PLAとLAMの設定
phpLDAPadminとLDAP Account Managerをコンテナの中で動くように設定してある。
8081ポートに直接アクセスする方法でも使えるけれど、ここではApacheでSSL接続ができるようにしている。
Apacheの設定
コンテナのポート80を8081で開けているので、そこへProxyする。
今回は、ミラーサーバー(mirror.hogeserver.hogeddns.jp)への同居で、Apacheはインストール済みなので、そこに設定を追加する。
/etc/apache2/sites-available/myservice.conf
<VirtualHost *:80>
…
<VirtualHost *:443>
ServerAdmin webmaster@hogeserver.hogeddns.jp
ServerName addc.hogeserver.hogeddns.jp
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
ProxyPreserveHost On
ProxyPass /phpldapadmin http://localhost:8081/phpldapadmin
ProxyPassReverse /phpldapadmin http://localhost:8081/phpldapadmin
ProxyPass /lam http://localhost:8081/lam
ProxyPassReverse /lam http://localhost:8081/lam
<Location /phpldapadmin>
order deny,allow
Allow from 192.168.110.0/24 fdnn:nnnn:nnnn:nnnn::/64
Deny from all
</Location>
<Location /lam>
order deny,allow
Allow from 192.168.110.0/24 fdnn:nnnn:nnnn:nnnn::/64
Deny from all
</Location>
# SSL
SSLEngine on
SSLCertificateFile /etc/ssl/private/wild.hoge.crt
SSLCertificateKeyFile /etc/ssl/private/wild.hoge.key
</VirtualHost>
※このサービスにアクセスできる範囲を限定するケースがありそうなので、書き方を整理しておいた。
設定を有効化する。
$ sudo a2ensite myservice $ sudo a2enmod proxy_http ssl $ sudo systemctl restart apache2
phpLDAPadmin
phpLDAPadminは、初期設定が済ませてあって、サイトにアクセスするだけで使えるようになっている。
https://hogeserver.hogeddns.jp/phpldapadmin/
ログイン画面には、ユーザーとしてadministratorが入力されているので、パスワードだけを入力すれば利用可能。
細かな設定は、コンテナの中で/var/www/phpldapadmin/config/config.phpを変更すればOK。
LDAP Acount Managerの初期設定
こちらのサイトで色々と教えてくれている。
Server World / OpenLDAP : LDAP Account Manager インストール
LDAP Account Manager - Manual
まず、サイトにアクセスする。
https://hogeserver.hogeddns.jp/lam/
ログイン画面が表示されたら、右上の LAM configuration をクリックする。

一般的には、コンフィグファイルを手であれこれ修正するけれども、このツールはそれをGUIでできるようにしてくれている。
Edit server profilesをクリックする。

コンフィグファイルにlamという名前が付けられている。
パスワードlamを入力し、OKをクリックすると設定画面に入ることができる。

全般設定では、このような値を設定している。
Login methodとして、LDAPを選択することもできる。
サーバー証明書・秘密鍵を用意している場合、Server addressには証明書の発行先(Subject Alternative Name)にあったものにしておく。
今回用意したのは、SANにhogeserver.hogeddns.jp, *.hogeserver.hogeddns.jpが設定されているワイルドカードな証明書だったので、hogeserver.hogeddns.jpを設定した。
証明書の設定と違った名前でアクセスすると、「(-1) LDAP error, server says: Can't contact LDAP server - (unknown error code)」のエラーが発生する。

アカウントタイプの設定も重要。ユーザーが一覧表でちゃんと表示されるかどうかが決まる。

モジュールは、デフォルトで入っているものを削除して、Winodwsを追加する。


保存するとログイン画面が表示されるので、Samba ad dcに登録されているAdministratorのパスワードを入力すればログインできる。
バックアップからの復元
現行システムのバックアップを復元
現在運用中のSamba ad dcは Version 4.7.6-Ubuntu であり、samba-toolに4.9から実装されているバックアップ・リストア機能が使えない。
一番心配なのが、自前で取っているバックアップがちゃんと働くのかどうか、ということだったが、過去に実現できていなかった拡張属性の復元を追加実装することとなった。
現在動作中のSamba ad dcに影響を与えないように、本番環境にファイアウォールの設定を入れ、試験環境からアクセスできなくする。
その目的で以下を実行。テスト環境からの接続ができなくなる。
$ sudo ufw insert 1 deny from 192.168.110.4 comment "For test"
※これをやらずにテストしていたら、本番環境に入り込んでしまって、システムが色々と不具合を起こしはじめた…。
これまでhogeserer.hogeddns.jpとかやってきたが、ここで、復元の対象となるRealm、Domainをdocker-compose.ymlに書く。
また、当然、証明書類が違っているはずなので、使っている場合はpackage/certディレクトリに入れておく。
コンテナとボリュームを削除した上で、コンテナを起動する。
$ sudo docker compose down --volume $ sudo docker compose up
※まっさら状態に戻るので、もしも試験環境を取っておきたいなら、バックアップを先に取っておく。
バックアップデーターをコンテナの中に入れる。
$ sudo docker cp samba4_private.yyyy-mm-dd.tar.bz2 samba:/root/ $ sudo docker cp samba4_sysvol.yyyy-mm-dd.tar.bz2 samba:/root/
コンテナに入り復元していく。
$ sudo docker exec -it samba /bin/bash --login
# cd root
Samba ad dcのプロセスを停止。
# pkill -SIGTERM ^samba$ # pkill -SIGTERM ^rsync$ ← セカンダリーDCを立てている場合
バックアップを展開。
$ tar jxvf samba4_private.yyyy-mm-dd.tar.bz2 $ tar jxvf samba4_sysvol.yyyy-mm-dd.tar.bz2
現在のデーターを削除し、展開したバックアップデーターを配置。
# rm -rf /var/lib/samba/private/* # mv private/* /var/lib/samba/private/ # rmdir private/ # rm -rf /var/lib/samba/sysvol/* # mv sysvol/* /var/lib/samba/sysvol/ # rmdir sysvol
LDAPSを有効にしている場合、今の操作でCAファイルが消えている(バックアップにserver.crtやserver.keyがない場合)。
/var/lib/samba/private/tlsを確認して、なければコピーする。
# cp -a packages/cert/server.crt packages/cert/server.key /var/lib/samba/private/tls/
拡張属性について、復旧する方法が分かった。samba-tool ntacl set ~ が使用できる。
過去記事を修正し、拡張属性が設定できるコマンドリストを出力するようにした。ここで、実行する。
# cd /var/lib/samba # sudo bash sysvol/NTACL # sudo rm sysvol/NTACL
コンテナを抜けて、再起動。
# exit
$ sudo docker compose stop $ sudo docker compose up
※様子を見たかったので、stop→upにしたけれど、restartでも大丈夫だと思う。
復元時には、sysvolの拡張属性の再設定をするように書かれている(と思う)。
既に復元はされているはずだけれど、リセット的な意味合いもありそうなので実行しておく。
(事前に拡張属性を出力しておいて、念押し確認で一致を見るのは良いことかもしれない)
$ sudo docker exec samba net cache flush $ sudo docker exec samba samba-tool ntacl sysvolreset
コンテナに入って、軽く試してみた。
$ sudo docker exec -it samba /bin/bash --login
# samba-tool dns zonelist localhost -U rohhie Password for [MYHOME\rohhie]: 16 zone(s) found pszZoneName : hogeserver.hogeddns.jp ← 実際は、ホームラボのドメインが表示されている(マスクした) Flags : DNS_RPC_ZONE_DSINTEGRATED DNS_RPC_ZONE_UPDATE_SECURE ZoneType : DNS_ZONE_TYPE_PRIMARY Version : 50 dwDpFlags : DNS_DP_AUTOCREATED DNS_DP_DOMAIN_DEFAULT DNS_DP_ENLISTED pszDpFqdn : DomainDnsZones.hogeserver.hogeddns.jp … pszZoneName : hogeserver.hogeddns.jp ← ホームラボだけで通用するように追加したゾーン Flags : DNS_RPC_ZONE_DSINTEGRATED DNS_RPC_ZONE_UPDATE_SECURE ZoneType : DNS_ZONE_TYPE_PRIMARY Version : 50 dwDpFlags : DNS_DP_AUTOCREATED DNS_DP_DOMAIN_DEFAULT DNS_DP_ENLISTED pszDpFqdn : DomainDnsZones.hogeserver.hogeddns.jp … # dig @localhost temp.hogeserver.hogeddns.jp +short 192.168.110.2 # getent passwd root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin … MYHOME\rohhie:*:3000055:100::/home/rohhie:/bin/bash … # samba-tool user edit hogeuser → viでユーザーの情報が表示され、Kopano用の属性なども表示された。 # samba-tool group edit parent → viでグループの情報が表示され、Kopano用の属性なども表示された。
現行のシステムでも同じ情報を表示させて確認し、同じ結果が出ることを確認。
また、DNSのAレコードを書き換えて、違う結果が出ることも確認。
上手く復元ができた。
テスト環境用のバックアップ・リストア
テストが不十分なため、利用する場合は自己責任で。
Use at your own risk, Because the test is insufficient.
投稿を整理するにあたり、テスト環境は何度も何度も作り直しを繰り返していた。
一番心配だった拡張属性(NTACL)の復元ができるようになったので、テスト環境用のバックアップとリストアができるようにスクリプトを作成した。
backup.sh
#!/bin/bash # Stop the samba process. pkill -SIGTERM ^samba$ while pgrep ^samba$ [ $? -eq 0 ] do echo "wait..." sleep 1 done # Create backup files. TMP_TARGET=/root/packages/backup-$(hostname)-$(date +'%Y-%m-%d-%H-%M-%S').tar # Samba # Configuration. cd / tar -cvf $TMP_TARGET etc/samba --xattrs # Private directory. cd /var/ tar -uvf $TMP_TARGET lib/samba/private --xattrs --warning=no-file-ignored # SysVol directory. cd ./lib/samba/ find ./sysvol -exec bash -c 'TMP=$(samba-tool ntacl get "{}" --as-sddl); echo "samba-tool ntacl set \"$TMP\" \"{}\""' \; > NTACL cd ../../ tar -uvf $TMP_TARGET lib/samba/sysvol lib/samba/NTACL lib/samba/bind-dns --xattrs rm NTACL # Bind # Configuration. cd / tar -uvf $TMP_TARGET etc/bind --xattrs # Lib directory cd /var/ tar -uvf $TMP_TARGET lib/bind --xattrs # Compress. gzip $TMP_TARGET # Finish. /usr/sbin/samba --interactive --no-process-group & echo "Backed up."
※青文字のところを上手く処理すれば、本番環境をそのまま復元するのにも使えるかもしれない。
復元は少し慎重。
バックアップファイル名を指定しただけだとドライランするだけ。バックアップファイル名と共に--executeを付けると、リストアを実行する。
restore.sh
#!/bin/bash
WORKDIR=${PWD}
# Check parameters.
if [ $# = 0 ]; then
echo "Usage: restore.sh [path to backup file] [--execute]
--execute Execute a restore.
If this parameter is not present, a dry run is performed."
exit 0
fi
if [ ! -e $1 ]; then
echo "File to be restored not found: $1"
exit -1
fi
# Extract file.
if [ -d ./restore ]; then
echo "The directory \"restore\" exists. Aborted."
exit 0
fi
mkdir ./restore
tar -zxvf $1 -C ./restore
if [ $? -ne 0 ]; then
echo "Failed to extract file."
exit -1
fi
#
if [ -z $2 ]; then
# Restore acl.
cd restore/lib/samba/
bash ./NTACL
echo "Finished dry run."
elif [ $2 = "--execute" ]; then
# Stop the samba process.
pkill -SIGTERM ^samba$
while
pgrep ^samba$
[ $? -eq 0 ]
do
echo "wait..."
sleep 1
done
# Samba
# Restore files.
rm -rf /etc/samba/*
mv restore/etc/samba/* /etc/samba/
rm -rf /var/lib/samba/private/*
mv restore/lib/samba/private/* /var/lib/samba/private/
rm -rf /var/lib/samba/bind-dns
mv restore/lib/samba/bind-dns /var/lib/samba/
rm -rf /var/lib/samba/sysvol/*
mv restore/lib/samba/sysvol/* /var/lib/samba/sysvol/
# Bind
# Restore files.
rm -rf /etc/bind/*
mv restore/etc/bind/* /etc/bind/
rm -rf /var/lib/bind/*
mv restore/lib/bind/* /var/lib/bind/
# Delete working files.
rm -rf ./restore
# Restore acl.
cd /var/lib/samba
bash $WORKDIR/restore/lib/samba/NTACL
cd $WORKDIR
# Do sysvol reset.
net cache flush
samba-tool ntacl sysvolreset
# Start the samba process.
/usr/sbin/samba --interactive --no-process-group &
if [ $SMB_USEBIND9 = "true" ]; then
/usr/sbin/rndc stop
/usr/sbin/named -u bind
fi
echo "Restored."
fi
これで、テストがやりやすくなるかなと。
セカンダリーDC
何分、セカンダリーDCを構築するのは初めてのことなので、何をやるのか整理しておく必要があった。
Samba Wiki / Joining a Samba DC to an Existing Active Directory
雑廉堂Wiki / Samba DCを既存のActive Directoryに参加させる
セカンダリーDCを立ち上げる手順をざっくり整理すると、
- コンテナを起動すると、自動でsamba-toolを使ってプライマリーDCにjoinする。
- idmapを合わせる。
- プライマリーDCからsysvolを定期的に持ってくるようにする。
といったところ。
作業のベースとなるイメージの作成
こちらも何度も試行錯誤しており、ベースイメージを作った。
プライマリーDCと同じものを使っている。
ファイル構成
ファイル構成はプライマリーDCとほぼ同じだけれど、docker-compose.ymlをセカンダリーDCの設定に変更する。
また、設定用のスクリプトはセカンダリーDCに作り込んでいる。
~/samba/ ├ docker-compose.yml ├ Dockerfile ├ entrypoint.sh ← 実行権限を付ける └ packages/ ├ config-secondary.sh ← 実行権限を付ける ├ phpLDAPadmin-1.2.3.tar.gz ← あればphpLDAPadminが使えるようにする └ cert ← あればLDAPSを使えるようにする(プライマリーDCに入れたなら、こちらにも入れておく) ├ ca.crt ├ server.crt ├ server.key ← アクセス権限 0600 └ ca.crl
docker-compose.yml
架空のレルム HOGESERVER.HOGEDDNS.JP (HOGEDOMAIN) に参加する。
環境に合わせて変更するのはこのファイル。
後のファイルは、この設定に合わせて動作するようになっている。
SMB_HOSTIPでは、このコンテナを動かすホストのIPアドレスを指定しており、Join時に使う。
コンテナで動作させる=NAT配下にいるようなもの なので、この指定が必要。
SMB_PRIMARYでは、このコンテナがセカンダリーDCであることを指定している。
DNSについては、hogeserver.hogeddns.jpをプライマリーDCに聞きに行く必要があるので、 参加する際にはプライマリーDCのIPアドレスを指定しておく。
hostname: addc2としている、このaddc2がこのサーバーの名前になる。
→ addc2.hogeserver.hogeddns.jp
運用上、付けたい名前があれば、ここに設定しておく。
~/samba/docker-compose.yml
version: "3.9"
services:
samba:
build: ./
image: custom/samba:1.0.0
container_name: samba
restart: unless-stopped
environment:
TZ: Asia/Tokyo
SMB_REALM: HOGESERVER.HOGEDDNS.JP
SMB_DOMAIN: HOGEDOMAIN
SMB_ADMINPASS: p@ssword123
SMB_HOSTIP: 192.168.110.34
SMB_RPC_PORTS: 49152-49200
SMB_PURPOSE: "secondary"
SMB_USEBIND9: "false"
RSY_PRIMARY: 192.168.110.4
RSY_PASS: p@ssword234
volumes:
- samba_etc:/etc/samba
- samba_lib:/var/lib/samba
- bind_etc:/etc/bind
- bind_lib:/var/lib/bind
- lam:/var/lib/ldap-account-manager
networks:
samba:
ipv4_address: 172.26.0.102
ports:
- 192.168.110.34:53:53 #DNS
- 192.168.110.34:53:53/udp #DNS
- 192.168.110.34:135:135 #End Point Mapper(WINS)
- 192.168.110.34:137:137/udp #NetBIOS Name Service
- 192.168.110.34:138:138/udp #NetBIOS Datagram
- 192.168.110.34:139:139 #NetBIOS Session
- 192.168.110.34:445:445 #SMB over TCP
- 192.168.110.34:389:389 #LDAP
- 192.168.110.34:389:389/udp #LDAP
- 192.168.110.34:636:636 #LDAPS
- 192.168.110.34:88:88 #Kerberos
- 192.168.110.34:88:88/udp #Kerberos
- 192.168.110.34:464:464 #Kerberos kpasswd
- 192.168.110.34:464:464/udp #Kerberos kpasswd
- 192.168.110.34:3268:3268 #Global Catalog
- 192.168.110.34:3269:3269 #Global Catalog SSL
#RPC The same value as SMB_RPC_PORTS.
- 192.168.110.34:49152-49200:49152-49200
- 8081:80 #phpLDAPadmin & LDAP Account Manager
hostname: addc2
dns:
- 192.168.110.4 #Used for domain to join
#- 192.168.110.1 #Used for normal operation
dns_search:
- hogeserver.hogeddns.jp
privileged: true
devices:
- /dev/net/tun
cap_add:
- NET_ADMIN
networks:
samba:
ipam:
config:
- subnet: 172.26.0.0/16
gateway: 172.26.0.1
volumes:
samba_etc:
samba_lib:
bind_etc:
bind_lib:
lam:
config-secondary.sh
処理の流れはプライマリーDCと同様で、provitionの代わりにjoinしている。
| フェーズ | ボリューム | コンテナ | 動作 |
|---|---|---|---|
| 1 | なし | なし | Samba ad dcドメインに参加する。 /etc/samba/smb.conf はここで生成されたものを永続化している。 続けて、フェーズ2を実行する。 |
| 2 | あり | なし | 認証設定(Winbindを追加)、Kerberos設定、rsync設定、cron設定を実行する。 また、rsyncでsysvolを持ってきてsysvolresetを実行する。 また、cronには、5分ごとにrsyncを呼び出す設定を追加している。 これらは永続化していないので、コンテナが作られる度に再設定をする。 続けて、フェーズ3を実行する。 |
| 3 | あり | あり | コンテナ内部のリゾルバを127.0.0.11→127.0.0.1に向ける。 これはコンテナを実行する度に設定が必要。 結果として、Samba ad dcが名前解決をするようになる。 |
プライマリーDCと同期するという観点で設定を作り込み、とりあえずは動くレベルになったかと思う。
sysvolがレプリケーションできるように設定してみているが、ホームラボでは活用していないので、上手くでできているかどうかはファイルの状態でしか判断できていない。
~/samba/packages/config-secondary.sh
#!/bin/bash
echo "Secondary domain controller settings."
#----------------------------------------------------------------------
# New volumes.
#----------------------------------------------------------------------
if [ -z "$(ls /var/lib/samba/private)" ]; then
echo "New volumes."
# Make join parameters.
SMB_TMP_PARAM="
--username=administrator
--password=$SMB_ADMINPASS
--realm=$SMB_REALM
--option=\"dns forwarder = 127.0.0.11\"
--option=\"dns update command = /usr/sbin/samba_dnsupdate --current-ip $SMB_HOSTIP\"
--option=\"rpc server dynamic port range = $SMB_RPC_PORTS\"
--option=\"template homedir = /home/%D/%U\"
--option=\"template shell = /bin/bash\"
--option=\"winbind enum users = yes\"
--option=\"winbind enum groups = yes\"
--option=\"idmap config $SMB_DOMAIN:unix_nss_info = yes\"
--option=\"idmap config $SMB_DOMAIN:unix_primary_group = yes\"
--option=\"idmap_ldb:use rfc2307 = yes\"
"
if [ $SMB_USEBIND9 = "true" ]; then
SMB_TMP_PARAM+=" --dns-backend=BIND9_DLZ"
else
SMB_TMP_PARAM+=" --dns-backend=SAMBA_INTERNAL"
fi
# LDAPS settings.
mkdir /var/lib/samba/private/tls/
TMP_LDAPS=0
cp -a /root/packages/cert/ca.crt /usr/local/share/ca-certificates/ && \
update-ca-certificates && \
TMP_LDAPS=$(($TMP_LDAPS | 0x01)) && \
SMB_TMP_PARAM+=" --option=\"tls cafile = /usr/local/share/ca-certificates/ca.crt\""
cp -a /root/packages/cert/server.crt /var/lib/samba/private/tls/ && \
TMP_LDAPS=$(($TMP_LDAPS | 0x02)) && \
SMB_TMP_PARAM+=" --option=\"tls certfile = /var/lib/samba/private/tls/server.crt\""
cp -a /root/packages/cert/server.key /var/lib/samba/private/tls/ && \
TMP_LDAPS=$(($TMP_LDAPS | 0x04)) && \
chmod 600 /var/lib/samba/private/tls/server.key && \
SMB_TMP_PARAM+=" --option=\"tls keyfile = /var/lib/samba/private/tls/server.key\""
cp -a /root/packages/cert/ca.crl /var/lib/samba/private/tls/ && \
TMP_LDAPS=$(($TMP_LDAPS | 0x08)) && \
SMB_TMP_PARAM+=" --option=\"tls crlfile = /var/lib/samba/private/tls/ca.crl\""
if [ $(($TMP_LDAPS & 0x07)) -eq 7 ]; then
echo "Enable LDAPS."
SMB_TMP_PARAM+=" --option=\"tls enabled = true\"
--option=\"tls verify peer = as_strict_as_possible\"
"
else
echo "Disable Strong Auth."
SMB_TMP_PARAM+="
--option=\"ldap server require strong auth = no\"
"
fi
set -f
SMB_TMP_PARAM=$(echo $SMB_TMP_PARAM)
#echo "join parameters: $SMB_TMP_PARAM"
set +f
# Join domain settings.
mv --backup=numbered /etc/samba/smb.conf /etc/samba/smb.conf.bak
eval samba-tool domain join $SMB_REALM DC "$SMB_TMP_PARAM"
if [ $? -ne 0 ]; then exit 0; fi
# Deletion of IP addresses in the container registered in Primary DNS
MYHOSTIP=$(grep $(hostname) /etc/hosts | sed "s/^\(.*\)\s.*/\1/")
MYHOSTNM=$(hostname)
samba-tool dns update $SMB_REALM \
$SMB_REALM $MYHOSTNM \
A $MYHOSTIP $SMB_HOSTIP \
--username Administrator --password $SMB_ADMINPASS
# Delete myhostip after 30 sec.
/bin/bash -c "sleep 30;
samba-tool dns delete localhost \
$SMB_REALM $MYHOSTNM \
A $MYHOSTIP \
--username Administrator --password $SMB_ADMINPASS
" &
fi
#----------------------------------------------------------------------
# Volumes is left.
#----------------------------------------------------------------------
if [ ! -e /root/packages/configured ]; then
echo "New container."
# Register CA certificates.
cp -a /root/packages/cert/ca.crt /usr/local/share/ca-certificates/ && \
update-ca-certificates
# Authentication sttings.
sed -i "s/^\(passwd: \+\)[a-z ]\+$/\1compat winbind/" /etc/nsswitch.conf
sed -i "s/^\(group: \+\)[a-z ]\+$/\1compat winbind/" /etc/nsswitch.conf
# Create krb5.conf
mv --backup=numbered /etc/krb5.conf /etc/krb5.conf.bak
cat <<EOF > /etc/krb5.conf
[libdefaults]
dns_lookup_realm = false
dns_lookup_kdc = true
default_realm = $SMB_REALM
EOF
# Make rsync configuration.
cat <<EOF > /etc/rsyncd.secret.sysvol-replication
$RSY_PASS
EOF
chmod 600 /etc/rsyncd.secret.sysvol-replication
# Reset sysvol.
echo "Reset sysvol."
rsync -XAavx \
--delete-after \
--password-file=/etc/rsyncd.secret.sysvol-replication \
--contimeout=10 \
rsync://sysvol-replication@$RSY_PRIMARY/SysVol \
/var/lib/samba/sysvol/
samba-tool ntacl sysvolreset
# Replicate sysvol every 5 minutes.
echo "*/5 * * * * root rsync -XAavx --delete-after --password-file=/etc/rsyncd.secret.sysvol-replication rsync://sysvol-replication@$RSY_PRIMARY/SysVol /var/lib/samba/sysvol/" >> /etc/crontab
# Suppress apache warning.
echo "ServerName localhost" | tee /etc/apache2/conf-available/fqdn.conf
a2enconf fqdn
# Setup phpLdapAdmin.
if [ -e /root/packages/phpLDAPadmin-1.2.3.tar.gz ]; then
a2dismod php8.1
a2enmod php7.3
tar zxf /root/packages/phpLDAPadmin-1.2.3.tar.gz -C /var/www/
mv /var/www/phpLDAPadmin-1.2.3 /var/www/phpldapadmin
cp /etc/phpldapadmin/apache.conf /etc/phpldapadmin/apache.conf.bak
sed -i "s@/usr/share/phpldapadmin/htdocs@/var/www/phpldapadmin@g" /etc/phpldapadmin/apache.conf
cp /var/www/phpldapadmin/config/config.php.example /var/www/phpldapadmin//config/config.php
if [ $(grep "tls verify peer = as_strict_as_possible" /etc/samba/smb.conf -c) -ne 0 ]; then
sed -i "$ i\$servers->setValue('server','host','ldaps://$(hostname).${SMB_REALM,,}');" /var/www/phpldapadmin/config/config.php
else
sed -i "$ i\$servers->setValue('server','host','ldap://$(hostname).${SMB_REALM,,}');" /var/www/phpldapadmin/config/config.php
fi
sed -i "$ i\$servers->setValue('login','bind_id','administrator@${SMB_REALM,,}');" /var/www/phpldapadmin/config/config.php
sed -i "$ i\$config->custom->appearance['hide_template_warning'] = true;" /var/www/phpldapadmin/config/config.php
sed -i "s/\$servers->setValue('server','name','My LDAP Server');/\$servers->setValue('server','name','$SMB_DOMAIN');/" /var/www/phpldapadmin/config/config.php
# Customize phpLDAPadmin
# for PHP7.0
sed -i "s/password_hash/password_hash_custom/g" /var/www/phpldapadmin/lib/*
sed -i '2567d; 2568d; 2569i \\t\tforeach ($dn as $key => $rdn) {\n\t\t\t$a[$key] = preg_replace_callback('\''/\\\\\\([0-9A-Fa-f]{2})/'\'', function ($m) { return '\'\''.chr(hexdec('\''\\\\1'\'')).'\'\''; }, $rdn\'');\n\t\t}' /var/www/phpldapadmin/lib/functions.php
sed -i '2574c \\t\treturn preg_replace_callback('\''/\\\\\\([0-9A-Fa-f]{2})/'\'', function ($m) { return'\'\''.chr(hexdec('\''\\\\1'\'')).'\'\''; }, $dn);' /var/www/phpldapadmin/lib/functions.php
sed -i '1119d; 1120d; 1121i \\t\t\tforeach ($dn as $key => $rdn) {\n\t\t\t\t$a[$key] = preg_replace_callback('\''/\\\\\\([0-9A-Fa-f]{2})/'\'', function ($m) { return '\'\''.chr(hexdec('\''\\\\1'\'')).'\'\''; }, $rdn\'');\n\t\t\t}' /var/www/phpldapadmin/lib/ds_ldap.php
sed -i '1126c \\t\t\treturn preg_replace_callback('\''/\\\\\\([0-9A-Fa-f]{2})/'\'', function ($m) { return'\'\''.chr(hexdec('\''\\\\1'\'')).'\'\''; }, $dn);' /var/www/phpldapadmin/lib/ds_ldap.php
# for PHP7.3
sed -i '54c function my_autoload($className) {' /var/www/phpldapadmin/lib/functions.php
sed -i '777c spl_autoload_register("my_autoload");' /var/www/phpldapadmin/lib/functions.php
sed -i '1083c \\t\t$CACHE[$sortby] = __create_function('\''$a, $b'\'',$code);' /var/www/phpldapadmin/lib/functions.php
sed -i '1091a function __create_function($arg, $body) {\n\tstatic $cache = array();\n\tstatic $maxCacheSize = 64;\n\tstatic $sorter;\n\n\tif ($sorter === NULL) {\n\t\t$sorter = function($a, $b) {\n\t\t\tif ($a->hits == $b->hits) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn ($a->hits < $b->hits) ? 1 : -1;\n\t\t};\n\t}\n\n\t$crc = crc32($arg . "\\\\x00" . $body);\n\n\tif (isset($cache[$crc])) {\n\t\t++$cache[$crc][1];\n\t\treturn $cache[$crc][0];\n\t}\n\n\tif (sizeof($cache) >= $maxCacheSize) {\n\t\tuasort($cache, $sorter);\n\t\tarray_pop($cache);\n\t}\n\n\t$cache[$crc] = array($cb = eval('\''return function('\''.$arg.'\''){'\''.$body.'\''};'\''), 0);\n\treturn $cb;\n}\n' /var/www/phpldapadmin/lib/functions.php
fi
# Mark as configured.
touch /root/packages/configured
fi
#----------------------------------------------------------------------
# Container and Volumes is left.
#----------------------------------------------------------------------
echo "Setting to do every time"
# Resolver settings.
cp /etc/resolv.conf /root/packages/resolv.conf
sed -i "s/nameserver 127.0.0.11/nameserver 127.0.0.1/" /root/packages/resolv.conf
cat /root/packages/resolv.conf > /etc/resolv.conf
# Switch DNS backend.
if [ $SMB_USEBIND9 = "true" ]; then
if [ ! -e /var/lib/samba/bind-dns/named.conf ]; then
samba_upgradedns --dns-backend=BIND9_DLZ
fi
# Make bind9 configuration.
if [ $(grep "bind-dns" /etc/bind/named.conf -c) -eq 0 ]; then
cp -a /etc/bind/named.conf /etc/bind/named.conf.bak
sed -i "\$a include \"/var/lib/samba/bind-dns/named.conf\";" /etc/bind/named.conf
cp -a /etc/bind/named.conf.options /etc/bind/named.conf.options.bak
sed -i "/listen-on-v6/a\\\n\tforwarders { 127.0.0.11; };\n\tallow-query { any; };\n\tallow-transfer { none; };\n\ttkey-gssapi-keytab \"/var/lib/samba/bind-dns/dns.keytab\";\n\tminimal-responses yes;" /etc/bind/named.conf.options
cp -a /etc/bind/named.conf.local /etc/bind/named.conf.local.bak
sed -i "s@^//include@include@" /etc/bind/named.conf.local
fi
if [[ $(grep -c "server services" /etc/samba/smb.conf) -eq 0 ]]; then
sed -i "9a\\\tserver services = -dns" /etc/samba/smb.conf
fi
else
if [ -e /var/lib/samba/bind-dns/named.conf ]; then
samba_upgradedns --dns-backend=SAMBA_INTERNAL
sed -i "/server services/d" /etc/samba/smb.conf
fi
fi
ファイルを作ったら、実行権を付けておく。
$ chmod +x ~/samba/packages/config-secondary.sh
その他のファイル
その他のファイルは、プライマリーDCと同じ。
プライマリーDCからコピーしてきて配置する。
プライマリーDCでrsyncを動かす
セカンダリーDCは、プライマリーDCのsysvolを5分おきに取りに行く。
プライマリーDCでrsyncを起動して、セカンダリーDCからの要求を受け付けるようにする。
Primary: ~/samba/docker-compose.yml
…
RSY_SECONDARY: "192.168.110.34"
RSY_PASS: p@ssword234
…
※コメントを外して有効化する。
RSY_SECONDARYで、セカンダリーDCのIPアドレスを指定する。
そのまま/etc/rsyncd.conのhosts allowに設定するので、スペース区切りで複数指定することが可能。CIDR形式での指定も可能。
RSY_PASSはrsyncで使用するパスワードを設定しておく。
設定を変更したら、プライマリーDCのコンテナを起動し直す。
addc:~/samba$ sudo docker compose stop addc:~/samba$ sudo docker compose up
これで、プライマリーの起動スクリプトでrsyncが設定され、rsyncが起動する。
コンテナの起動
ファイルの準備ができたら、ファイアウォールを設定する。
$ sudo ufw allow from 172.26.0.102 to 192.168.110.34 comment "From Container"
コンテナを起動すると、自動的にドメインに参加する。
$ sudo docker compose up --build
スクリプトが処理を進めていくとき、ちょっとまずそうなエラー…例えば、rsyncに失敗などが発生したときは、設定を見直してbuildすれば良い。
ドメインに参加する際、コンテナの中で割り振られたIPアドレスをプライマリーDCに通知するようだ。
このままにしておくと、このメッセージが出続けることになる。
samba | Failed to connect host 172.26.0.102 on port 135 - NT_STATUS_HOST_UNREACHABLE samba | Failed to connect host 172.26.0.102 (12222878-52d1-4677-9d83-f15c6cc66119._msdcs.hogeserver.hogeddns.jp) on port 135 - NT_STATUS_HOST_UNREACHABLE.
これは、設定スクリプトでプライマリーDCのDNSを更新して対処している。
コンテナのIPアドレス → ホストのIPアドレス に更新。
また、セカンダリーDCのDNSには、コンテナのIP、ホストのIPの2レコードが存在する。
そのため、Sambaが起動した頃を見計らって(30秒後)、レコードを削除しに行っている。
同期が先に済んでしまってレコードがなくなっている場合もあるが、このコマンドが空振りするだけで問題はない。
なお、本来は、ネットワークインターフェースがいくつかあるなら、それをbind interfaces only設定で絞り込むのが、あるべき姿なのかなと。
Ubuntuのドメイン参加では、実際にそうしている。
ところが、bind interfaces onlyを設定してみたところ、プライマリーDCとの通信ができなくなってしまった。
適切な設定項目が見つかったら、それを設定するとして、今回は上記の対症療法を結論とした。
bind interfaces onlyを設定し、通信ができない状態になったときに、プライマリーDCに出力されていたログをメモしておく。
samba | Failed to connect host 192.168.110.34 on port 135 - NT_STATUS_CONNECTION_REFUSED samba | Failed to connect host 192.168.110.34 (3d8be95e-ad29-475b-bb3a-fd8c78c1d923._msdcs.hogeserver.hogeddns.jp) on port 135 - NT_STATUS_CONNECTION_REFUSED.
それと、コンテナが起動した後、プライマリーDCでこのエラーが出続けることがある。
samba | Failed to bind to uuid e3514235-4b06-11d1-ab04-00c04fc2dcd2 for ncacn_ip_tcp:192.168.110.34[49153,seal,krb5,target_hostname=fc27b6f2-bd9b-4bbc-b975-373f55add1d7._msdcs.hogeserver.hogeddns.jp,target_principal=GC/addc2.hogeserver.hogeddns.jp/hogeserver.hogeddns.jp,abstract_syntax=e3514235-4b06-11d1-ab04-00c04fc2dcd2/0x00000004,localaddress=172.26.0.101] NT_STATUS_UNSUCCESSFUL
止まらないようなら、プライマリーDCのコンテナを再起動する。
チケットが上手く処理できていないように見えており、krb5.confのcheck-ticket-addressesというキーワードを発見し、noaddressesを調べるに至ったが、デフォルトでtrueになっているようだ。再起動すれば解決するので、割り切り。
idmapの一致
プライマリーDCとセカンダリーDCでIDを一致させるために、以下の処理が必要とのこと。
プライマリーDCでIDマップのバックアップを取る。
addc:~/samba$ sudo docker exec samba tdbbackup -s .bak /var/lib/samba/private/idmap.ldb addc:~/samba$ sudo docker cp samba:/var/lib/samba/private/idmap.ldb.bak ./ addc:~/samba$ sudo docker exec samba rm /var/lib/samba/private/idmap.ldb.bak
セカンダリーDCに転送。
addc:~/samba$ sudo chown rohhie:rohhie idmap.ldb.bak ← 所有者rootで600なので、転送ができない…所有者を操作者に変更。 addc:~/samba$ scp idmap.ldb.bak addc2:/home/rohhie/samba/ addc:~/samba$ rm idmap.ldb.bak
※ファイルの転送方法は何でも良い。
セカンダリーDCで、Samba ad dcのプロセスを停止する。
$ sudo docker exec samba pkill -SIGTERM ^samba$
ファイルを配置して、リセットコマンドを投入。
$ sudo docker cp idmap.ldb.bak samba:/var/lib/samba/private/idmap.ldb $ sudo docker exec samba chown root:root /var/lib/samba/private/idmap.ldb $ rm idmap.ldb.bak $ sudo docker exec samba net cache flush $ sudo docker exec samba samba-tool ntacl sysvolreset
コンテナを停止して、改めて起動する。
$ sudo docker compose stop $ sudo docker compose up
これで設定ができた。
双方のコンテナの中で以下を実行したところ、ユーザーとパスワードのIDが一致していた。
# getent passwd … HOGEDOMAIN\administrator:*:0:100::/home/HOGEDOMAIN/administrator:/bin/bash HOGEDOMAIN\guest:*:3000012:100::/home/HOGEDOMAIN/guest:/bin/bash HOGEDOMAIN\krbtgt:*:3000068:100::/home/HOGEDOMAIN/krbtgt:/bin/bash HOGEDOMAIN\rohhie:*:3000023:100::/home/HOGEDOMAIN/rohhie:/bin/bash HOGEDOMAIN\ssoauth:*:3000069:100::/home/HOGEDOMAIN/ssoauth:/bin/bash HOGEDOMAIN\hoge:*:3000070:100::/home/HOGEDOMAIN/hoge:/bin/bash HOGEDOMAIN\hogewife:*:3000071:100::/home/HOGEDOMAIN/hogewife:/bin/bash # getent group … BUILTIN\cryptographic operators:x:3000096: BUILTIN\event log readers:x:3000097: BUILTIN\certificate service dcom access:x:3000098: HOGEDOMAIN\cert publishers:x:3000099: HOGEDOMAIN\ras and ias servers:x:3000100: HOGEDOMAIN\allowed rodc password replication group:x:3000101: …
DNSの修正
セカンダリーDCが立ち上がったこのタイミングでは、名前解決が以下の流れになっている。
問い合わせ(1) → [addc ] → [router]
↑
問い合わせ(2) → [addc2]
自分たちで解決できる名前(この段階ではhogeserver.hogeddns.jp)については、addcとaddc2が回答してくれるが、解決できないものはrouterに聞きに行く。
addc2がドメインに参加する時、routerはaddc.hogeserver.hogeddns.jpを知らないので、DNSとしてaddc(192.168.110.4)を指定しておく必要があった。
addc2がセカンダリーDCとして認識された今、addcとaddc2はDNSが変更される度に同期している。
さて…今、もし、addcが落ちたらどうなるか。
hogeserver.hogeddns.jpの範囲はaddc2が名前解決をしてくれる。これはOK。
だけれども、この範囲を超えた名前解決をする場合(e.g. rohhie.net)、addc2は自分で情報を持っていないので、addcに聞きに行く。
addcが落ちているので、名前解決がタイムアウトする。
addcに頼る必要はないのだから、名前解決は次のような流れにするのが望ましい。
問い合わせ(1) → [addc ] → [router]
||同期
問い合わせ(2) → [addc2] → [router]
そこで、セカンダリーDCのコンテナを一旦止める。
$ sudo docker compose stop
DNSをaddcからrouterに切り替える。
docker-compose.yml
version: "3.9"
services:
samba:
…
dns:
#- 192.168.110.4 #Used for domain to join
- 192.168.110.1 #Used for normal operation
…
セカンダリーDCを起動する。
$ sudo docker compose up
これで、addcが落ちていても、名前解決ができるようになった。
ドメインから離脱
セカンダリーDCで以下のコマンドを実行。
# samba-tool domain demote -U administrator
Using addc.hogeserver.hogeddns.jp as partner server for the demotion
Password for [HOGEDOMAIN\administrator]: ユーザーAdministraotrのパスワード[Enter]
これで、ドメインを離脱することができた。
強制的にドメインから外す
セカンダリーDCがドメインに参加した状態で、うっかりセカンダリーDCのコンテナとボリュームを削除してしまった。
この場合は、プライマリーDCから強制的にセカンダリーDCを削除する。
addc:~/samba$ sudo docker exec -it samba /bin/bash --login
# samba-tool domain demote --remove-other-dead-server=ADDC2
これで、セカンダリーDCの情報がすべて削除された。
リストアドDC
どこかのDCで行われた変更は、DC全体で同期されるので、誰かがどこかでデーターを壊せば、それが広がってしまう。
この場合、壊れたDCを停止し、バックアップからデーターを復元して(samba-tool domain backup restore)、他のDCは再度ドメインに参加する(samba-tool domain join dc)ことで、バックアップのデーターが同期される、ということのようだった。
なるほど…と、改めて、プライマリーDCとセカンダリーDCにできあがっているsmb.confを読んでみたところ、全く同じものになっていた。
同じ値が入るようにとoptionsを設定していたのは確かだけれど、それ以外の箇所もnetbios nameを除き、みんな同じ。
全く同じ設定で、全く同じ情報を持つ、そうか、そういうことだったのか。
そこから考えるリストアのシナリオは以下。
- 新しいサーバーaddcrを立てて、リストアして待ち受ける。
- addcからaddcrにjoin。
- addc2からaddcにjoin。
実際にリストアしてみると、DNSにNSの登録がない。復元用のデーターを供給するためだけに立ち上がるようだ。
バックアップ
まずはこちらを確認。
Samba Wiki / Back up and Restoring a Samba AD DC
以前のバージョンでは、samba-toolに実装されているバックアップが使えず、バックアップ対象を調べて調べて…これだろう、というものを定期的にバックアップしている。
今回のバージョンでは標準機能が使えそうだ。
# samba --version Version 4.15.9-Ubuntu
※4.9以降で標準機能が使える。ありがたい。
さて、プライマリーDCで、以下のコマンドを実行。
offlineはローカルのサーバーのバックアップを取ることを指し示しているだけで、稼働中でも問題なくバックアップが取れるとのこと。
# samba-tool domain backup offline --targetdir=/root/ # ll /root -rw-r--r-- 1 root root 1738308 Aug 14 13:55 samba-backup-2022-08-14T13-55-02.655028.tar.bz2
できあがった、samba-backup-<datetime>.tar.bz2を保管しておけば良い。
作業のベースとなるイメージの作成
こちらも何度も試行錯誤しており、ベースイメージを作った。
プライマリーDCと同じものを使っている。
ファイル構成
ファイル構成はプライマリーDCとほぼ同じだけれど、docker-compose.ymlをリストアドDCの設定に変更する。
設定用のスクリプトはリストアドDC用に作り込んであり、packagesディレクトリに放り込んだバックアップファイルを使ってリストアする。
~/samba/
├ docker-compose.yml
├ Dockerfile
├ entrypoint.sh ← 実行権限を付ける
└ packages/
├ config-restore.sh ← 実行権限を付ける
├ phpLDAPadmin-1.2.3.tar.gz ← あればphpLDAPadminが使えるようにする
├ samba-backup-YYYY-MM-DDTHH-MM-SS.nnnnnn.tar.bz2 ← 標準機能で作成したバックアップ
└ cert ← プライマリーDCやセカンダリーDCで入れている場合には必要
├ ca.crt
├ server.crt
├ server.key ← アクセス権限 0600
└ ca.crl
docker-compose.yml
プライマリーDC、セカンダリーDCとほとんど同じ。
IPアドレスとホスト名だけが変わっている。
~/samba/docker-compose.yml
version: "3.9"
services:
samba:
#image: ubuntu:jammy
build: ./
image: custom/samba:1.0.0
container_name: samba
restart: unless-stopped
environment:
TZ: Asia/Tokyo
SMB_REALM: HOGESERVER.HOGEDDNS.JP
SMB_DOMAIN: HOGEDOMAIN
SMB_ADMINPASS: p@ssword123
SMB_HOSTIP: 192.168.110.10
SMB_RPC_PORTS: 49152-49200
SMB_PURPOSE: "restore"
volumes:
- samba_etc:/etc/samba
- samba_lib:/var/lib/samba
- bind_etc:/etc/bind
- bind_lib:/var/lib/bind
- lam:/var/lib/ldap-account-manager
networks:
samba:
ipv4_address: 172.26.0.103
ports:
- 192.168.110.10:53:53 #DNS
- 192.168.110.10:53:53/udp #DNS
- 192.168.110.10:135:135 #End Point Mapper(WINS)
- 192.168.110.10:137:137/udp #NetBIOS Name Service
- 192.168.110.10:138:138/udp #NetBIOS Datagram
- 192.168.110.10:139:139 #NetBIOS Session
- 192.168.110.10:445:445 #SMB over TCP
- 192.168.110.10:389:389 #LDAP
- 192.168.110.10:389:389/udp #LDAP
- 192.168.110.10:636:636 #LDAPS
- 192.168.110.10:88:88 #Kerberos
- 192.168.110.10:88:88/udp #Kerberos
- 192.168.110.10:464:464 #Kerberos kpasswd
- 192.168.110.10:464:464/udp #Kerberos kpasswd
- 192.168.110.10:3268:3268 #Global Catalog
- 192.168.110.10:3269:3269 #Global Catalog SSL
#RPC The same value as SMB_RPC_PORTS.
- 192.168.110.10:49152-49200:49152-49200
- 873:873 #rsync
- 8081:80 #phpLDAPadmin & LDAP Account Manager
hostname: addcr
dns:
- 192.168.110.1
dns_search:
- hogeserver.hogeddns.jp
privileged: true
devices:
- /dev/net/tun
cap_add:
- NET_ADMIN
networks:
samba:
ipam:
config:
- subnet: 172.26.0.0/16
gateway: 172.26.0.1
volumes:
samba_etc:
samba_lib:
bind_etc:
bind_lib:
lam:
config-restore.sh
用意されたバックアップデータを復元して実行する。
本来のSambaの実装では、リストアされたディレクトリで上手く動く想定だけれども、せっかくのまっさら環境なので、復元したデーターを標準のディレクトリに移動し、復元時にsmb.confに入れられるディレクトリ指定を消して、標準的なディレクトリで起動させている。
証明書関係は、プライマリーDCやセカンダリーDCに入っている場合に、smb.confと共に復旧されるが、ca.crtだけは/usr/local/share/ca-certificatsに保管してあるのでバックアップ対象になっておらず、復旧できない。そのため、コンテナ起動時に与えてあげる必要がある。これは失敗だったなーと思うものの、CAの証明書なら持っているだろうし、なくしても作り直せば良いのだから、きっと困ることはないだろう。割り切りとする。
DNSバックエンドがBIND9だった場合、リストアされた環境でもBIND9で動かそうと考えたのだけれども、管理するゾーンのNSがないためエラーが発生して起動できなかった。NSはプライマリーが接続するときに登録されるようになっている訳なので、DNSバックエンドを内蔵のものに切り替える処理を入れている。
~/samba/packages/config-restore.sh
#!/bin/bash
echo "Restore domain controller settings."
#----------------------------------------------------------------------
# New volumes.
#----------------------------------------------------------------------
if [ -z "$(ls /var/lib/samba/private)" ]; then
echo "New volumes."
if [ $(ls /root/packages/samba-backup-* | wc -w) -ne 1 ]; then
echo "There must be one backup file."
exit 0
fi
samba-tool domain backup restore \
--backup-file=$(ls /root/packages/samba-backup-*) \
--newservername=$(hostname) \
--targetdir=/root/packages/restore \
--host-ip=$SMB_HOSTIP
mv /root/packages/restore/etc/* /etc/samba/
rmdir /root/packages/restore/etc
mv /root/packages/restore/private/* /var/lib/samba/private/
rmdir /root/packages/restore/private
mv /root/packages/restore/state/sysvol /var/lib/samba/
mv /root/packages/restore/state/bind-dns /var/lib/samba/
mv /root/packages/restore/state/*.tdb /var/lib/samba/
rmdir /root/packages/restore/state
rm /root/packages/restore/gencache.tdb
rm /root/packages/restore/backup.txt
rmdir /root/packages/restore
sed -i "/binddns dir/d" /etc/samba/smb.conf
sed -i "/cache directory/d" /etc/samba/smb.conf
sed -i "/lock directory/d" /etc/samba/smb.conf
sed -i "/private dir/d" /etc/samba/smb.conf
sed -i "/state directory/d" /etc/samba/smb.conf
sed -i "s/--current-ip [0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}/--current-ip $SMB_HOSTIP/" /etc/samba/smb.conf
sed -i "s@/root/packages/restore/state/sysvol@/var/lib/samba/sysvol@g" /etc/samba/smb.conf
# Change the DNS back end to internal.
if [ -e /var/lib/samba/bind-dns/named.conf ]; then
samba_upgradedns --dns-backend=samba_internal
sed -i "/server services/d" /etc/samba/smb.conf
fi
fi
#----------------------------------------------------------------------
# Volumes is left.
#----------------------------------------------------------------------
if [ ! -e /root/packages/configured ]; then
echo "New container."
# Register CA certificates.
cp -a /root/packages/cert/ca.crt /usr/local/share/ca-certificates/ && \
update-ca-certificates
# Authentication sttings.
sed -i "s/^\(passwd: \+\)[a-z ]\+$/\1compat winbind/" /etc/nsswitch.conf
sed -i "s/^\(group: \+\)[a-z ]\+$/\1compat winbind/" /etc/nsswitch.conf
# Copy krb5.conf
mv --backup=numbered /etc/krb5.conf /etc/krb5.conf.bak
cp /var/lib/samba/private/krb5.conf /etc/
# Suppress apache warning.
echo "ServerName localhost" | tee /etc/apache2/conf-available/fqdn.conf
a2enconf fqdn
# Setup phpLdapAdmin.
if [ -e /root/packages/phpLDAPadmin-1.2.3.tar.gz ]; then
a2dismod php8.1
a2enmod php7.3
if [ $(grep "ldap server require strong auth" /etc/samba/smb.conf -c) -ne 0 ]; then
sed -i "/ldap server require strong auth/d" /etc/samba/smb.conf
fi
sed -i "/\[global\]/a \\\tldap server require strong auth = no" /etc/samba/smb.conf
tar zxf /root/packages/phpLDAPadmin-1.2.3.tar.gz -C /var/www/
mv /var/www/phpLDAPadmin-1.2.3 /var/www/phpldapadmin
cp /etc/phpldapadmin/apache.conf /etc/phpldapadmin/apache.conf.bak
sed -i "s@/usr/share/phpldapadmin/htdocs@/var/www/phpldapadmin@g" /etc/phpldapadmin/apache.conf
cp /var/www/phpldapadmin/config/config.php.example /var/www/phpldapadmin//config/config.php
sed -i "$ i\$servers->setValue('server','host','ldap://127.0.0.1');" /var/www/phpldapadmin/config/config.php
sed -i "$ i\$servers->setValue('login','bind_id','administrator@${SMB_REALM,,}');" /var/www/phpldapadmin/config/config.php
sed -i "$ i\$config->custom->appearance['hide_template_warning'] = true;" /var/www/phpldapadmin/config/config.php
sed -i "s/\$servers->setValue('server','name','My LDAP Server');/\$servers->setValue('server','name','$SMB_DOMAIN');/" /var/www/phpldapadmin/config/config.php
# Customize phpLDAPadmin
# for PHP7.0
sed -i "s/password_hash/password_hash_custom/g" /var/www/phpldapadmin/lib/*
sed -i '2567d; 2568d; 2569i \\t\tforeach ($dn as $key => $rdn) {\n\t\t\t$a[$key] = preg_replace_callback('\''/\\\\\\([0-9A-Fa-f]{2})/'\'', function ($m) { return '\'\''.chr(hexdec('\''\\\\1'\'')).'\'\''; }, $rdn\'');\n\t\t}' /var/www/phpldapadmin/lib/functions.php
sed -i '2574c \\t\treturn preg_replace_callback('\''/\\\\\\([0-9A-Fa-f]{2})/'\'', function ($m) { return'\'\''.chr(hexdec('\''\\\\1'\'')).'\'\''; }, $dn);' /var/www/phpldapadmin/lib/functions.php
sed -i '1119d; 1120d; 1121i \\t\t\tforeach ($dn as $key => $rdn) {\n\t\t\t\t$a[$key] = preg_replace_callback('\''/\\\\\\([0-9A-Fa-f]{2})/'\'', function ($m) { return '\'\''.chr(hexdec('\''\\\\1'\'')).'\'\''; }, $rdn\'');\n\t\t\t}' /var/www/phpldapadmin/lib/ds_ldap.php
sed -i '1126c \\t\t\treturn preg_replace_callback('\''/\\\\\\([0-9A-Fa-f]{2})/'\'', function ($m) { return'\'\''.chr(hexdec('\''\\\\1'\'')).'\'\''; }, $dn);' /var/www/phpldapadmin/lib/ds_ldap.php
# for PHP7.3
sed -i '54c function my_autoload($className) {' /var/www/phpldapadmin/lib/functions.php
sed -i '777c spl_autoload_register("my_autoload");' /var/www/phpldapadmin/lib/functions.php
sed -i '1083c \\t\t$CACHE[$sortby] = __create_function('\''$a, $b'\'',$code);' /var/www/phpldapadmin/lib/functions.php
sed -i '1091a function __create_function($arg, $body) {\n\tstatic $cache = array();\n\tstatic $maxCacheSize = 64;\n\tstatic $sorter;\n\n\tif ($sorter === NULL) {\n\t\t$sorter = function($a, $b) {\n\t\t\tif ($a->hits == $b->hits) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn ($a->hits < $b->hits) ? 1 : -1;\n\t\t};\n\t}\n\n\t$crc = crc32($arg . "\\\\x00" . $body);\n\n\tif (isset($cache[$crc])) {\n\t\t++$cache[$crc][1];\n\t\treturn $cache[$crc][0];\n\t}\n\n\tif (sizeof($cache) >= $maxCacheSize) {\n\t\tuasort($cache, $sorter);\n\t\tarray_pop($cache);\n\t}\n\n\t$cache[$crc] = array($cb = eval('\''return function('\''.$arg.'\''){'\''.$body.'\''};'\''), 0);\n\treturn $cb;\n}\n' /var/www/phpldapadmin/lib/functions.php
fi
# Mark as configured.
touch /root/packages/configured
fi
#----------------------------------------------------------------------
# Container and Volumes is left.
#----------------------------------------------------------------------
echo "Setting to do every time"
# Resolver settings.
cp /etc/resolv.conf /root/packages/resolv.conf
sed -i "s/nameserver 127.0.0.11/nameserver 127.0.0.1/" /root/packages/resolv.conf
cat /root/packages/resolv.conf > /etc/resolv.conf
ファイルを作ったら、実行権を付けておく。
$ chmod +x ~/samba/packages/config-restore.sh
その他のファイル
その他のファイルは、プライマリーDCと同じ。
プライマリーDCからコピーしてきて配置する。
コンテナの起動
ファイルの準備ができたら、ファイアウォールを設定する。
$ sudo ufw allow from 172.26.0.103 to 192.168.110.10 comment "From Container"
コンテナを起動する。
$ sudo docker compose up --build
スクリプトによりリストアされるので、どんな状態になっているのか確認してみたところ、ユーザーは復元していた。
$ sudo docker exec -it samba /bin/bash --login
# samba-tool user list hogewife ssoauth Administrator hoge Guest rohhie krbtgt
コンピューターを確認すると、プライマリーDCとセカンダリーDCが存在しない。
# samba-tool computer list ADDCR$ WORK$ WINTEMP$
DNSにはNSが登録されておらず、addcやaddc2に関する情報はない。
これこそが、復元用のDCたらしめている設定、ということのようだ(addcrはNSではなく、これからJoinするDCがNSになっていく)。
# samba-tool dns query localhost hogeserver.hogeddns.jp @ all -U administrator
Password for [HOGEDOMAIN\administrator]:
Name=, Records=1, Children=0
SOA: serial=33, refresh=900, retry=600, expire=86400, minttl=3600, ns=addcr.hogeserver.hogeddns.jp., email=hostmaster.hogeserver.hogeddns.jp. (flags=600000f0, serial=110, ttl=3600)
Name=WINTEMP, Records=1, Children=0
A: 192.168.110.21 (flags=f0, serial=110, ttl=1200)
Name=work, Records=1, Children=0
A: 192.168.110.3 (flags=f0, serial=110, ttl=3600)
プライマリーDCの復旧
ドメインに参加
リストアドDCに、プライマリーDCを参加させてみる。
addc:~/samba$ sudo docker exec -it samba /bin/bash --login
# samba-tool domain join HOGESERVER.HOGEDDNS.JP DC --server=192.168.110.10 -U administrator
Joinはできたようだ。
addcrでDNSの状態を見てみる。
# samba-tool dns query localhost hogeserver.hogeddns.jp @ all -U administrator
Password for [HOGEDOMAIN\administrator]:
Name=, Records=1, Children=0
SOA: serial=16, refresh=900, retry=600, expire=86400, minttl=3600, ns=addcr.hogeserver.hogeddns.jp., email=hostmaster.hogeserver.hogeddns.jp. (flags=600000f0, serial=16, ttl=3600)
Name=addc, Records=1, Children=0
A: 172.26.0.101 (flags=f0, serial=16, ttl=900)
Name=WINTEMP, Records=1, Children=0
A: 192.168.110.21 (flags=f0, serial=110, ttl=1200)
Name=work, Records=1, Children=0
A: 192.168.110.3 (flags=f0, serial=110, ttl=3600)
joinする際に、--host-ipを指定したかったが、そのようなオプションはなかったので、addcがコンテナの中で割り当てているIPアドレスが設定されている。
addcとaddcr双方でIPアドレスを修正する。
# samba-tool dns update localhost hogeserver.hogeddns.jp addc A 172.26.0.101 192.168.110.4 -U administrator # samba-tool dns update 192.168.110.10 hogeserver.hogeddns.jp addc A 172.26.0.101 192.168.110.4 -U administrator # exit
addcのコンテナを再起動する。
addc:~/samba$ sudo docker compose stop addc:~/samba$ sudo docker compose up
他のコンソールで中に入り、DNSの状態を確認してみる。
addc:~/samba$ sudo docker exec -it samba /bin/bash --login
# samba-tool dns query localhost hogeserver.hogeddns.jp @ all -U administrator
Password for [HOGEDOMAIN\administrator]:
Name=, Records=3, Children=0
SOA: serial=34, refresh=900, retry=600, expire=86400, minttl=3600, ns=addcr.hogeserver.hogeddns.jp., email=hostmaster.hogeserver.hogeddns.jp. (flags=600000f0, serial=34, ttl=3600)
NS: addc.hogeserver.hogeddns.jp. (flags=600000f0, serial=18, ttl=900)
A: 192.168.110.4 (flags=600000f0, serial=19, ttl=900)
Name=_sites, Records=0, Children=1
Name=_tcp, Records=0, Children=4
Name=_udp, Records=0, Children=2
Name=addc, Records=1, Children=0
A: 192.168.110.4 (flags=f0, serial=17, ttl=900)
Name=DomainDnsZones, Records=0, Children=2
Name=ForestDnsZones, Records=0, Children=2
Name=WINTEMP, Records=1, Children=0
A: 192.168.110.21 (flags=f0, serial=110, ttl=1200)
Name=work, Records=1, Children=0
A: 192.168.110.3 (flags=f0, serial=110, ttl=3600)
修正できた。
この修正は、今のコンテナの環境で起動しているから必要なのであって、smb.confでbind interface指定ができる環境なら、Joinするだけでこの状態になりそうだ。
IDマップの復旧
結論からすると、idmap.ldbを復旧すれば良いように見える。
とりあえず、見てみよう。
一旦、ユーザーとグループを列挙させる。
# getent passwd # getent group
続いて、
# ldbsearch -H /var/lib/samba/private/sam.ldb '(sAMAccountName=*)' sAMAccountName objectSid > /tmp/sam.txt # ldbsearch -H /var/lib/samba/private/idmap.ldb dn xidNumber > /tmp/idmap.txt
この段階で、sam.ldbが52レコード程、idmap.ldbで37行出力された。
思った通りにできず、かっこ悪いけれど、加工メモ。
# sed -zi "s/\n/\t/g" /tmp/sam.txt # sed -i "s/#/\n#/g" /tmp/sam.txt
sam.ldbについて、復旧前後をExcelで適当に加工して比較してみたところ、完全に一致した。
idmap.ldbについても、同様の加工をして比較してみたところ、完全に一致した。
セカンダリーDCでJoinしたときと同様の手順を踏めば、問題なく復旧できるところが見えた。
復旧中のaddcで以下を実行。バックアップファイルの名前は適宜変更する。
addc:~/samba$ sudo docker exec -it samba mkdir /root/packages/work addc:~/samba$ sudo docker cp samba-backup-YYYY-MM-DDTHH-MM-SS.nnnnnn.tar.bz2 samba:/root/packages/work/ addc:~/samba$ sudo docker exec -it samba /bin/bash --login
■プロセス停止 # pkill -SIGTERM ^samba$ ■IDマップの上書き # cd /root/packages/work/ # tar jxvf samba-backup-2022-08-20T13-28-16.775420.tar.bz2 # cp private/idmap.ldb /var/lib/samba/private/
sysvolの拡張属性の復旧
ここまできて、sysvolには拡張属性がセットされていることを思い出した。
拡張属性を見るコマンドはというと…
雑廉堂Wiki / Windows ACLs を利用して共有を設定する
Samba Wiki / Setting up a Share Using Windows ACLs
# samba-tool ntacl get /var/lib/samba/sysvol/hogeserver.hogeddns.jp/ --as-sddl
これを踏まえて、展開した上で、拡張属性を設定する。
# rm -r /var/lib/samba/sysvol/*
# tar -zxvf sysvol.tar.gz -C /var/lib/samba/sysvol/
# find /var/lib/samba/sysvol/ -name "*.NTACL" -exec bash -c 'TMP=$(dirname "{}")/$(basename "{}" .NTACL); samba-tool ntacl set $(cat "{}") "$TMP" && rm "{}"' \;
# net cache flush
# samba-tool ntacl sysvolreset
# exit
コンテナを再起動する。
addc:~/samba$ sudo docker compose stop addc:~/samba$ sudo docker compose up
この後、Windowsでグループポリシーの管理を開いたところ、接続できない旨のエラーが表示された。
何度開き直しても、このメッセージが表示される。
そこで、このドメインを一度削除し、改めてhogeserver.hogeddns.jpを追加したところ、問題が解消した。
少しずつ調整は必要だが、以上でプライマリーDCの復旧が完了した。
FSMOロールの復旧
テスト環境でKopanoを起動し、LDAP認証させてみようとした。
その過程で、スキーマの登録をしたところ、このようなエラーが出た。
# bash kopano_schema_add.sh DC=hogeserver,DC=hogeddns,DC=jp ./ \
-H ldap://addc2.hogeserver.hogeddns.jp \
-U Administrator%p@ssword123 \
-writechanges
dos2unix: converting file kopano-ads.ldf.unix to Unix format...
ERR: (Unwilling to perform) "LDAP error 53 LDAP_UNWILLING_TO_PERFORM - <00002035: schema_data_add: we are not master: reject add request
> <>" on DN CN=Kopano-Quota-Override,CN=Schema,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp at block before line 21
Modify failed after processing 0 records
Error: ldbmodify reported an error
FSMOロールの復旧が必要なことが分かった。
[Samba] We are not schema master on all DCs
# samba-tool fsmo show SchemaMasterRole owner: CN=NTDS Settings,CN=ADDCR,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp InfrastructureMasterRole owner: CN=NTDS Settings,CN=ADDCR,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp RidAllocationMasterRole owner: CN=NTDS Settings,CN=ADDCR,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp PdcEmulationMasterRole owner: CN=NTDS Settings,CN=ADDCR,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp DomainNamingMasterRole owner: CN=NTDS Settings,CN=ADDCR,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp DomainDnsZonesMasterRole owner: CN=NTDS Settings,CN=ADDCR,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp ForestDnsZonesMasterRole owner: CN=NTDS Settings,CN=ADDCR,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp
以下のコマンドで復旧できる。
# samba-tool fsmo seize --role=all -U administrator Attempting transfer... Transfer unsuccessful, seizing... Seizing rid FSMO role... FSMO seize of 'rid' role successful … Attempting transfer... Failed to connect to ldap URL 'ldap://d0764035-7f49-43fb-bf4e-d37cf7bb8f49._msdcs.hogeserver.hogeddns.jp' - LDAP client internal error: NT_STATUS_OBJECT_NAME_NOT_FOUND Failed to connect to 'ldap://d0764035-7f49-43fb-bf4e-d37cf7bb8f49._msdcs.hogeserver.hogeddns.jp' with backend 'ldap': LDAP client internal error: NT_STATUS_OBJECT_NAME_NOT_FOUND …
※途中でエラーが2つ出るけれども、成功の表示が7回。ロールは7つなので、恐らくは問題ないであろう。
復旧したようだ。
# samba-tool fsmo show SchemaMasterRole owner: CN=NTDS Settings,CN=ADDC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp InfrastructureMasterRole owner: CN=NTDS Settings,CN=ADDC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp RidAllocationMasterRole owner: CN=NTDS Settings,CN=ADDC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp PdcEmulationMasterRole owner: CN=NTDS Settings,CN=ADDC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp DomainNamingMasterRole owner: CN=NTDS Settings,CN=ADDC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp DomainDnsZonesMasterRole owner: CN=NTDS Settings,CN=ADDC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp ForestDnsZonesMasterRole owner: CN=NTDS Settings,CN=ADDC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=hogeserver,DC=hogeddns,DC=jp
セカンダリーDCの復旧
こちらは、一旦まっさらに戻して、復旧したaddcにjoinすることにした。
$ sudo docker compose down --volume
DNSをプライマリーDCに変更する。
docker-compose.yml
version: "3.9"
services:
samba:
…
dns:
dns:
- 192.168.110.4 #Used for domain to join
#- 192.168.110.1 #Used for normal operation
…
コンテナを起動。
$ sudo docker compose up --build
この後に、IDマップを一致させるために、idmap.ldbをコピーして反映させ、DNSの設定を元に戻してコンテナを再起動。
プライマリーDCはrsyncの設定済みなので、Joinさえ上手くいけば復旧が完了する。
1回目は、addcのDNSにaddc2がNSとして登録されない問題が発生した。
もう一度まっさらにして、2回目に成功した。
2回目は、addcにaddc2のAレコードが登録されていたので、これが良かったようだ。
コンテナのIPアドレスが追加されてしまう問題がどうしても発生するが、その他の運用はかなり楽になるので、致し方ないところ。
以上で、セカンダリーDCの復旧が完了した。


コメントはこちらから お気軽にどうぞ ~ 投稿に関するご意見・感想・他