OpenLDAPでユーザ管理 (6)

次はクライアント側の設定。

ldap の設定ファイルは /usr/pkg/etc/ldap.conf になるようだ。 nss_ldap も pam-ldap も共通のファイルを用いる。デフォルトのファイルは /usr/pkg/share/examples/nss_ldap/ldap.conf と /usr/pkg/share/examples/pam-ldap/ldap.conf に置かれている。両者の diff を取ると、バージョンが異なる。あとコメントアウトされた箇所がそれなりに違う。

-# @(#)$Id: ldap.conf,v 2.49 2009/04/25 01:53:15 lukeh Exp $
+# @(#)$Id: ldap.conf,v 1.38 2006/05/15 08:13:31 lukeh Exp $

/usr/pkg/etc/ldap.conf の base を書き換え、uri を追加した。

(略)
# The distinguished name of the search base.
base dc=example,dc=co,dc=jp
(略)
uri ldap://aries.example.co.jp/
(略)

次に /etc/nsswitch.conf の group と passwd のエントリを ldap を参照するように修正。

(略)
group:          files ldap
(略)
passwd:         files ldap
(略)

id(1) で LDAP に登録されたユーザが引けるかどうか確認。

$ id allice
uid=6400(allice) gid=6525(ldapusers) groups=6525(ldapusers)
$

正しく引けている。

次は PAM の設定。/etc/pam.d/system に pam_ldap.so を記述する。以下は抜粋。

# auth
auth            sufficient      /usr/pkg/lib/security/pam_ldap.so
auth            sufficient      pam_skey.so             no_warn try_first_pass
auth            sufficient      pam_krb5.so             no_warn try_first_pass
auth            optional        pam_afslog.so           no_warn try_first_pass
auth            required        pam_unix.so             no_warn try_first_pass nullok

# account
account         sufficient      /usr/pkg/lib/security/pam_ldap.so
account         required        pam_krb5.so
account         required        pam_unix.so

# session
session         sufficient      /usr/pkg/lib/security/pam_ldap.so
session         required        pam_lastlog.so          no_fail no_nested

# password
password        sufficient      /usr/pkg/lib/security/pam_ldap.so
password        sufficient      pam_krb5.so             no_warn try_first_pass
password        required        pam_unix.so             no_warn try_first_pass

LDAP Admin でユーザ allice alice にパスワードを設定しておく。

$ login alice
Password: (LDAP Admin で設定した alice のパスワード)
(略)
NetBSD 6.0.1 (GENERIC)

Welcome to NetBSD!

$

OpenLDAPでユーザ管理 (5)

前回でトップレベルの DN と、管理者の DN エントリを手作業で登録したので、GUI な LDAP 管理ツールが利用できるようになった。

ここからは LDAP Admin を使用する。Windows で動作する LDAP 管理ツールだ。使用したバージョンは 1.5.1。

LDAP サーバへの接続設定。新規登録、変更するなら Account に管理者の Username と Password を設定する。Username はもちろん管理者の DN で。

トップレベルに Organizational unit を追加。Organizational Unit の名前に People、Group をそれぞれ指定する。

メニューバーの [Tools] – [Session preferences] で [ID Settings] タブ内の設定を変更する。ここでは、User ID、Group ID の範囲をともに 6000-6999 にしている。

ou=Group の下に Group エントリを作成、Group name は ldapusers にする。

ou=People の下に User エントリを作成、ここではユーザ名を allice alice としている。

[Create User] の [Membership] タブのところで、Primary group として、先に作成した ldapusers を指定する。[Set…] ボタンを押すと、LDAP に登録されているグループが表示され、選択できる。

これで、ユーザとグループの登録ができた。登録後はこんな感じ。ou=Group と ou=People の下にそれぞれ各グループとユーザのエントリがぶら下がる木構造になっている。

OpenLDAPでユーザ管理 (4)

LDAP サーバは起動したが、この段階ではデータベースは空の状態。

最初にいくつかのエントリを登録しないといけないらしい。

一つはデータベースのトップを表すエントリ、もう一つは管理者のエントリだ。ユーザアカウント管理のためにはまだ登録しないといけないエントリがあるが、まずはこの2つのエントリを登録する必要がある。

$ cat example.ldif
dn: dc=example,dc=co,dc=jp
objectclass: dcObject
objectclass: organization
o: Example Company 
dc: example

dn: cn=Manager,dc=example,dc=co,dc=jp
objectclass: organizationalRole
cn: Manager
$

ここには空行を挟んで2つのエントリが記述されている。前半がトップのエントリ、後半が管理者のエントリだ。dn は識別名 (Distinguished Name) のこと。他の属性で短すぎて意味を推測しにくいものをメモしておく。これらは core.schema で定義されている。

  • o (organizarionName) 組織名
  • cn (commonName) 一般名
  • dc (domainComponent) ドメインの構成要素

