가이드

SSH 키 설정: 서버에 비밀번호 없이 로그인하기

업데이트: · Skillaria.Top

SSH 키 설정은 세 단계로 끝납니다. ssh-keygen -t ed25519로 키 쌍을 만들고, ssh-copy-id user@host로 공개 키를 서버에 복사한 뒤 로그인을 확인합니다. 이후 /etc/ssh/sshd_config에서 비밀번호 로그인을 끄고(PasswordAuthentication no), 자주 접속하는 서버는 ~/.ssh/config에 정리합니다.

SSH 키는 파일 두 개로 이루어집니다. 개인 키(private key)는 내 컴퓨터에 남고, 공개 키(public key)는 서버에 저장됩니다. 접속할 때 서버는 내가 공개 키에 대응하는 개인 키를 가지고 있는지 확인하고, 비밀번호 없이 들여보냅니다. 비밀번호보다 편리할 뿐 아니라 훨씬 안전합니다. 키를 무작위 대입으로 알아내는 것은 사실상 불가능하기 때문입니다. 아래에서는 키 생성부터 비밀번호 로그인 차단까지 SSH 키 설정 전 과정과, 사람들이 가장 자주 막히는 오류를 정리합니다.

키 인증의 원리

키는 비대칭입니다. 공개 키(id_ed25519.pub)는 누구에게 보여 주어도 괜찮습니다. 그것으로 개인 키를 다시 만들 수 없기 때문입니다. 개인 키(id_ed25519)는 내 컴퓨터를 떠나지 않으며 네트워크로 전송되지도 않습니다.

접속할 때 클라이언트는 서버에게 어떤 키로 들어가려는지 알립니다. 서버는 사용자의 ~/.ssh/authorized_keys 파일에서 그 공개 키를 찾고, 찾으면 세션 데이터에 개인 키로 서명하라고 요구합니다. 서명은 공개 키로 검증되고, 로그인이 허용됩니다. 이 과정에서 비밀번호는 전혀 전송되지 않습니다.

1단계. 키 생성: ssh-keygen

내 컴퓨터(Linux, macOS, 또는 OpenSSH가 내장된 Windows 10/11)에서 실행합니다:

ssh-keygen -t ed25519 -C "alena@laptop"

-t는 알고리즘을, -C는 공개 키 끝에 붙는 주석을 지정합니다. 주석은 나중에 이 키가 누구의 것인지 알아보는 데 도움이 됩니다. Ed25519는 요즘 권장되는 알고리즘입니다. 키가 짧고, 빠르고, 믿을 만합니다. 서버가 매우 오래되어 Ed25519를 지원하지 않는다면 최소 3072비트 RSA를 쓰세요: ssh-keygen -t rsa -b 4096.

Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/alena/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/alena/.ssh/id_ed25519
Your public key has been saved in /home/alena/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:Xq3v0m6c1y2pVv8m3N0uYv9yQm0e6dFv5gH2rZt1aBc alena@laptop

패스프레이즈가 필요한가

패스프레이즈는 디스크에 있는 개인 키를 암호화합니다. 노트북을 도난당하거나 파일이 유출되어도, 패스프레이즈가 없으면 키는 쓸모가 없습니다. 개인 용도의 키에는 패스프레이즈를 거세요. 접속할 때마다 입력하는 번거로움은 ssh-agent로 줄입니다. 에이전트는 열어 둔 키를 세션 동안 메모리에 보관합니다.

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -l      # 불러온 키 목록

패스프레이즈 없는 키는 CI나 백업 스크립트처럼 자동화에 쓸 때 적합합니다. 이런 키는 서버에서 권한을 제한하는 것이 좋습니다(아래에서 설명합니다).

2단계. 공개 키를 서버에 복사: ssh-copy-id

가장 쉬운 방법은 ssh-copy-id입니다. 한 번 비밀번호로 접속해서, 공개 키를 서버의 ~/.ssh/authorized_keys에 추가하고 올바른 권한을 설정합니다.

ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@203.0.113.10
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/alena/.ssh/id_ed25519.pub"
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
deploy@203.0.113.10's password:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'deploy@203.0.113.10'"
and check to make sure that only the key(s) you wanted were added.

서버가 기본이 아닌 포트에서 대기하면 -p 2222를 추가하세요.

ssh-copy-id가 없을 때

Windows에는 ssh-copy-id가 없습니다. 아래 명령 하나로 키를 직접 보낼 수 있습니다:

cat ~/.ssh/id_ed25519.pub | ssh deploy@203.0.113.10 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

클라우드 제공업체는 보통 서버를 만들 때 공개 키를 물어보며, 이 키는 cloud-init을 통해 authorized_keys에 들어갑니다.

3단계. 로그인 확인

ssh deploy@203.0.113.10

