Edited at

FreeBSD 12.0 on Raspberry Pi 3 B+ で Samba AD を構築

主な流れは Samba Wiki の通り。

なお、ここでは以下の環境でセットアップを行う


  • IPv4 Address: 192.168.160.19/24

  • 上位の DNS サーバ: 192.168.160.1

  • FQDN: server-dcl01.ad.example.com

  • Active Directory ドメイン名: ad.example.com

  • NetBIOS ドメイン名: EXAMPLE

  • DNS については Samba 内蔵ではなく BIND を使用

この際の /etc/rc.conf は以下の通り


/etc/rc.conf

#hostname="generic"

#ifconfig_DEFAULT="DHCP"
sshd_enable="YES"
sendmail_enable="NONE"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"
growfs_enable="YES"

## ---- additional ---- ##
hostname="server-dcl01.ad.example.com"
ifconfig_ue0="inet 192.168.160.19 netmask 255.255.255.0"
defaultrouter="192.168.160.1"


また FreeBSD 12.0-RELEASE 及び Raspberry Pi でと謳ってはいるが、10.x や 11.x 及び i386 や amd64 でも同様の手順で構築できる1


net/samba48 をインストール


pkg から

Raspberry Pi 3 B+ (aarch64) 向けの pkg Repository が提供されているので2、 pkg コマンドから必要なものはすべてインストールできる。

# pkg install samba48

Updating FreeBSD repository catalogue...
pkg: Repository FreeBSD load error: access repo file(/var/db/pkg/repo-FreeBSD.sqlite) failed: No such file or directory
Fetching meta.txz: 100% 940 B 0.9kB/s 00:01
Fetching packagesite.txz: 100% 6 MiB 327.3kB/s 00:18
Processing entries: 100%
FreeBSD repository update completed. 29068 packages processed.
All repositories are up to date.
Updating database digests format: 100%
(略)


ports から

もちろん ports から build してインストールすることもできる。その場合必要なものすべてを build するのに大体 8時間くらいかかる(かかった)。


dns/bind911 をインストール

BIND に関しては、標準から変更する箇所があるので、 pkg ではなく ports からインストール必要がある。

変更箇所は


  • GSSAPI_HEIMDAL Using security/heimdal

を有効にすること(標準では GSSAPI_NONE となっている)3

選択肢として Base システムの Heimdal を使う GSSAPI_BASE もあるが、こちらでは Dynamic DNS Update が正しく行われなない(詳しくは後述)。


作業前に


/etc/hosts

DC としての自分自身の名前を解決できるように /etc/hosts に下記を追記

192.168.160.19   server-dcl01.ad.example.com server-dcl01


/etc/fstab

Samba で Active Directory を組む際には、使用するファイルシステムが POSIX ACL をサポートしている必要があるため4、 /etc/fstab へ acls 追記した上で再起動するか、またはファイルシステムをマウントし直しておく

# Custom /etc/fstab for FreeBSD embedded images

/dev/ufs/rootfs / ufs rw,acls 1 1
/dev/msdosfs/MSDOSBOOT /boot/msdos msdosfs rw,noatime 0 0
tmpfs /tmp tmpfs rw,mode=1777,size=50m 0 0

# mount -u -o acls /

# mount
/dev/ufs/rootfs on / (ufs, local, soft-updates, acls)
devfs on /dev (devfs, local, multilabel)
/dev/msdosfs/MSDOSBOOT on /boot/msdos (msdosfs, local, noatime)
tmpfs on /tmp (tmpfs, local)


一度 Samba の設定を行っている場合


  • 既存の /usr/local/etc/smb4.conf は削除

  • /var/db/samba4 以下に以前の環境のファイルがないこと確認

  • /etc/krb5.conf を削除


プロビジョニング (Active Directory ドメインの作成)

設定してるパラメータは以下の通り


  • --domain : NETBIOS ドメイン EXAMPLE

  • --realm : Active Directory ドメイン ad.example.com

  • --adminpass : Administrator パスワード(大文字小文字数字混在 8文字以上。これを満たさないとエラー)5

  • --use-rfc2307 : POSIX 属性 (UID/GID) を格納可能にする

  • --dns-backend : DNS Backend を指定。ここでは BIND 9.11 を用いるので BIND9_DLZ

  • --server-role : Domain Controller として設定しているので dc

