さくらのクラウドで普通のLDAP認証ができるサーバーを量産する

会社でSSHの公開鍵やSUDOの権限をLDAPで一元管理していっているのですが、忘れないうちにLDAPクライアント側の構築方法を書いてみます。
なお、サーバーはさくらのクラウド上で構築し、LDAPサーバーはldap1.example.comというFQDNでアクセスできるものとします。

手順

OSとパッケージ

クラウドなので基本となるインスタンスを1台構築し複製することにします。
複製したインスタンスは普通のサーバーとして使う想定ですのでディストリビューションにはGentoo Linuxを使用します。
最近構築したのでカーネルバージョンは4.0.5と新しめです。

インスタンスの複製はロードバランサとサーバクローンで簡単スケールアウトというTIPSにスクリーンショット付きで解説されています。

# uname -a
Linux base 4.0.5-gentoo #1 SMP Wed Jul 1 02:23:16 JST 2015 x86_64 Intel(R) Xeon(R) CPU E5-2640 0 @ 2.50GHz GenuineIntel GNU/Linux

SSSD経由でLDAP認証を行うために必要なパッケージをインストールします。 USEフラグ設定のポイントは以下のとおりです。

  • OpenLDAPはクライアントのみでよいためminimalを指定
  • SSH公開鍵は後述するsss_ssh_authorizedkeysで取得するためOpenSSHにはldap指定不要
  • SSSDにはsshsudoを指定
  • sudoにはldapを指定
    (これは今回SUDOの設定をSSSD経由ではなくLDAPから直接取得したためです)
# emerge -pvq openldap openssh sssd sudo
[ebuild   R   ] net-nds/openldap-2.4.38-r2  USE="berkdb crypt gnutls ipv6 minimal sasl ssl syslog tcpd -cxx -debug -experimental -icu -iodbc -kerberos -odbc -overlays -perl -samba (-selinux) -slp -smbkrb5passwd" ABI_X86="(64) -32 (-x32)" 
[ebuild   R   ] net-misc/openssh-6.9_p1-r2  USE="hpn pam pie ssl -X -X509 -bindist -debug -kerberos -ldap -ldns -libedit -sctp (-selinux) -skey -ssh1 -static" 
[ebuild   R   ] sys-auth/sssd-1.12.4  USE="manpages nls ssh sudo -acl -augeas -autofs -locator -netlink -nfsv4 -python -samba (-selinux) {-test}" ABI_X86="(64) -32 (-x32)" PYTHON_SINGLE_TARGET="python2_7 -python3_3 -python3_4" PYTHON_TARGETS="python2_7 python3_3 -python3_4" 
[ebuild   R   ] app-admin/sudo-1.8.12  USE="ldap nls pam sendmail -offensive (-selinux) -skey" 

時代はflaggieなのでflaggieでUSEフラグを設定するといいと思います。

LDAPクライアントの設定

パッケージをインストールしたらLDAPクライアントとして仕立てていきます。

LDAPクライアントとしての基本的な設定を/etc/openldap/ldap.confに書きます。

# grep -vE '^\s*($|#)' /etc/openldap/ldap.conf
BASE dc=example,dc=co,dc=jp
URI ldap://ldap1.example.co.jp ldap://ldap2.example.co.jp
tls_reqcert naver
sudoers_base ou=SUDOers,dc=example,dc=co,dc=jp
nss_initgroups backlink
binddn cn=Authenticator,dc=example,dc=co,dc=jp
bindpw P@ssw0rd!

sudoコマンドが読む/etc/ldap.conf.sudoファイルはldap.confへのsymlinkにしています。 なお、sudoがどのldap.confを読んでいるかはリンク先の方法で調べることができます。

sudoがどのldap.confを読んでいるか確認する - Qiita

# ls -l /etc/openldap/ldap.conf /etc/ldap.conf.sudo
lrwxrwxrwx 1 root root  18 Jul 19 16:35 /etc/ldap.conf.sudo -> openldap/ldap.conf
-rw-r--r-- 1 root root 250 Jul 19 16:36 /etc/openldap/ldap.conf

SSSDの設定

続いてSSSDの設定を行います。 ドメインはexampleとしています。

# grep -vE '^\s*($|#)' /etc/sssd/sssd.conf
[sssd]
config_file_version = 2
services = nss,pam,sudo,ssh
domains = example
debug_level = 1
[nss]
filter_users = root,ldap,named,avahi,haldaemon,dbus,radiusd,news,nscd
[pam]
[sudo]
subdomain_enumerate = true
debug_level = 9
[domain/example]
id_provider = ldap
auth_provider = ldap
sudo_provider = ldap
ldap_search_base = dc=example,dc=co,dc=jp
ldap_sudo_search_base = ou=SUDOers,dc=example,dc=co,dc=jp
ldap_tls_reqcert = never
ldap_uri = ldap://ldap1.example.co.jp
ldap_schema = rfc2307
debug_level = 1
enumerate = true
ldap_default_bind_dn = cn=Authenticator,dc=example,dc=co,dc=jp
ldap_default_authtok = P@ssw0rd!
ldap_group_object_class = posixGroup
ldap_group_search_base = ou=Group,dc=example,dc=co,dc=jp
ldap_group_name = cn
ldap_group_member = memberUid
ldap_id_use_start_tls = false
chpass_provider = ldap
cache_credentials = true

Name Service Switchの設定

passwd,shadow,groupsssを参照するようnsswitch.confを設定します。
sudoersldapsss両方を参照するよう設定していますが、これは私がうまくSSSD経由でSUDOersを取得できなかったためこのようになっています。。

