/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
cfengine メモ #0 - cfengine の構成パターン
I, newbie » cfengineによるシステム管理の自動化: その1 を読んで、cfengine よさげだなぁ、ってことで導入を検討することに。
このブログでは、上記エントリで「ややこしいけど魅力的」と書かれている cfengine について、自分なりに試したことや整理したことについてメモしていこうと思います。日本語のドキュメントが少ないですし、実際に手を動かしてみないと理解しにくいものなので、これを使ってみようかな、という方に少しでもお役に立てれば幸いです。
まず、cfengine ってそもそも何?というところですが、上記の I, newbie さんのエントリがわかりやすいので省略。今回は cfengine の構成パターンについて整理してみます。
単一マシンで利用するパターン
単一のマシンで cfengine を実行します。実際にこのパターンで運用することはない(cfengine 使う意味がない)と思いますが、cfengine の動作を理解するためのはじめの一歩として、まずはこのパターンで実行してみると良いです。
cfagent は cfengine に含まれるコマンドラインツールなのですが、以下の様に実行することで、設定情報がなどが書かれた cfagent.conf の内容にしたがって、自身の設定を行います。
# cfagent -f cfagent.conf
クライアント主導パターン
cfengine サーバ(設定情報を一元管理するサーバ)と cfengine クライアント(cfengine による管理対象サーバ)の2種類によって構成されます。今度は新しく cfserved というものが出てきましたが、これも cfengine に含まれているプログラムでデーモンとして常駐し、cfengine クライアントに cfagent.conf や他のファイルなどを提供したり、他のホストから cfagent を起動するリクエストを受け付けたり(これについては後述)します。
動作の流れは次のようになります。
- cfengine クライアントは cfengine サーバから最新の cfagent.conf を取得する。(どのサーバから取得するか、どのファイルを取得するか、といった情報が update.conf に記述されている。)
- cfengine クライアントは取得した cfagent.conf の内容にしたがって、自身の設定を行う。
この様に、最新の cfagent.conf の取得と実行は、クライアントサイド主導で行われますので、このパターンを「クライアント主導パターン」としています。実際の運用では、cron で定期的に実行することになるかと思います。
サーバ主導パターン
このパターンもサーバ/クライアント構成になっていますが、クライアント主導パターンと違うのは、クライアント側でも cfservd が動いていることと、サーバ側で cfrun というコマンドを実行していることです。cfrun も cfengine に含まれるコマンドラインツールで、リモートの cfserved に対して、cfagent を実行するようリクエストを出します。
このパターンでの動作の流れは次のようになります。
- サーバ側で cfagent.conf の更新をトリガーに cfrun を実行して、クライアントの cfagent をキックする。
- キックされた cfagent が cfagent.conf を取得し、その内容にしたがって自身の設定を行う。
何百とサーバがある環境だと、クライアントがサーバにアクセスする負荷もバカにならないので、クライアント主導型の様に、何も変更がないのに cron で定期的に実行するのも無駄ですし、一気にアクセスがこないように cron のスケジューリングを調整するのも面倒ですよね。そういった場合にはこのパターンが適しているかと思います。
cfrun は1ホストに対して1回実行というわけではなく、cfrun.hosts というファイルに書かれたホスト全部に対してコマンド一発実行もできますし、一度に起動できるプロセス数もオプションで指定できるので、サーバに一気にアクセスが集中する、ということがないようにコントロールすることも容易です。
以上が cfengine の構成パターンとして代表的なものになります。
次回以降、実際の使い方、注意点、運用上のノウハウなど少しづつ書いていきたいと思います。(まぁ、まだ運用してないので、ノウハウなんかないですが。)