비밀번호를 더 묻지 않거나(키의 패스프레이즈만 묻는다면) 모든 것이 정상입니다. 새 서버에 처음 접속하면 SSH가 서버 호스트 키의 지문을 보여 주며 신뢰할지 묻습니다. yes라고 답하면 지문이 ~/.ssh/known_hosts에 저장되고, 이후 서버 키가 바뀌면 SSH가 경고합니다.

클라이언트가 어떤 키를 시도하는지, 서버가 왜 거부하는지 보려면 자세히 모드로 접속하세요:

ssh -v deploy@203.0.113.10

~/.ssh/config: 서버 짧은 이름 쓰기

서버가 여러 대면 매번 사용자, IP, 포트, 키 경로를 입력하기 번거롭습니다. 이 정보를 ~/.ssh/config에 적어 두세요:

Host prod
    HostName 203.0.113.10
    User deploy
    Port 2222
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Host bastion
    HostName bastion.example.com
    User alena

Host db-internal
    HostName 10.0.0.15
    User admin
    ProxyJump bastion

Host *
    ServerAliveInterval 60
    AddKeysToAgent yes

이제 ssh prod만 입력하면 됩니다. scp, rsync, Git도 이 이름을 이해합니다: rsync -av ./site/ prod:/var/www/.

  • IdentitiesOnly yes — 지정한 키만 사용합니다. 이 줄이 없으면 클라이언트는 에이전트의 모든 키를 시도하고, 서버의 시도 횟수 제한 때문에 올바른 키에 닿기 전에 연결이 끊길 수 있습니다.
  • ProxyJump — 중간 서버(배스천)를 거쳐 내부 서버에 한 명령으로 접속합니다.
  • ServerAliveInterval — 60초마다 신호를 보내 유휴 상태에서 연결이 끊기지 않게 합니다.

설정 파일의 권한은 600이어야 합니다. 그렇지 않으면 SSH가 읽지 않을 수 있습니다: chmod 600 ~/.ssh/config.

에이전트 포워딩: 언제 쓰고 왜 위험한가

때로는 서버에서 다시 다른 곳으로 접속해야 합니다. 예를 들어 비공개 저장소에서 git pull을 할 때입니다. 이때 개인 키를 서버에 복사하면 안 됩니다. 대신 ssh -A나 ForwardAgent yes를 씁니다. 그러면 세션 동안 서버가 내 에이전트를 사용할 수 있게 됩니다. 하지만 그 서버에서 root 권한을 가진 누구든, 내가 접속해 있는 동안 에이전트를 쓸 수 있습니다. 따라서 포워딩은 신뢰하는 호스트에서만 켜고, 중간 서버를 거칠 때는 에이전트를 열지 않는 ProxyJump를 쓰세요.

4단계. 비밀번호 로그인 끄기

비밀번호 로그인이 켜져 있는 동안에는 서버가 무작위 대입 공격의 표적이 됩니다. 키로 로그인되는 것을 확인했다면 비밀번호를 끄세요. 중요: 새 창에서 로그인이 되는지 확인하기 전에는 현재 세션을 닫지 마세요. 그렇지 않으면 접속 권한을 잃을 수 있습니다.

/etc/ssh/sshd_config를 엽니다(메인 설정이 Include로 /etc/ssh/sshd_config.d/를 읽는다면, 그곳에 파일을 만듭니다). 다음을 설정하세요:

PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
PermitRootLogin no

PermitRootLogin no은 root로 직접 로그인하는 것을 막습니다. 관리자는 자기 계정으로 접속한 뒤 sudo로 권한을 올립니다. root 없이는 안 된다면 PermitRootLogin prohibit-password를 쓰세요. 이 경우 root는 키로만 들어올 수 있습니다.

문법을 검사하고 서비스를 다시 불러옵니다:

sudo sshd -t
sudo systemctl reload ssh      # Debian/Ubuntu; RHEL 계열에서는 sshd

sshd -t는 설정이 올바르면 아무 말도 하지 않습니다. 이제 새 터미널에서 키 로그인이 되는지 확인하고, 비밀번호로는 서버가 거부하는지 확인하세요:

$ ssh -o PubkeyAuthentication=no deploy@203.0.113.10
deploy@203.0.113.10: Permission denied (publickey).

추가 보호

비밀번호 차단이 가장 중요한 조치입니다. 그다음에는 보통 방화벽으로 22번 포트를 제한하고(ufw allow from 198.51.100.0/24 to any port 22), 여러 번 실패한 IP를 차단하는 fail2ban을 설치합니다. SSH 보호 상태는 sudo fail2ban-client status sshd로 봅니다.

자동화용 키는 authorized_keys에서 키 앞에 옵션을 붙여 제한할 수 있습니다. 예를 들어 from="198.51.100.7",no-port-forwarding,no-pty ssh-ed25519 AAAA... backup은 한 주소에서만, 대화형 셸 없이 들어오도록 허용합니다.

