=====================
環境
- CentOS 6.5
- OpenLDAP
Overview
まともに管理すると煩雑になりがちなsudoをLDAPで一元的に管理したい。
Installation
with Ansible
インストール手順は全てplaybook化してあります。
$ git clone git@github.com:shufo/ansible-sudo-ldap.git
$ cd ansible-sudo-ldap
$ vagrant up
でVagrant仮想マシン上に以下の手動でのインストール手順を再現したOpenLDAP+sudoなテスト環境が出来ます。(要Ansible, Vagrant)
立ち上がったら
$ vagrant ssh
[vagrant@vagrant ~]$ sudo su
[root@vagrant ~]$ su - test
[test@vagrant ~]$ sudo cat /var/log/secure
"Enter [test]'s Password:" password
で動作確認出来ます。
リモートに構築する場合はansible_hosts
ファイルを編集し
default ansible_ssh_host=127.0.0.1 ansible_ssh_port=22
playbookを直接実行してください。
ansible-playbook site.yml -i ansible_hosts
クライアント側のみ構築する場合はtasks/main.yml
のLDAPサーバ側用のタスクをコメントアウトしてください。
---
# - include: server.yml
- include: client.yml
手動
LDAPサーバ設定
-
OpenLDAP、依存パッケージのインストール
yum install openldap openldap-servers openldap-clients pam_ldap
-
LDAPディレクトリ初期化
mkdir /var/lib/ldap
chown ldap:ldap /var/lib/ldap
rm -fR /etc/openldap/slapd.d/*
- 設定ファイルコピー
```bash
cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
cp /usr/share/openldap-servers/slapd.conf.obsolete /etc/openldap/slapd.conf
-
LDAPサーバのrootパスワード生成
/usr/sbin/slappasswd -s password
```/etc/openldap/slapd.conf
# スキーマファイル設定
include /etc/openldap/schema/corba.schema
include /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/duaconf.schema
include /etc/openldap/schema/dyngroup.schema
include /etc/openldap/schema/inetorgperson.schema
include /etc/openldap/schema/java.schema
include /etc/openldap/schema/misc.schema
include /etc/openldap/schema/nis.schema
include /etc/openldap/schema/openldap.schema
include /etc/openldap/schema/ppolicy.schema
include /etc/openldap/schema/collective.schema
# 接続プロトコル
allow bind_v2
# 管理ファイル
pidfile /var/run/openldap/slapd.pid
argsfile /var/run/openldap/slapd.args
# TLS設定
#TLSCACertificatePath /etc/openldap/ssl/cacert.pem
#TLSCertificateFile /etc/openldap/ssl/server.crt
#TLSCertificateKeyFile /etc/openldap/ssl/server.key
# userPasswordに関するアクセス権
access to attrs=userPassword
by self write
by dn="cn=Directory Manager,dc=example,dc=com" write
by anonymous auth
by * none
# その他の属性に対するアクセス権
access to *
by self write
by dn="cn=Directory Manager,dc=example,dc=com" write
by * read
# monitorデータベースに対するアクセス権
database monitor
access to *
by dn.exact="cn=Directory Manager,dc=example,dc=com" read
by * none
# データベース設定
database bdb
suffix "dc=example,dc=com"
checkpoint 1024 15
rootdn "dc=example,dc=com"
rootpw {SSHA}jadajsdna〜中略〜hogehoge
directory /var/lib/ldap
# indexの設定
index objectClass eq,pres
index ou,cn,mail,surname,givenname eq,pres,sub
index uidNumber,gidNumber,loginShell eq,pres
index uid,memberUid eq,pres,sub
index nisMapName,nisMapEntry eq,pres,sub
-
LDAPサーバにsudo用のschemaを読みこませる
schema.OpenLDAP
をスキーマに追加。cp /usr/share/doc/sudo-1.8.6p3/schema.OpenLDAP /etc/openldap/schema/sudo.schema
/etc/openldap/slapd.confに
/etc/openldap/slapd.confinclude /etc/openldap/schema/sudo.schema
を追加。
-
openldapを起動
service slapd start
-
エントリを作成する
ベースになるエントリを作成します。
add_ou.ldifdn: dc=example,dc=com objectClass: dcObject objectClass: organization dc: example o: example dn: ou=people,dc=example,dc=com objectClass: organizationalUnit ou: people dn: ou=groups,dc=example,dc=com objectClass: organizationalUnit ou: groups
ldapadd -D "cn=Directory Manager,dc=example,dc=com" -w password -f add_ou.ldif
-
ユーザを作成する
サンプルとして
test
ユーザを作成する。add_user.ldifdn: uid=test,ou=people,dc=example,dc=com
objectClass: account
objectClass: posixAccount
uid: test
cn: test
userPassword: {SSHA}hogehoge〜中略〜
loginShell: /bin/bash
uidNumber: 1000
gidNumber: 1000
homeDirectory: /home/test
`posixAccount`クラスの必須属性は`loginShell`、`uidNumber`、`gidNumber`、`homeDirectory`なのでこの4つは最低限含める必要があります。
```bash
ldapadd -D "cn=Directory Manager,dc=example,dc=com" -w password -f add_user.ldif
-
グループを作成する
サンプルとして
members
グループを作成する。add_group.ldifdn: cn=members,ou=groups,dc=example,dc=com objectClass: top cn: members objectClass: posixGroup gidNumber: 1000
ldapadd -D "cn=Directory Manager,dc=example,dc=com" -w password -f add_group.ldif
-
sudoers用ouを作成する
vim sudoersOU.ldif
sudoersOU.ldifdn: ou=SUDOers,dc=example,dc=com description: SUDOers objectClass: organizationalUnit objectClass: top ou: SUDOers
ldapadd -x -D "cn=Directory Manager,dc=example,dc=com" -w password -f sudoersOU.ldif
-
/etc/sudoersを編集する
[root@agenttest user.0]# cat /etc/sudoers | grep -v "^#" | grep -v "^\s*$"
Cmnd_Alias FILE_READ = /bin/cat, /bin/more, /usr/bin/tail
Cmnd_Alias SERVICE = /sbin/service
Cmnd_Alias NETWORK_LOOKUP = /bin/ping, /bin/netstat, /usr/bin/nslookup
Cmnd_Alias DELEGATING = /bin/chown, /bin/chmod, /bin/chgrp
Defaults !visiblepw
Defaults always_set_home
Defaults env_reset
Defaults env_keep="COLORS DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR LS_COLORS"
Defaults env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
Defaults env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
Defaults env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
Defaults env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"
Defaults !root_sudo
Defaults !lecture
Defaults log_host
Defaults log_year
Defaults logfile=/var/log/sudo.log
Defaults ignore_dot
Defaults ignore_local_sudoers
Defaults timestamp_timeout=0
Defaults passprompt="Enter [%u]'s Password:"
Defaults badpass_message="The password is not corresponding. Try again."
Defaults insults
Defaults secure_path=/sbin:/bin:/usr/sbin:/usr/bin
root ALL=(ALL) ALL
%members ALL=(ALL) FILE_READ
%wheel ALL=NOPASSWD: ALL
解説: `Cmnd_Alias`で定義したコマンドの集まりを各グループに対して割り当てている。
`%members ALL=(ALL) FILE_READ`で`members`グループに`FILE_READ`で定義した`/bin/cat, /bin/more, /usr/bin/tail`コマンドの実行を許可している。`members`グループのユーザに対して`ALL`(全て)のホストから`ALL`(任意)のユーザ権限で`FILE_READ`で定義したコマンドが実行可能という意味。`less`ではなく`more`を許可しているのは`less`は`:!/bin/bash`とless内でコマンドを実行することでrootのシェルを取得出来るから。
`!root_sudo`でrootでのsudoを禁止、`!lecture`で最初にでる説明を非表示、`ignore_local_sudoers`でLDAP参照のみにしてローカルの/etc/sudoersを無視するようにしている。
- `sudoers2ldif`でldifファイルに変換する
```bash
export SUDOERS_BASE=ou=SUDOers,dc=example,dc=com
cat /etc/sudoers | perl /usr/share/doc/sudo-1.8.6p3/sudoers2ldif > sudoers.ldif
dn: cn=defaults,ou=SUDOers,dc=example,dc=com
objectClass: top
objectClass: sudoRole
cn: defaults
description: Default sudoOption's go here
sudoOption: !visiblepw
sudoOption: always_set_home
sudoOption: env_reset
sudoOption: env_keep="COLORS DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR LS_COLORS"
sudoOption: env_keep+="MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
sudoOption: env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
sudoOption: env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
sudoOption: env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"
sudoOption: !root_sudo
sudoOption: !lecture
sudoOption: log_host
sudoOption: log_year
sudoOption: logfile=/var/log/sudo.log
sudoOption: ignore_dot
sudoOption: ignore_local_sudoers
sudoOption: timestamp_timeout=0
sudoOption: passprompt="Enter [%u]'s Password:"
sudoOption: badpass_message="The password is not corresponding. Try again."
sudoOption: secure_path=/sbin:/bin:/usr/sbin:/usr/bin
〜中略〜
-
LDIFをインポートする
sudoers2ldif
で変換したLDIFをインポートするldapadd -x -D "cn=Directory Manager,dc=example,dc=com" -w password -f sudoers.ldif
LDAPクライアント側設定
- 依存パッケージのインストール
yum install openldap-clients nss-pam-ldapd pam_ldap openssh-ldap authconfig
- 認証周りを
authconfig
で設定
# LDAPによるユーザ情報参照を有効にする
authconfig --enableldap --update
# LDAPによる認証を有効にする
authconfig --enableldapauth --update
# ユーザのホームディレクトリの自動作成を有効にする
authconfig --enablemkhomedir --update
# shadowパスワードの使用を有効にする
authconfig --enableshadow --update
# local認証を有効にする
authconfig --enablelocauthorize --update
# LDAPサーバのURIを指定
authconfig --ldapserver=ldap://127.0.0.1:389 --update
# LDAPサーバのベースDNを指定
authconfig --ldapbasedn=dc=example,dc=com --update
以上のコマンドを実行した結果のPAMの設定は以下です。
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth required pam_env.so
auth sufficient pam_unix.so nullok try_first_pass
auth requisite pam_succeed_if.so uid >= 500 quiet
auth sufficient pam_ldap.so use_first_pass
auth required pam_deny.so
account required pam_unix.so broken_shadow
account sufficient pam_localuser.so
account sufficient pam_succeed_if.so uid < 500 quiet
account [default=bad success=ok user_unknown=ignore] pam_ldap.so
account required pam_permit.so
password requisite pam_cracklib.so try_first_pass retry=3 type=
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password sufficient pam_ldap.so use_authtok
password required pam_deny.so
session optional pam_keyinit.so revoke
session required pam_limits.so
session optional pam_mkhomedir.so skel=/etc/skel umask=077
session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session required pam_unix.so
session optional pam_ldap.so
pam_mkhomedir
モジュールを有効にしているのでユーザのホームディレクトリが存在しない場合自動的に作られます。自動削除はされないので必要なくなったら削除しましょう。
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth required pam_env.so
auth sufficient pam_unix.so nullok try_first_pass
auth requisite pam_succeed_if.so uid >= 500 quiet
auth sufficient pam_ldap.so use_first_pass
auth required pam_deny.so
account required pam_unix.so broken_shadow
account sufficient pam_localuser.so
account sufficient pam_succeed_if.so uid < 500 quiet
account [default=bad success=ok user_unknown=ignore] pam_ldap.so
account required pam_permit.so
password requisite pam_cracklib.so try_first_pass retry=3 type=
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password sufficient pam_ldap.so use_authtok
password required pam_deny.so
session optional pam_keyinit.so revoke
session required pam_limits.so
session optional pam_mkhomedir.so skel=/etc/skel umask=077
session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session required pam_unix.so
session optional pam_ldap.so
- sudo-ldapの設定
sudo-ldap.conf
はauthconfig
では設定出来ないので手動で設定します。
[root@localhost]# sudo -V
ldap.conf path: /etc/sudo-ldap.conf
[root@localhost ]# cat /etc/sudo-ldap.conf | grep -v "^#" | grep -v "^\s*$"
binddn cn=Directory Manager
bindpw password
uri ldap://127.0.0.1:389
sudoers_base ou=SUDOers,dc=example,dc=com
sudoers_debug 1
- sudoersの参照先をldapに切り替え
[root@localhost]# cat /etc/nsswitch.conf | grep sudoers
sudoers: ldap files
- 確認
他ユーザにsuして確認してみる。
[root@localhost]# su - test
[shufo@localhost ~]$ sudo cat /var/log/secure
sudo: ldap_set_option: debug -> 0
sudo: ldap_set_option: ldap_version -> 3
sudo: ldap_sasl_bind_s() ok
sudo: Looking for cn=defaults: cn=defaults
sudo: found:cn=defaults,ou=SUDOers,dc=example,dc=com
sudo: ldap search '(|(sudoUser=test)(sudoUser=%test)(sudoUser=%#501)(sudoUser=ALL))'
sudo: searching from base 'ou=SUDOers,dc=example,dc=com'
sudo: adding search result
sudo: result now has 0 entries
sudo: ldap search '(sudoUser=+*)'
sudo: searching from base 'ou=SUDOers,dc=example,dc=com'
sudo: adding search result
sudo: result now has 0 entries
sudo: sorting remaining 0 entries
sudo: searching LDAP for sudoers entries
sudo: done with LDAP searches
sudo: user_matches=1
sudo: host_matches=0
sudo: sudo_ldap_lookup(0)=0x40
Enter [test]'s Password: [パスワード入力]
test is not allowed to run sudo on localhost. This incident will be reported.
LDAPサーバに問い合わせされているのがログから分かる。
実際に問い合わせているクエリはbaseDNのou=SUDOers,dc=example,dc=com
を(|(sudoUser=shufo)(sudoUser=%shufo)(sudoUser=%#501)(sudoUser=ALL))
で検索している。