Site Icon THEREiS최신 글 게시판 · 010번 읽는 중

제 목 :

SSH Keygen으로 키 만들어서 호스트 접속하기

올린이
[야훔]
날짜
태그

오늘 아침 서버에 키를 하나 새로 만들어 넣으려는데 ssh-keygen 옵션이 하나도 기억나지 않았다. 검색해 보니 명령어만 툭 던져 놓은 글, 개념만 길게 설명한 글, 몇 년 전 기준으로 쓴 글이 섞여 있어서 한 번에 정리된 곳이 없었다. 그래서 다음의 나를 위해 한 번에 정리해 둔다.

순서는 이렇다.

  1. 비대칭 키가 뭔지
  2. 왜 SSH 키를 만드는지, 그리고 접속할 때 실제로 무슨 일이 일어나는지
  3. 가장 간단하게 키 만들기
  4. 키 종류를 골라서 만들기
  5. AWS의 .pem 키는 정체가 뭔지
  6. 접속이 안 될 때 트러블슈팅

1. 비대칭 키란?

암호화 방식은 크게 두 가지다.

  • 대칭 키: 잠글 때와 열 때 같은 키를 쓴다. 빠르지만, 그 키를 상대에게 어떻게 안전하게 전달하느냐가 문제다.
  • 비대칭 키: 서로 다른 두 개의 키가 한 쌍으로 묶여 있다. 하나는 공개 키(public key), 하나는 **개인 키(private key)**다.

비대칭 키의 핵심 규칙은 단 하나다.

한쪽 키로 처리한 것은 짝이 되는 다른 키로만 풀거나 확인할 수 있다.

이 규칙을 두 가지 방향으로 쓴다.

비대칭 키의 두 가지 쓰임새: 암호화와 서명

  • 공개 키는 이름 그대로 공개해도 된다. 서버에 올려 두고, 깃허브에 등록하고, 동료에게 보내도 된다.
  • 개인 키는 절대로 내 컴퓨터 밖으로 나가면 안 된다. 개인 키를 가진 사람이 곧 “나”다.

SSH 로그인에서 쓰는 건 ②번, 서명 쪽이다. “나는 이 공개 키의 짝인 개인 키를 갖고 있다”를 개인 키를 직접 보내지 않고 증명하는 것이다. 자물쇠(공개 키)는 서버 문에 걸어 두고, 열쇠(개인 키)는 내 주머니에만 있다고 생각하면 편하다.

2. ssh-keygen으로 키를 만드는 이유

비밀번호 대신 키로 로그인하기

SSH는 원격 서버의 터미널에 접속하는 프로토콜이다. 비밀번호로도 접속할 수 있지만 문제가 많다.

  • 비밀번호는 매번 네트워크를 타고 서버로 전달된다(암호화된 채널 안이긴 하지만).
  • 사람이 외울 수 있는 길이라 무차별 대입 공격에 약하다. 22번 포트를 열어 두면 하루에도 수천 번씩 로그인 시도가 들어온다.
  • 스크립트나 CI에서 자동으로 접속하기 불편하다.

키로 로그인하면 개인 키는 내 컴퓨터를 떠나지 않고, 수천 비트짜리 키를 대입으로 맞추는 건 사실상 불가능하다. 그래서 ssh-keygen으로 키 쌍을 만들고, 공개 키를 서버에 등록하는 것이다.

authorized_keys: 서버의 출입 명단

서버는 “이 공개 키들의 주인은 들어와도 된다”는 명단을 사용자 홈 디렉토리의 아래 파일에 보관한다.

~/.ssh/authorized_keys

파일 내용은 그냥 공개 키를 한 줄에 하나씩 적어 둔 텍스트다.

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... test@macbook
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... thereis@nas

deploy 계정으로 접속하고 싶다면 /home/deploy/.ssh/authorized_keys에 내 공개 키가 있어야 한다. 계정마다 명단이 따로라는 점을 기억해 두자.

키로 접속하는 과정

ssh deploy@server를 치면 실제로는 아래 과정이 진행된다.