管理者の dn は、slapd.conf の rootdn で指定したものと一致させる。

LDIF を手書きするなど随分とめんどくさいし、間違えたらどうなるのだろうと不安であるが、このエントリは最初に登録するだけなので我慢して記述する。ファイル名はなんでもよいが、example.ldif とした。

ldapadd での登録の前に、オプション ‘-n’ をつけて実行する。

$ ldapadd -x -D "cn=Manager,dc=example,dc=co,dc=jp" -W -f example.ldif -n
!adding new entry "dc=example,dc=co,dc=jp"

!adding new entry "cn=Manager,dc=example,dc=co,dc=jp"

$

エラーはなさそうだが、これでチェックになっているのかどうかはよくわからない。

‘-n’ を外して ldapadd を実行すると、パスワードを入力するプロンプトが現れた。パスワードを設定した覚えはないので、空のまま enter を押す。

$ ldapadd -x -D "cn=Manager,dc=example,dc=co,dc=jp" -W -f init.ldif 
Enter LDAP Password: (何も入力せずにenter)
ldap_bind: Server is unwilling to perform (53)
        additional info: unauthenticated bind (DN with no password) disallowed
$

何かが失敗しているようだ。試しにでたらめな文字列をパスワードとして入力してみる。

$ ldapadd -x -D "cn=Manager,dc=example,dc=co,dc=jp" -W -f init.ldif 
Enter LDAP Password: (でたらめな文字列を入力してenter)
ldap_bind: Invalid credentials (49)
$

当然失敗するがエラーメッセージは異なっている。

もう一度 slapd.conf を確認すると、

(略)
rootdn          "cn=Manager,dc=example,dc=co,dc=jp"
# Cleartext passwords, especially for the rootdn, should
# be avoid.  See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
rootpw          secret
# The database directory MUST exist prior to running slapd AND 
(略)

うむ、この rootpw の ‘secret’ は何かのキーワードじゃなくて、パスワードそのものだったようだ。

$ ldapadd -x -D "cn=Manager,dc=example,dc=co,dc=jp" -W -f init.ldif   
Enter LDAP Password: (slapd.conf の rootpw に設定したパスワード)
adding new entry "dc=example,dc=co,dc=jp"

adding new entry "cn=Manager,dc=example,dc=co,dc=jp"

$

今度は無事成功である。

確認してみる。

$ ldapsearch -x -b 'dc=example,dc=co,dc=jp' '(objectclass=*)'
# extended LDIF
#
# LDAPv3
# base  with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# example.co.jp
dn: dc=example,dc=co,dc=jp
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example

# Manager, example.co.jp
dn: cn=Manager,dc=example,dc=co,dc=jp
objectClass: organizationalRole
cn: Manager

# search result
search: 2
result: 0 Success

# numResponses: 3
# numEntries: 2
$ 

こちらも問題なし。

OpenLDAPでユーザ管理 (3)

/usr/pkg/etc/openldap/slapd.conf の編集。

システムにログインするユーザの認証には、最初から slapd.conf に記述されている core.schema に加え、3つのスキーマ cosine.schema、inetorgperson.schema、nis.schema が必要となる。

include         /usr/pkg/etc/openldap/schema/core.schema
include         /usr/pkg/etc/openldap/schema/cosine.schema
include         /usr/pkg/etc/openldap/schema/inetorgperson.schema
include         /usr/pkg/etc/openldap/schema/nis.schema

suffix を編集する。ここではドメイン名が example.co.jp であるとして

suffix          "dc=example,dc=co,dc=jp"
rootdn          "cn=Manager,dc=example,dc=co,dc=jp"

/etc/rc.conf に slapd の起動オプションを追加して、

slapd=YES

slapd を起動。

$ sudo /etc/rc.d/slapd start

動作確認。

$ ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
# extended LDIF
#
# LDAPv3
# base <> with scope baseObject
# filter: (objectclass=*)
# requesting: namingContexts 
#

#
dn:
namingContexts: dc=example,dc=co,dc=jp

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
$ 

あたりまえだがドキュメント通り、確かに動いている。

OpenLDAPでユーザ管理 (2)

まずはテスト環境の構築。

以前の経験から、設定を間違うとローカルにログインできなくなってヤバイ、という知識はあるので、本運用の前にテスト環境で動作、運用の確認を行なっていく。

そして確か、ローカルユーザを LDAP で管理するのはよろしくない、という話があったように思うので、ユーザアカウント情報を保持する LDAP サーバとなるホストと、LDAP に登録された情報を使ってユーザ認証を行う LDAP クライアントとして振る舞うホストの2台をセットアップする。どちらも NetBSD だ。

最終的には、LDAP サーバ上でのユーザ認証も LDAP を使ってやりたいけれども、それは、LDAP が障害で落ちているときとかのフォールバックとか、その辺の解決方法がわかってからの作業とする。