実行すると下記の通り。

# samba-tool domain provision --domain=EXAMPLE --realm=ad.example.com --adminpass=XXXXXXXXXX --use-rfc2307 --dns-backend=BIND9_DLZ --server-role dc

Looking up IPv4 addresses
Looking up IPv6 addresses
No IPv6 address will be assigned
Setting up share.ldb
Setting up secrets.ldb
Setting up the registry
Setting up the privileges database
Setting up idmap db
Setting up SAM db
Setting up sam.ldb partitions and settings
Setting up sam.ldb rootDSE
Pre-loading the Samba 4 and AD schema
Adding DomainDN: DC=ad,DC=example,DC=com
Adding configuration container
Setting up sam.ldb schema
Setting up sam.ldb configuration data
Setting up display specifiers
Modifying display specifiers
Adding users container
Modifying users container
Adding computers container
Modifying computers container
Setting up sam.ldb data
Setting up well known security principals
Setting up sam.ldb users and groups
Setting up self join
Adding DNS accounts
Creating CN=MicrosoftDNS,CN=System,DC=ad,DC=example,DC=com
Creating DomainDnsZones and ForestDnsZones partitions
Populating DomainDnsZones and ForestDnsZones partitions
See /var/db/samba4/private/named.conf for an example configuration include file for BIND
and /var/db/samba4/private/named.txt for further documentation required for secure DNS updates
Setting up sam.ldb rootDSE marking as synchronized
Fixing provision GUIDs
A Kerberos configuration suitable for Samba AD has been generated at /var/db/samba4/private/krb5.conf
Setting up fake yp server settings
Once the above files are installed, your Samba AD server will be ready to use
Server Role: active directory domain controller
Hostname: server-dcl01
NetBIOS Domain: EXAMPLE
DNS Domain: ad.example.com
DOMAIN SID: S-1-5-21-XXXXXXXXXX-XXXXXXXXX-XXXXXXXXXX

なお、 --interactive として対話的に設定を行うこともできる。

# samba-tool domain provision --use-rfc2307 --interactive

これによって生成される設定ファイルは /usr/local/etc/smb4.conf に置かれる


smb4.conf

# Global parameters

[global]
netbios name = SERVER-DCL01
realm = AD.EXAMPLE.COM
server role = active directory domain controller
server services = s3fs, rpc, nbt, wrepl, ldap, cldap, kdc, drepl, winbindd, ntp_signd, kcc, dnsupdate
workgroup = EXAMPLE
idmap_ldb:use rfc2307 = yes

[netlogon]
path = /var/db/samba4/sysvol/ad.example.com/scripts
read only = No

[sysvol]
path = /var/db/samba4/sysvol
read only = No



プロビジョニング後の諸設定


Kerberos

/var/db/sabma4/private/ 以下に krb5.conf が生成されているので、これを /etc/ へコピー 6


BIND 9.11

今回は DNS 周りを BIND で賄うため、Active Directory の構築に必要な設定を named.conf に追記しておく。なお、ここでは


  • Active Directory 以外の用途では BIND を使用しない

  • Active Directory 管理外の問い合わせ内容については、 forwarder で上位の DNS へ転送

とする。


/usr/local/etc/namedb/namede.conf

// If named is being used only as a local resolver, this is a safe default.

// For named to be accessible to the network, comment this option, specify
// the proper IP address, or delete this option.
listen-on { 192.168.160.19; 127.0.0.1; };

// If you have IPv6 enabled on this system, uncomment this option for
// use as a local resolver. To give access to the network, specify
// an IPv6 address, or the keyword "any".
// listen-on-v6 { ::1; };

// Dynamic DNS Updates Using Kerberos
tkey-gssapi-keytab "/var/db/samba4/private/dns.keytab";
// tkey-gssapi-keytab "/usr/local/etc/named/dns.keytab";
tkey-domain "AD.EXAMPLE.COM";