sequenceDiagram autonumber participant C as 내 PC (클라이언트)<br/>~/.ssh/id_ed25519 (개인 키) participant S as 원격 서버 (sshd)<br/>~/.ssh/authorized_keys C->>S: TCP 22번 포트로 연결 S-->>C: 서버의 호스트 키(공개 키) 전달 Note over C: ~/.ssh/known_hosts와 비교<br/>처음이면 "Are you sure...?" 질문 C->>S: 키 교환 (Diffie-Hellman) S-->>C: 키 교환 완료 Note over C,S: 이제부터 모든 통신은 세션 키로 암호화 C->>S: "deploy 계정으로, 이 공개 키로 로그인할게요" Note over S: authorized_keys에 이 공개 키가 있나? S-->>C: 있음. 그럼 증명해 봐 C->>S: 세션 고유값을 개인 키로 서명해서 전송 Note over S: 등록된 공개 키로 서명 검증 S-->>C: 검증 성공 → 로그인 허용 🎉

정리하면 SSH 접속에는 키가 두 번 등장한다.

단계 누가 누구를 확인하나 쓰이는 파일
호스트 인증 (2~3번) 클라이언트가 서버를 확인 (“내가 접속하려던 그 서버 맞아?”) 클라이언트의 ~/.ssh/known_hosts
사용자 인증 (6~10번) 서버가 클라이언트를 확인 (“너 들어와도 되는 사람 맞아?”) 서버의 ~/.ssh/authorized_keys

어느 쪽에서도 개인 키 자체는 네트워크로 나가지 않는다. 오가는 건 공개 키와 서명뿐이다.

3. ssh-keygen으로 간단하게 키 만들기

일단 만들기

아무 옵션 없이 실행하면 된다.

