Edited at

ssh password authentication + Google Authenticator

More than 1 year has passed since last update.

sshのパスワード認証(公開鍵認証ではない) + MFAtoken によるログインの設定方法です。

やりたいことは、クラメソさんのこの記事のパスワード認証版です。


  • 検証には、AWSさんから、Amazon Linux AMI 2017.03.1 (HVM), SSD Volume Type (ami-3bd3c45c) を利用しました。

  • MFAtoken は Google Authenticator です。

[Note] 本ドキュメントの command枠 のコピペ作業で、動作できるように作っています。(ミスを避けるため vi による編集を避けた)


1. pre-conditions


1.1 Login to the server

AWSの操作は省略します。下記のAMIをつかってサーバを起動しました。


  • Amazon Linux AMI 2017.03.1 (ami-3bd3c45c) をつかってEC2を起動します。

  • 起動後、サーバーへログインします。


1.2 Chenge timezone (追記: たぶん変更しなくても大丈夫)

Timezoneの設定はこちらを参考にしました。

timezoneファイル差し替え


command

sudo cp /etc/localtime /etc/localtime.org

sudo ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
&& cat /etc/localtime

reboot後変更したタイムゾーンがUTCにもどらないための設定


command

sudo cp /etc/sysconfig/clock /etc/sysconfig/clock.org

sudo sh -c "echo -e 'ZONE=\"Asia/Tokyo\"\nUTC=false' > /etc/sysconfig/clock" \
&& cat /etc/sysconfig/clock


1.3 Update packages


command

sudo yum update



1.4 Installing google/google-authenticator


command

sudo yum install google-authenticator qrencode-libs -y



2. How to setup


2.1 Editing sshd_config


/etc/ssh/sshd_config の編集

編集するsshd_configのバックアップをとります.


commnad

cp /etc/ssh/sshd_config ${HOME}/_bak_sshd_config


sshd_configが下記になるよう編集します。

PasswordAuthentication は yes でも no でもどちらでも大丈夫です。

/etc/pam.d/sshdpassword-auth を有効にすることでこの設定は関係なく上手く動くようです。


  • ChallengeResponseAuthentication yes

  • UsePAM yes

現状を確認します。


command

cat /etc/ssh/sshd_config \

| grep -e ^PasswordAuthentication \
-e ^ChallengeResponseAuthentication \
-e ^UsePAM


response

PasswordAuthentication no

ChallengeResponseAuthentication no
UsePAM yes

ここでは ChallengeResponseAuthenticationyes になるよう編集する必要があることがわかりましたので、修正します。


command

BEFORE="ChallengeResponseAuthentication no"

AFTER="ChallengeResponseAuthentication yes"
sudo sed -i s/"${BEFORE}"/"${AFTER}"/g /etc/ssh/sshd_config

再度内容を確認します。


command

cat /etc/ssh/sshd_config \

| grep -e ^ChallengeResponseAuthentication


response

ChallengeResponseAuthentication yes


ec2-userは今まで通り公開鍵認証のログインのままとします。


command

sudo sh -c "cat << EOF >> /etc/ssh/sshd_config

# -- EC2 USER Setting --
Match User ec2-user
AuthenticationMethods publickey
PubkeyAuthentication yes
PasswordAuthentication no
EOF" && tail /etc/ssh/sshd_config



response

#   X11Forwarding no

# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs serverMatch User ec2-user

# -- EC2 USER Setting --
Match User ec2-user
AuthenticationMethods publickey
PubkeyAuthentication yes
PasswordAuthentication no



sshdの再起動

sshdの再起動します。


command

sudo service sshd restart



response

Stopping sshd:                                             [  OK  ]

Starting sshd: [ OK ]


2.2 Editing PAM sshd

次にPAMの設定を修正し、sshログイン認証時にGoogle Authenticatorが使われるようにします。


/etc/pam.d/google-authの作成

同じファイル名のファイルがないことを確認します。


command

ls -l /etc/pam.d/google-auth



response

ls: cannot access /etc/pam.d/google-auth: No such file or directory


google-authという名前のファイルを作成します。これは /etc/pam.d/sshd から読み込みます。


command

sudo sh -c "cat << EOF > /etc/pam.d/google-auth