LDAP サーバ Aries、クライアント Taurus、ともに NetBSD 6.0.1 i386、pkgsrc-2012Q4 でセットアップし、Aries には databases/openldap を、Taurus には databases/openldap-client をインストールした。インストールされた OpenLDAP のバージョンは 2.4.33 (openldap-2.4.33)。

Taurus には databases/nss_ldap と、security/pam-ldap もインストールする。

参考リンク

(4/4 追記)

  • LDAP 使って認証する側 (Taurus) には、databases/openldap-client いらなかった。
  • 参考リンクを追加

OpenLDAPでユーザ管理 (1)

これまで NetBSD (FreeBSD も)のユーザ管理は NIS でやってきた。

NIS は自分自身、管理の実績もあるし、なによりシステム標準なので手っ取り早く立ち上げることができる。機能が古いのと、セキュリティに難があるのが欠点ではあるけれども。ちなみに NIS+ は知らない。

それが、いまどき世間では LDAP を使うのが標準のようだ。そう思って OpenLDAP を当時管理していた FreeBSD にインストールしていじったのがかれこれ数年前。認証するところまでは設定したものの、ユーザ管理がかえって面倒とか、障害時の取扱いのノウハウがよくわからないとかで採用には至らなかった。

でも、当時と違って今は便利なツールとか、様々なノウハウが公開されている(ような気がする)ので、NetBSD-6 もリリースされたことだし、再度の挑戦をしてみることにした。

とはいえ、以前に行った作業などほぼ忘れている。概念はおぼろげに頭の中にあるが、手順については完全に忘れている。一から調べながらの作業になりそう。調べるといっても、Google で検索すると古い情報やら新しい情報やらが混在してでてくるので要注意だ。個人的には、ページに日付を入れていないのはどうかと思う(たとえ個人のメモであっても)。

この文も、作業をしながら、確認しながら書いていくので、今後の展開は不明である。もしかしたら途中で挫折してしまうかもしれないことを断っておく。

もし、いつかどこかでこの文を見かけた人がいたとして、続きが見当たらなかったらお察しください。

Dovecot でローカル配信する

Dovecot 1.x の時代、ローカル配信は Dovecot 付属の deliver を使うのが主流だった。

Dovecot 2.x になってから、deliver は dovecot-lda になって delibver は dovecot-lda へのシンボリックリンクに変わった。

そのせいかどうかはわからない(Dovecot 1.x の時代にどうであったかはわからない)が、system user じゃない virual user、つまり、OS のユーザじゃなく Dovecot 上にしか登録されていないユーザ、への配信がどうもうまくいかない。

Postfix 側の方の設定によるものなのか、 Dovecot 側なのかということもわからないのだが、パーミッションの関係かもしれないと思って Dovecot2 のドキュメントの Dovecot LDA with Postfix – Virtual users with multiple uids の節を読んでみると、dovecot-lda を setuid root しろとか、sudo で起動しろとか書いてある。

さらに、Dovecot LDA のセクションを読むと冒頭に、いや、いまどき普通 LMTP でしょ、とか書いてある。

Nowadays you should probably use the LMTP server instead, because it’s somewhat easier to configure (especially related to permissions) and gives better performance.

普通 LMTP というならしかたがない、ということで、ドキュメントを見ながら色々試行錯誤したまとめ。

まず、OS上のユーザ(システムユーザ)とDovecot上のユーザ(仮想ユーザ)の扱い。これは別ドメインとして管理することにして、OSのユーザへのローカル配信はPostfixで、仮想ユーザへの配信を dovecot-lmtp で行うことにした。そうすればシステムユーザに対しては /etc/mail/aliases とか ~/.forward も従来通り有効だし、レガシーなメールアプリケーションとも親和性がよいだろう。

postfix 側の設定は、/etc/postfix/main.cf に以下を追加する。

virtual_mailbox_domains = mbox.$mydomain
virtual_transport = lmtp:unix:private/dovecot-lmtp

1行目が Dovecot で管理する仮想ドメインの指定。2行目が仮想ドメインに配信するソケットの指定で、各要素がコロン ‘:’ で区切られている。

1つ目の ‘lmtp’ がプロトコル。2つ目の ‘unix’ がソケットの種類で、ここでは UNIX ドメインのソケットであることを示している。3つ目の ‘private/dovecot-lmtp’ は UNIX ドメインソケットのパスで、相対パスになっている。絶対パスだと ‘/var/spool/postfix/private/dovecot-lmtp’ だ。もちろん環境依存である。

Dovecot 側の設定では、関係するところを抜粋した。

protocols = imap lmtp

protocol lmtp {
  mail_plugins = quota
}

service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    user = postfix
    group = wheel
    mode = 0666
  }
}