# grep -vE '^\s*($|#)' /etc/nsswitch.conf
passwd:      compat sss
shadow:      compat sss
group:       compat sss
hosts:       files dns
networks:    files dns
services:    db files
protocols:   db files
rpc:         db files
ethers:      db files
netmasks:    files
netgroup:    files
bootparams:  files
automount:   files
aliases:     files
sudoers:     files ldap sss

PAMの設定

ディストリビューションによってデフォルトの設定がやや異なりますが、今回はこのように設定しました。
おおむねpam_sss.soを使用している行が追加した行です。合わせてpam_unix.soを使用している行をrequiredからsufficientに変えています。
またログイン時にホームディレクトリが作成されるようにpam_mkhomedir.soを使用しています。なお、/homeはNFSで共有されておりどのサーバーに入っても同じホームディレクトリが見えるようにしています。

# grep -vE '^\s*($|#)' /etc/pam.d/system-auth
auth            required        pam_env.so 
auth            sufficient      pam_unix.so try_first_pass likeauth nullok 
auth            sufficient      pam_sss.so use_first_pass
auth            optional        pam_permit.so
account required        pam_unix.so 
account [default=bad success=ok user_unknown=ignore]            pam_sss.so
account optional        pam_permit.so
password        required        pam_cracklib.so difok=2 minlen=8 dcredit=2 ocredit=2 retry=3 
password        sufficient      pam_unix.so try_first_pass use_authtok nullok sha512 shadow 
password        sufficient      pam_sss.so use_authtok
password        optional        pam_permit.so
session         required        pam_limits.so 
session         required        pam_env.so 
session         required        pam_unix.so 
session         optional        pam_mkhomedir.so skel=/etc/skel/ umask=0077
session         optional        pam_sss.so
session         optional        pam_permit.so

OpenSSHの設定

OpenSSH 6.2からAuthorizedKeysCommandという項目名で公開鍵を取得する外部プログラムを呼び出せるようになっています。
この設定とSSSDが提供するsss_ssh_authorizedkeysコマンドによってLPKパッチを当てなくてもLDAPからSSSDを経由して公開鍵を取得できるようになります。
余談ですがLDAPサーバー側はLPKスキーマが欲しいのでOpenSSHのUSEフラグにldapを指定してインストールしています。

# grep -vE '^\s*($|#)' /etc/ssh/sshd_config
PubkeyAuthentication yes
AuthorizedKeysCommand /usr/bin/sss_ssh_authorizedkeys
AuthorizedKeysCommandUser nobody
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
PrintMotd no
PrintLastLog no
UsePrivilegeSeparation sandbox          # Default for new installations.
Subsystem       sftp    /usr/lib64/misc/sftp-server
AcceptEnv LANG LC_*

このようにsss_ssh_authorizedkeysコマンドの引数にユーザー名を渡すと公開鍵が取得できることを確認できます。

[mazgi@base] $ sss_ssh_authorizedkeys mazgi
ssh-rsa AAAA********Hs2V mazgi@BRUICHLADDICH.local
ssh-rsa AAAA********61rn mazgi@Ardbeg.local

デーモンの起動

ここまで設定できたらsshdsssdを起動します。
この例ではホームディレクトリをマウントするためにnfsclientも起動しています。

# rc-status
Runlevel: default
 netmount                                                          [  started  ]
 local                                                             [  started  ]
Dynamic Runlevel: hotplugged
Dynamic Runlevel: needed
 rpcbind                                                           [  started  ]
 rpc.pipefs                                                        [  started  ]
 rpc.idmapd                                                        [  started  ]
 rpc.statd                                                         [  started  ]
 nfsclient                                                         [  started  ]
Dynamic Runlevel: manual
 net.eth0                                                          [  started  ]
 sshd                                                              [  started  ]
 sssd                                                              [  started  ]
 net.eth1                                                          [  started  ]

ここまでの手順でLDAPに登録されている公開鍵でSSHログインしてsudoできるようになります。

[mazgi@localhost] $ id
uid=10001(mazgi) gid=10000(example) groups=10000(example),11001(level1),11002(level2),11003(level3),11004(level4),11005(level5)
[mazgi@localhost] $ sudo -ll
Matching Defaults entries for mazgi on localhost:
    ignore_local_sudoers, insults, !authenticate, !env_reset

User mazgi may run the following commands on localhost:

LDAP Role: level1
    RunAsUsers: root
    Commands:
    /bin/false

LDAP Role: level2
    RunAsUsers: root
    Commands:
    /usr/bin/tail
    /usr/bin/tailf
    /usr/bin/less
    /bin/ls
    /usr/bin/sha1sum
    /usr/bin/sha224sum
    /usr/bin/sha256sum
(snip)

ちゃんとログインできてUIDとグループとSUDO情報が取得できていますね!

おわりに

会社ではこのインスタンスを複製して本番環境や社内サービスに使っています。
クラウドなので複製後は以下の3ステップでサーバーが使い始められます。楽チンですね!

  • IPアドレスの設定
  • ホスト名の設定
  • SSHホスト鍵の再生成

参考にさせていただいたページ

flaggieをはじめ数々のGentoo TIPSについてはEmacs ひきこもり生活を参考にさせていただいています。

SSSDの設定についてはsssd.conf ファイルの設定をはじめとしたRed Hat社が公開してくださっているRHELのドキュメントが大変参考になります。

さくらのクラウドでサーバーを複製する方法はさくらのクラウドニュースで紹介されているロードバランサとサーバクローンで簡単スケールアウトというTIPSが参考になります。