Google Authenticator로 리눅스 SSH MFA 가장 빠르게 적용하기




리눅스 서버에 MFA를 적용하는 가장 간단한 방법은 Google Authenticator다. 무료이고, 외부 의존성이 없고, 30분이면 끝난다. 이 글에서는 설치부터 PAM 설정, SSH 연동, 운영 시 주의사항까지 한 편에 정리한다.


왜 Google Authenticator인가

1편에서 여러 MFA 방식을 비교했다. 그중 Google Authenticator(pam_google_authenticator)는 가장 진입 장벽이 낮은 선택이다.

  • 무료. 라이선스 비용이 없다.
  • 외부 의존성 제로. 인터넷이 끊겨도 동작한다. 별도 서버도 불필요하다.
  • 표준 기반. RFC 6238(TOTP) 표준을 따르므로 Google Authenticator뿐 아니라 Authy, Microsoft Authenticator, 1Password 등 대부분의 TOTP 앱과 호환된다.
  • 검증됨. 수년간 널리 사용되어 온 오픈소스 프로젝트다.

서버 1~2대에 빠르게 MFA를 적용하고 싶다면, 이것부터 시작하는 것을 권한다.


전체 흐름

[사용자 PC] → SSH → [리눅스 서버]
                        ├── 1. 비밀번호 검증 (pam_unix)
                        └── 2. TOTP 코드 검증 (pam_google_authenticator)
                                ↕
                          외부 통신 없음
                          서버 로컬에서 완결

동작 원리는 단순하다. 서버와 사용자의 TOTP 앱이 같은 시크릿 키를 공유하고, 현재 시간을 기반으로 동일한 6자리 코드를 각각 생성한다. 서버는 사용자가 입력한 코드가 자신이 생성한 코드와 일치하는지 비교할 뿐이다. 네트워크 통신이 필요 없는 이유다.


Step 1. PAM 모듈 설치

Ubuntu/Debian:

sudo apt update
sudo apt install libpam-google-authenticator

RHEL/CentOS:

sudo yum install epel-release
sudo yum install google-authenticator

설치가 끝나면 pam_google_authenticator.so 모듈이 PAM 모듈 디렉토리에 추가된다.


Step 2. 사용자별 TOTP 등록

MFA를 적용할 각 사용자 계정으로 로그인한 뒤 실행한다. root가 아니라 해당 사용자 본인이 실행해야 한다.

google-authenticator

대화형 프롬프트가 나온다. 권장 응답은 다음과 같다.

Do you want authentication tokens to be time-based (y/n) y

y. 시간 기반 OTP(TOTP)를 사용한다. 이벤트 기반(HOTP)보다 보안성이 높다.

이 시점에서 QR 코드가 터미널에 표시된다. 핸드폰의 TOTP 앱(Google Authenticator, Authy 등)으로 스캔한다. QR 코드 아래에 시크릿 키도 텍스트로 표시되므로, QR 스캔이 어려운 환경이라면 수동 입력할 수 있다.

이어서 비상 복구 코드(Emergency scratch codes) 5개가 출력된다. 핸드폰을 분실했을 때 사용할 수 있는 일회용 코드이므로 반드시 안전한 곳에 보관해야 한다.

나머지 질문은 다음과 같이 응답한다.

Do you want me to update your "~/.google_authenticator" file? (y/n) y

y. 설정 파일을 저장한다.

Do you want to disallow multiple uses of the same authentication token? (y/n) y

y. 같은 코드를 30초 내에 재사용하지 못하게 한다. 중간자 공격 방지에 유효하다.

By default, a new token is generated every 30 seconds by the mobile app.
...
Do you want to do so? (y/n) n

n. 시간 윈도우를 기본값(±30초)으로 유지한다. 서버 시간이 정확하다면 넓힐 필요 없다.

Do you want to enable rate-limiting? (y/n) y

y. 30초당 3회 시도 제한을 걸어 무차별 대입을 방지한다.

완료되면 홈 디렉토리에 ~/.google_authenticator 파일이 생성된다. 이 파일에 시크릿 키와 설정이 저장된다.


Step 3. PAM 설정

SSH 인증 시 TOTP 검증을 추가한다.

sudo vi /etc/pam.d/sshd

파일 끝에 다음 줄을 추가한다.

auth required pam_google_authenticator.so

인증 조합별 설정

비밀번호 + TOTP (가장 일반적):

@include common-auth (또는 auth substack password-auth) 아래에 추가한다. 비밀번호를 먼저 검증하고, 통과하면 TOTP 코드를 요구한다.

@include common-auth
auth required pam_google_authenticator.so

SSH 키 + TOTP (가장 강력):

SSH 키 인증 후 추가로 TOTP를 요구하는 조합이다. 이 경우 PAM 설정과 함께 sshd_config에서 AuthenticationMethods도 설정해야 한다 (Step 4에서 다룬다).

점진적 적용: nullok 옵션

아직 TOTP를 등록하지 않은 사용자가 있다면, nullok 옵션을 추가한다.

auth required pam_google_authenticator.so nullok

이렇게 하면 ~/.google_authenticator 파일이 없는 사용자는 기존 방식(비밀번호만)으로 로그인할 수 있다. 모든 사용자의 등록이 완료되면 nullok을 제거하여 MFA를 강제한다.


Step 4. SSH 데몬 설정

sudo vi /etc/ssh/sshd_config

다음 항목을 확인하고 변경한다.

ChallengeResponseAuthentication yes
KbdInteractiveAuthentication yes
UsePAM yes