#%PAM-1.0
auth required pam_env.so
auth sufficient pam_google_authenticator.so nullok
auth requisite pam_succeed_if.so uid >= 500 quiet
auth required pam_deny.so
EOF"
&& cat /etc/pam.d/google-auth


/etc/pam.d/sshdの編集

編集する /etc/pam.d/sshd のバックアップをとります.


command

cp /etc/pam.d/sshd ${HOME}/_bak_pam_sshd


現在の変数の状況を確認します。


command

cat /etc/pam.d/sshd | grep ^auth



response

auth       required pam_sepermit.so

auth substack password-auth
auth include postlogi

google authentication を有効にするためこのファイルを編集します。


command

BEFORE="auth       substack     password-auth"

AFTER="auth substack password-auth\nauth substack google-auth"
sudo sed -i s/"${BEFORE}"/"${AFTER}"/g /etc/pam.d/sshd

もう一度ファイルを確認します。


command

cat /etc/pam.d/sshd | grep "^auth"



response

auth       required pam_sepermit.so

auth substack password-auth
auth substack google-auth
auth include postlogin

もう一度サービスを再起動します(いらないかも...)


command

sudo service sshd restart

Stopping sshd: [ OK ]
Starting sshd: [ OK ]


2.3 Creating ".google_authenticator" at first user's login

/etc/profile.d/google-authenticator.shを作成し、root と ec2-user以外のユーザがはじめてログインしたとき、google_authenticatorの初期設定がなされ、ユーザの ${HOME}/.google_authenticator が強制的に作成されるよう設定します。

同名のファイルがないかを確認します。


command

ls -l /etc/profile.d/google-authenticator.sh



response

ls: cannot access /etc/profile.d/google-authenticator.sh: No such file or directory


/etc/profile.d/google-authenticator.sh を作成します


command

cat << EOF > google-authenticator.sh

#!/bin/sh

trap 'exit' SIGINT

