요약
이 글에서는 OpenVPN 서버가 LinOTP 백엔드에 대해 OTP(일회용 비밀번호)로 사용자 인증을 수행하도록 설정하는 전체 과정을 설명합니다. 주요 단계는 LinOTP 설치, PAM 모듈(pam_py_linotp) 설치 및 구성, OpenVPN의 PAM 연동입니다.
TL;DR
OpenVPN에서 LinOTP로 2단계 인증을 적용하려면 LinOTP를 설치하고 pam_py_linotp를 PAM 스택에 추가한 뒤 OpenVPN에서 openvpn-auth-pam.so 플러그인을 사용해 PAM을 호출하면 됩니다. 클라이언트 인증서와 OTP 조합으로 보안을 강화할 수 있습니다.
대상 독자
- 자체 VPN을 운영하는 시스템/네트워크 관리자
- 여러 유형의 OTP 토큰(하드웨어, 스마트폰 앱 등)을 중앙에서 관리하려는 보안 담당자
- OpenVPN과 PAM, LinOTP 연동에 익숙해지고 싶은 엔지니어
전제 조건
- OpenVPN이 설치되어 있고 기본 서버/클라이언트 설정이 작동하는 환경
- 루트 또는 sudo 권한
- LinOTP 설치 가능한 서버(같은 호스트에 설치 가능)
- Python 환경 및 패키지 설치 도구(pip 등)
핵심 개념 한 줄 정의
- LinOTP: 중앙에서 OTP 토큰을 발급/관리하고 검증 요청을 처리하는 오픈소스 인증 서버.
- PAM(Pluggable Authentication Modules): 리눅스의 인증 플러그인 프레임워크.
- pam_py_linotp: LinOTP 검증을 위한 Python 기반 PAM 모듈.
LinOTP 설치 개요
- 배포판 패키지(예: Debian/Ubuntu)나 Python Package Index를 통해 설치할 수 있습니다. 데모나 빠른 시험용으로는 pip를 통한 설치가 편리합니다. 최신 버전을 확인하세요.
- LinOTP 백엔드와 OpenVPN 데몬을 같은 머신에 두면 설정과 디버깅이 단순해집니다. 단, 운영 환경에서는 보안 및 리소스 관점에서 분리 배포를 고려하세요.
중요: 실제 운영에서는 HTTPS와 인증서 관리를 통해 LinOTP API 엔드포인트를 보호하세요.
PAM을 통한 LinOTP 인증 구성
LinOTP에는 C로 작성된 pam_linotp 모듈도 있지만, 개발용 라이브러리 설치와 컴파일 작업이 필요합니다. 더 간단한 대안으로 pam_py_linotp(파이썬 모듈)를 사용하면 설정이 수월합니다.
다음은 pam_py_linotp를 OpenVPN 서버에 설치하는 일반 방법입니다.
터미널에서 압축을 확인하고 설치:
tar -ztf pam_py_linotp-0.1.tar.gz
cd pam_py_linotp-0.1/
sudo python setup.py install
또는 pip로 빠르게 설치:
sudo pip install pam_py_linotp
또는 단일 파이썬 모듈을 지정한 위치에 복사:
cd pam_py_linotp-0.1/
cp src/ pam_linotp.py /lib/security
pam_py_linotp를 PAM 스택에서 사용하려면 libpam-python이 필요합니다. 배포판에 따라 설치하세요:
sudo apt-get install libpam-python
또는
yum install libpam-python
이제 다른 서비스(ssh, gdm, kdm 등)에도 동일한 2단계 인증 구성을 쉽게 적용하기 위해 공통 인증 파일(common-linotp)을 만들겠습니다.
auth [success=1 default=ignore] pam_python.so /lib/security/pam_linotp.py \
debug url=https://localhost/validate/check
auth requisite pam_deny.so
auth required pam_permit.so
설명:
- pam_python.so 다음의 첫 번째 인수는 설치하거나 복사한 파이썬 모듈 경로입니다.
- url 매개변수는 LinOTP 검증 API의 위치(프로토콜 및 포트 포함)를 지정합니다. LinOTP가 같은 머신에서 실행된다면 localhost로 둘 수 있지만 운영 환경에서는 실제 호스트명이나 IP, 그리고 HTTPS를 사용한 포트 번호를 기입하세요.
이 파일을 /etc/pam.d/common-linotp 같은 위치에 저장해 두면 이후 PAM 정의에서 @include로 재사용할 수 있습니다.
OpenVPN에 PAM 연동하기
클라이언트 구성 예(client.ovpn):
client
dev tun
proto udp
remote your.server.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client.crt
key client.key
comp-lzo
verb 3
auth-user-pass
- 서버 이름과 인증서 파일명을 환경에 맞게 조정하세요.
서버 구성 예(server.conf):
port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh2048.pem
server 192.168.42.0 255.255.255.0
ifconfig-pool-persist ipp.txt
keepalive 10 120
comp-lzo
persist-key
persist-tun
status openvpn-status.log
verb 3
plugin /usr/lib/openvpn/openvpn-auth-pam.so openvpn
- openvpn-auth-pam.so 플러그인은 OpenVPN이 PAM을 호출하도록 해 줍니다. 위에서 만든 PAM 구성은 /etc/pam.d/openvpn에서 참조됩니다.
/etc/pam.d/openvpn 파일 내용 예:
@include common-linotp
session sufficient pam_permit.so
account sufficient pam_permit.so
- session과 account에 pam_permit.so를 사용하면 OpenVPN 서버에 로컬 사용자 계정을 만들지 않아도 됩니다. 인증은 LinOTP가 수행합니다.
- 사용자가 올바른 OTP(및 필요하면 PIN)를 입력하면 VPN 연결이 성립합니다.
보안 권장 사항
- LinOTP API와 PAM 통신은 반드시 HTTPS로 보호하세요. 인증서 유효성 검사를 활성화하고 자체 서명 인증서를 사용하는 경우 클라이언트와 서버가 신뢰하도록 설정하세요.
- OTP와 클라이언트 인증서를 조합하면 “장치 소유 + 사용자 인증”의 이중 보안이 됩니다.
- 로그 접근 권한을 제한하고 실패한 인증 시도에 대한 모니터링을 설정하세요.
중요: 운영 환경에서는 LinOTP와 OpenVPN이 동일 호스트에 있는 것이 편리하나, 보안 정책상 분리 배포를 고려하세요.
문제 해결(언제 실패하는가 그리고 해결법)
- 인증 실패: LinOTP의 로그와 /var/log/auth.log(또는 배포판별 인증 로그)를 확인하세요. PAM 모듈의 debug 옵션을 활성화하면 추가 정보를 얻을 수 있습니다.
- 네트워크 문제: OpenVPN 서버에서 LinOTP API에 접속 가능한지(curl 또는 wget으로) 확인하세요. 방화벽과 포트 설정을 점검하세요.
- 모듈 위치 문제: pam_python이나 pam_linotp.py의 경로가 잘못되어 PAM 로딩 실패가 발생할 수 있습니다. /lib/security 경로와 모듈 권한을 확인하세요.
- 클라이언트 입력 문제: 클라이언트의 auth-user-pass 동작은 사용 중인 OpenVPN 클라이언트에 따라 다를 수 있습니다. 대부분 대화형으로 OTP를 입력하게 되지만, 자동화 스크립트나 GUI에서 올바르게 작동하는지 확인하세요.
대안과 확장
- RADIUS를 통한 통합: 이미 RADIUS 기반 인증 인프라가 있다면 LinOTP를 RADIUS 프로토콜로 연동하여 사용하는 방법도 있습니다. 대규모 환경에서 중앙 인증을 쉽게 통합할 수 있습니다.
- Web API 직접 호출: PAM 대신 OpenVPN이나 다른 서비스에서 직접 LinOTP Web API를 호출해 인증을 수행하는 커스텀 플러그인을 개발할 수 있습니다.
- 하드웨어 토큰 통합: LinOTP는 다양한 토큰 타입을 지원하므로 하드웨어 OTP 또는 스마트폰 앱(예: TOTP)을 동시에 관리할 수 있습니다.
운영자 역할별 체크리스트
- 관리자(설치/설정 담당): LinOTP 설치, HTTPS 설정, pam_py_linotp 설치, common-linotp 파일 생성, /etc/pam.d/openvpn 구성
- 보안 담당자: 인증 로그 모니터링 설정, SSL/TLS 인증서 관리, 권한 최소화
- 네트워크 운영자: 방화벽 및 포트 허용, OpenVPN 서버 네트워크 설정, IP 풀 검토
빠른 점검 절차(체크리스트)
- LinOTP 서비스가 HTTPS로 동작하는가?
- pam_py_linotp 모듈이 설치되어 있고 경로가 올바른가?
- /etc/pam.d/common-linotp 파일에 올바른 URL과 옵션이 있는가?
- OpenVPN 서버.conf에 plugin으로 openvpn-auth-pam.so가 지정되어 있는가?
- /etc/pam.d/openvpn에서 common-linotp를 포함하고 있는가?
- 클라이언트에서 auth-user-pass로 OTP를 입력할 수 있는가?
결정 흐름(빠른 판단용)
graph TD
A[사용자 접속 요청] --> B{클라이언트 인증서 유효성 확인}
B -- 유효 --> C{PAM 인증 호출}
B -- 무효 --> Z[연결 거부]
C -- LinOTP 인증 성공 --> D[VPN 연결 허용]
C -- LinOTP 인증 실패 --> Y[인증 실패 로그 기록]
결론
이 가이드에서는 OpenVPN을 LinOTP로 인증하도록 설정하는 방법(핵심 단계: LinOTP 설치, pam_py_linotp 설치 및 PAM 구성, OpenVPN에서 PAM 호출)을 설명했습니다. 클라이언트 인증서와 OTP를 함께 사용하면 장치 기반과 사용자 기반의 이중 인증으로 보안 수준을 높일 수 있습니다.
요약: LinOTP와 pam_py_linotp를 활용하면 다양한 OTP 토큰을 중앙에서 관리하면서 OpenVPN에 2단계 인증을 비교적 간단히 도입할 수 있습니다.
요약된 핵심 사항
- LinOTP는 중앙 OTP 관리와 검증 API를 제공합니다.
- pam_py_linotp와 libpam-python을 설치하면 PAM으로 LinOTP를 호출할 수 있습니다.
- OpenVPN은 openvpn-auth-pam.so 플러그인을 통해 PAM 인증을 수행합니다.