Contents
see ListSSH 보안은 포트 변경보다 운영 기준이 먼저입니다
리눅스 서버를 운영하다 보면 SSH는 거의 항상 외부에 노출되는 관리 통로가 됩니다. 그래서 단순히 22번 포트를 다른 번호로 바꾸는 것만으로는 충분하지 않습니다. 포트 변경은 자동 스캔을 조금 줄일 수 있지만, 비밀번호 로그인, root 직접 로그인, 과도한 재시도, 퇴사자 계정 방치, 접속 로그 미점검이 그대로라면 실제 위험은 남습니다. 실무에서는 '누가 어떤 키로 접속할 수 있는지', '실패한 접속이 언제 차단되는지', '장애 상황에서 복구 접속 수단이 남아 있는지'를 함께 설계해야 합니다.
이 문서는 운영 서버에서 바로 적용할 수 있는 SSH 하드닝 순서를 정리합니다. 핵심은 비밀번호 인증 제거, root 직접 로그인 차단, 허용 사용자 축소, 방화벽과 차단 정책 적용, 로그 점검 자동화입니다. 모든 변경은 한 번에 적용하지 말고 현재 열린 SSH 세션을 유지한 상태에서 새 터미널로 재접속 테스트를 통과한 뒤 반영해야 합니다. SSH 설정을 잘못 바꾸면 정상 관리자도 잠길 수 있으므로, 클라우드 콘솔 접속이나 임시 복구 계정을 먼저 확인하는 것이 좋습니다.
1. 현재 접속 구조와 복구 경로를 먼저 확인합니다
보안을 강화하기 전에 현재 서버에 어떤 계정이 있고, 어떤 서비스가 배포에 사용하는지 확인해야 합니다. 운영 자동화가 deploy 계정으로 접속하는지, 백업 스크립트가 root 권한을 요구하는지, 관리자가 VPN을 통해 접속하는지에 따라 설정 값이 달라집니다. 특히 AllowUsers를 설정하면 목록에 없는 계정은 키가 맞아도 접속할 수 없습니다. 따라서 배포 서버, CI, 모니터링 서버의 접속 계정을 모두 적어둔 뒤 변경해야 합니다.
- 클라우드 콘솔 또는 직렬 콘솔 접속이 가능한지 확인합니다.
- 현재 로그인한 SSH 세션은 설정 검증이 끝날 때까지 닫지 않습니다.
- 관리자 개인 계정과 배포 전용 계정을 분리합니다.
- sudo 권한은 필요한 계정에만 부여하고, 공용 계정 사용을 줄입니다.
2. sshd 설정은 별도 파일로 관리합니다
대부분의 최신 배포판은 /etc/ssh/sshd_config.d 디렉터리의 조각 설정을 읽을 수 있습니다. 기본 파일 전체를 직접 수정하면 패키지 업데이트 때 충돌이 생기기 쉽기 때문에, 운영 정책은 별도 파일에 넣는 편이 관리하기 좋습니다. 아래 예시는 비밀번호 로그인과 root 직접 로그인을 막고, 공개키 인증만 허용하며, 접속 가능한 계정을 제한합니다. AllowUsers는 실제 서버 계정명으로 바꿔야 합니다.
# /etc/ssh/sshd_config.d/10-hardening.conf
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
AuthenticationMethods publickey
AllowUsers deploy adminuser
MaxAuthTries 3
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding no
AllowTcpForwarding no
설정 파일을 작성한 뒤에는 바로 재시작하지 말고 문법 검사를 먼저 실행합니다. 배포판에 따라 서비스 이름이 ssh 또는 sshd일 수 있습니다. Ubuntu 계열은 보통 ssh, RHEL 계열은 sshd를 사용합니다. 문법 검사가 통과하면 reload를 사용해 적용하고, 새 터미널에서 실제 접속을 테스트합니다.
sudo sshd -t
sudo systemctl reload ssh || sudo systemctl reload sshd
ssh deploy@서버주소
3. 방화벽은 접속 위치 기준으로 좁힙니다
SSH 자체 설정만으로도 위험을 줄일 수 있지만, 가능하다면 네트워크 레벨에서 먼저 접근 범위를 제한해야 합니다. 사무실 고정 IP, VPN 대역, 배포 서버의 고정 IP만 SSH에 접근하도록 열어두면 무작위 스캔과 대입 시도가 크게 줄어듭니다. 클라우드 보안 그룹을 사용한다면 OS 방화벽보다 앞단에서 필터링되므로 더 효과적입니다. 단, 재택 근무나 이동 접속이 필요한 조직에서는 먼저 VPN을 마련하고 SSH는 VPN 내부에서만 허용하는 구성이 안정적입니다.
# UFW 예시: VPN 대역에서만 SSH 허용
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 10.8.0.0/24 to any port 22 proto tcp
sudo ufw enable
sudo ufw status verbose
방화벽을 적용할 때는 현재 접속한 IP가 허용 목록에 포함되는지 반드시 확인해야 합니다. 원격 서버에서 ufw enable을 실행한 뒤 접속이 끊기면 복구가 번거로울 수 있습니다. 클라우드 보안 그룹과 OS 방화벽을 동시에 쓰는 경우에는 두 곳의 허용 규칙이 서로 맞는지도 점검해야 합니다.
4. 실패한 로그인은 차단하고 로그로 남깁니다
공개키 인증만 허용하더라도 공격자는 계속 계정명을 바꿔가며 접속을 시도할 수 있습니다. 이런 시도는 CPU 부담은 작아도 로그를 오염시키고, 잘못 열린 계정이 생겼을 때 위험해집니다. fail2ban 같은 도구를 사용하면 일정 시간 안에 실패가 반복되는 IP를 자동으로 차단할 수 있습니다. 운영 환경에서는 차단 시간이 너무 길면 정상 관리자가 실수로 잠길 수 있으므로 처음에는 1시간 정도로 시작하고 로그를 보며 조정하는 편이 안전합니다.
# /etc/fail2ban/jail.d/sshd.local
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = %(sshd_log)s
bantime = 1h
findtime = 10m
maxretry = 5
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
sudo journalctl -u ssh -u sshd --since today
차단 도구를 도입한 뒤에는 정상 접속 실패와 공격성 접속 실패를 구분해서 봐야 합니다. 특정 사무실 IP가 반복 차단된다면 직원의 오래된 키, 잘못 저장된 비밀번호, CI 환경 변수 오류일 수 있습니다. 반대로 여러 국가와 네트워크에서 다양한 계정명으로 실패가 반복된다면 방화벽 제한이나 VPN 전환을 더 강하게 검토해야 합니다.
5. 키 관리 정책을 문서화합니다
SSH 보안의 절반은 설정이고, 나머지 절반은 키 관리입니다. 개인 키를 공유하거나 여러 서버에 같은 공용 계정을 쓰면 누가 접속했는지 추적하기 어렵습니다. 관리자마다 개인 계정을 만들고 authorized_keys에는 소유자와 발급일을 주석으로 남기는 것이 좋습니다. 퇴사자나 외주 작업자의 키는 작업 종료일에 제거하고, 배포용 키는 사람의 노트북이 아니라 CI 시크릿 저장소나 배포 서버에만 둡니다.
- 개인별 SSH 키를 사용하고 공용 개인 키를 금지합니다.
- authorized_keys 각 줄 끝에 이름, 목적, 발급일을 남깁니다.
- 관리자 계정과 배포 계정을 분리합니다.
- 퇴사, 프로젝트 종료, 노트북 분실 시 키 폐기 절차를 정합니다.
- 정기 점검 때 마지막 로그인 기록과 등록 키 목록을 함께 확인합니다.
운영 체크리스트
SSH 보안 점검은 한 번 설정하고 끝나는 작업이 아니라 운영 루틴입니다. 신규 서버를 만들 때는 공개키 인증, root 차단, 허용 사용자 제한, 방화벽 제한, 실패 로그인 차단을 기본 템플릿에 포함합니다. 기존 서버는 접속이 끊기지 않도록 콘솔 복구 경로를 확인한 뒤 한 대씩 적용합니다. 적용 후에는 새 세션 접속 테스트, sudo 권한 확인, 배포 파이프라인 실행, fail2ban 상태 확인, journalctl 로그 확인까지 마쳐야 합니다.
- 비밀번호 로그인과 root 직접 로그인이 꺼져 있는지 확인합니다.
- AllowUsers 또는 그룹 정책으로 접속 계정을 좁힙니다.
- SSH 접근 원본을 VPN이나 고정 IP로 제한합니다.
- 실패 로그인 차단 정책을 적용하고 오탐을 확인합니다.
- 개인별 키 등록, 폐기, 주석 규칙을 문서화합니다.
- 설정 변경 전후로 sshd -t와 새 터미널 접속 테스트를 수행합니다.