if [ "\$USER" != "root" -a "\$USER" != "ec2-user" ]; then
if [ ! -f "
\$HOME/.google_authenticator" ]; then
echo "setup google-authenticator..."
/usr/bin/google-authenticator -t -d -w 17 -u -f
fi
fi
EOF
sudo cp google-authenticator.sh /etc/profile.d/google-authenticator.sh
sudo chmod +x /etc/profile.d/google-authenticator.sh
cat /etc/profile.d/google-authenticator.sh


-W 17 はもし、/usr/bin/google-authenticator を直だたきしたあと、4つめの "window" に関する質問 y で答えると、設定される値です。ここを調整しないとなぜかログインできなかったです。サーバとTokenデバイス間の Time-skew?


3. Test


3.1 Creating Test User

サーバー側へのログイン用のユーザを作ります。

/etc/pam.d/google-authの設定により、UIDは必ず500以上にする必要があります。

ユーザ名を決定します。


command

NEWUSER=<'任意のユーザ名'>


ユーザを作成します。


command

sudo useradd ${NEWUSER}


ユーザの状態を確認します。


command

id -a ${NEWUSER}



response

uid=501(<'任意のユーザ名'>) gid=501(<'任意のユーザ名'>) groups=501(<'任意のユーザ名'>)


初期パスワードを設定します。


command

sudo passwd ${NEWUSER}



3.2 Test


初回ログイン

テストを実施します。


command

ssh <'作成したユーザ'>@<'サーバー名'>


下記スクリーンショットの1行目の "Password" で Unixパスワードを入力しました。

1回目は、MFATokenの設定がされていないので、そのままログインできます。

Kobito.o4XnfV.png


2回目以降

サーバにログインします。


command

ssh <'作成したユーザ'>@<'サーバー名'>


PasswordでUnixパスワードを入力し、Verification code でMFATokenを入力します。


response

Password: 

Verification code:
Last login: Mon Aug 7 22:18:47 2017 from aa20111001946f573a19.userreverse.dion.ne.jp

__| __|_ )
_| ( / Amazon Linux AMI
___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2017.03-release-notes/



4. Refereces


5. Appendix


/etc/ssh/sshd_config

#   $OpenBSD: sshd_config,v 1.93 2014/01/10 05:59:19 djm Exp $

# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.

# This sshd was compiled with PATH=/usr/local/bin:/bin:/usr/bin

# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.

# If you want to change the port on a SELinux system, you have to tell
# SELinux about this change.
# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER
#
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::

# The default requires explicit activation of protocol 1
#Protocol 2

# HostKey for protocol version 1
#HostKey /etc/ssh/ssh_host_key
# HostKeys for protocol version 2
HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_dsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key

# Lifetime and size of ephemeral version 1 server key
#KeyRegenerationInterval 1h
#ServerKeyBits 1024

# Ciphers and keying
#RekeyLimit default none

# Logging
# obsoletes QuietMode and FascistLogging
#SyslogFacility AUTH
SyslogFacility AUTHPRIV
#LogLevel INFO

# Authentication:

#LoginGraceTime 2m
#PermitRootLogin yes
# Only allow root to run commands over ssh, no shell
PermitRootLogin forced-commands-only
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10

#RSAAuthentication yes
#PubkeyAuthentication yes

# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile .ssh/authorized_keys

#AuthorizedPrincipalsFile none

#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody

# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#RhostsRSAAuthentication no
# similar for protocol version 2
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# RhostsRSAAuthentication and HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes

# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
# EC2 uses keys for remote access
PasswordAuthentication no

# Change to no to disable s/key passwords
#ChallengeResponseAuthentication yes
ChallengeResponseAuthentication yes

# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
#KerberosUseKuserok yes

# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
#GSSAPIEnablek5users no

# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
# WARNING: 'UsePAM no' is not supported in Amazon Linux AMI and may cause several
# problems.
# Leaving enabled as described so that account and session checks are run
UsePAM yes

#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
#PrintMotd yes
# Explicitly enable
PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
UsePrivilegeSeparation sandbox # Default for new installations.
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#ShowPatchLevel no
#UseDNS yes
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none

# no default banner path
#Banner none

# Accept locale-related environment variables
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
AcceptEnv XMODIFIERS

# override default of no subsystems
Subsystem sftp /usr/libexec/openssh/sftp-server

# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs serverMatch User ec2-user
Match User ec2-user
AuthenticationMethods publickey
PubkeyAuthentication yes
PasswordAuthentication no



/etc/pam.d/google-auth

#%PAM-1.0

auth required pam_env.so
auth sufficient pam_google_authenticator.so nullok
auth requisite pam_succeed_if.so uid >= 500 quiet
auth required pam_deny.so


/ssh/pam.d/sshd

#%PAM-1.0

auth required pam_sepermit.so
auth substack password-auth
auth substack google-auth
auth include postlogin
# Used with polkit to reauthorize users in remote sessions
-auth optional pam_reauthorize.so prepare
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 required pam_namespace.so
session optional pam_keyinit.so force revoke
session include password-auth
session include postlogin
# Used with polkit to reauthorize users in remote sessions
-session optional pam_reauthorize.so prepare


/etc/profile.d/google-authenticator.sh

#!/bin/sh

trap 'exit' SIGINT

if [ "$USER" != "root" -a "$USER" != "ec2-user" ]; then
if
[ ! -f "$HOME/.google_authenticator" ]; then
echo "setup google-authenticator..."
/usr/bin/google-authenticator -t -d -w 17 -u -f
fi
fi



Memo: 1回目はパスワード、2回目はMFATokenのみの動作

1回目はパスワード、2回目はMFATokenのみのログインにしたい場合、/etc/pam.d/sshd を下記のようにします。またgoogle-authは必要ありません。なぜかは分からないけど、いろいろ触っていたらできた。

ようわからん。。。


/etc/pam.d/sshd

#%PAM-1.0

auth required pam_sepermit.so
#auth substack password-auth
auth sufficient pam_google_authenticator.so
auth requisite pam_succeed_if.so uid >= 500 quiet
auth substack password-auth
#auth substack google-auth
auth include postlogin
# Used with polkit to reauthorize users in remote sessions
-auth optional pam_reauthorize.so prepare
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 required pam_namespace.so
session optional pam_keyinit.so force revoke
session include password-auth
session include postlogin
# Used with polkit to reauthorize users in remote sessions
-session optional pam_reauthorize.so prepare