Security - SSH 프로세스 정리

2026. 1. 1. 13:56·CKA

네, 원문의 내용을 충실히 살리면서, 초보자도 "아, 이래서 안전하구나!"라고 무릎을 칠 수 있도록 상세하고 친절하게 풀어쓴 버전입니다. 개발 블로그에 그대로 복사해서 붙여넣으셔도 손색없도록 구조화하고 가독성을 높였습니다.


[Deep Dive] SSH 접속의 모든 것: ssh -i key.pem을 쳤을 때 일어나는 9단계 과정

개발자라면 AWS EC2나 리눅스 서버에 접속하기 위해 하루에도 수십 번씩 아래 명령어를 입력합니다.

ssh -i my-key.pem ec2-user@1.2.3.4

엔터를 누르고 프롬프트가 뜨기까지 걸리는 시간은 불과 1초. 하지만 그 짧은 찰나에 내부에서는 고도의 암호화 수학과 엄격한 인증 절차가 숨 가쁘게 돌아갑니다.

이 글은 SSH 접속 시 실제로 무슨 일이 벌어지는지, "인증(로그인)"과 "암호화(통신 보호)"를 명확히 분리하여 아주 상세하게 정리한 글입니다. 이 원리만 알면 SSH 접속 에러나 보안 경고가 떴을 때 당황하지 않고 원인을 찾을 수 있습니다.


0. 가장 먼저 잡아야 할 핵심 개념 2가지

SSH 과정을 이해하기 위해선 딱 하나, "키(Key)가 두 번 등장한다"는 사실을 먼저 기억해야 합니다. 많은 분들이 이 둘을 혼동합니다.

1) 로그인(인증)을 위한 키: "신분증"

  • 종류: 클라이언트 사용자 키 (my-key.pem, id_rsa 등)
  • 목적: "내가 이 서버에 들어갈 권한이 있는 사람인지" 증명하는 용도입니다.
  • 특징: 서버에 접속할 때 딱 한 번 신원 확인용으로 쓰입니다.

2) 통신(암호화)을 위한 키: "암호 코드북"

  • 종류: 세션 대칭키 (Session Key)
  • 목적: "SSH 세션 안의 모든 데이터(명령어, 출력 결과, 파일 전송 등)를 암호화"하는 용도입니다.
  • 특징: 접속할 때마다 서버와 클라이언트가 협상해서 새로 만듭니다. (일회용)

💡 핵심 결론:
우리가 명령어에 넣는 -i my-key.pem은 통신을 암호화하는 키가 아닙니다. 오직 "로그인 증명"에만 쓰입니다. 통신 암호화는 접속 때마다 새로 만든 대칭키로 수행합니다.


1. AWS EC2 .pem의 정체: 서버에는 무엇이 저장될까?

AWS에서 인스턴스를 만들 때 다운로드한 .pem 파일, 그리고 서버의 관계는 다음과 같습니다.

  • 내 컴퓨터 (Client): my-key.pem (개인키)를 가지고 있습니다. 이것은 절대 남에게 보여주면 안 되는 '도장'과 같습니다.
  • AWS 서버 (Server): 인스턴스 생성 시, 해당 키 페어의 공개키(Public Key)가 기본 사용자 계정의 authorized_keys 파일에 자동 등록됩니다.
  • 위치 예시: /home/ec2-user/.ssh/authorized_keys

즉, 서버는 "이 공개키에 딱 맞는 도장(개인키)을 가진 사람만 들여보내줘"라고 설정된 상태입니다. 그래서 우리는 공개키 내용을 외우지 않아도, 내 컴퓨터에 있는 개인키(pem)만으로 접속이 가능한 것입니다.

(참고: 만약 pem 파일에서 공개키 내용을 다시 뽑아보고 싶다면 아래 명령어를 씁니다.)

ssh-keygen -y -f my-key.pem > my-key.pub

2. SSH 접속 전체 단계 (The Full Flow)

이제 ssh -i my-key.pem ec2-user@<IP>를 입력하고 엔터를 탁! 쳤을 때 일어나는 일을 시간 순서대로 뜯어보겠습니다.

