RADIUS 서버나 Agent 없이, 리눅스 서버에 패키지 하나만 설치해서 푸시 알림 기반 MFA를 적용할 수 있다. Duo Security의 pam_duo 모듈을 사용하면 된다. 10명 이하 무료 플랜이 있어서 소규모 팀에서 바로 시작할 수 있다.
왜 Duo인가
1편에서 다양한 MFA 방식을 비교했고, 2편에서는 Google Authenticator를 다뤘다. Google Authenticator는 간편하지만 매번 6자리 코드를 직접 입력해야 하고, 서버마다 개별 등록이 필요하다는 한계가 있었다.
Duo Security는 이 두 가지 불편함을 해결한다.
- 푸시 알림: 코드를 입력하는 대신, 핸드폰에 뜨는 알림을 한 번 탭하면 인증이 끝난다.
- 중앙 관리: 사용자 등록과 MFA 정책을 Duo 관리 콘솔에서 일원화할 수 있다.
- RADIUS 불필요: 전용 PAM 모듈(pam_duo)이 Duo Cloud API를 직접 호출하므로, 별도 RADIUS Agent나 서버가 필요 없다.
- 10명 이하 무료: Duo Free 플랜으로 비용 없이 시작할 수 있다.
전체 구조
[사용자 PC] → SSH → [리눅스 서버]
├── 1. 비밀번호 검증 (pam_unix)
└── 2. Duo 인증 (pam_duo)
│ HTTPS (TCP 443)
↓
[Duo Cloud]
│
↓
[핸드폰 - Duo Mobile 푸시 알림]
Google Authenticator와 비교하면, 서버 로컬에서 TOTP를 검증하는 대신 Duo Cloud에 인증을 위임하는 구조다. 서버에서 Duo API로 HTTPS 요청을 보내고, Duo가 사용자의 핸드폰으로 푸시 알림을 발송하고, 승인 결과를 서버에 돌려준다.
이 때문에 서버에서 Duo Cloud(TCP 443)로 Outbound 통신이 가능해야 한다. 인터넷이 차단된 폐쇄망에서는 사용할 수 없다.
Step 1. Duo 계정 생성 및 애플리케이션 등록
1-1. Duo 가입
https://signup.duo.com에서 가입한다. 10명 이하는 무료 플랜(Duo Free)으로 시작할 수 있다.
1-2. Unix Application 생성
- Duo Admin Panel 접속
- Applications → Protect an Application
Unix Application을 검색하고 Protect 클릭- 생성된 애플리케이션에서 세 가지 값을 확인한다:
- Integration key (ikey)
- Secret key (skey)
- API hostname (host)
이 세 값을 안전하게 기록해둔다. 이후 서버 설정에서 사용한다.
1-3. 사용자 등록
Duo Admin Panel → Users에서 SSH 접속을 허용할 사용자를 추가한다. Username은 리눅스 사용자명과 동일해야 한다.
사용자는 Duo에 처음 접속할 때 자동으로 등록(enrollment)할 수도 있고, 관리자가 미리 등록해둘 수도 있다.
사용자 핸드폰에 Duo Mobile 앱(iOS/Android)을 설치하고, Duo에 등록해야 푸시 알림을 받을 수 있다.
Step 2. Duo Unix 패키지 설치
Ubuntu/Debian
# Duo 저장소 GPG 키 추가
curl -s https://duo.com/DUO-GPG-PUBLIC-KEY.asc | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/duo.gpg
# 저장소 추가
echo "deb [arch=amd64] https://pkg.duosecurity.com/Ubuntu $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/duosecurity.list
# 설치
sudo apt update
sudo apt install duo-unix
RHEL/CentOS
# 저장소 파일 생성
cat <<EOF | sudo tee /etc/yum.repos.d/duosecurity.repo
[duosecurity]
name=Duo Security Repository baseurl=https://pkg.duosecurity.com/RedHat/\$releasever/\$basearch enabled=1 gpgcheck=1 EOF # GPG 키 가져오기 및 설치 sudo rpm –import https://duo.com/DUO-GPG-PUBLIC-KEY.asc sudo yum install duo_unix
설치가 완료되면 /etc/duo/pam_duo.conf 설정 파일과 /lib64/security/pam_duo.so PAM 모듈이 생성된다.
Step 3. Duo 설정
sudo vi /etc/duo/pam_duo.conf
Step 1에서 확인한 세 가지 값을 입력한다.
[duo]
; Duo integration key
ikey = DIXXXXXXXXXXXXXXXXXX
; Duo secret key
skey = YourSecretKeyHere
; Duo API hostname
host = api-XXXXXXXX.duosecurity.com
; Duo 서비스 장애 시 동작
; safe = MFA 없이 로그인 허용 (가용성 우선)
; secure = 로그인 차단 (보안 우선)
failmode = safe
; 푸시 알림에 로그인 정보(IP, 사용자명) 포함
pushinfo = yes
; 자동으로 푸시 알림 발송 (사용자가 '1' 누를 필요 없음)
autopush = yes
failmode 선택
이 설정은 중요하다. Duo Cloud에 연결할 수 없을 때(네트워크 장애, Duo 서비스 장애 등)의 동작을 결정한다.
| 값 | 동작 | 적합 환경 |
|---|---|---|
safe | MFA 없이 로그인 허용 | 가용성이 중요한 환경 (개발, 스테이징) |
secure | 로그인 차단 | 보안이 최우선인 환경 (프로덕션) |
secure로 설정하면 Duo 장애 시 SSH 접속이 완전히 차단될 수 있으므로, 반드시 콘솔(IPMI, 하이퍼바이저 등) 접근 경로를 확보해둬야 한다.
권한 설정
Secret key가 포함된 설정 파일이므로 권한을 제한한다.
sudo chmod 600 /etc/duo/pam_duo.conf
그룹 기반 선택 적용
특정 그룹 사용자에게만 Duo MFA를 적용하려면 groups 옵션을 사용한다.
; duo-mfa 그룹에 속한 사용자만 MFA 적용
groups = duo-mfa
# 그룹 생성 및 사용자 추가
sudo groupadd duo-mfa
sudo usermod -aG duo-mfa username
이 그룹에 속하지 않은 사용자는 Duo 인증을 건너뛴다. 점진적 전환 시 유용하다.
Step 4. PAM 설정
sudo vi /etc/pam.d/sshd
배포판에 따라 PAM 설정 구조가 다르다. 핵심은 pam_unix(비밀번호 검증) 다음에 pam_duo를 배치하는 것이다.
Ubuntu/Debian
기존:
@include common-auth
변경:
#@include common-auth
auth required pam_unix.so
auth sufficient /lib64/security/pam_duo.so
auth required pam_deny.so
RHEL/CentOS
기존:
auth substack password-auth
변경:
auth required pam_sepermit.so
auth required pam_env.so
#auth substack password-auth
auth requisite pam_unix.so try_first_pass nullok
auth sufficient /lib64/security/pam_duo.so
auth required pam_deny.so
auth include postlogin
PAM 설정 해설
| 줄 | 역할 |
|---|---|
auth requisite pam_unix.so | 비밀번호 검증. 실패하면 즉시 거부 (Duo까지 가지 않음) |
auth sufficient pam_duo.so | Duo 인증 성공 시 로그인 허용 |
auth required pam_deny.so | Duo 인증 실패 시 로그인 거부 |
pam_duo.so의 경로는 배포판에 따라 /lib64/security/pam_duo.so 또는 /lib/security/pam_duo.so일 수 있다. 설치 후 실제 경로를 확인한다.
find / -name "pam_duo.so" 2>/dev/null
Step 5. SSH 데몬 설정
sudo vi /etc/ssh/sshd_config
UsePAM yes
ChallengeResponseAuthentication yes
UseDNS no
UseDNS no는 Duo 권장 설정이다. DNS 역조회 대신 IP 주소를 직접 PAM에 전달하여, 푸시 알림에 정확한 접속 IP가 표시되도록 한다.
Ubuntu 22.04 이상에서는 ChallengeResponseAuthentication 대신 KbdInteractiveAuthentication을 사용한다.
UsePAM yes
KbdInteractiveAuthentication yes
UseDNS no
SSH 키 + Duo MFA 조합
SSH 키 인증 후 추가로 Duo 인증을 요구하려면:
AuthenticationMethods publickey,keyboard-interactive
Step 6. SSH 재시작 및 테스트
⚠️ 필수: 반드시 현재 SSH 세션을 유지한 채 별도 터미널에서 테스트한다.
sudo systemctl restart sshd
새 터미널에서 접속:
ssh user@your-server
최초 접속 (미등록 사용자)
사용자가 Duo에 아직 등록되지 않았다면, 등록 링크가 표시된다.
Please enroll at https://api-XXXXXXXX.duosecurity.com/portal?code=XXXXX&akey=XXXXX
이 URL을 브라우저에서 열어 Duo Mobile 앱을 등록하면 된다.
정상 흐름 (autopush = yes)
$ ssh user@your-server
Password: ← 비밀번호 입력
Pushed a login request to your device...
← 핸드폰에서 Duo Mobile 푸시 승인
Success. Logging you in...
user@your-server:~$ ← 로그인 성공
autopush = yes로 설정했기 때문에 비밀번호 입력 후 자동으로 푸시 알림이 발송된다. 사용자는 핸드폰에서 “Approve”를 탭하기만 하면 된다.
수동 선택 (autopush = no)
autopush = no로 설정하면 인증 방법을 선택할 수 있다.
Password:
Duo login for user
1. Duo Push to XXX-XXX-1234
2. Phone call to XXX-XXX-1234
3. SMS passcodes to XXX-XXX-1234
Passcode or option (1-3): 1 ← '1' 입력하면 푸시 발송
Google Authenticator와의 비교
같은 서버에 적용한다고 했을 때의 차이를 정리하면:
| 항목 | Google Authenticator | Duo Security |
|---|---|---|
| 설치 | apt install libpam-google-authenticator | apt install duo-unix |
| 사용자 등록 | 서버에서 google-authenticator 실행 | Duo 콘솔 또는 자동 |
| 인증 방식 | 6자리 코드 직접 입력 | 푸시 알림 한 번 탭 |
| 인증 소요 시간 | 앱 열기 → 코드 확인 → 입력 (10~15초) | 알림 뜸 → 탭 (3~5초) |
| 외부 통신 | 없음 | HTTPS (Duo Cloud) |
| 오프라인 | ✅ 동작 | ❌ 불가 (Duo 연결 필요) |
| 중앙 관리 | ❌ | ✅ Duo Admin Panel |
| 서버 추가 시 | 서버마다 사용자별 QR 등록 | 서버마다 duo_unix 설치 + 설정 |
| 비용 | 무료 | 10명↓ 무료 |
| 사용자 정책 | 없음 (서버별 개별) | 그룹별 정책, 접근 제어 |
요약: Google Authenticator는 외부 의존 없이 동작하는 것이 강점이고, Duo는 사용자 경험(푸시 알림)과 중앙 관리가 강점이다.
운영 시 알아둘 것
서버 추가 시
새 서버에 Duo MFA를 적용하려면 해당 서버에 duo_unix 패키지를 설치하고 pam_duo.conf에 같은 API 키를 넣으면 된다. Duo 콘솔에서 추가 작업은 불필요하다. 다만 모든 서버에 같은 Secret key가 배포되므로, Ansible 같은 도구로 일괄 관리하는 것을 권장한다.
RADIUS 방식(4편에서 다룰 Okta 등)과 비교하면, RADIUS는 서버 쪽에 PAM 설정만 넣고 Agent가 인증을 중계하는 반면, Duo는 서버마다 모듈과 API 키가 필요하다. 서버가 수십 대를 넘어가면 이 차이가 체감된다.
Duo Cloud 장애 대비
failmode = safe로 설정하면 Duo Cloud에 연결할 수 없을 때 MFA 없이 로그인이 허용된다. 가용성이 중요한 환경에서는 이 설정이 적합하지만, 보안 관점에서는 MFA가 우회되는 셈이다.
failmode = secure로 설정하면 더 안전하지만, 반드시 콘솔 접근 경로를 확보해둬야 한다.
사용자 핸드폰 분실
Duo Admin Panel에서 해당 사용자의 디바이스를 삭제하고, 새 핸드폰으로 재등록하면 된다. Google Authenticator와 달리 서버에 접속할 필요 없이 콘솔에서 원격으로 처리할 수 있다.
관리자가 일시적으로 Bypass 코드를 생성해줄 수도 있다. 사용자는 이 코드로 로그인한 뒤 새 핸드폰을 등록하면 된다.
트러블슈팅
푸시 알림이 안 옴
서버에서 Duo Cloud로 HTTPS 통신이 가능한지 확인한다.
curl -I https://api-XXXXXXXX.duosecurity.com
방화벽에서 TCP 443 Outbound가 차단되어 있다면 열어줘야 한다.
“Permission denied” 에러
/etc/duo/pam_duo.conf의ikey,skey,host값이 정확한지 확인- Duo에 등록된 Username과 리눅스 사용자명이 일치하는지 확인
- SELinux가 활성화된 경우 pam_duo의 외부 통신을 차단할 수 있다. Duo 공식 문서의 SELinux 설정을 참고한다.
SSH 접속이 완전히 차단됨
콘솔로 접속한 뒤 PAM 설정을 복원한다.
sudo vi /etc/pam.d/sshd
# pam_duo.so 관련 줄을 주석 처리하고
# 원래 common-auth 또는 password-auth를 복원
sudo systemctl restart sshd
정리
| 항목 | 내용 |
|---|---|
| 소요 시간 | 30~40분 |
| 비용 | 10명 이하 무료 (Duo Free) |
| 별도 서버 | 불필요 |
| RADIUS | 불필요 |
| 필요 통신 | 서버 → Duo Cloud (HTTPS, TCP 443) |
| 인증 방식 | 푸시 알림, TOTP, 전화, SMS |
| 적합 환경 | 소규모 팀, 푸시 알림 원할 때, 중앙 관리 필요할 때 |
| 한계 | 외부 통신 필수, 서버마다 모듈 설치 필요 |
Duo는 “코드 입력이 귀찮고, 푸시 한 번이면 끝나는 게 좋다”는 팀에 딱 맞는 선택이다. 서버 수가 적고 Ansible 같은 자동화가 되어 있다면 관리 부담도 크지 않다.
다음 편에서는 이미 Okta를 사용하는 조직에서 RADIUS Agent를 Docker로 구성하여 SSH MFA를 적용하는 방법을 다룬다.