방화벽으로 접근 통제, 공개키 인증, 그리고 fail2ban 으로 인증에 실패한 클라이언트 차단등으로 보안을 강화했지만 직원 PC가 해킹되어 원격으로 조정이 가능하거나 공개키와 암호가 유출될 경우 여전히 위협은 남게 됩니다.


이런 문제는 여러 인증 방법을 혼용하여 인증하는 Two Factor 인증을 통해 방지할 수 있으며 가장 많이 사용되는 일회용 암호(OTP; One Time Password) 방식을 적용하여 SSH 보안을 강화할 수 있습니다.


일회용 암호(One Time Password)란

전통적으로 암호와 같이 특정 정보를 알 경우 인증해주는 방식을 "지식 기반 인증(knowledge factor authentication)" 이라고 합니다. "지식 기반 인증"은 별도의 비용이 들지 않고 사용자들이 익숙한 장점이 있지만 보통 그 사용자의 개인 정보와 연관된 것을 사용하는 경우가 많아서 추측에 의한 무작위 공격에 취약하고 암호가 유출됐을 경우 유출 사실도 알기가 어려운 문제가 있습니다.

이를 해결하기 위해 암호를 복잡하게 설정하고 주기적으로 바꾸도록 강제하는 등의 여러 방법이 있지만 암호의 특성상 유출에 대한 근본적인 해결은 어렵습니다.


일회용 암호는 기존 암호의 단점에 대한 해결책으로 아주 짧은 시간만 유효한 암호를 사용하며 재활용이 불가능하므로 암호 유출 문제를 근본적으로 해결할 수 있으며 많이 사용하는 방식은 서버와 OTP 클라이언트간에 공유 비밀 키(shared secret key)를 나눠 갖고 시간을 맞춘 후에 일회용 비밀 번호를 생성하는 TOTP(Time-Based One-time Password) 방식입니다. 


구글 OTP 솔루션

액정이 달린 별도의 하드웨어 방식의 OTP 솔루션이 존재했지만 시스템 구축이 복잡하고 도입 가격이 비싸며 분실할수 있고(별도로 휴대해야 하므로 분실이 잦은 편입니다.) 배터리 사용 기간이 제한되어 있고 서버와 공유하는 비밀 키가 유출되면 기존 OTP 하드웨어를 버리고 새로 마련해야 하는 등  여러 가지 문제로 인해 도입이 쉽지 않았습니다.

스마트폰 시대로 넘어오면서 스마트폰 앱 형식의 OTP 가 나오면서 배터리와  OTP 하드웨어 분실 문제는 어느 정도 해결이 되었지만 솔루션 비용은 여전히 OTP 도입의 장벽이었습니다.


google authenticator 는  TOTP 를 구현한 오픈 소스 프로젝트로 유닉스의 인증 모듈인 PAM(Pluggable authentication module) 라이브러리와 유틸리티, 모바일 app 으로 나뉘어져 있으므로 인증이 필요한 서비스(예: ssh 서비스)에 적용하여 two factor 인증 기반으로 보안을 강화할 수 있습니다.