[1단계] TCP 연결 (네트워크 레벨)

가장 먼저 클라이언트는 서버의 22번 포트로 TCP 연결을 시도합니다. (노크)

  • 여기서 막힌다면?
  • AWS Security Group(보안 그룹)에서 22번 포트를 열어주지 않았거나,
  • 네트워크 방화벽, 라우팅 문제일 가능성이 99%입니다.

[2단계] 프로토콜 버전 교환

연결이 되면 서로 인사를 나눕니다.

  • "안녕? 나는 SSH-2.0 버전을 써."
  • "반가워, 나도 SSH-2.0 지원해."

[3단계] 알고리즘 협상 (KEXINIT)

이제 앞으로 어떻게 통신할지 '규칙'을 정하는 회의를 합니다. 서로 지원 가능한 알고리즘 목록을 교환하고 합의합니다.

  • 키 교환 방식(KEX): (EC)DHE, Curve25519 등 ("우리 암호키 어떻게 만들까?")
  • 대칭 암호(Cipher): AES-GCM, ChaCha20 등 ("데이터는 뭘로 잠글까?")
  • 무결성(MAC): ("데이터가 변조됐는지 어떻게 확인할까?")

[4단계] 키 교환 (Key Exchange) → 공유 비밀 생성 (★중요)

이 단계가 보안의 핵심입니다. 세션 대칭키(암호 코드북)를 만들기 위한 재료를 만듭니다. 주로 디피-헬먼(Diffie-Hellman) 방식을 사용합니다.

  1. 클라이언트: 비밀값 a를 만들고, 이를 가공한 공개값 A를 서버에 보냅니다.
  2. 서버: 비밀값 b를 만들고, 이를 가공한 공개값 B를 클라이언트에 보냅니다.
  3. 마법:
  • 클라이언트는 (내 비밀 a + 서버 공개값 B)를 계산 → 값 S 도출
  • 서버는 (내 비밀 b + 클라이언트 공개값 A)를 계산 → 값 S 도출
  • 수학적으로 두 S는 동일한 값이 나옵니다!

핵심 포인트:
네트워크 선을 타고 A와 B가 왔다 갔다 했지만, 이것만 봐서는 해커가 절대 비밀값 S를 유추할 수 없습니다. 즉, 진짜 암호키는 전송되지 않고 각자 자리에서 '생성'됩니다. 그래서 스니핑(도청)이 불가능합니다.

[5단계] 세션 대칭키 파생 + 암호화 채널 시작

위에서 만든 공유 비밀 S 하나로 끝이 아닙니다. 이를 바탕으로 여러 개의 키를 파생시킵니다.

  • 클라이언트 → 서버 갈 때 쓸 암호키
  • 서버 → 클라이언트 올 때 쓸 암호키
  • 데이터 무결성 검증 키 등

"자, 이제부터 이 키들로 암호화해서 말하자!"라고 신호를 보낸 뒤, 이 시점 이후의 모든 SSH 패킷은 암호화됩니다.
(아직 로그인 안 했습니다! 로그인 정보를 안전하게 보내기 위해 보안 터널부터 뚫은 것입니다.)

[6단계] 서버 검증 (Host Key Verification)

터널은 뚫렸는데, 저쪽 끝에 있는 게 '진짜 내 서버'가 맞을까요? 해커가 만든 가짜 서버면 어쩌죠?

  1. 서버는 자신의 서버 호스트키(개인키)로 현재까지의 대화 내용을 서명해서 보냅니다.
  2. 클라이언트는 서버가 보낸 서버 호스트 공개키로 서명을 검증합니다.
  3. 그리고 내 컴퓨터의 ~/.ssh/known_hosts 파일을 봅니다.
  • 첫 접속: "어? 이 서버 키는 처음 보는데? 믿을래?" → Are you sure... (yes/no)? (이걸 TOFU: Trust On First Use라고 합니다.)
  • 재접속: 저장된 키와 다르면? → WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! 경고를 띄웁니다. (중간자 공격 가능성)

