puppet 今試すなら バージョン 0.22.1 を使え、そして gem で入れるな
gem がだめなわけは、puppetrun が入らないから。(0.22.1, 0.22.2 で確認。)puppetrun 使わないなら gem で構わないけど。metadata 覗いたら、executables の中に puppetrun がない。こんな感じ。
executables: - puppet - puppetd - puppetmasterd - puppetdoc - puppetca
とりあえずチケットに入れておいた。
あと、最新のバージョン 0.22.2 だと、以下のエラーが出る。
$ sudo puppetd --listen --no-client -v
/usr/lib/ruby/site_ruby/1.8/puppet/util/config.rb:29:in `[]': Undefined configuration parameter 'authconfig' (ArgumentError)
from /usr/lib/ruby/site_ruby/1.8/puppet.rb:83:in `[]'
from /usr/bin/puppetd:360
--listen オプション使うときには、/etc/puppet/namespaceauth.conf が必要で、authconfig にはこのパスがセットされるはずなんだけど、セットされていないためのエラーっぽい。これは trunk では直ってる。
もうひとつ、puppetrun 実行時のエラー。
$ sudo puppetrun --host kenny.southpark
Failed to load ruby LDAP library. LDAP functionality will not be available
/usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/core_ext/module/introspection.rb:5:in `parent': private method `split' called for :Client:Symbol (NoMethodError)
from /usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:463:in `const_missing'
from /usr/local/bin/puppetrun:343
from /usr/local/bin/puppetrun:335:in `fork'
from /usr/local/bin/puppetrun:335
kenny.southpark finished with exit code 1
これは puppetrun に以下の一行を追加すれば直る。
require 'puppet/network/client/runner'
puppet の実行ファイル
Puppet Executables より。またもや超意訳、というかメモ。
puppet
スタンドアロンなインタプリタ。manifest ファイルを直接読んで、自ホストに適用する。あまり使うことはないと思う。
puppetca
SSLv3 証明書ハンドリングのためのコマンド。この辺参照。
puppetd
puppet クライアント側で実行するデーモン。デフォルトでは、puppet サーバに対して定期的に問い合わせに行くけれど、
$ puppetd --listen --no-client
と実行することで、puppet サーバからキックされるのを待ち受ける状態になる。(サーバは後述の puppetrun を実行してキックする。)
puppetdoc
puppet ソースからドキュメントを抽出するためのツール。これもあまり使わないと思う。
puppetmasterd
puppet サーバ側で起動するデーモン。
puppetrun
puppet クライアントをサーバ側からキックする時に使うコマンド。
$ puppetrun --host hostA --host hostB
という感じで特定のクライアントのみキックできるし、
$ puppetrun --all --parallel 5
とかですべてのクライアントをキックする(ただし同時にキックするのは 5 クライアント)といったことができる。
$ puppetrun --class web
とかで web クラスのクライアントのみキックとかもできる。ただし、--all や --class は、クライアントホストを LDAP で管理している場合のみ。
うちではこれをメインに使うことになりそう。サーバの数が数百台とかあるから、クライアントから定期的にポーリングされる負荷も馬鹿にならないし、いっぺんにファイルとりにこられたりすると、とんでもないことになるので。
puppet の通信の仕組みにちょっと立ち入ってみる
puppet のクライアント/サーバ間通信は https + XMLRPC で、認証は SSLv3 の証明書認証が利用されています。
通常、SSLv3 で証明書認証とかいうと、CA とか、自己署名証明書とか、色々めんどくさかったりしますが、puppet はこの辺りはほとんど自動で処理してくれるので、とても楽です。
例えば、puppet サーバ側では、puppetmasterd をはじめて起動した時に、CA 関連ファイルや自己署名証明書などを、/etc/puppet/ssl 以下に勝手に作ってくれます。
$ ls -R /etc/puppet/ssl /etc/puppet/ssl: ca/ certs/ csr_kenny.southpark.pem private/ private_keys/ public_keys/ /etc/puppet/ssl/ca: ca_crl.pem ca_key.pem inventory.txt requests/ signed/ ca_crt.pem ca_pub.pem private/ serial /etc/puppet/ssl/ca/private: ca.pass /etc/puppet/ssl/ca/requests: /etc/puppet/ssl/ca/signed: kenny.southpark.pem /etc/puppet/ssl/certs: ca.pem kenny.southpark.pem /etc/puppet/ssl/private: /etc/puppet/ssl/private_keys: kenny.southpark.pem /etc/puppet/ssl/public_keys: kenny.southpark.pem
あれ、CA 証明書っぽいものが二つある、と思ったら、ca/ca_crt.pem と certs/ca.pem はまったく同じものでした。
また、CA 証明書とは別に、kenny.southpark.pem というものができていますが、これはおそらく、自身が puppet クライアントになる時に利用するものと思われます。
CA 証明書の中身を覗いてみるとこんな感じ。
$ sudo openssl x509 -text -in /etc/puppet/ssl/ca/ca_crt.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 0 (0x0)
Signature Algorithm: sha1WithRSAEncryption
Issuer: CN=kenny.southpark
Validity
Not Before: Mar 20 14:29:16 2007 GMT
Not After : Mar 18 14:29:16 2012 GMT
Subject: CN=kenny.southpark
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:ea:83:02:5a:83:08:02:c8:bc:cd:d0:26:07:e7:
44:f7:a0:0e:0f:26:23:82:ba:e4:ed:d7:c8:88:c6:
43:b7:0a:5d:16:39:a2:6a:48:f9:8f:a5:9d:35:2f:
24:1e:ec:38:6b:73:0f:23:17:84:70:7e:08:08:96:
bd:e6:51:53:f2:fe:1d:ec:2f:d0:9a:5b:3d:ea:92:
8a:39:f5:ff:02:ff:6b:e4:d2:ef:9f:d2:c3:d6:35:
d8:5c:51:42:d9:16:59:62:c5:da:9a:9d:cd:f7:91:
a7:06:0b:28:8e:7f:4a:52:bc:5f:c3:5c:cb:b3:e3:
81:d0:1b:ca:b6:7f:73:b2:3f
Exponent: 65537 (0x10001)
X509v3 extensions:
Netscape Comment:
Puppet Ruby/OpenSSL Generated Certificate
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Key Identifier:
82:0D:36:AD:29:30:30:2D:CC:2D:EB:EA:F9:32:07:44:80:11:D3:E6
X509v3 Key Usage:
Certificate Sign, CRL Sign
Signature Algorithm: sha1WithRSAEncryption
e0:0b:a7:28:39:8e:09:cc:91:85:ce:13:19:c1:9b:ba:21:c3:
d8:09:c2:ee:93:ac:8d:76:91:18:7a:31:01:fc:55:8b:84:e6:
69:3f:f5:a3:62:ce:cc:af:87:21:42:d4:0d:ab:02:62:26:4f:
c2:f4:a2:22:4f:52:a5:06:bd:88:4c:65:89:9e:98:4c:cb:82:
ce:09:50:e0:4b:67:59:1e:d7:26:75:2f:6f:3d:d3:d4:92:55:
79:06:5e:56:39:2b:15:b0:67:d9:00:79:09:37:86:1a:a1:30:
e0:ce:e8:2b:0a:16:92:73:a3:b8:1f:16:c8:60:f7:7d:c5:24:
09:66
-----BEGIN CERTIFICATE-----
MIICIzCCAYygAwIBAgIBADANBgkqhkiG9w0BAQUFADAaMRgwFgYDVQQDDA9rZW5u
eS5zb3V0aHBhcmswHhcNMDcwMzIwMTQyOTE2WhcNMTIwMzE4MTQyOTE2WjAaMRgw
FgYDVQQDDA9rZW5ueS5zb3V0aHBhcmswgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ
AoGBAOqDAlqDCALIvM3QJgfnRPegDg8mI4K65O3XyIjGQ7cKXRY5ompI+Y+lnTUv
JB7sOGtzDyMXhHB+CAiWveZRU/L+Hewv0JpbPeqSijn1/wL/a+TS75/Sw9Y12FxR
QtkWWWLF2pqdzfeRpwYLKI5/SlK8X8Ncy7PjgdAbyrZ/c7I/AgMBAAGjeTB3MDgG
CWCGSAGG+EIBDQQrFilQdXBwZXQgUnVieS9PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0
aWZpY2F0ZTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSCDTatKTAwLcwt6+r5
MgdEgBHT5jALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEFBQADgYEA4AunKDmOCcyR
hc4TGcGbuiHD2AnC7pOsjXaRGHoxAfxVi4TmaT/1o2LOzK+HIULUDasCYiZPwvSi
Ik9SpQa9iExliZ6YTMuCzglQ4EtnWR7XJnUvbz3T1JJVeQZeVjkrFbBn2QB5CTeG
GqEw4M7oKwoWknOjuB8WyGD3fcUkCWY=
-----END CERTIFICATE-----
次にクライアント側ですが、こちらもはじめて puppetd(クライアント側で起動するデーモン)を実行した時に、秘密鍵、公開鍵、CSR を自動的に作成し、サーバに対して CSR への署名を求めることが、起動時のメッセージから読み取れます。
$ sudo /usr/sbin/puppetd --server mizzy.org --test err: No certificate; running with reduced functionality. info: Creating a new SSL key at /var/lib/puppet/ssl/private_keys/cartman.southpark.pem info: Creating a new certificate request for cartman.southpark info: Requesting certificate warning: peer certificate won't be verified in this SSL session notice: Did not receive certificate
サーバ側では、証明書リクエストが来ていることを、次のようなコマンドで確認できます。
$ sudo puppetca --list cartman.southpark
これに署名するには、
$ sudo puppetca --sign cartman.southpark
と実行するだけです。これで puppet クライアント/サーバ間で無事通信できるようになります。
セキュアな通信が割りと簡単に実現できていい感じ。
puppet でファイルが変更されたら指定したコマンドを実行するレシピ
puppet で ファイルの配布 ができたので、次はファイルが変更されたら特定のコマンドを実行、にチャレンジ。これは FAQ にやり方書いてました。
puppet サーバで管理している /etc/httpd/conf.d/ 以下のファイルが変更されたら、puppet クライアント上のファイルを更新して httpd を再起動するレシピはこんな感じ。
class web {
define httpd {
$path = '/etc/httpd/conf.d'
file { $path:
source => 'puppet://mizzy.org/files/etc/httpd/conf.d',
recurse => 'true',
}
exec { 'httpd restart':
command => '/etc/init.d/httpd restart',
subscribe => File[$path],
refreshonly => true
}
}
httpd { 'httpd settings': }
}
node 'www.mizzy.org' {
include web
}
/etc/httpd/cond.d/perl.conf を変更して puppet クライアント上で puppetd --test を実行するとこんな感じに。
$ sudo /usr/sbin/puppetd --server mizzy.org --test
info: Caching configuration at /var/lib/puppet/localconfig.yaml
notice: Starting configuration run
info: //www.mizzy.org/web/httpd[httpd settings]/file=/etc/httpd/conf.d/perl.conf: Removing old backup of type file
notice: //www.mizzy.org/web/httpd[httpd settings]/file=/etc/httpd/conf.d/perl.conf/source: source changed '{md5}b78c3e53dd7fef842c99f105e9e4204f' to '{md5}a28770c2cdfc4c23faa2ea41b2e67397'
info: //www.mizzy.org/web/httpd[httpd settings]/file=/etc/httpd/conf.d/perl.conf: Scheduling refresh of exec[httpd restart]
notice: //www.mizzy.org/web/httpd[httpd settings]/exec=/etc/init.d/httpd restart: Triggering 'refresh' from 1 dependencies
notice: Finished configuration run in 7.42 seconds
ファイルが更新されてない場合はこうなる。
$ sudo /usr/sbin/puppetd --server mizzy.org --test info: Caching configuration at /var/lib/puppet/localconfig.yaml notice: Starting configuration run notice: Finished configuration run in 6.80 second
puppet file server 1
puppet サーバ上のファイルをクライアントに配布するには、file server 機能を利用するらしい。というわけで、ドキュメント File Serving Configuration から要点を抜き出してみる。
/etc/puppet/fileserver.conf の設定
[module]
path /path/to/files
allow *.domain.com
deny *.wireless.domain.com
こう設定すると、
/path/to/files/sudoers
というファイルを
puppet://server/module/sudoers
で取得できるようになる。
manifest の設定
"the Puppet language" が記述される設定ファイルを manifest と呼ぶらしい。要は puppet クライアントをどう管理するか、が記述された設定ファイルですね。(上の /etc/puppet/fileserver.conf は manifest ではない。)
puppet file server 上のファイルを配布するには、以下の様な設定を manifest に記述。
# copy a remote file to /etc/sudoers
file { "/etc/sudoers":
mode => 440,
owner => root,
group => root,
source => "puppet://server/module/sudoers"
}
source がポイント。
詳細は File Serving Configuration を参照。
puppet の言語構造
Installation Guide を読めば、とりあえず puppet を動かすことはできるけど、やりたいことをやろうと思ってもすぐにできるわけでもない。というわけで、ドキュメントをちゃんと読んでみることにした。
まずは puppet の設定ファイルで使われている内部言語の理解から、ということで、Language Structures を超意訳してみる。
Types
puppet 設定の基本構成単位。管理されるコンピュータ上のオブジェクト(ファイルとかパッケージとか)を表すもので、あらかじめ用意されたビルトインタイプ以外にも、自ら定義することも可能。
file { "/etc/passwd": owner => root, mode => 644 }
package { apache: install => true }
詳しくは Type Reference を参照。
Assignment
変数が利用できる。
$variable = value
$x = foo $y = bar $z = "$x$y"
Bringing Config files together
設定ファイルに、別の設定ファイルをインポートできる。
import "filename"
正規表現も利用可能。
import "classes/*" import "packages/[a-z]*"
Scope
{ } によってスコープが形成される。
変数は一度割り当てられると、同一スコープ内では変更できないが、サブスコープ内では同一名の変数を割り当てることができる。
$var = value
# override $var
define testing {
$var = othervalue
}
Components
ここでいう Components とは、自分で定義する Type のことっぽい。Components の定義と利用は以下の様な感じ。
define svnserve($source, $path, $user = false, $password = false) {
file { $path:
create => directory,
owner => root,
group => root
}
$svncmd = $user ? {
false => "/usr/bin/svn co --non-interactive $source/$name .",
default => "/usr/bin/svn co --non-interactive --username $user --password '$password' $source/$name ."
}
exec { $svncmd:
cwd => $path,
require => file[$path],
creates => "$path/.svn"
}
}
svnserve { dist:
source => "https://reductivelabs.com/svn",
path => "/dist",
user => "puppet",
password => "password"
}
svnserve { "dist/config/apps/puppet":
source => "https://reductivelabs.com/svn",
path => "/etc/puppet",
user => "puppet",
password => "password"
}
利用する時はビルトインタイプと構文上の違いはない。
Server Classes
Class を定義してインクルードすることができる。
class[inherits ] { ... }
継承も可能。
# really simple example
class solaris {
file {
"/etc/passwd": owner => root, group => root, mode => 644;
"/etc/shadow": owner => root, group => root, mode => 440
}
}
class solworkstation inherits solaris {
file {
"/etc/sudoers": owner => root, group => root, mode => 440;
"/bin/sudo": owner => root, group => root, mode => 4111
}
}
include solworkstation
以下の例だと、$operatingsystem の値と同名の Class と、$hostname に応じた Class がインクルードされる。
include $operatingsystem, $hostname ? {
myhost => classA, default => classB
}
$operatingsystem とか $hostname とかは、Facterというライブラリを使ってプリセットされているみたい。
Classes vs. Components
Classes と Components の違いは以下の通り。
- Classes はシングルトンなので、ホスト上でひとつしかないものを定義するのに利用する(OSの種類とか、特定のパッケージとかサービスとか。)
- Components はホスト上で複数あるオブジェクト(バーチャルホストなど)を定義するのに利用する。
あと、Classes は引数を受け取れない、という違いもある。
Subclssing
Class は継承ができる。
class unix {
file { "/etc/sudoers":
owner => root,
group => root,
mode => 440
}
}
class bsd inherits unix {
File["/etc/sudoers"] {
group => wheel
}
}
Using Classes Outside of Puppet
puppet サーバで設定された Class 名が、puppet クライアントの /etc/puppet/classes.txt に保存されるので、それを外部プログラムなどから読み込んで利用したりできるよ、とうことらしい。
FC4 で yum insall した puppet の場合は、/var/lib/puppet/classes.txt に保存されていた。
Nodes
node{ ... }
特定のホストに適用する設定を割り当てる。
以下の例だと、file type はすべてのホストに割り当てられるけど、webserver class と dbserver class の中に書かれた設定は、それぞれ特定のホストにのみ割り当てられる。
class webserver { ... }
class dbserver { ... }
file { "/etc/sudoers": mode => 440 } # apply to everyone
node host1, host2 {
include webserver
}
node host3, host4 {
include dbserver
}
node は継承することも可能。
node base {
include $operatingsystem
}
node kirby inherits base {
include webserver
}
FQDN で指定する時は、シングルクォートで囲む。
node 'host.domain.com' {
...
}
Conditionals
条件指定が可能。
以下の例は $os が何かによって、 $owner に入る値が変わる。
define testing(os) {
$owner = $os ? {
sunos => adm,
redhat => bin,
default => root
}
file { "/some/file": owner => $owner }
}
以下の例は $operatingsystem が何かによって、適用する class が変わる。
case $operatingsystem {
sunos: { solaris {} } # apply the solaris class
redhat: { redhat {} } # apply the redhat class
default: { generic {} } # apply the generic class
}
Reserved words
true, define, inherits, class は予約語。
Comments
sh スタイルのコメントが利用可。
puppet の node 設定ではまる
- http://reductivelabs.com/trac/puppet/wiki/InstallationGuide
- http://reductivelabs.com/trac/puppet/wiki/TestingGuide
- http://people.redhat.com/dlutter/puppet-app.html
といったあたりを読みながら puppet を試していたのですが、node の設定ではまったのでメモ。
pueppt では、
node nag.example.com {
include yum-rawhide
include horde-db-pg
include horde-nag
}
といった設定でターゲットとなるホストと、そのホストでどのようなタスクを実行するかを定義できるのですが、これで puppetmasterd を実行すると、
Syntax error at '.' at /etc/puppet/manifests/site.pp:5
と怒られます。そこで、
node 'nag.example.com' {
include yum-rawhide
include horde-db-pg
include horde-nag
}
とクォートしてあげると OK でした。最初に挙げた URL にあるチュートリアルの例ではクォートされておらず、そのままやるとはまりますのでご注意を。
追記
Language Structures を読んだら、「You can specify fully-qualified node names, but you have to single-quote the names:」ってちゃんと書いてあった。
cfengine よりも puppet がよさげ
I, newbie » Links Roundup 経由で puppet というシステム管理ツールを知って以来ずっと気になっていたのですが、このエントリの著者さんが OSC2007 の発表資料(PDF)で「Puppet is so sexy.」と書かれているのを見て、本気で触ってみることにしました。
puppet がどんなものかは、上記資料とか だ!日記さんのエントリ にも書かれているのですが、本家の Cfengine vs. Puppet というエントリから cfengine との違いを一部適当に意訳してみると、こんな感じです。
- next-generation version of cfengine ということで、cfengine をベースとしながらも、より良いものを目指している。
- リソース抽象化レイヤーにより、OS やディストリビューションの違いを意識しなくても良い。
- タスクの実行順序を制御できる。(cfengine ではできないor難しいらしい。)
- 設定ファイルで記述する内部言語が強力になっている。
- type の拡張が簡単。
- Ruby でできている。
というわけで、cfengine の導入を検討して、こんなエントリ を書いたりしてたのですが、cfengine は捨てて puppet でいこうかな、と思ってます。
emacs 用のヘルパーモード なんかも提供されているのがさらに好印象です。vim 用もあるし。
それから、まだ Experimental ですが、puppetshow という Rails でできたウェブインターフェースもあるようです。
/etc/sudoers を LDAP で管理する
/etc/sudoers を LDAP で一元管理とかできないのかなぁ、と思っていたら、ちゃんと対応してた。
利用方法はわりと簡単で、上記リンクの README.LDAP (ソースに同じものが同梱されてる)を見ればすぐわかるけど、一応ここにやったことをメモ。ほとんど README からの抜粋です。
手元の Slackware に元から入っている sudo は LDAP 対応していないので、ここからダウンロード して以下の手順でインストール。
$ ./configure --with-ldap $ make $ sudo make install
でもって /etc/ldap.conf に以下の記述を追加。(元々 LDAP は利用していて、基本的な設定はできているので、追加は一行だけ。)
sudoers_base ou=SUDOers,o=southpark
LDAP 側の設定はまずスキーマの追加。
#
# schema file for sudo
#
attributetype ( 1.3.6.1.4.1.15953.9.1.1
NAME 'sudoUser'
DESC 'User(s) who may run sudo'
EQUALITY caseExactIA5Match
SUBSTR caseExactIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.15953.9.1.2
NAME 'sudoHost'
DESC 'Host(s) who may run sudo'
EQUALITY caseExactIA5Match
SUBSTR caseExactIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.15953.9.1.3
NAME 'sudoCommand'
DESC 'Command(s) to be executed by sudo'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.15953.9.1.4
NAME 'sudoRunAs'
DESC 'User(s) impersonated by sudo'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.15953.9.1.5
NAME 'sudoOption'
DESC 'Options(s) followed by sudo'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL
DESC 'Sudoer Entries'
MUST ( cn )
MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoOption $
description )
)
次に sudoers 用のコンテナ ou=SUDOers, o=southpark と、デフォルト設定用の cn=defaults, ou=SUDOers, o=southpark を LDAP エントリに追加。
dn: ou=SUDOers,o=southpark objectclass: organizationalunit ou: SUDOers dn: cn=defaults,ou=SUDOers,o=southpark objectclass: top objectclass: sudorole cn: defaults sudoOption: ignore_local_sudoers
sudoOption: ignore_local_sudoers があると、/etc/sudoers ファイルを見なくなる。
最後に sudo 用 role エントリを追加して準備 OK。
dn: cn=role1,ou=SUDOers,o=southpark changetype: add objectclass: top objectclass: sudorole cn: role1 sudouser: miya sudohost: ALL sudocommand: ALL
sudouser, sudohost, sudocommand は複数設定可。! で否定になる。なので、特定のユーザだけ許可しない、という場合には、
sudouser: ALL sudouser: !miya
なんて書き方もできる。同様に特定のホストだけ許可しない、という場合には、
sudohost: ALL sudohost: !kenny
とかできるし、特定のコマンドだけ許可しない、という場合には、
sudocommand: ALL sudocommand: !/sbin/reboot
とかできる。もちろんこれらの組み合わせも OK。
あと、ユーザではなくグループで指定したい場合には
sudouser: %group
とする。(これは README.LDAP には明記されてない。/etc/sudoers の書き方から類推すればわかるけど。)
OpenSSH の公開鍵を LDAP で管理
OpenSSH LDAP Public key patch を試してみたのでメモ。(略して lpk patch とか言うらしい。)
SSH で公開鍵認証を行う場合、通常はホームディレクトリの .ssh/authorized_keys を参照しますが、このパッチを適用すると、authrized_keys の代わりに LDAP データベース内のユーザエントリが持つ sshPublicKey 属性を参照して、アクセスを許可するかどうかを判断する、という動作になります。
以下、試した手順です。
インストール
OpenSSH ダウンロードサイト から OpenSSH 本体を入手し、lpk サイト から lpk patch を入手しておきます。
4.3p1-0.3.7 patch が最新のようなので、本体は 4.3p1 をダウンロードしておきます。
入手したら、以下のような感じでインストールします。
$ cd openssh-4.3p1 $ patch < ../openssh-lpk-4.3p1-0.3.7.patch $ ./configure --with-ldap $ make $ sudo make install
sshd の設定
/usr/loca/etc/sshd_config に以下のような設定をして、sshd を再起動します。
UseLPK yes LpkServers ldap://myhost.mydomain.com LpkUserDN ou=People,dc=mydomain,dc=com
LDAP スキーマの設定
lpk patch をあてると、 ソースディレクトリに以下のような内容の openssh-lpk.schema がつくられます。
# # $Id: openssh-lpk-4.3p1-0.3.7.patch,v 1.3 2006/04/18 15:29:09 eau Exp $ # # LDAP Public Key Patch schema for use with openssh-ldappubkey # Author: Eric AUGE# # Based on the proposal of : Mark Ruijter # # octetString SYNTAX attributetype ( 1.3.6.1.4.1.22054.500.1.1.1.13 NAME 'sshPublicKey' DESC 'MANDATORY: OpenSSH Public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) # printableString SYNTAX yes|no objectclass ( 1.3.6.1.4.1.22054.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY DESC 'MANDATORY: OpenSSH LPK objectclass' MUST ( sshPublicKey $ uid ) )
OpenLDAP であればこいつを /etc/openldap/schema の下にでも置いて、slapd.conf で include してやれば OK でしょう。
Sun のやつであれば config/schema/99user.ldif あたりに以下の記述を追加すれば OK。
objectclasses: ( 1.3.6.1.4.1.22054.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY DESC 'MANDATORY: OpenSSH LPK objectclass' MUST ( sshPublicKey $ uid ) ) attributetypes: ( 1.3.6.1.4.1.22054.500.1.1.1.13 NAME 'sshPublicKey' DESC 'MANDATORY: OpenSSH Public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
LDAP ユーザエントリへの公開鍵追加
最後に LDAP のユーザエントリへ公開鍵を登録します。以下のような LDIF をつくって ldapmodify で反映させてやれば OK。
dn: uid=xxx, ou=people, o=southpark changetype: modify add: objectclass objectclass: ldapPublicKey - add: sshPublicKey sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIB3dsrwqXqD7E4zYYrxwdDKBUQxKMioXy9pxFVai64kAPxjU9KS qIo7QfkjslfsjflksjfldfkjsldfjLX/5zkzRmT28I5piGzunPv17S89z8XwSsuAoR1t86t+5dlI 7eZE/gVbn2UQkQq7+kdDTS2yXV6VnC52N/kKLG3ciBkBAw== General Purpose RSA Key
これで公開鍵認証ができるようになります。
lpk patch をあてるとソースディレクトリに以下のドキュメントがつくられますので、詳細はこれらを読むと良いんではないでしょうか。
- README.lpk
- lpk-user-example.txt