단 상용 제품이 아니다보니 관리가 약간 까다롭고 운영이 불편한 점이 있으므로 대량의 서버를 관리해야 한다면 Duo Security(https://duo.com/) 나 Authy (https://authy.com/)같은 OTP 전문 서비스를 도입하는 것이 좋으며 관리하는 장비가 많지 않고 초기 도입 비용이 없을 경우 google authenticator 가 적절한 선택입니다.


설치

  1. 사전에 EPEL 저장소가 설치되어 있어야 하며 fail2ban으로 SSH 강화하기 부분을 참고하세요.

  2. 서버용 구글 otp 를 설치합니다.

    $ sudo yum install google-authenticator -y
    CODE

google-authenticator 설정

  1. 먼저 사용하는 스마트 폰의 앱 스토어에서 "google authenticator" 또는 "google OTP" 를 키워드로 검색해서 나온 OTP 앱을 설치합니다.

  2. 구글 OTP 를 적용하려는 서버에 로그인 한 후에 two factor 인증을 사용하려는 계정(예: lesstif)으로 google-authenticator 명령어를 실행하며 각 옵션의 의미는 다음과 같습니다.

    $ google-authenticator -t -d  --label webserver --issuer example.com -r 3 -R 30 -s ~/.ssh/google_authenticator
    CODE
    • -t, --time-based: 시간 기반 OTP 를 설정합니다.

    • -d, --disallow-reuse: 이전에 사용한 TOTP 토큰의 재사용을 금지합니다.

    • -l, --label=<label>: 사용할 label 을 지정하며 구분할 수 있도록 해당 서버의 이름이나 도메인 이름등을 입력합니다. 여기서는 webserver 로 label 을 지정했습니다.
    • -i, --issuer=<issuer>: 사용할 발급자를 지정하며 여기에서는 사이트의 메인 도메인 이름을 입력합니다.
    • -r, --rate-limit=N:  -R로 설정한 M초동안 허용할 로그인 횟수를 지정합니다.
    • -R, --rate-time=M: M 초동안 허용할 로그인 횟수를 지정하며 -r 3 -R 30 은 30초 이내에 최대 3번의 로그인 시도를 허용합니다.
    • -S, --step-size=S: OTP 토큰을 갱신할 시간을 지정하며 기본 값은 30이며 이경우 30초마다 토큰을 새로 생성합니다.
    • -w, --window-size=W: OTP 토큰은 -S 로 지정한 토큰 갱신 시간(예: 30초) 동안만 유효하지만 입력시 초 단위로 이를 맞추기는 쉽지 않습니다. 즉 31초에 입력할 경우 OTP 토큰이 갱신되므로 무효화되어 버리며 이런 불편함을 줄이이고 -w 로 지정한 시간만큼 앞위로 유효하게 되며 5로 지정할 경우 토큰 갱신 시간이 30초라면 35초까지 해당 OTP 토큰이 유효합니다.
    • -s, --secret=<file>: google otp 의 secret 을 저장할 파일 경로를 지정하며 기본 설정은 $HOME/.google_authenticator 이지만 SELinux를 사용하는 경우 ssh 데몬의 접근을 차단해서 제대로 동작하지 않습니다. 그러므로 SELinux 를 사용하는 경우 .ssh 폴더에 넣어야 제대로 동작하며 SELinux 에 대한 내용은 다음 장에서 자세히 다룹니다.
  3. 그러면 아래와 같이 URL 문자열이 표시되며 텍스트로 QR 코드와 secret key가 표시됩니다. 구글 OTP 에 사이트를 등록하려면 아래의 secret key 를 입력해야 하지만 번거로우므로 QR Code 를 스캔하는 것이 편리합니다. 아래의 문자열을 복사해서 브라우저에 입력하면 QR 이미지가 뜨며 이것은  google OTP 앱에서 연결하기 위한 QR 이미지이므로 브라우저를 닫지 않고 열어둡니다.

    https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/webserver%3Fsecret%3DIVS7VVNOVJ7ZKWQSXOMGNRYW6I%26issuer%3Dexample.com
    
    
    
    
    Your new secret key is: IVS7VVNOVJ7ZKWQSXOMGNRYW6I
    CODE
  4. 아래와 같이 scratch code 가 표시되는데 만약 폰을 분실했을 경우 아래 코드를 입력하면 OTP 로그인을 할 수 있으며 한번 사용한 코드는 재사용이 불가능합니다. 비상시에 대비한 복구 코드로 .ssh/google_authenticator 에 저장되어 있으며 유출될 경우 OTP 로그인이 가능해 지는 문제가 있으므로 판단해서 삭제하면 됩니다.

    Your verification code is 323214
    Your emergency scratch codes are:
      73074445
      94801293
      33157957
      70212597
      49916872
    CODE
  5. 이제 OTP 앱을 띄워서 우측 상단의 계정 설정을 클릭합니다

    .

  6. 바코드 스캔을 선택하고 3번에서 브라우저에서 열은 QR 코드가 있는 화면을 열고 스캔합니다.

  7. 스캔이 정상적으로 끝나면 자동으로 앱의 초기 화면으로 이동하며 아래 그림처럼 추가한 사이트 목록과 함께 OTP 토큰이 표시됩니다.


PAM  설정

이제 ssh 데몬이 google authenticator 를 사용하도록 PAM 설정을 변경해야 합니다.

  1. PAM 의 sshd 설정 파일을 편집기로 엽니다.

    vi /etc/pam.d/sshd
    CODE
  2. "#%PAM-1.0" 아래에 다음 내용을 추가하고 저장합니다.. google_authenticator 는 설정 파일의 이름임.

    #%PAM-1.0
    auth       required     pam_google_authenticator.so secret=${HOME}/.ssh/google_authenticator ##TODO 진하게 표시
    auth       required     pam_sepermit.so
    CODE

    google authenticator 설정 파일의 기본 경로는 ${HOME}/google_authenticator 이지만 이 경로에 저장할 경우 SELinux 가 sshd 의 접근을 차단하므로 정상적으로 동작하지 않습니다.

    SELinux 의 차단 이유와 해결 방법은 다음 장인 "SELinux 사용하기" 에서 자세하게 다룹니다.


  3. 만약 OTP 사용 여부를 사용자가 결정하도록 하려면 다음과 같이 nullok 를 설정에 추가해 주면 됩니다.

    #%PAM-1.0
    auth       required     pam_google_authenticator.so nullok secret=${HOME}/.ssh/google_authenticator ##TODO 진하게 표시
    auth       required     pam_sepermit.so
    CODE


    nullok 설정이 있으면 사용자의 홈 디렉터리에 .ssh/google_authenticator 가 있으면 OTP 로 로그인을 하고 없으면 다른 인증 방식으로 로그인을 수행합니다.



sshd 설정

이제 ssh 이제 ssh 데몬이 google authenticator 를 사용하도록 PAM 설정을 변경해야 합니다.

/etc/ssh/sshd_config.내에 설정을 다음과 같이 수정

  1. 편집기로 sshd 설정 파일을 엽니다.

    vi /etc/ssh/sshd_config
    CODE
  2. 다음 설정을 찾아서 아래와 같이 변경합니다.

    PasswordAuthentication yes
    ChallengeResponseAuthentication yes
    UsePAM yes
    CODE
  3. ssh 데몬을 재구동합니다.

    systemctl restart sshd
    CODE


이제 모든 설정이 완료되었고 사용하는 SSH 클라이언트 프로그램에서 설정을 수정해야 하며 인증 수단으로 keyboard-interactive 를 설정하면 됩니다.


SSH Client 설정

SecureCRT 설정

  1. 세션 옵션으로 들어갑니다.
  2. SSH2 -> Authentication 에 "Keyboard interactive" 가 체크되어 있는지 확인하고 가장 위에 올라 오도록 설정합니다.

  3. 이제 스마트폰의 구글 OTP 를 구동하고 버에 ssh 로 연결하면 아래와 같은 OTP 입력 창에 뜹니다. 거기에 구글 OTP 에서 생성한 암호를 입력합니다.

  4. 암호 입력창에는 기존에 사용하던 암호를 입력합니다.


putty 설정

  1. putty 를 구동한 후에 OTP 를 사용할 세션 설정으로 들어갑니다.
  2. ConnectionSSHAuth 설정에 들어갑니다.
  3. Authentication methos → Attempt "keyboard-interactive auth 가 체크되어 있는지 확인합니다.

  4. Verification code: 에 일회용 비밀 번호를 입력하고 Password: 에 암호를 입력합니다.




ssh 클라이언트 설정

ssh 커맨드나 Mac 의 iTerm 등의 ssh 클라이언트는 ssh 의 기본 설정 파일인 ~/.ssh/config 파일을 사용하므로 여기에 다음과 같이 OTP 를 사용하도록 설정하면 되며 아래는 example.com 에 연결할 경우 설정 예제입니다.

위의 예와 같이 PasswordAuthentication, ChallengeResponseAuthentication 를 yes 로 하고 PreferredAuthenticationskeyboard-interactive 를 설정한 후에 ssh example.com 처럼 서버에 연결을 시도한 후에 아래의 프롬프트에 OTP 와 암호를 입력하면 됩니다. 


만약 여러 가지 이유로 서버의 OTP 설정파일인 .ssh/google_authenticator  가 변경되었다면 구글 OTP 앱의 주소를 삭제하고 새로 추가해야 합니다.


TOTP 는 서버와 클라이언트가 공유하는 secret key 를 현재 시간 값을 사용하여 1회용 암호를 생성하므로 시간이 틀리다면 제대로 동작하지 않습니다.

대개의 스마트폰은 자동으로 시간이 동기화되지만 리눅스 서버는 아니므로 로그인이 안 될 경우 리눅스의 현재 시간을 확인하고 다르다면 동기화를 해야 합니다.

저자는 ntpdate ntp.postech.ac.kr 명령으로 포항공대의 서버와 시간을 일치시킵니다.