원격 리눅스 서버에 공개키 기반 인증으로 접속을 시도할 때 Permission denied (publickey) 에러가 발생하며 셸 세션 진입이 거부되는 현상은 서버 인스턴스를 신규 구축하거나 계정 권한을 정비한 직후 매우 빈번하게 발생합니다. 로컬 머신에서 생성한 공개키(id_ed25519.pub 또는 id_rsa.pub)의 내용을 서버의 authorized_keys 파일에 분명히 등록했음에도 접속이 가로막히면 원인을 빠르게 파악하기 어렵습니다.
OpenSSH 서버 데몬(sshd)은 클라이언트가 제출한 서명 정보가 일치하더라도, 파일 시스템 상의 디렉터리 퍼미션, 소유권, 상위 경로의 쓰기 권한, SELinux 보안 컨텍스트 중 단 하나라도 보안 정책에 부합하지 않으면 보안 유지를 위해 키 검증 자체를 거부합니다.
에러 증상과 SSH 클라이언트 및 서버 로그 분석
공개키 인증 실패 시 클라이언트 터미널에는 보안상의 이유로 상세한 실패 사유가 노출되지 않고 간략한 접근 거부 메시지만 출력됩니다:
deployer@192.168.1.100: Permission denied (publickey).
인증 거부의 원인을 진단하려면 클라이언트 명령어에 상세 디버그 플래그(-vvv)를 부여하여 SSH 핸드셰이크 과정을 추적해야 합니다:
# 상세 디버그 모드로 SSH 접속 시도
ssh -vvv -i ~/.ssh/id_ed25519 deployer@192.168.1.100
디버그 로그를 살펴보면 클라이언트가 지정된 비밀키에 대응하는 공개키를 서버에 제시하지만, 서버가 이를 수락하지 않고 연결을 종료하는 흐름을 확인할 수 있습니다:
debug1: Authentications that can continue: publickey
debug1: Offering public key: /Users/username/.ssh/id_ed25519 ED25519 SHA256:7uK... explicit
debug2: we did not send a packet, explain: ...
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
deployer@192.168.1.100: Permission denied (publickey).
클라이언트가 아무리 상세 로그를 출력해도 서버가 공개키를 거부한 실제 이유는 서버 내부 로그에만 기록됩니다. OpenSSH는 잠재적 공격자에게 시스템 취약점 단서를 주지 않기 위해 클라이언트 통신 패킷에는 구체적인 거부 사유를 담지 않기 때문입니다.
서버 콘솔에 접근할 수 있는 환경(웹 콘솔, 기존 연결 세션, IPMI 등)에서 배포판별 인증 로그를 실시간으로 확인합니다:
# Debian 및 Ubuntu 계열 인증 로그 확인
sudo journalctl -u ssh -e --no-pager
# RHEL, Rocky Linux, CentOS 계열 인증 로그 확인
sudo journalctl -u sshd -e --no-pager
인증이 거부되는 순간 서버 로그에는 다음과 같은 명확한 원인이 기록됩니다:
Authentication refused: bad ownership or modes for directory /home/deployer/.ssh
Authentication refused: bad ownership or modes for file /home/deployer/.ssh/authorized_keys
Authentication refused: bad ownership or modes for directory /home/deployer
User deployer not allowed because account is locked
여기서 특히 주목해야 할 로그는 bad ownership or modes for directory /home/deployer입니다. .ssh 디렉터리와 authorized_keys 파일의 권한을 올바르게 맞추었더라도, 부모 경로인 홈 디렉터리 자체의 퍼미션이 잘못되어 있으면 인증이 전면 거부됩니다.
StrictModes 보안 아키텍처와 디렉터리 권한 검증 원리
OpenSSH 데몬의 기본 설정 파일(/etc/ssh/sshd_config)에는 StrictModes yes 옵션이 기본값으로 활성화되어 있습니다.
StrictModes는 사용자의 공개키 파일을 읽기 전에 파일 및 상위 디렉터리의 소유권과 접근 모드를 검증하는 보안 아키텍처입니다. 만약 /home/deployer 홈 디렉터리에 그룹이나 타 사용자의 쓰기 권한(chmod 777 또는 chmod 775)이 부여되어 있다면, 동일한 그룹에 속한 다른 사용자나 악의적인 로컬 프로세스가 해당 디렉터리 안의 .ssh 폴더를 다른 이름으로 바꾸고 임의의 공개키가 담긴 가짜 .ssh/authorized_keys를 생성할 수 있습니다.
이러한 권한 상승 공격(Privilege Escalation)을 원천 차단하기 위해, OpenSSH는 루트 디렉터리(/)부터 시작하여 /home, /home/deployer, /home/deployer/.ssh, /home/deployer/.ssh/authorized_keys에 이르는 전체 경로 트리를 순회 검증합니다.
| 검사 대상 경로 | 필수 소유자 | 필수 퍼미션 | 허용되지 않는 모드 및 보안 위험 |
|---|---|---|---|
/home/deployer |
deployer:deployer |
750 또는 755 |
775, 777 (그룹/타인 쓰기 허용 시 인증 차단) |
~/.ssh |
deployer:deployer |
700 |
755, 777 (타인의 디렉터리 진입 및 파일 열람 위험) |
~/.ssh/authorized_keys |
deployer:deployer |
600 |
644 초과 쓰기 권한(타인에 의한 공개키 변조 위험) |
~/.ssh/id_ed25519 (클라이언트) |
로컬 사용자 | 600 |
644 (비밀키 노출 방지를 위해 클라이언트가 접속 차단) |
이 검증 체계에 따라 상위 홈 디렉터리부터 authorized_keys 파일까지 그룹 및 타인의 쓰기 권한(w)을 완전히 차단하는 것이 OpenSSH 인증 실패를 해결하는 핵심 메커니즘입니다.
파일 권한 복구와 sshd 설정 가이드
서버 SSH 터미널이나 복구 콘솔에서 파일 및 디렉터리 권한을 순서대로 복구합니다.
먼저 홈 디렉터리부터 authorized_keys 파일까지의 소유권과 권한 모드를 표준 규격에 맞추어 일괄 설정합니다:
# 대상 계정 및 홈 디렉터리 변수 정의
TARGET_USER="deployer"
USER_HOME=$(eval echo "~${TARGET_USER}")
# 1. 홈 디렉터리의 그룹 및 타인 쓰기 권한 제거 (755)
chmod 755 "${USER_HOME}"
# 2. .ssh 디렉터리와 내부 파일의 소유권을 대상 사용자로 동기화
chown -R "${TARGET_USER}:${TARGET_USER}" "${USER_HOME}/.ssh"
# 3. .ssh 디렉터리를 소유자 전용 접근(700)으로 제한
chmod 700 "${USER_HOME}/.ssh"
# 4. authorized_keys 파일을 소유자 전용 읽기/쓰기(600)로 제한
chmod 600 "${USER_HOME}/.ssh/authorized_keys"
권한 설정이 완료되면 OpenSSH 데몬의 설정 파일(/etc/ssh/sshd_config 또는 /etc/ssh/sshd_config.d/*.conf)에서 공개키 인증이 정상 활성화되어 있는지 확인합니다:
# /etc/ssh/sshd_config.d/99-security.conf
# 공개키 인증 활성화
PubkeyAuthentication yes
# 기본 공개키 파일 탐색 경로 지정
AuthorizedKeysFile .ssh/authorized_keys
# 엄격한 권한 검증 모드 유지
StrictModes yes
# 패스워드 인증 비활성화 (보안 강화)
PasswordAuthentication no
KbdInteractiveAuthentication no
만약 계정이 비활성화되어 User deployer not allowed because account is locked 에러가 발생한 경우라면, 패스워드 해시가 잠김 상태(!)로 되어 있는 것이 원인일 수 있습니다. 공개키 전용 계정이라도 PAM 모듈에 따라 계정 만료나 잠김이 적용되므로 다음 명령어로 계정 상태를 해제합니다:
# 계정 잠금 상태 확인
sudo passwd -S deployer
# 패스워드 잠금 해제 (패스워드가 없는 계정인 경우)
sudo usermod -U deployer
SSH 데몬 검증 및 단계별 연결 테스트
설정 파일을 수정한 후 서비스를 즉시 재시작하면 설정 오류가 발생했을 때 현재 접속 중인 관리자 세션까지 끊겨 서버가 고립될 위험이 있습니다.
반드시 기존 SSH 연결 창을 열어둔 상태에서 새로운 터미널 창을 띄워 다음 절차대로 안전하게 검증합니다.
먼저 sshd -t 명령어로 설정 파일의 문법적 무결성을 사전 점검합니다:
# sshd 설정 구문 문법 검사 (출력이 없으면 정상)
sudo sshd -t
문법 오류가 없다면 실행 중인 세션을 끊지 않고 새 설정만 반영하도록 데몬을 재로드(reload)합니다:
# 배포판에 맞추어 SSH 데몬 설정 재로드
sudo systemctl reload ssh 2>/dev/null || sudo systemctl reload sshd
이제 로컬 머신에서 특정 개인키를 직접 지정하여 상세 디버그 옵션과 함께 접속을 시도합니다:
# 특정 개인키 명시 및 포트 지정 연결 테스트
ssh -i ~/.ssh/id_ed25519 -vvv -p 22 deployer@192.168.1.100
접속 시도 시 터미널에 다음과 같은 성공 로그가 출력되며 정상적으로 셸 프롬프트가 열리는지 확인합니다:
debug1: Offering public key: /Users/username/.ssh/id_ed25519 ED25519 SHA256:7uK... explicit
debug1: Server accepts key: /Users/username/.ssh/id_ed25519 ED25519 SHA256:7uK... explicit
debug1: Authentication succeeded (publickey).
Authenticated to 192.168.1.100 ([192.168.1.100]:22) using "publickey".
서버 측 로그(journalctl -u ssh -e)에서도 다음과 같이 세션 오픈 로그가 기록되면 공개키 인증 복구가 완전하게 마무리된 것입니다:
Accepted publickey for deployer from 192.168.1.50 port 54321 ssh2: ED25519 SHA256:7uK...
pam_unix(sshd:session): session opened for user deployer(uid=1001) by (uid=0)
실무 환경 사이드 이펙트 방지 FAQ
파일 권한을 정상적으로 부여했음에도 특정 인프라 환경이나 배포판 정책에 따라 예기치 않은 인증 실패가 발생할 수 있습니다.
ssh-agent에 등록된 키가 많아 발생하는 Too many authentication failures 에러
로컬 머신의 ssh-agent에 깃허브, 개발 서버, 개인 키 등 여러 개의 비밀키가 로드되어 있으면, SSH 클라이언트는 서버에 접속할 때 에이전트에 등록된 키를 순서대로 하나씩 제출합니다. OpenSSH 서버의 기본 최대 인증 시도 횟수(MaxAuthTries 6)를 초과하면 서버는 올바른 키를 제출해보기도 전에 연결을 강제로 끊어버립니다:
Received disconnect from 192.168.1.100 port 22:2: Too many authentication failures
이 문제는 로컬 머신의 ~/.ssh/config 파일에 IdentitiesOnly yes 지시어를 추가하여 해결합니다. 해당 호스트에 접속할 때는 에이전트의 다른 키를 탐색하지 않고 명시된 키만 제출하도록 제한합니다:
Host my-remote-server
HostName 192.168.1.100
User deployer
Port 22
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Rocky Linux 및 RHEL에서 권한이 600인데도 차단되는 SELinux 컨텍스트 불일치
SELinux가 Enforcing 상태인 엔터프라이즈 리눅스 환경에서는 파일 권한이 600이라도 파일에 부여된 보안 컨텍스트가 올바르지 않으면 sshd 프로세스가 파일을 읽지 못합니다. 관리자가 sudo로 임시 디렉터리에서 authorized_keys 파일을 복사해 온 경우 흔히 default_t나 admin_home_t 컨텍스트가 그대로 남아 차단됩니다.
/var/log/audit/audit.log에 denied { read } 감시 로그가 기록되어 있다면 다음 명령어로 컨텍스트를 진단하고 표준 SSH 레이블(ssh_home_t)로 복구합니다:
# SELinux 보안 컨텍스트 확인
ls -dZ ~/.ssh ~/.ssh/authorized_keys
# 표준 ssh_home_t 컨텍스트로 일괄 재설정
restorecon -R -v ~/.ssh
암호화된 홈 디렉터리(eCryptfs) 환경에서의 공개키 미인식 문제
사용자 홈 디렉터리가 eCryptfs나 PAM 기반 암호화 파일 시스템으로 구성된 서버의 경우, 사용자가 패스워드를 입력하여 로그인하기 전까지는 홈 디렉터리 내부가 암호화된 바이너리 상태로 잠겨 있습니다. 결과적으로 sshd가 로그인 이전에 ~/.ssh/authorized_keys를 읽지 못해 공개키 인증이 항상 거부됩니다.
이 경우 authorized_keys 파일을 암호화되지 않는 시스템 공용 경로에 별도로 보관하도록 /etc/ssh/sshd_config를 조정해야 합니다:
# 시스템 공용 디렉터리에 계정별 공개키 분리 보관
AuthorizedKeysFile /etc/ssh/authorized_keys/%u .ssh/authorized_keys
설정 후 /etc/ssh/authorized_keys/deployer 경로에 공개키를 배치하고 소유자를 root:root, 퍼미션을 644로 지정하면 암호화 홈 환경에서도 정상 인증이 동작합니다.
클라이언트 측 비밀키 퍼미션 경고(Permissions 0644 are too open)
서버가 아닌 클라이언트 머신에서 비밀키 파일의 권한이 644나 664처럼 타인에게 읽기 가능하게 열려 있으면, OpenSSH 클라이언트는 키 유출 위험을 감지하여 접속 자체를 중단합니다:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/Users/username/.ssh/id_ed25519' are too open.
It is required that your private key files are NOT accessible by others.
클라이언트 머신에서 비밀키 파일의 권한을 소유자 전용으로 수정해야 정상 접속이 가능합니다:
# 로컬 머신 개인키 파일 권한 축소
chmod 600 ~/.ssh/id_ed25519
원격 인프라 환경에서 안정적인 SSH 세션을 유지하고 네트워크 리소스를 안전하게 관리하는 추가 기법은 리눅스 파일 디스크립터 증설 가이드와 TIME_WAIT 소켓 누적 해결을 함께 참고하여 전반적인 서버 운영 안정성을 높일 수 있습니다.
