서버 보안 점검 3편: SSH 비밀번호 차단과 root 로그인 정책

Linux 2026년 8월 24일

SSH 포트를 기본값에서 바꾸는 것만으로는 인증 정책이 강해지지 않는다. 더 중요한 것은 비밀번호 인증이 실제로 꺼져 있는지, 공개키 인증이 정상인지, root가 어떤 방식으로 접속할 수 있는지, 로그인 셸을 가진 계정이 누구인지다.

이번 점검에서는 SSH 설정의 유효값과 외부 관찰 결과를 확인했다. 비밀번호 인증 비활성화와 공개키 인증 활성화는 확인됐지만, root의 공개키 로그인은 여전히 허용되는 상태였다. 그래서 전체를 “강화 완료”라고 하지 않고 항목별로 판정했다.

세 줄 요약

  • PasswordAuthentication noPubkeyAuthentication yes가 확인돼 비밀번호 대신 공개키를 사용하는 기본 방향은 맞았다.
  • PermitRootLogin without-password는 root 로그인을 차단하는 값이 아니라 root의 공개키 로그인을 허용하는 설정이다.
  • MaxAuthTries 6은 Ubuntu 24.04 문서 기준 기본값이므로 별도 강화 성공으로 계산하지 않았다.

실제 점검 결과

공개용 원고에서는 실제 포트, 호스트명과 계정명을 치환했다.

항목 보존된 설정·결과 판정 해석
SSH 포트 비표준 포트 사용 보조 조치 자동 스캔 소음을 줄일 수 있지만 인증 강화는 아님
외부 관찰 SSH 경로가 filtered 부분 성공 점검 출발지에서 직접 상태를 판별할 수 없었음
비밀번호 인증 PasswordAuthentication no 성공 SSH password 인증 비활성화 설정 확인
공개키 인증 PubkeyAuthentication yes 성공 공개키 인증 허용 설정 확인
root 로그인 PermitRootLogin without-password 부분 성공 root password는 막지만 root key 로그인은 허용
인증 시도 횟수 MaxAuthTries 6 기준값 기본값이므로 추가 강화로 보지 않음
로그인 가능 계정 로그인 셸을 가진 계정이 복수 확인 필요 각 계정의 필요성·키·잠금 상태 재검토 필요
실제 재접속 시험 보존된 결과 없음 확인 필요 설정 확인과 실제 로그인 성공을 혼동하지 않음

without-password는 현재 OpenSSH 문서에서 prohibit-password의 이전 별칭이다. 이 값은 root의 비밀번호와 keyboard-interactive 인증을 막지만 공개키 로그인을 허용한다. root 로그인을 완전히 막으려면 PermitRootLogin no가 필요하다.

그러나 원격 서버에서 이 값을 즉시 바꾸는 것은 위험하다. 작동하는 비root sudo 계정과 공개키 접속을 별도 세션에서 먼저 검증하지 않으면 스스로 접속을 차단할 수 있다.

1. 설정 파일보다 실제 적용값을 확인한다

Ubuntu의 SSH 구성은 기본 파일 외에 Include 파일과 Match 블록의 영향을 받을 수 있다. 주석을 검색하는 것보다 sshd -T로 유효 구성을 확인한다.

sudo sshd -T |
  grep -E '^(port|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|permitrootlogin|maxauthtries|allowusers|allowgroups) '

rg를 쓰는 환경이라면 다음과 같다.

sudo sshd -T |
  rg '^(port|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|permitrootlogin|maxauthtries|allowusers|allowgroups) '

공개 글에는 실제 포트와 사용자 목록을 넣지 않고 다음처럼 상태만 남긴다.

port=<SSH_PORT>
passwordauthentication=no
pubkeyauthentication=yes
permitrootlogin=prohibit-password
maxauthtries=6

특정 사용자·주소에 적용되는 Match 규칙이 있다면 조건을 지정해 확인할 수 있다.

sudo sshd -T \
  -C user='<ADMIN_USER>',host='<APP_HOST>',addr='<CLIENT_IP>' |
  grep -E '^(passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|permitrootlogin) '

실제 사용자와 클라이언트 IP가 포함된 출력은 공개하지 않는다.

2. 비밀번호 인증과 keyboard-interactive를 구분한다

점검에서 PasswordAuthentication no는 확인됐다. 이는 중요한 성공이지만 PAM을 사용하는 환경에서는 keyboard-interactive가 비밀번호와 비슷한 인증 경로로 작동할 수 있다. 따라서 다음 항목도 함께 본다.

sudo sshd -T |
  grep -E '^(passwordauthentication|kbdinteractiveauthentication|usepam) '

운영 정책이 공개키 전용이라면 PasswordAuthentication 한 줄만으로 “모든 비키 인증이 완전히 차단됐다”고 단정하지 않는다. 실제 클라이언트에서 비밀번호 강제 시험을 하되, 계정 잠금 정책과 운영 영향에 주의한다.

ssh \
  -o PreferredAuthentications=password \
  -o PubkeyAuthentication=no \
  -p '<SSH_PORT>' \
  '<ADMIN_USER>@<APP_HOST>'