ChallengeResponseAuthenticationno로 되어있으면 TOTP 코드 입력 프롬프트가 표시되지 않는다.

SSH 키 + TOTP 조합을 원하는 경우

AuthenticationMethods publickey,keyboard-interactive

이 설정은 SSH 키 인증을 먼저 통과한 뒤, keyboard-interactive(TOTP)를 추가로 요구한다.


Step 5. SSH 재시작

⚠️ 필수: 반드시 현재 SSH 세션을 유지한 채, 별도 터미널에서 테스트한다. 설정 오류 시 접속이 차단될 수 있다.

sudo systemctl restart sshd

Step 6. 테스트

새 터미널에서 SSH 접속을 시도한다.

ssh user@your-server

정상 흐름:

$ ssh user@your-server
Password:                          ← 비밀번호 입력
Verification code:                 ← TOTP 앱의 6자리 코드 입력
Last login: ...
user@your-server:~$                ← 로그인 성공

테스트 체크리스트

  • [ ] 올바른 비밀번호 + 올바른 TOTP → 로그인 성공
  • [ ] 올바른 비밀번호 + 틀린 TOTP → 로그인 실패
  • [ ] 틀린 비밀번호 → TOTP 프롬프트 없이 즉시 실패
  • [ ] nullok 설정 시, 미등록 사용자 → 기존 방식으로 로그인 성공

서버 시간 동기화

TOTP는 시간 기반이므로 서버 시간이 정확해야 한다. 서버와 핸드폰의 시간이 30초 이상 어긋나면 코드가 불일치한다.

# NTP 동기화 활성화
sudo timedatectl set-ntp true

# 현재 시간 확인
timedatectl

# 시간 동기화 상태 확인
timedatectl show-timesync --all    # systemd 기반
ntpstat                             # ntpd 기반

NTP가 비활성화되어 있거나 시간이 어긋나 있다면, MFA 적용 전에 반드시 먼저 해결해야 한다.


운영 시 알아둘 것

사용자 추가 시

새 사용자가 서버에 접속해야 하면, 해당 사용자로 로그인한 뒤 google-authenticator를 실행해서 TOTP를 등록해야 한다. 관리자가 대신 해줄 수 없다 — QR 코드를 사용자 본인의 핸드폰으로 스캔해야 하기 때문이다.

# 사용자 계정으로 전환 후
su - newuser
google-authenticator

핸드폰 분실/교체 시

두 가지 복구 방법이 있다.

방법 1. 비상 복구 코드 사용

초기 설정 시 출력된 5개의 복구 코드 중 하나로 로그인한 뒤, google-authenticator를 다시 실행하여 새 QR을 등록한다. 복구 코드는 일회용이다.

방법 2. 관리자가 시크릿 파일 초기화

복구 코드도 없다면, 관리자(root)가 해당 사용자의 설정 파일을 삭제한다. nullok 옵션이 켜져 있다면 사용자는 비밀번호만으로 로그인할 수 있고, 이후 다시 google-authenticator를 실행하면 된다.

# 관리자가 실행
sudo rm /home/username/.google_authenticator

여러 서버에 적용할 때의 한계

이 방식의 가장 큰 한계는 서버마다 개별 등록이 필요하다는 점이다. 사용자가 서버 A, B, C에 접속해야 하면, 각 서버에서 google-authenticator를 실행하고 QR 코드를 각각 스캔해야 한다. TOTP 앱에 항목이 서버 수만큼 늘어난다.

서버가 3~4대를 넘어가기 시작하면, 이 관리 부담이 체감된다. 이 시점이 되면 Duo(3편)나 Okta RADIUS(4편) 같은 중앙 관리 방식을 검토할 때다.

root 계정

root에도 MFA를 적용하려면 root로 google-authenticator를 별도 실행해야 한다. 다만 root 계정에 MFA를 적용하면 비상 시 복구가 어려워질 수 있으므로, 콘솔 접근 경로를 반드시 확보해둬야 한다.


트러블슈팅

Verification code 프롬프트가 안 나옴

sshd_config에서 ChallengeResponseAuthentication yesKbdInteractiveAuthentication yes가 설정되어 있는지 확인한다. 변경 후 sshd 재시작을 빠뜨리는 경우가 많다.

올바른 코드를 입력해도 실패

서버 시간을 확인한다. timedatectl로 현재 시간이 정확한지, NTP 동기화가 활성화되어 있는지 확인한다. 서버와 핸드폰 시간이 30초 이상 차이나면 코드가 불일치한다.

SSH 접속이 완전히 차단됨

콘솔(물리/IPMI/하이퍼바이저)로 접속한 뒤, /etc/pam.d/sshd에서 pam_google_authenticator.so 줄을 주석 처리하고 sshd를 재시작한다.

# 콘솔에서
sudo vi /etc/pam.d/sshd
# auth required pam_google_authenticator.so  ← 주석 처리
sudo systemctl restart sshd

정리

항목내용
소요 시간30분
비용무료
별도 서버불필요
외부 통신불필요
호환 앱Google Authenticator, Authy, Microsoft Authenticator, 1Password 등
적합 환경서버 1~3대, 빠르게 MFA를 적용하고 싶을 때
한계서버마다 개별 등록, 중앙 관리 불가

Google Authenticator는 “지금 당장 MFA를 켜야 한다”는 상황에서 가장 합리적인 선택이다. 서버가 늘어나 관리가 부담스러워지면, 그때 다른 방식으로 전환하면 된다.

다음 편에서는 RADIUS 없이 푸시 알림 방식의 MFA를 적용할 수 있는 Duo Security를 다룬다.




댓글 남기기