요약: 이 단계는 중간자 공격(MITM)을 막는 단계입니다. 해커가 중간에서 가짜 서버 흉내를 내도, 서버의 호스트 키가 없으면 이 검증을 통과 못 합니다.

[7단계] 사용자 인증 시작 (User Authentication)

드디어 안전한 터널 위에서 로그인을 시도합니다.
"나 ec2-user로 로그인할게."
서버는 가능한 인증 방법을 알려줍니다. (EC2는 보통 비밀번호 끄고 publickey 방식만 켜둡니다.)

[8단계] 공개키 인증 (Public Key Authentication) → -i pem이 쓰이는 구간

이제 우리가 가진 my-key.pem이 주인공으로 등장합니다.

  1. 클라이언트: "나 my-key.pem에 해당하는 공개키 가지고 있어. 이걸로 인증할게."
  2. 서버: authorized_keys 파일을 뒤집니다. "어, 그 공개키 등록되어 있네? 하지만 네가 진짜 그 키 주인인지는 확인해야겠어."
  3. 검증 요청: 서버는 임의의 데이터(난수 등)를 주며 말합니다. "이거 네 개인키로 서명(Sign)해서 보내봐."
  4. 서명 생성: 클라이언트는 pem 파일(개인키)을 이용해 데이터를 암호화 서명(Sig)합니다.
  • Sig = Sign(private_key, Data)
  1. 검증: 클라이언트는 서명값 Sig만 서버로 보냅니다. 서버는 가지고 있던 공개키로 이를 풉니다.
  • Verify(public_key, Data, Sig) == True
  1. 결과: 풀리면 로그인 성공!

중요:
개인키 파일(.pem) 자체는 절대로 네트워크를 타고 전송되지 않습니다. 가는 건 오직 '서명값'뿐입니다. 서명값은 매번 달라지므로 해커가 이걸 훔쳐봐도 재사용할 수 없습니다.

[9단계] 세션 채널 오픈 → 모든 데이터 암호화 통신

로그인이 성공하면 터널 안에 실제 데이터를 주고받을 '채널(Channel)'이 열립니다.
이제 우리가 치는 ls, cd 같은 명령어와 그 결과, 파일 전송 등 모든 트래픽은 [5단계]에서 만든 세션 대칭키로 암호화되어 흐릅니다.


3. "누가 훔쳐보면 어쩌죠?" 보안 Q&A

Q1. 해커가 네트워크 패킷을 스니핑하면 어떻게 되나요?
A. 아무것도 볼 수 없습니다.
[5단계] 이후의 모든 데이터는 대칭키로 암호화되어 있습니다. 해커 눈에는 a1b2c3d4... 같은 무의미한 난수만 보입니다. 암호화 키는 네트워크로 전송된 적 없이 각자 계산해서 만들었기 때문에 해커가 가질 수 없습니다.

Q2. 그럼 SSH는 무적입니까?
A. 2가지 약점은 조심해야 합니다.

  1. 무지성 Yes (MITM): 접속할 때 "이 서버 키 바뀌었는데 접속할래?"라는 경고를 무시하고 Yes를 누르거나, StrictHostKeyChecking=no 옵션을 남발하면, 해커가 만든 가짜 서버에 접속해서 정보를 털릴 수 있습니다.
  2. 개인키(pem) 유출: 내 컴퓨터에 있는 .pem 파일이 털리면 끝입니다. 그 파일만 있으면 누구든 나와 똑같이 로그인할 수 있습니다. 그래서 "프라이빗 키는 절대 공유 금지"인 것입니다.

4. 올바른 키 관리: "내 키는 나만, 친구는 친구 키로"

팀원과 서버를 같이 써야 할 때, 절대 내 .pem 파일을 메신저로 보내주지 마세요.

  • 나만 접속: 서버 authorized_keys에 내 공개키만 있음.
  • 친구 추가: 친구에게 "너의 공개키(Public Key)를 줘"라고 한 뒤, 서버 authorized_keys에 한 줄 추가해 줍니다.
  • 친구 차단: 싸웠다면 친구의 공개키 줄만 지우면 됩니다. (내 키는 안전함)

