Google OTP를 사용한 SSH 인증
OTP는 One-Time-Password의 약자로 특정한 알고리즘에 의해 일정 시간 마다 생성되는 일회성 암호로 사용자를 확인하는 인증 방법입니다. OTP 기술을 활용한 다양한 보안 프로그램들이 있으며, 그 중에서 유명한 OTP 앱으로는 Google OTP가 있습니다. (한국 플레이스토어 앱 이름은 구글 OTP라고 자주 부르지만 정확한 영문 명칭은 Google Authenticator입니다.)
SSH 프로토콜로 원격 서버에 접속할 때 2FA(Two-Factor-Authentication)인증을 구성하기 위한 방법 중 하나로 Google OTP 코드를 사용할 수 있습니다.
2FA 인증을 설정하면서 보안상으로 볼 수 있는 이점이 크며 여기에 OTP 방식의 인증을 추가하는 것이므로 기존의 패스워드 방식의 인증보다는 더욱 안전한 계정 보호가 가능할 것입니다.
리눅스 Google Authenticator 설치
먼저 리눅스용 Google Authenticator를 설치해야 합니다. 아래 두 방법 중에서 하나만 선택하여 진행하면 됩니다.
[방법 1] : 패키지 설치 (권장)
패키지 설치는 의존성 체크와 함께 간편한 설치가 가능하므로 권장되는 방법입니다.
각 리눅스 배포판에서 기본으로 제공되는 패키지 관리자를 사용할 것입니다. 아래 내용을 참고하여 패키지 설치 명령을 실행합니다. (패키지 설치는 root 권한을 가진 사용자로 진행합니다.)
RedHat 계열 (RHEL / CentOS / Fedora)
[root@localhost ~]# yum install google-authenticator
만약 위와 같이 입력했는데도 설치할 패키지 파일이 존재하지 않는다고 하면, epel-release
패키지를 먼저 설치한 후 진행해보시기 바랍니다.
[root@localhost ~]# yum install epel-release
Debian 계열 (Debian / Ubuntu)
[root@localhost ~]# apt install libpam-google-authenticator
CentOS에서 설치된 예시는 다음과 같습니다.
# yum install google-authenticator Loaded plugins: fastestmirror, langpacks Determining fastest mirrors * base: mirror.kakao.com * epel: mirror.premi.st * extras: mirror.kakao.com * updates: mirror.kakao.com epel 12770/12770 google-chrome 3/3 Package google-authenticator-1.04-1.el7.x86_64 already installed and latest version Nothing to do
[방법 2] : 수동 설치
만약 위 방법으로 설치가 어려운 경우 다음 방법으로 수동 설치를 진행합니다. 먼저 관련된 패키지가 없다면 다음 패키지를 모두 설치해줍니다.
- pam-devel
- gcc
- autoconf
- automake
- libtool
- git
패키지 관리자를 사용할 수 있다면 다음과 같이 사용합니다.
[root@localhost ~]# yum install pam-devel gcc autoconf automake libtool git
이후 git clone
명령어로 google-authenticator-libpam
파일을 다운로드합니다.
[root@localhost ~]# git clone https://github.com/google/google-authenticator-libpam
다운로드한 폴더로 이동하여 패키지를 컴파일한 후에 설치합니다.
[root@localhost ~]# cd google-authenticator-libpam [root@localhost ~]# ./bootstrap.sh [root@localhost ~]# ./configure --libdir=/lib64 [root@localhost ~]# make install
SSH 인증을 위한 PAM 모듈 설정
기본적인 패키지 설치가 완료되었다면 이제 SSH 인증을 위한 몇가지 구성이 필요합니다. PAM(Pluggable Authentication Modules) 모듈을 사용하기 위해서 Google Authenticator 라이브러리를 추가해주어야 합니다.
먼저 SSH 서비스 데몬과 관련된 PAM 설정 파일인 /etc/pam.d/sshd
를 수정해야 합니다. 텍스트 에디터를 사용하여 파일을 열어보겠습니다.
[root@localhost ~]# vim /etc/pam.d/sshd
이후 다음 한 줄을 하단에 포함합니다.
auth required pam_google_authenticator.so nullok
여기서 우측의 nullok
를 포함하거나 뺄 수 있습니다. nullok
가 포함되면 리눅스 내의 모든 사용자가 각각의 secret key를 생성해야 합니다. 만약 동일한 secret key를 다 같이 사용하고자 할 때에는 nullok
를 제외시켜주면 됩니다.
추가하고 나면 다음과 같이 보여질 것입니다. (일부 운영체제 환경에 따라 설정 파일 내 모습이 다르게 보일 수는 있습니다.)
이제 SSH 서버의 설정 파일인 sshd_config
파일을 텍스트 에디터로 수정해보겠습니다. 여기에도 몇가지 요구되는 것들이 있습니다.
[root@localhost ~]# vim /etc/ssh/sshd_config
변경해야 할 내용들은 다음과 같습니다.
- PasswordAuthentication : 패스워드 인증을 사용할 것인가 (OTP 인증 시에는 패스워드 인증을 사용하지 않음)
- ChallengeResponseAuthentication : 시도-응답 인증 방식을 사용할 것인가 (2FA인증을 위해서도 필요)
- UsePAM : 인증에 PAM 모듈을 사용할 것인가
- PermitEmptyPasswords : 비어있는 사용자 암호를 허용할 것인가
파일이 열리면 아래 설정 값과 같은지 확인해봅니다. 만약 아래와 값이 다르다면, 수정해줍니다. (PasswordAuthentication
의 경우 필요하다면 yes
로 지정해도 됩니다.)
(추가로 PermitEmptyPasswords
의 항목에 대한 값이 yes
인 경우 추후 Google OTP 인증이 원활하지 않을 수 있습니다. 가능하면 이 항목의 값을 no
로 변경해주는 것이 좋습니다.)
PasswordAuthentication no ChallengeResponseAuthentication yes UsePAM yes PermitEmptyPasswords no
이제 SSH 서버 프로세스를 재시작해야 합니다. 다음 명령어를 사용하여 서비스를 재시작합니다.
[root@localhost ~]# service sshd restart
만약 systemd 를 사용 중인 최신 리눅스인 경우 다음과 같이 사용해도 됩니다.
[root@localhost ~]# systemctl restart sshd
만일의 에러에 대비하여 네트워크 시간을 동기화하여 시간 오차로 인한 인증 실패 문제를 예방할 수 있습니다. 하단의 명령어를 참고하여 NTP
서비스를 재시작합니다.
# RedHat / CentOS [root@localhost ~]# service ntpd restart # Debian / Ubuntu [root@localhost ~]# service ntp restart
OTP 인증파일이란?
인증을 위한 서버 설정은 어느정도 완료되었지만, SSH 서버가 갱신되었다 하더라도 각 사용자의 홈 디렉토리에 .google_authenticator
파일이 없으면 OTP 인증을 진행하지 않습니다. Challenge-Response-Authentication의 기본 설정인 패스워드만 물어볼 것입니다.
때문에 OTP 사용자 인증을 위해서는 Google Authenticator 인증 파일을 생성해야 합니다.
이 파일을 생성하는 도중에 OTP 인증에 대한 시크릿 키(Secret Key)가 나타날 것입니다. 시크릿 키는 쉽게 말하자면 OTP 토큰 값이 나타나는 패턴에 대한 일련의 해시값입니다.
시크릿 키는 공개 키 사용자 인증(Public Key Authentication)에서의 개인 키와 비슷한 역할을 하므로 인증할 대상자를 제외하고는 시크릿 키를 절대 공유해서는 안됩니다. 따라서 .google-authenticator
파일 또한 권한을 소유자에게만 지정해주어야 합니다. (이는 생성 시 알아서 진행될 것입니다.)
OTP 앱에서 이 서버와 유효한 인증 정보를 교환하기 위해서는 시크릿 키가 앱과 서버 모두 동일해야 합니다.
Google Authenticator 인증 파일 생성 (과정 1)
먼저 인증할 서버의 터미널에서 다음과 같이 입력합니다. 여기서 OTP 인증을 사용할 사용자 계정으로 명령을 입력해야 합니다. (예를 들어 user 라는 계정이 OTP를 사용하려면 해당 계정으로 전환한 후 명령을 실행해야 합니다.)
[user@localhost ~]$ google-authenticator
먼저 다음 프롬프트가 나타날 것입니다. 아래 프롬프트는 시간 기반(Time-based) 인증을 사용할 것인지에 대한 여부이므로 y
를 입력하여 다음으로 넘어갑니다.
Do you want authentication tokens to be time-based (y/n) y
이후 시크릿 키와 복구 코드가 나타날 것입니다. 시크릿 키를 쉽게 등록할 수 있는 QR코드 또한 나타납니다. (이는 Google OTP 앱에서만 사용 가능합니다.)
Warning: pasting the following URL into your browser exposes the OTP secret to Google: https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/[email protected]%3Fsecret%3D[SECRET KEY]%26issuer%3Dlocalhost.localdomain [QR코드가 여기에 나타납니다.] Your new secret key is: MHZSIJYMO################# Your verification code is 684### Your emergency scratch codes are: 4612#### ####9217 5569#### ####8321 7916####
만약 QR코드가 아래와 같이 제대로 나타난다면 OTP 앱에서 쉽게 추가할 수도 있습니다. (제대로 보이지 않는다면 터미널 글꼴이나 글자 크기를 변경해보세요.)
Google OTP 클라이언트 설치하기
이제 이 시크릿 키를 OTP 앱에 저장해야 합니다. 터미널에서 작업 하던 것을 잠깐 멈추고 (터미널을 종료하지 않아야 합니다!!) 모바일에서 OTP 클라이언트를 설치해보도록 하겠습니다.
- 안드로이드 플레이스토어 다운로드 : https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2
- 애플 앱스토어 다운로드 : https://itunes.apple.com/kr/app/google-authenticator/id388497605?mt=8
이외에도 제 3자 OTP 클라이언트에서 구글 OTP에서 사용하는 인증 알고리즘을 지원한다면 이를 설치하셔도 좋습니다. 여러 운영체제에서 사용이 가능하지만 여기서는 안드로이드 앱으로 진행해보도록 하겠습니다.
설치가 완료되었다면 실행하여 Secret Key를 등록해보도록 하겠습니다.
Google OTP 화면이 보이면 하단 우측에 있는 추가(+) 버튼을 클릭합니다.
QR코드를 스캔하고자 하면 ‘바코드 스캔’을 선택합니다. 그러면 즉시 OTP 코드가 추가되어 더 이상 OTP 앱에서 구성할 것은 없습니다.
만약 터미널에 나타나는 QR코드가 제대로 인식되지 않을 경우 하단의 ‘제공된 키 입력’ 을 선택합니다.
‘제공된 키 입력’을 선택했다면 다음과 같이 시크릿 키를 수동으로 입력해주어야 합니다. 계정 이름은 OTP 코드들을 구분하기 쉬운 별칭이면 어떤 이름이어도 상관없습니다.
이제 아래와 같이 OTP 코드가 나타난다면 등록 과정에는 일단 성공한 것입니다. 일정 시간이 지나면 하단의 토큰은 지속적으로 변경 될 것입니다.
Google Authenticator 인증 파일 생성 (과정 2)
아직 인증 서버 내 터미널에서의 몇가지 작업이 남아있어 계속 진행하도록 하겠습니다.
Do you want me to update your "/home/test/.google_authenticator" file? (y/n) y
위 프롬프트는 .google_authenticator
파일을 홈 디렉토리에 생성하겠냐는 물음입니다. y
를 입력하여 계속합니다.
만약 SELinux가 켜져있을 경우 이 파일을 읽지 못하여 문제가 발생할 수 있습니다. 인증 파일 읽기에 문제가 발생하면 추후 파일에 대한 액세스가 가능한지 확인해보셔야 합니다.
Do you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks (y/n) y
위 프롬프트는 30초 마다 생성되는 한 토큰에 대해 두 번 이상 인증하게 하여 중간자 공격(man-in-middle-attack)을 예방할 것인지에 대한 여부입니다. 여기서는 권장값인 y
를 입력합니다. n
을 입력하면 이미 인증된 후 다음 토큰이 생성될 때 까지 인증이 거부됩니다.
By default, a new token is generated every 30 seconds by the mobile app. In order to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. This allows for a time skew of up to 30 seconds between authentication server and client. If you experience problems with poor time synchronization, you can increase the window from its default size of 3 permitted codes (one previous code, the current code, the next code) to 17 permitted codes (the 8 previous codes, the current code, and the 8 next codes). This will permit for a time skew of up to 4 minutes between client and server. Do you want to do so? (y/n) n
이번에는 시간 동기화를 진행하면서 발생하는 시간상 오차 및 왜곡을 방지하고자 하는 옵션입니다. 기존에 허용되는 OTP 토큰은 현재 시간에 생성된 토큰의 이전과 다음 각각 1개씩 허용됩니다. 예를 들어 이전 토큰이 ‘111111’이었고 현재 토큰이 ‘222222’, 다음 예상 토큰이 ‘333333’이라면 입력 가능한 토큰은 이 세가지가 모두 허용됩니다.
이러한 허용 범위(이전 1개, 현재, 다음 1개)을 17개 (이전 8개, 현재, 다음 8개)로 넓힐 것인지에 대한 여부입니다.
가능하면 n
으로 설정하는 것이 좋지만 만약 시간차이로 인한 인증 실패에 걱정이 된다면 y
로 지정해도 무방합니다.
If the computer that you are logging into isn't hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s. Do you want to enable rate-limiting? (y/n) y
마지막으로 묻는 내용은 무차별 대입 공격(brute-force-attack)을 방지하기 위한 설정입니다. 30초 마다 생성되는 토큰에 3회 이상 인증에 실패하는 경우 일시적으로 로그인을 차단하도록 하는 내용입니다. 이 역시 y
로 설정하는 것을 권장합니다.
이제 .google_authenticator
파일이 생성되어있을 것입니다. 파일에는 다음과 같이 시크릿 키와 백업 키, 그리고 설정했던 내용들이 포함되어 있습니다.
MHZSIJYMO################# " RATE_LIMIT 3 30 " WINDOW_SIZE 17 " DISALLOW_REUSE " TOTP_AUTH 4612#### ####9217 5569#### ####8321 7916####
문제없이 생성되었다면 이제 SSH 서버 접속 및 인증 테스트를 진행해보도록 하겠습니다.
OTP 정보를 사용하여 SSH 접속하기
OTP 인증 파일을 생성하였고 사용 준비가 모두 완료되었습니다. 이제 실제로 SSH 서버에 접속하여 테스트해보도록 하겠습니다.
Challenge-Response 인증을 사용하기 위해서는 이러한 인증을 지원하는 SSH 클라이언트가 필요합니다. 여기서는 Windows용 SSH 클라이언트인 Xshell을 사용해보도록 하겠습니다.
Xshell을 열어 상단 메뉴의 파일 - 새로 만들기
를 클릭합니다.
세션 파일의 이름과 접속할 서버의 호스트 주소를 입력한 후 확인 또는 연결을 클릭합니다.
세션에 연결한 후에는 사용자 계정 및 암호를 물어볼 것입니다.
인증 방법은 ‘Keyboard Interactive’로 선택한 후 (또는 자동으로 선택될 것입니다.) 하단의 프롬프트에 나타난 내용대로 암호를 입력하면 됩니다.
먼저 Password:
프롬프트가 나타났으므로 사용자의 일반 암호를 입력합니다.
이제 ‘Verification code:
‘ 가 나타났습니다. 이 것이 바로 OTP 인증 토큰을 입력하는 부분입니다.
OTP 클라이언트(여기서는 안드로이드 Google OTP 앱)를 실행한 후 방금 전에 생성했던 키의 토큰 값 6자리를 여기에 입력해주시면 됩니다.
토큰이 정상 확인되면 SSH 서버에 성공적으로 접속된 것을 확인할 수 있을 것입니다.
이상으로 모든 OTP 인증 설정이 완료되었습니다.