// acl
allow-query { 192.168.160.0/24; 127.0.0.1; };

(中略)

// If you've got a DNS server around at your upstream provider, enter
// its IP address here, and enable the line below. This will make you
// benefit from its cache, thus reduce overall DNS traffic in the Internet.

forwarders {
192.168.160.1;
};

(中略)

// include bind9_dlz module settings
include "/var/db/samba4/private/named.conf";


更に、場合によっては...

Dynamic DNS Update が正しく行われているかの確認のため、下記のような設定を加えておくとトラブルシュートが楽になる。


/usr/local/etc/namedb/named.conf

// logging

category database { log_database ; } ;
channel log_database {
file "/var/log/named/database.log" versions 4 size 1m ;
severity info ;
print-time yes ;
print-severity yes ;
print-category yes ;
} ;

category update { log_update ; } ;
category update-security { log_update ; } ;
channel log_update {
file "/var/log/named/update.log" versions 4 size 1m ;
severity debug ;
print-time yes ;
print-severity yes ;
print-category yes ;
} ;



/var/db/samba4/private/named.conf

    # For BIND 9.11.x

database "dlopen /usr/local/lib/shared-modules/bind9/dlz_bind9_11.so -d 3";


注意点として、/var/db/samba4/private/named.conf を include している箇所は 必ず name.conf の options セクション外に記述 すること。でないと

/var/db/samba4/private/named.conf:12: unknown option 'dlz'

と警告され、bind が起動しない。

ここまでで BIND の設定は一通り完了する。

あとは /etc/rc.conf へ自動起動の設定などを加えれば良い。この際、Samba との連携においては chroot 環境下だとうまく動かないので 必ず chroot の設定をはずすこと


/etc/rc.conf

# BIND 9.11

named_enable="YES" # Run named, the DNS server
named_chrootdir="" # Chroot directory (or "" not to auto-chroot it)
# named_uid="root"


この状態で BIND を起動してみる7

# /usr/local/etc/rc.d/named start

wrote key file "/usr/local/etc/namedb/rndc.key"
Starting named.


FreeBSD 12.0-RELEASE 以降での問題点?

FreeBSD 11.x-RELEASE 以前であればこの状態でも問題はなかったのだが、

12.0-RELEASE 以降、実行ユーザ分離の仕組みが変わったのか、起動後に /var/db/samba4/private/dns.keytab を(パーミッションの関係で)読み込むことができず、結果 Kerberos 周りで TKEY is unacceptable というエラーが出て、認証が通らなくなってしまう。

解決方法は


  • BIND を root 権限で実行する

  • /var/db/samba4/private/dns.keytab を /usr/local/etc/named 以下にコピーした上で bind ユーザのみ読み取り可 とする

がある。

ドキュメントが間に合っていないのか、FreeBSD 外の環境ではそもそも問題になっていないのか、Samba 公式にこのあたりの記述が見当たらない。そのためどちらが良いかの判別がつかないが、 BIND を root の権限で動作させるよりは /var/db/samba4/private/dns.keytab を /usr/local/etc/named 以下においておくほうが安全のような気がする。

実際 Samba のアップデートなどによって /var/db/samba4/private/dns.keytab が変更されることは(経験上)今まで観測されたことはないため、実害というほどのものはない(鍵が分散してしまうというリスクが多少存在はする)。

そのため、ここでは


  • BIND 実行ユーザは bind のまま

  • dns.keytab を /usr/local/etc/named/ へコピーしてパーミッションを適切に変更

ですすめる。


DNS Resolver

無事に BIND が起動できたら、 /etc/resolv.conf を下記のように編集して、名前解決に自ホスト上で行うよう変更する


/etc/resolv.conf

search ad.example.com

domain ad.example.com
nameserver 192.168.16.19



ntpd

Active Directory 管理下の Windows 機が Domain Controller と時刻の同期を取れるように ntpd を設定しておく。


/etc/ntp.conf

(略)

restrict default limited kod nomodify notrap noquery nopeer mssntp
restrict source limited kod nomodify notrap noquery mssntp

