環境
- CentOS 6.5
Overview
SSHを多要素認証にしたい。
公開鍵認証が端末の紛失などによって突破された場合の保険としてTOTP(Time-Based One Time password)のGoogle Authenticator認証を追加する。
Requirements
- pam_google_authenticator
- pam_ldap
Install
- 依存パッケージのインストール
yum install openldap-clients nss-pam-ldapd pam_ldap openssh-ldap
- pam_google_authenticatorのDL & インストール
tar jxf libpam-google-authenticator-1.0-source.tar.bz2
cd libpam-google-authenticator-1.0
make && make install
- LDAPクライアントの設定
authconfig-tui
・ユーザ情報
「LDAPを使用」にチェック
・認証
「シャドウパスワードを使用」
「LDAP認証を使用」
「ローカル認証は十分です」
にチェック
・LDAP設定
「サーバー」「baseDN」を入力しOKを押す。
uri ldap://210.129.173.120/
base dc=tako,dc=asia
# host 210.129.173.120
binddn cn=Directory Manager
bindpw password
ssl no
- PAMの設定
/etc/pam.d/sshd
# %PAM-1.0
auth required pam_sepermit.so
auth required pam_google_authenticator.so
# auth include password-auth
account required pam_nologin.so
account include password-auth
password include password-auth
# pam_selinux.so close should be the first session rule
session required pam_selinux.so close
session required pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session required pam_selinux.so open env_params
session optional pam_keyinit.so force revoke
session include password-auth
session required pam_mkhomedir.so skel=/etc/skel umask=0022
auth required pam_google_authenticator.so
を追記します。
ここでauth include password-auth
をコメントアウトし無効にするのがポイントです。これをしないとパスワードログインが有効であると認識されます。
/etc/pam.d/system-auth
# %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
/etc/pam.d/password-auth
# %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
- sshd_configの設定
以下の項目を設定する。
RSAAuthentication yes
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication yes
RequiredAuthentications2 publickey,keyboard-interactive
AuthorizedKeysCommand /usr/libexec/openssh/ssh-ldap-wrapper
AuthorizedKeysCommandRunAs nobody
UsePAM yes
解説: RequiredAuthentications2
はRHEL系のOpenSSHのみ有効。
Debian系はOpenSSH6.2以上で同じ意味のAuthenticationMethods
が使える。
RequiredAuthentications2 publickey,keyboard-interactive
で認証方法を2つ指定している。
- LDAP用のスキーマをインポートする
attributetype ( 1.3.6.1.4.1.24552.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.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
DESC 'MANDATORY: OpenSSH LPK objectclass'
MUST ( sshPublicKey $ uid )
)
- LDAPに公開鍵を登録。
dn: uid=test,ou=people,dc=tako,dc=asia
givenName: test
objectClass: person
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: posixAccount
objectClass: top
objectClass: ldapPublicKey
uid: test
cn: test
sn: user
userPassword:: e1NTSEF9VjlzaDEvd1pmQ0Z0Vjc1NGdGZGdKN2tlNitFNk9PRDJUTnRWcHc9PQ=
=
homeDirectory: /home/test
sshPublicKey: ssh-rsa ...... hoge@localhost
uidNumber: 100
gidNumber: 500
上記の/etc/ssh/sshd_configで設定した
AuthorizedKeysCommand /usr/libexec/openssh/ssh-ldap-wrapper
が
実際にLDAPサーバを検索するときにかけるフィルタは
(&(objectClass=posixAccount)(objectClass=ldapPublicKey))
なのでこの2つのオブジェクトクラスが必要。openssh-ldapを使わない場合はAuthorizedKetsCommandにLDAPサーバを検索して公開鍵を返すスクリプト、例えば以下のようなスクリプトで検索し、posixAccountクラスは不要。
# !/bin/bash
uri=ldap://127.0.0.1/
binddn="cn=Directory Manager"
bindpw=password
base="dc=example,dc=com"
uid=$1
/usr/bin/ldapsearch -LLL -H ${uri} -w "${bindpw}" -D "${binddn}" -b "${base}" "(& (objectClass=ldapPublicKey) (uid=${uid}))" "sshPublicKey" | tail -n +2 | sed -e "s/sshPublicKey\: //g" | sed -e 's/^[ ]*//g' | awk '{printf $0}'
- アカウント情報を引けるか確認
[root@hoge]# id test
uid=100(test) gid=500(vagrant) groups=500(vagrant)
引けない場合は/etc/pam_ldap.confにある設定が正しいか確認。
- ユーザを作成
adduser test
- google-authenticator用のシークレットファイルを作る
$ su - test
$ google-authenticator -t -D -f -u -W
バーコードのURLが表示されるのでブラウザで開き、iPhoneまたはAndroidの「Google Authenticator」で検索して出てくるアプリで読み取ってtokenを登録する
- 確認
$ ssh example.com -l test
Authenticated with partial success.
Verification code: <<Google AuthenticatorのOTPを入力>>
ここにモバイル端末のGoogle Authenticatorアプリで表示されているワンタイムパスワードを入力し、無事ログイン出来れば完了です。