userdb {
  driver = passwd-file
  args = username_format=%n /usr/pkg/etc/dovecot/userdb
}

protocols に lmtp を入れておくのは当然。

‘service lmtp’ が LMTP サーバの定義。プロトコルには UNIX と INET が使用できるが、Postfix からのローカル配信限定という条件なので、UNIX のみにした。したがって、’unix_listener’ の定義のみで、その直後に記述されている ‘/var/spool/postfix/private/dovecot-lmtp’ というのが待ち受けるソケットのパスになる。当然ながら、先の Postfix 側の設定と対応する。

ソケットの場所、ユーザとグループ、パーミッションは、Postfix の他のソケットと揃えておいた。NetBSD 5.1.2 では /var/spool/postfix/private が 0700 で、中のソケットが 0666 というレイアウトになっている。

そして最後に userdb の設定(これが一番ハマった)。ここでは仮想ユーザの検索ドライバとして passwd-file を使用し、args で指定している ‘/usr/pkg/etc/dovecot/userdb’ から仮想ユーザの情報を得ている。

args に ‘username_format=%n’ とあるのは、LMTP に検索キーとして渡される宛先アドレスからユーザ名を抽出するための設定。Postfix から dovecot-lmtp へはドメインを含む(メールアドレスの ‘@’ 右側を含む)宛先アドレスが渡される。仮想ユーザをドメイン込で passwd-file に記述していればそのままでいいが、ユーザ名部分のみ(’@’ の左側部分のみ)だと一致しないということで、ユーザが見つからないという結果になる。

複数のドメインを取り扱う場合にはドメイン込で記述する必要があるが、単一のドメインの場合は、略したいので ‘username_format=%n’ という設定が必要となる。

Dovecot ってサンプルとかチュートリアルがまだまだ少ないよね。

Dovecot 起動時に FD 足りないと言ってくる

NetBSD で Dovecot-2.1.12 起動時に以下の warning がでてくる。Dovecot は pkgsrc でインストールしたもの。

Warning: fd limit (ulimit -n) is lower than required under max. load (768 < 1000), because of default_client_count

FD、つまり一度にオープンできるファイルの数が足りないということらしい。

ulimit -n 1024; /etc/rc.d/dovecot start

と warning は出なくなる。問題はこの設定をどこでするか。

最初 login.conf でするのかと思ったけれど、warning message 中の 768 という数字はデフォルトではない。

とすると、どこかで設定してるはず、と思って /etc/rc*, /etc/rc.d/* に対して 768 で grep かけてみると、/etc/rc.d/dovecot の中に、下のような変数があった。

dovecot_fdlimit=${dovecot_fdlimit-"768"}

rc スクリプト書いた時には 768 でよかったけど、今ではもっと大きくしないといけない、ってことか。

ということで、/etc/rc.conf に以下を記述。

dovecot_fdlimit=1024

Google Apps Script で Bubble Chart は使えないの?

ふと思い立って Google Apps Script の学習を開始。

Google スプレッドシートのグラフ(バブルチャート bubble chart)の制御をしたかったんだけど、いろいろと解説ページをググってスプレッドシートにスクリプトでチャート(散布図 scatter chart)を貼り付ける、っていうのはできた。

function myFunction() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet();
  var app = UiApp.createApplication();

  var data = Charts.newDataTable()
  .addColumn(Charts.ColumnType.NUMBER, "X")
  .addColumn(Charts.ColumnType.NUMBER, "Y")
  .addRow([1, 1])
  .addRow([2, 0])
  .build();

  var chart = Charts.newScatterChart()
  .setDataTable(data)
  .build();

  app.add(chart);
  sheet.show(app);
}

でも、バブルチャートの作り方がわからない。 Charts に newBubbleChart() というメソッドはないようだ。

Google Chart Tools にはバブルチャートが含まれているのに、Google Apps Script の Charts Services には含まれていないってどういうこと?

Hyper-V 上の NetBSD リブート問題

以前のエントリでも触れたように、Hyper-V 上で NetBSD 6.0 を使用する場合、リブート時にハングアップしてしまう問題がある。

Hyper-V は Windows Server 2008 R2 付属のもの、NetBSD は NetBSD/i386 6.0 release での確認。SMP と ACPI を無効にして起動している。ACPI を無効にしなければ問題ないのだが、Hyper-V のレガシネットワーク・インターフェースを tlp(4) で使用するためには netbsd -12 のように ACPI と SMP を無効にして起動しないとネットワークが使用できない。

で、今回 6.0.1 release が出たので試してみた。

結論は、ダメ。変わらず。

試しているうちに、shutdown -v -x -r now のように、VERBOSE と DEBUG を有効にしたら再起動できる場合があることがわかった。いつもO.K.なわけではない。大丈夫だったりダメだったり。

何かデバイスのタイミング的に依存する話なのだろうか。