자주 나는 오류와 해결

Permission denied (publickey)

가장 흔한 오류입니다. 원인을 자주 나는 순서대로 정리했습니다:

  1. 서버의 잘못된 권한. 디렉터리나 파일을 다른 사용자가 쓸 수 있으면 sshd는 authorized_keys를 무시합니다. 해결: chmod 700 ~/.ssh, chmod 600 ~/.ssh/authorized_keys, 그리고 홈 디렉터리가 그룹이나 다른 사용자에게 쓰기 가능하지 않도록 하세요.
  2. 잘못된 소유자. 파일을 sudo로 만들었다면 root 소유가 됩니다. 해결: sudo chown -R deploy:deploy /home/deploy/.ssh.
  3. 키를 다른 사용자에게 넣음. root용으로 키를 복사했는데 deploy로 접속하거나, 그 반대인 경우입니다.
  4. 클라이언트가 다른 키를 제시함. ssh -v의 Offering public key 줄에서 어떤 키를 시도하는지 보입니다. -i나 IdentityFile로 올바른 키를 지정하세요.
  5. 복사하면서 키가 깨짐. 공개 키는 한 줄이어야 합니다. 클립보드에서 복사하면서 생긴 줄바꿈이 키를 망가뜨립니다.

서버 쪽 원인은 로그에 나옵니다: sudo journalctl -u ssh -n 30(RHEL에서는 -u sshd). 이런 줄을 볼 수 있습니다: Authentication refused: bad ownership or modes for directory /home/deploy/.ssh.

UNPROTECTED PRIVATE KEY FILE

클라이언트가 다른 사용자가 읽을 수 있는 개인 키를 쓰지 않으려 합니다. 해결: chmod 600 ~/.ssh/id_ed25519.

REMOTE HOST IDENTIFICATION HAS CHANGED

호스트 키가 known_hosts에 저장된 것과 다릅니다. 서버를 다시 설치했거나 IP가 바뀐 뒤에 나타나지만, 같은 메시지가 중간자 공격에서도 나타납니다. 서버를 정말 다시 만들었는지 확인한 뒤 옛 항목을 지우세요: ssh-keygen -R 203.0.113.10.

Too many authentication failures

에이전트가 서버에 너무 많은 키를 보내서, 서버가 MaxAuthTries 한도에서 연결을 끊었습니다. 해결: ~/.ssh/config에 IdentitiesOnly yes와 명확한 IdentityFile을 적으세요.

마무리

SSH 키 설정은 5분이면 끝나는 작업입니다. ssh-keygen -t ed25519, ssh-copy-id, 로그인 확인, 그다음 PasswordAuthentication no를 적용하고 두 번째 세션을 열어 둔 채 sshd를 다시 불러오세요. ~/.ssh/config는 긴 명령을 줄여 주고, 700/600 권한은 «Permission denied» 오류의 대부분을 해결합니다. SSH, rsync, 그리고 방화벽과 fail2ban으로 서버를 보호하는 방법은 강의에서 실습과 함께 다룹니다.

자주 묻는 질문

모든 서버에 SSH 키 하나만 써도 되나요?

기술적으로는 가능하며 많은 사람이 그렇게 합니다. 하지만 업무, 개인 프로젝트, CI에는 키를 따로 만드는 편이 좋습니다. 키 하나가 유출되어도 나머지 서버가 열리지 않습니다.

Windows에서 SSH 키는 어디에 저장되나요?

내장 OpenSSH는 C:\Users\이름\.ssh\ 폴더에 보관합니다. 여기에 id_ed25519, id_ed25519.pub, known_hosts, config가 있습니다. PowerShell에서 같은 <code>ssh-keygen</code> 명령으로 생성합니다.

기존 키의 패스프레이즈를 바꾸려면?

<code>ssh-keygen -p -f ~/.ssh/id_ed25519</code>를 실행하세요. 이전 패스프레이즈와 새 패스프레이즈를 묻습니다. 키 자체는 바뀌지 않으므로 서버에 다시 보낼 필요가 없습니다.

특정 키의 접속 권한을 회수하려면?

서버의 <code>~/.ssh/authorized_keys</code>에서 해당 공개 키 줄을 삭제하세요. 키 끝에 있는 주석이 줄을 찾는 데 도움이 됩니다.

개인 키만 남았을 때 공개 키를 얻으려면?

<code>ssh-keygen -y -f ~/.ssh/id_ed25519</code>가 개인 키에서 계산한 공개 키를 출력합니다.

영상으로 이 주제 배우기

이 주제는 “Linux: с нуля до уверенного администрирования” 강의에서 실습과 함께 자세히 다룹니다.

강의로 이동