# for Samba AD DC time sync
ntpsigndsocket /var/run/samba4/ntp_signd

(略)


/etc/rc.conf へ下記を追記して、


/etc/rc.conf

ntpd_enable="YES"


ntpd を起動させる

# /etc/rc.d/ntpd start

Starting ntpd.


Samba 起動設定

ここまでで Active Directory の Domain Controller としての基本的な設定は完了なので、 rc.conf へ samba の設定を追記して


/etc/rc.conf

# Samba 4

samba_server_enable="YES"
samba_enable="YES"
nmbd_enable="YES"
smbd_enable="YES"
# You need to enable winbindd separately, by adding:
winbindd_enable="YES"

起動

# /usr/local/etc/rc.d/samba_server start

Performing sanity check on Samba configuration: OK
Starting samba.


確認


smbclient で Samba 自体へアクセスできるかどうか

# smbclient -L localhost -UAdministrator

Enter EXAMPLE\Administrator's password:

Sharename Type Comment
--------- ---- -------
netlogon Disk
sysvol Disk
IPC$ IPC IPC Service (Samba 4.8.7)
Reconnecting with SMB1 for workgroup listing.

Server Comment
--------- -------

Workgroup Master
--------- -------

# smbclient //localhost/sysvol -UAdministrator -c 'ls'
Enter EXAMPLE\Administrator's password:
. D 0 Tue Dec 25 00:06:23 2018
.. D 0 Tue Dec 25 11:45:23 2018
ad.example.com D 0 Tue Dec 25 00:06:08 2018

29216156 blocks of size 1024. 21703456 blocks available


DNS で必要なレコードを引けるかどうか

# host -t srv _ldap._tcp.dc._msdcs.ad.example.com

_ldap._tcp.dc._msdcs.ad.example.com has SRV record 0 100 389 server-dcl01.ad.example.com.

# host -t SRV _ldap._tcp.ad.example.com
_ldap._tcp.ad.example.com has SRV record 0 100 389 server-dcl01.ad.example.com.

# host -t SRV _kerberos._udp.ad.example.com.
_kerberos._udp.ad.example.com has SRV record 0 100 88 server-dcl01.ad.example.com.

# host -t a server-dcl01.ad.example.com.
server-dcl01.ad.example.com has address 192.168.160.19