보너스 팁: AWS Security Group에서 22번 포트는 0.0.0.0/0(전체 허용) 대신 My IP로 내 IP만 허용하세요. 키가 털려도 네트워크 레벨에서 막을 수 있는 최후의 보루입니다.


5. 실제로 눈으로 확인해보기 (실습)

백문이 불여일견, 터미널에서 -vvv 옵션을 붙여 접속해보세요. 위에서 설명한 9단계가 로그로 쏟아집니다.

ssh -vvv -i my-key.pem ec2-user@1.2.3.4

확인해볼 포인트:

  • debug1: kex: algorithm: : 어떤 키 교환 방식을 썼는지
  • debug1: Authentications that can continue: : 서버가 어떤 인증을 허용하는지
  • debug1: Offering public key: : 내 공개키를 들이미는 과정
  • debug1: Authentication succeeded : 인증 성공!

6. 운영자를 위한 최소 보안 체크리스트

  1. 비밀번호 로그인 끄기: /etc/ssh/sshd_config에서 PasswordAuthentication no 설정
  2. 개인키 권한 잠그기: 로컬에서 chmod 400 my-key.pem (나만 읽기 가능)
  3. SSH 접속 경고 무시 금지: known_hosts 경고가 뜨면 무조건 확인하기. (IP가 바뀌었는지, 진짜 해킹인지)
  4. IP 제한: 보안 그룹(방화벽)으로 접속 가능한 IP 최소화하기.

요약

SSH 접속은 (1) 키 교환 마법을 통해 둘만의 암호 코드를 '생성'하여 도청을 막고, (2) 질문-답변(서명) 방식을 통해 '키 파일 자체 전송 없이' 소유자를 증명하는 안전한 기술입니다.

'CKA' 카테고리의 다른 글

Security - 인증서 생성 방법  (0) 2026.01.01
Security - TLS in Kubernetes  (0) 2026.01.01
Security - 대칭키/비대칭키/CA  (0) 2026.01.01
Security - Authentication 기초  (0) 2025.12.31
Security - 개요  (0) 2025.12.31
'CKA' 카테고리의 다른 글
  • Security - 인증서 생성 방법
  • Security - TLS in Kubernetes
  • Security - 대칭키/비대칭키/CA
  • Security - Authentication 기초
5jyan5
5jyan5
  • 5jyan5
    jyan
    5jyan5
  • 전체
    오늘
    어제
    • 분류 전체보기 (243)
      • 김영한의 스프링 핵심 원리(기본편) (8)
      • 김영한의 스프링 핵심 원리 - 고급편 (11)
      • 김영한의 스프링 MVC 1편 (1)
      • 김영한의 스프링 DB 1편 (3)
      • 김영한의 스프링 MVC 2편 (3)
      • 김영한의 ORM 표준 JPA 프로그래밍(기본편) (9)
      • 김영한의 스프링 부트와 JPA 활용2 (2)
      • 김영한의 실전 자바 - 중급 1편 (1)
      • 김영한의 실전 자바 - 고급 1편 (9)
      • 김영한의 실전 자바 - 고급 2편 (9)
      • Readable Code: 읽기 좋은 코드를 작성.. (2)
      • 김영한의 실전 자바 - 고급 3편 (9)
      • CKA (119)
      • 개발 (37)
      • 경제 (4)
      • 리뷰 (1)
      • 정보 (2)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      락
      cglib
      단방향 맵핑
      프록시 팩토리
      스레드
      hibernate5module
      @discriminatorvalue
      jpq
      Target
      Thread
      페치 조인
      log trace
      JPQL
      WAS
      고급
      김영한
      gesingleresult
      빈 후처리기
      버퍼
      @discriminatorcolumn
      requset scope
      typequery
      reentarantlock
      @args
      프록시
      양방향 맵핑
      자바
      jdk 동적 프록시
      조회 성능 최적화
      @within
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.2
    5jyan5
    Security - SSH 프로세스 정리
    상단으로

    티스토리툴바