기대 결과는 비밀번호 인증이 제공되지 않아 접속이 거부되는 것이다. 이 테스트 결과는 보존된 기록에 없으므로 현재 글에서는 확인 필요로 남긴다.

3. root 공개키 로그인을 끄기 전 준비한다

현재 상태를 공개용으로 정리하면 다음과 같다.

root_password_login=blocked
root_public_key_login=allowed

더 강한 목표가 root 직접 로그인 전면 차단이라면 다음 절차를 따른다.

  1. 비root 관리자 계정에 승인한 공개키가 있는지 확인한다.
  2. 새 터미널에서 그 계정으로 실제 SSH 로그인한다.
  3. sudo -v와 필요한 운영 명령이 정상인지 확인한다.
  4. 기존 SSH 세션을 닫지 않은 상태에서 설정을 변경한다.
  5. sshd -t가 성공한 뒤 reload한다.
  6. 또 다른 새 세션에서 재접속을 확인한 뒤 기존 세션을 종료한다.

목표 설정은 다음과 같다.

PermitRootLogin no

문법 검사와 reload 예시는 다음과 같다.

sudo sshd -t
sudo systemctl reload ssh

이 글은 변경 명령을 실제로 적용했다고 주장하지 않는다. 보존된 결과는 root key 로그인이 허용된 상태까지이며, 전면 차단은 운영 전제를 검증한 뒤 수행할 후속 조치다.

4. 로그인 가능한 계정을 목록으로 점검한다

로그인 셸을 가진 계정을 확인한다.

getent passwd |
  awk -F: '$7 !~ /(nologin|false)$/ {print $1 ":" $7}'

sudo 그룹도 확인한다.

getent group sudo

실제 점검에서는 root, 클라우드 이미지 기본 계정, 배포·관리 계정 등 복수 계정이 확인됐다. 공개 글에는 실명을 적지 않고 다음 질문만 남긴다.

  • 이 계정은 현재 운영에 필요한가
  • 홈 디렉터리의 authorized_keys는 승인된 키만 포함하는가
  • 사용하지 않는 기본 계정은 잠겨 있는가
  • sudo 권한이 꼭 필요한 계정에만 있는가
  • 퇴역한 노트북·자동화의 키가 남아 있지 않은가

키 전문과 fingerprint는 게시하지 않는다. 운영자 로컬에서는 fingerprint만 비교할 수 있다.

find /home -xdev -path '*/.ssh/authorized_keys' -type f -print

이 명령의 출력도 실제 사용자명과 홈 경로를 노출하므로 공개하지 않는다.

5. 리스닝 주소와 방화벽을 다시 대조한다

SSH가 어느 주소에 바인딩됐는지 확인한다.

sudo ss -lntp |
  grep -E 'sshd|:<SSH_PORT>[[:space:]]'

실제 셸에서는 <SSH_PORT>를 운영값으로 바꾼다. 공용망 SSH가 필요 없다면 사설 오버레이 주소에만 바인딩하거나, 클라우드·호스트 방화벽에서 승인한 소스만 허용하는 방안을 검토한다.

외부 스캔의 filtered 결과는 공격 표면 축소에 긍정적이지만 다음을 증명하지는 않는다.

  • 다른 출발 네트워크에서도 같은지
  • IPv6에도 같은 규칙이 적용되는지
  • 클라우드 방화벽과 호스트 방화벽 중 어느 계층이 차단했는지
  • SSH daemon이 내부에서 모든 인터페이스에 리스닝 중인지

6. 로그는 IP 대신 이벤트 개수만 공개한다

SSH 로그에는 사용자명과 원격 IP가 포함된다. 공개용 점검에서는 원문 대신 이벤트 종류를 집계한다.

sudo journalctl -u ssh \
  --since '24 hours ago' \
  --no-pager |
  grep -Eo 'Failed password|Invalid user|Accepted publickey' |
  sort |
  uniq -c

이 집계는 공격 여부를 확정하는 증거가 아니라 변화 추세를 보는 자료다. 정확한 원인 분석은 운영자 로컬에서 시간대, 소스 주소, 대상 계정과 방화벽 기록을 대조해야 한다.

이번 점검의 결론

비밀번호 인증 비활성화와 공개키 인증 활성화는 성공으로 판정할 수 있다. 외부에서 SSH 경로가 직접 관측되지 않은 점도 공격 표면 축소에는 긍정적이다.

하지만 다음 이유로 “SSH 완전 강화 완료”라고 하지는 않는다.

  • root 공개키 로그인이 여전히 허용됨
  • MaxAuthTries 6은 추가 강화가 아닌 기본 수준
  • 로그인 셸을 가진 복수 계정의 필요성·키 상태가 미확인
  • 별도 세션을 이용한 공개키 재접속 성공 기록이 보존되지 않음
  • keyboard-interactive와 IPv6 경로의 최종 결과가 없음

후속 작업의 우선순위는 비root sudo 접속 검증, 불필요 계정 정리, root 직접 로그인 차단 검토, 방화벽 소스 제한, 재접속 시험 순서다.

다음 글

공식 문서

태그