# samba-tool dns query localhost ad.example.com @ ALL -UAdministrator
Password for [EXAMPLE\Administrator]:
Name=, Records=3, Children=0
SOA: serial=3, refresh=900, retry=600, expire=86400, minttl=3600, ns=server-dcl01.ad.example.com., email=hostmaster.ad.example.com. (flags=600000f0, serial=3, ttl=3600)
NS: server-dcl01.ad.example.com. (flags=600000f0, serial=1, ttl=900)
A: 192.168.160.19 (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=DomainDnsZones, Records=0, Children=2
Name=ForestDnsZones, Records=0, Children=2
Name=server-dcl01, Records=1, Children=0
A: 192.168.160.19 (flags=f0, serial=1, ttl=900)

# samba-tool dns serverinfo localhost -UAdministrator
Password for [EXAMPLE\Administrator]:
dwVersion : 0xece0205
fBootMethod : DNS_BOOT_METHOD_DIRECTORY
fAdminConfigured : FALSE
fAllowUpdate : TRUE
fDsAvailable : TRUE
pszServerName : SERVER-DCL01.ad.example.com
pszDsContainer : CN=MicrosoftDNS,DC=DomainDnsZones,DC=ad,DC=example,DC=com
aipServerAddrs : ['192.168.160.19']
aipListenAddrs : ['192.168.160.19']
aipForwarders : []
dwLogLevel : 0
dwDebugLevel : 0
dwForwardTimeout : 3
dwRpcPrototol : 0x5
dwNameCheckFlag : DNS_ALLOW_MULTIBYTE_NAMES
cAddressAnswerLimit : 0
dwRecursionRetry : 3
dwRecursionTimeout : 8
dwMaxCacheTtl : 86400
dwDsPollingInterval : 180
dwScavengingInterval : 0
dwDefaultRefreshInterval : 168
dwDefaultNoRefreshInterval : 168
fAutoReverseZones : FALSE
fAutoCacheUpdate : FALSE
fRecurseAfterForwarding : FALSE
fForwardDelegations : TRUE
fNoRecursion : FALSE
fSecureResponses : FALSE
fRoundRobin : TRUE
fLocalNetPriority : FALSE
fBindSecondaries : FALSE
fWriteAuthorityNs : FALSE
fStrictFileParsing : FALSE
fLooseWildcarding : FALSE
fDefaultAgingState : FALSE
dwRpcStructureVersion : 0x2
aipLogFilter : []
pwszLogFilePath : None
pszDomainName : ad.example.com
pszForestName : ad.example.com
pszDomainDirectoryPartition : DC=DomainDnsZones,DC=ad,DC=example,DC=com
pszForestDirectoryPartition : DC=ForestDnsZones,DC=ad,DC=example,DC=com
dwLocalNetPriorityNetMask : 0xff
dwLastScavengeTime : 0
dwEventLogLevel : 4
dwLogFileMaxSize : 0
dwDsForestVersion : 4
dwDsDomainVersion : 4
dwDsDsaVersion : 4
fReadOnlyDC : FALSE


Samba AD の状態確認

# samba-tool domain level show

Domain and forest function level for domain 'DC=ad,DC=example,DC=com'

Forest function level: (Windows) 2008 R2
Domain function level: (Windows) 2008 R2
Lowest function level of a DC: (Windows) 2008 R2

# samba-tool fsmo show
SchemaMasterRole owner: CN=NTDS Settings,CN=SERVER-DCL01,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ad,DC=example,DC=com
InfrastructureMasterRole owner: CN=NTDS Settings,CN=SERVER-DCL01,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ad,DC=example,DC=com
RidAllocationMasterRole owner: CN=NTDS Settings,CN=SERVER-DCL01,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ad,DC=example,DC=com
PdcEmulationMasterRole owner: CN=NTDS Settings,CN=SERVER-DCL01,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ad,DC=example,DC=com
DomainNamingMasterRole owner: CN=NTDS Settings,CN=SERVER-DCL01,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ad,DC=example,DC=com
DomainDnsZonesMasterRole owner: CN=NTDS Settings,CN=SERVER-DCL01,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ad,DC=example,DC=com
ForestDnsZonesMasterRole owner: CN=NTDS Settings,CN=SERVER-DCL01,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ad,DC=example,DC=com


winbind でユーザ等が引けるかどうか

# wbinfo -t

checking the trust secret for domain EXAMPLE via RPC calls succeeded

# wbinfo -u
EXAMPLE\administrator
EXAMPLE\guest
EXAMPLE\krbtgt
EXAMPLE\dns-server-dcl01

# wbinfo -g
EXAMPLE\cert publishers
EXAMPLE\ras and ias servers
EXAMPLE\allowed rodc password replication group
EXAMPLE\denied rodc password replication group
EXAMPLE\dnsadmins
EXAMPLE\enterprise read-only domain controllers
EXAMPLE\domain admins
EXAMPLE\domain users
EXAMPLE\domain guests
EXAMPLE\domain computers
EXAMPLE\domain controllers
EXAMPLE\schema admins
EXAMPLE\enterprise admins
EXAMPLE\group policy creator owners
EXAMPLE\read-only domain controllers
EXAMPLE\dnsupdateproxy


Kerberos の動作確認

# kinit administrator@AD.EXAMPLE.COM                        

administrator@AD.EXAMPLE.COM's Password:

# klist
Credentials cache: FILE:/tmp/krb5cc_0
Principal: administrator@AD.EXAMPLE.COM

Issued Expires Principal
Dec 25 15:46:46 2018 Dec 26 01:46:43 2018 krbtgt/AD.EXAMPLE.COM@AD.EXAMPLE.COM


(Kerberos を使った) Dynamic DNS Update の確認

# host -t a test.ad.example.com

Host test.ad.example.com not found: 3(NXDOMAIN)

# nsupdate -g
> update add test.ad.example.com 100 in a 192.168.160.190
> send
> quit

# klist
Credentials cache: FILE:/tmp/krb5cc_0
Principal: administrator@AD.EXAMPLE.COM

Issued Expires Principal
Dec 25 15:46:46 2018 Dec 26 01:46:43 2018 krbtgt/AD.EXAMPLE.COM@AD.EXAMPLE.COM
Dec 25 16:04:27 2018 Dec 26 02:04:04 2018 DNS/server-dcl01.ad.example.com@AD.EXAMPLE.COM

# host -t a test.ad.example.com
test.ad.example.com has address 192.168.160.190

# samba-tool dns query localhost ad.example.com @ ALL -UAdministrator
Password for [EXAMPLE\Administrator]:
Name=, Records=3, Children=0
SOA: serial=22, refresh=900, retry=600, expire=86400, minttl=3600, ns=server-dcl01.ad.example.com., email=hostmaster.ad.example.com. (flags=600000f0, serial=21, ttl=3600)
NS: server-dcl01.ad.example.com. (flags=600000f0, serial=21, ttl=900)
A: 192.168.16.19 (flags=600000f0, serial=21, 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=DomainDnsZones, Records=0, Children=2
Name=ForestDnsZones, Records=0, Children=2
Name=server-dcl01, Records=1, Children=0
A: 192.168.160.19 (flags=f0, serial=1, ttl=900)
Name=test, Records=1, Children=0
A: 192.168.160.190 (flags=f0, serial=21, ttl=100)

(このときの bind の log )
25-Dec-2018 18:31:29.426 update: info: client @0x4af2e000 192.168.160.19#39353/key administrator\@AD.EXAMPLE.COM: updating zone 'ad.example.com/NONE': adding an RR at 'test.ad.example.com' A 192.168.160.190

dns/bind911 で base の Heimdal を使っていると...

25-Dec-2018 16:49:12.039 update: info: client @0x49861800 192.168.160.19#29805/key administrator\@AD.EXAMPLE.COM: updating zone 'ad.example.com/NONE': update failed: rejected by secure update (REFUSED)

25-Dec-2018 16:49:12.037 database: error: samba_dlz: GSS server Update(krb5)(1) Update failed: An unsupported mechanism was requested: unknown mech-code 0 for mech 1 2 840 113554 1 2 2
25-Dec-2018 16:49:12.038 database: error: samba_dlz: gensec_spnego_server_negTokenInit_step: gssapi_krb5: parsing NEG_TOKEN_INIT content failed (next[(null)]): NT_STATUS_LOGON_FAILURE
25-Dec-2018 16:49:12.038 database: error: samba_dlz: spnego update failed

というエラーが出て Update が拒否されてしまう。






まとめ

ここまでで実際に機能する最低限の Active Directory が構築できる。

これ以降は、今回は環境が調達できなかったので実際にはできなかったが、


  • Windows 機を Active Directory に参加

  • Group Policy を設定して AD 内の Windows 機を管理

したりはもちろんのこと


  • Linux/*BSD/macOS の認証サーバとして AD を用いる

と言ったこともできる(が、それはまた機会があれば)


Raspberry Pi での所感

コマンドを実行したりでは特に問題はなさそうだが、ログを書き込んだりなどの I/O が発生すると多少待たされることがある。

実際に Raspberry Pi で AD を運用できうるかどうかは micro SD の性能や各種設定によるものと思う(こちらもいずれ試してみたいと思う)





  1. Linux でも、PATH などは違えど、作業自体は同様 



  2. 2018年12月25日現在 



  3. 以前は GSSAPI_BASE が標準だった…と思う 



  4. 厳密には sysvol を格納するファイルシステムで acls が有効になっている必要がある 



  5. --adminpass を指定しない場合はランダムに生成される 



  6. シンボリックリンクは非推奨。 /var/db/samba4/private はパーミッションの関係で root 以外のユーザには読めないため。 



  7. 初回起動時は多少時間がかかる。