터미널
ssh-keygen
Generating public/private ed25519 key pair.
Enter file in which to save the key (/Users/test/.ssh/id_ed25519):
Enter passphrase for "/Users/test/.ssh/id_ed25519" (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/testjuhn/.ssh/id_ed25519
Your public key has been saved in /Users/testjuhn/.ssh/id_ed25519.pub

질문은 두 개다.

  1. 저장 위치: 엔터를 치면 기본 위치(~/.ssh/id_<종류>)에 저장된다. 이미 같은 이름의 키가 있으면 덮어쓸지 묻는데, 여기서 y를 치면 기존 키는 사라진다. 조심하자.
  2. 패스프레이즈(passphrase): 개인 키 파일 자체를 잠그는 비밀번호다. 노트북을 잃어버려도 키 파일만으로는 쓸 수 없게 해 준다. 개인용 키라면 걸어 두는 걸 추천하고, CI처럼 사람이 입력할 수 없는 곳에서 쓸 키라면 비워 둔다.

결과물은 두 개의 파일이다.

파일 정체 어디에 두나
id_ed25519 개인 키 내 컴퓨터에만. 권한 600
id_ed25519.pub 공개 키 서버의 authorized_keys, 깃허브 등

참고: OpenSSH 9.5부터 기본 키 종류가 RSA에서 Ed25519로 바뀌었다. 예전 글에서 id_rsa가 생긴다고 설명하는 건 그 이전 버전 기준이다. 내 버전은 ssh -V로 확인할 수 있다.

자주 쓰는 옵션을 붙여서 만들기

키가 여러 개가 되면 이름과 메모를 붙여 두는 게 좋다.

터미널
ssh-keygen -t ed25519 -C "test@macbook-nas" -f ~/.ssh/nas_ed25519
옵션 의미
-t 키 종류 (ed25519, rsa, ecdsa …)
-b 키 길이(비트). RSA, ECDSA에서만 의미 있음
-C 주석(comment). 공개 키 맨 끝에 붙어서 “이게 누구 키였지?“를 알려 준다
-f 저장할 파일 경로
-N 패스프레이즈를 명령어에서 바로 지정 (-N ""이면 패스프레이즈 없음)

서버에 공개 키 등록하기

가장 편한 건 ssh-copy-id다. 아직은 비밀번호로 접속이 되는 상태여야 한다.

터미널
ssh-copy-id -i ~/.ssh/nas_ed25519.pub deploy@192.168.0.10

이 명령어가 서버의 ~/.ssh 폴더 만들기, authorized_keys에 공개 키 추가하기, 권한 맞추기까지 다 해 준다. ssh-copy-id가 없는 환경이라면 직접 넣어도 된다.

터미널
cat ~/.ssh/nas_ed25519.pub | ssh deploy@192.168.0.10 \
"mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

이제 키로 접속해 본다.

터미널
ssh -i ~/.ssh/nas_ed25519 deploy@192.168.0.10

알아 두면 좋은 부가 명령어

터미널
# 개인 키에서 공개 키 다시 뽑아내기 (.pub 파일을 잃어버렸을 때)
ssh-keygen -y -f ~/.ssh/nas_ed25519 > ~/.ssh/nas_ed25519.pub
# 키의 지문(fingerprint) 확인하기
ssh-keygen -lf ~/.ssh/nas_ed25519.pub
# 패스프레이즈 바꾸기 (없던 패스프레이즈 추가도 이걸로)
ssh-keygen -p -f ~/.ssh/nas_ed25519
# 서버를 재설치해서 호스트 키가 바뀌었을 때, known_hosts에서 옛 기록 지우기
ssh-keygen -R 192.168.0.10

4. ssh-keygen으로 만들 수 있는 키의 종류

-t 옵션으로 고를 수 있는 키 종류는 이렇다.

종류 (-t) 키 길이 (-b) 특징 추천
ed25519 고정 (256비트) 짧고 빠르고 안전하다. 현재 기본값 ✅ 기본으로 이것
rsa 기본 3072, 4096 권장 가장 오래되고 호환성이 가장 좋다. 키가 길다 오래된 장비, 일부 클라우드
ecdsa 256 / 384 / 521 타원 곡선 방식. 일부 환경에서 요구 특별한 이유가 있을 때만
ed25519-sk 고정 YubiKey 같은 FIDO 보안 키에 개인 키가 묶인다 하드웨어 키가 있다면
ecdsa-sk 고정 위와 같지만 ECDSA. Ed25519를 지원하지 않는 보안 키용 보안 키가 Ed25519 미지원일 때
dsa 1024 고정 취약해서 OpenSSH 10.0에서 지원이 완전히 제거됐다 ❌ 쓰지 말 것

종류를 지정해서 만들기

터미널
# Ed25519 (가장 무난)
ssh-keygen -t ed25519 -C "test@macbook"
# RSA 4096비트 (오래된 서버나 장비와 호환이 필요할 때)
ssh-keygen -t rsa -b 4096 -C "test@macbook"
# ECDSA 521비트 (주의: 512가 아니라 521이다)
ssh-keygen -t ecdsa -b 521 -C "test@macbook"
# FIDO 보안 키(YubiKey 등)에 묶인 키. 접속할 때마다 키를 터치해야 한다
ssh-keygen -t ed25519-sk -C "test@yubikey"

고민될 때는 그냥 ed25519를 쓰고, 상대 쪽에서 “그 키 종류는 지원 안 해요”라고 할 때만 rsa -b 4096으로 내려가면 된다.

5. AWS의 pem 키에 대하여

AWS EC2 인스턴스를 만들 때 **키 페어(Key pair)**를 고르거나 새로 만들라고 한다. 새로 만들면 my-key.pem 같은 파일을 딱 한 번 내려받게 해 준다. 이 파일의 정체를 알면 헷갈릴 게 없다.

pem 파일 = 개인 키

.pem은 특별한 무언가가 아니라 AWS가 대신 만들어 준 개인 키다. PEM은 키를 -----BEGIN ... PRIVATE KEY-----로 시작하는 텍스트로 저장하는 형식 이름일 뿐이다.

그러니까 AWS에서 키 페어를 만들면 이런 일이 일어난다.

flowchart TB A["AWS가 키 쌍 생성"] --> B["개인 키 → my-key.pem<br/>나에게 한 번만 다운로드"] A --> C["공개 키 → AWS가 보관"] C --> D["인스턴스 첫 부팅 시<br/>cloud-init이 주입"] D --> E["/home/ec2-user/.ssh/authorized_keys"] B --> F["ssh -i my-key.pem ec2-user@IP"] F -->|"서명 검증"| E

결국 우리가 앞에서 ssh-keygen + ssh-copy-id로 한 일을 AWS가 대신 해 준 것뿐이다. 그래서 접속도 똑같다.

터미널
chmod 400 my-key.pem
ssh -i my-key.pem ec2-user@3.35.xxx.xxx

기본 사용자 이름은 AMI마다 다르다.

AMI 기본 사용자
Amazon Linux ec2-user
Ubuntu ubuntu
Debian admin
RHEL ec2-user

pem 키 관련해서 알아 두면 좋은 것

  • AWS는 개인 키를 다시 주지 않는다. pem 파일을 잃어버리면 다시 받을 방법이 없다. EC2 Instance Connect나 Systems Manager(SSM)로 들어가서 authorized_keys에 새 공개 키를 넣는 식으로 복구해야 한다.

  • pem에서 공개 키를 뽑을 수 있다. 다른 서버에도 같은 키로 들어가고 싶다면 이렇게 하면 된다.

    터미널
    ssh-keygen -y -f my-key.pem > my-key.pub
  • 내가 만든 키를 AWS에 올릴 수도 있다. EC2 콘솔의 Key pairs → Import key pair에 ssh-keygen으로 만든 .pub 내용을 붙여 넣으면 된다. 개인 키를 AWS가 한 번도 만지지 않으니 이쪽이 더 깔끔하다.

  • .ppk는 PuTTY용 형식이다. 윈도우에서 PuTTY를 쓸 때나 필요하고, 맥이나 리눅스에서는 .pem을 고르면 된다.

  • 키 페어를 만들 때 RSA와 ED25519 중에 고를 수 있는데, 윈도우 인스턴스는 ED25519를 지원하지 않는다. 리눅스 인스턴스라면 ED25519를 고르면 된다.

6. 원격 호스트 접속 시 트러블슈팅

키를 다 만들고 등록까지 했는데 Permission denied (publickey)가 뜨면 일단 이것부터 친다.

터미널
ssh -v deploy@192.168.0.10 # 더 자세히 보려면 -vvv

클라이언트가 어떤 설정을 읽었는지, 어떤 키를 시도했는지, 서버가 뭐라고 답했는지가 다 나온다. 서버에 다른 경로로 들어갈 수 있다면 서버 로그도 같이 보면 원인이 바로 나온다.

터미널
# Ubuntu / Debian
sudo tail -f /var/log/auth.log
# 또는 (systemd 환경)
sudo journalctl -u ssh -f # RHEL 계열은 -u sshd

6-1. ssh_config 설정 이슈

SSH 설정 파일은 두 종류가 있는데 이름이 비슷해서 헷갈린다.

파일 쪽 역할
~/.ssh/config, /etc/ssh/ssh_config 클라이언트 내가 접속할 때 쓸 옵션
/etc/ssh/sshd_config 서버 (d = daemon) 서버가 접속을 받을 때 쓸 규칙

클라이언트: ~/.ssh/config

매번 -i, -p, 사용자 이름을 치기 귀찮으니 보통 이렇게 정리해 둔다.

Host nas
HostName 192.168.0.10
User deploy
Port 2222
IdentityFile ~/.ssh/nas_ed25519
IdentitiesOnly yes
Host aws-web
HostName 3.35.xxx.xxx
User ec2-user
IdentityFile ~/.ssh/my-key.pem
IdentitiesOnly yes
Host *
ServerAliveInterval 60

이제 ssh nas만 치면 된다. 여기서 자주 밟는 함정은 이렇다.

① Too many authentication failures

키가 여러 개 있으면 ssh는 IdentityFile로 지정한 키 말고도 ssh-agent에 들어 있는 키들을 하나씩 다 시도한다. 서버는 보통 시도 횟수를 6번(MaxAuthTries)으로 제한하기 때문에, 맞는 키를 내밀기 전에 쫓겨난다. **IdentitiesOnly yes**를 넣으면 지정한 키만 쓴다.

② 먼저 적힌 설정이 이긴다

ssh_config는 같은 옵션이 여러 번 나오면 처음 나온 값을 쓴다. 그래서 맨 위에 Host *로 User root 같은 걸 적어 두면, 아래의 Host nas에 적은 User deploy가 무시된다. 공통 설정인 Host *는 항상 맨 아래에 둔다.

헷갈릴 때는 실제로 적용될 최종 설정을 출력해 보면 된다.

터미널
ssh -G nas | grep -Ei '^(user|hostname|port|identityfile)'

③ config 파일 권한

~/.ssh/config를 다른 사용자가 쓸 수 있는 권한이면 Bad owner or permissions on ~/.ssh/config 오류를 내고 아예 접속을 시도하지 않는다.

터미널
chmod 600 ~/.ssh/config

서버: /etc/ssh/sshd_config

키는 맞는데도 안 되면 서버 설정을 의심한다.

PubkeyAuthentication yes # 키 로그인 허용 (기본값 yes)
AuthorizedKeysFile .ssh/authorized_keys # 공개 키 명단 위치
PasswordAuthentication no # 키 등록이 끝났으면 비밀번호 로그인은 막자
PermitRootLogin prohibit-password # root는 키로만 (아예 막으려면 no)

여기서 정말 많이 당하는 함정이 하나 있다. sshd_config를 고쳤는데 반영이 안 되는 경우다. 요즘 배포판은 sshd_config 맨 위에 이런 줄이 있다.

Include /etc/ssh/sshd_config.d/*.conf

sshd_config도 처음 나온 값이 이기기 때문에, sshd_config.d/ 안의 파일(예: 클라우드 이미지의 50-cloud-init.conf)에 PasswordAuthentication yes가 들어 있으면 본문에서 no로 바꿔도 소용이 없다. 실제로 적용된 값은 이렇게 확인한다.

터미널
sudo sshd -T | grep -Ei 'passwordauthentication|pubkeyauthentication|authorizedkeysfile'

설정을 고친 뒤에는 문법 검사 → 재시작 순서를 지킨다. 문법이 틀린 채로 재시작하면 sshd가 안 떠서 서버에 다시 못 들어갈 수 있다. 재시작할 때 지금 접속한 세션은 끊지 말고, 새 터미널에서 접속이 되는지 확인한 뒤에 닫자.

터미널
sudo sshd -t && sudo systemctl restart ssh # RHEL 계열은 sshd

6-2. authorized_keys의 777 권한 이슈

“권한 때문에 안 되나?” 싶어서 chmod 777을 날리는 순간 오히려 영영 안 된다. 이게 가장 억울한 케이스다.

sshd에는 StrictModes라는 옵션이 기본으로 켜져 있다. authorized_keys 파일, ~/.ssh 폴더, 홈 디렉토리 중 하나라도 다른 사람이 쓸 수 있는 권한이면 그 명단을 믿지 않는다. 누군가 그 파일에 몰래 자기 공개 키를 끼워 넣을 수 있다는 뜻이기 때문이다.

그래서 777로 열면 클라이언트에서는 그냥 Permission denied (publickey)만 보이고, 서버 로그에는 이런 줄이 남는다.

Authentication refused: bad ownership or modes for file /home/deploy/.ssh/authorized_keys

해결은 권한을 좁히는 것이다.

터미널
chmod 755 ~ # 또는 750. 핵심은 그룹/기타 사용자의 쓰기 권한 제거 (chmod go-w ~)
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R deploy:deploy ~/.ssh # sudo로 파일을 만들었다면 소유자가 root로 되어 있을 수 있다

서버와 클라이언트에서 맞춰야 할 권한을 한 번에 정리하면 이렇다.

위치 대상 권한 틀렸을 때
서버 홈 디렉토리 ~ 755 이하 (그룹/기타 쓰기 금지) 서버 로그에 bad ownership or modes
서버 ~/.ssh 700 〃
서버 ~/.ssh/authorized_keys 600 〃
클라이언트 ~/.ssh 700
클라이언트 개인 키 (id_ed25519, *.pem) 600 또는 400 UNPROTECTED PRIVATE KEY FILE!
클라이언트 공개 키 (*.pub) 644
클라이언트 ~/.ssh/config 600 Bad owner or permissions

클라이언트 쪽 개인 키도 같은 이유로 검사한다. 내려받은 pem 파일은 보통 644라서 처음 접속할 때 거의 반드시 이 경고를 보게 된다.

WARNING: UNPROTECTED PRIVATE KEY FILE!
Permissions 0644 for 'my-key.pem' are too open.
This private key will be ignored.
터미널
chmod 400 my-key.pem

권한을 다 맞췄는데도 RHEL / Rocky / CentOS 계열에서 안 된다면 SELinux 라벨 문제일 수 있다. 직접 만든 .ssh 폴더라면 restorecon -Rv ~/.ssh로 라벨을 되돌려 보자.

마치며

다시 까먹었을 때 이 부분만 보면 된다.

터미널
# 1. 키 만들기
ssh-keygen -t ed25519 -C "나@기기" -f ~/.ssh/서버이름_ed25519
# 2. 서버에 공개 키 등록
ssh-copy-id -i ~/.ssh/서버이름_ed25519.pub 사용자@서버
# 3. 접속
ssh -i ~/.ssh/서버이름_ed25519 사용자@서버
# 안 되면
ssh -v 사용자@서버 # 클라이언트 쪽 상황
sudo tail -f /var/log/auth.log # 서버 쪽 상황
chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys # 777은 절대 금지
  • 공개 키는 자물쇠, 개인 키는 열쇠. 자물쇠는 서버의 authorized_keys에 걸고, 열쇠는 내 주머니에만.
  • AWS의 .pem은 AWS가 대신 만들어 준 개인 키일 뿐이다.
  • 권한 문제는 넓히는 게 아니라 좁혀서 푼다.

아휴 이제 SSH 키 관련해서 5년은 정리 안해도 되겠지. 그럼 안녕!

오케이 거기까지

[ 꼬리말 ]승인 후 게시됩니다

꼬리말을 불러오는 중...