SSH key 회전 정책 — 우리는 분기에 한 번
"문제 생기면 바꾸자"에서 분기 1회 정책으로 전환한 이유와 절차. 결제·정산 환경의 SSH 키 유출 위험, 자동화 스크립트 키 관리 함정, 즉시 쓸 수 있는 회전 체크리스트까지 담았다.
결제·정산 인프라에서 SSH 키 유출은 왜 다른가
일반적인 웹 서비스에서 SSH 키가 유출되면 피해 범위는 대개 그 서버 하나다. 하지만 HEDVION처럼 결제 승인, 매출 정산, 은행 파일 전송을 직접 운영하는 환경에서는 이야기가 달라진다. 서버 하나에 SSH로 접근할 수 있다는 것은 정산 원장에, 가맹점 매출 데이터에, 은행 SFTP 연동 스크립트에 동시에 닿을 수 있다는 뜻이다. "키 하나"의 블래스트 레디어스가 일반 서비스와 근본적으로 다르다.
더 무서운 건 탐지 지연이다. 공격자가 SSH 키를 탈취한 뒤 매일 새벽 2시에 정산 파일만 조용히 읽어간다면, 서비스 이상 없이 몇 달이 흘러도 알 수 없다. 2022년 Heroku GitHub Actions 토큰 탈취 사고처럼, 자격증명 유출은 종종 수개월 뒤에야 발각된다. 결제 환경에서 90일 동안 모른다는 건 수억 원 규모의 거래 데이터가 외부에 노출될 수 있는 시간이다. 이것이 우리가 "문제 생기면 바꾸자"는 관행을 버린 핵심 이유다.
왜 분기인가 — 월별·연간 주기와의 실제 트레이드오프
키 회전 주기 결정은 보안 수준과 운영 비용 사이의 균형 문제다. 연간 회전은 너무 길다. 키가 1월 1일에 유출되면 12월 31일까지 유효하다. 정산 데이터 1년치가 통째로 위험에 노출된다. 월별 회전은 반대 문제가 있다. 우리는 세 명이고 SSH 접근이 필요한 서버가 프로덕션·스테이징 포함 총 7대다. 키 교체 한 사이클을 완료하는 데 한 사람당 약 2535분이 걸린다. 월별로 하면 세 명 합산 월 90105분, 연간 약 18~21시간이 순수 키 관리 작업에 소비된다.
분기 회전은 연간 약 4.5~5.5시간이다. 여기에 현실적인 변수가 하나 더 있다. 복잡하거나 부담스러운 절차는 미뤄지고, 미뤄진 정책은 없는 것과 같다. 분기 1회는 직전 분기 마지막 주에 슬랙 리마인더만 걸어두면 빠뜨리지 않고 지킬 수 있다. 우리가 내린 결론은 간단하다. 지켜지는 90일 주기가 지켜지지 않는 30일 주기보다 낫다. 물론 이 선택에는 전제가 있다. 서버 접근 로그와 CloudTrail을 병행해 이상 접근을 별도로 탐지할 수 있는 체계가 갖춰진 덕분에 분기를 선택할 수 있었다. PCI-DSS v4.0 수준의 규제 환경이라면 더 짧은 주기가 필요할 수 있다.
실전 절차 — "새 키 먼저, 구 키 나중에" 원칙
절차는 다섯 단계다. 중요한 것은 단계 수가 아니라 순서다.
- 새 키 페어 생성:
ssh-keygen -t ed25519 -C "팀원명@hedvion-YYYYQQ"— 코멘트에 분기 정보를 박아 누가 언제 만든 키인지 명확히 한다. Ed25519를 선택하는 이유는 RSA 4096보다 키가 짧고 서명이 빠르면서 보안 수준은 동등하거나 높기 때문이다. - 신규 공개키를 대상 서버의
~/.ssh/authorized_keys에 추가한다. 기존 키는 아직 남겨둔다. - 신규 키로 접속이 정상인지 반드시 검증한다.
- 검증 완료 후, 기존 공개키를
authorized_keys에서 제거한다. - 로컬의 기존 키 파일을
~/.ssh/archive/YYYYQQ/로 이동한다.
우리가 초기에 한 번 겪은 실수를 공유한다. 4번과 3번 순서를 바꿔 구 키를 먼저 제거했는데, ssh-add 에이전트에 로드된 키가 여전히 구 키여서 신규 키로 접속이 안 됐다. 다행히 해당 서버에 콘솔 접근 경로가 남아 있어 복구했지만, 정산 배치가 물려 있는 프로덕션 서버였다면 새벽 집계가 멈추는 상황이었다. 새 로프를 잡기 전에 기존 로프를 놓지 않는다. 이 순서는 협상 불가다.
자동화 키는 반드시 별도로 관리해야 한다
여기가 많은 팀이 빠뜨리는 함정이다. HEDVION 환경에는 "사람이 쓰는 키"와 "스크립트가 쓰는 키"가 따로 존재한다. 새벽 2시 정산 집계 크론잡, 은행 SFTP에 매일 파일을 올리는 배치, 이상 거래 알림 자동화 — 이 모두가 SSH 키를 사용한다.
2025년 3분기 회전 때 실제로 사고가 났다. 프로덕션 SFTP 접속에 쓰이는 배치 계정 키를 서버에서는 교체했는데, 배치 스크립트의 IdentityFile 경로를 업데이트하지 않았다. 새벽 2시 30분 배치 실패, 오전 8시 알람. 정산 결과는 당일 재실행으로 복구했지만 가맹점 담당자에게 지연 사유를 해명해야 했다. 이후 회전 체크리스트에 "자동화 키 레지스트리"를 별도로 추가했다. 어떤 서비스가 어느 서버에 어떤 키 파일로 SSH 접속하는지를 테이블로 관리하고, 회전 시 자동화 키를 먼저 교체해 테스트 실행으로 검증한 뒤 사람 키를 교체하는 순서를 고정했다.
키 네이밍과 이력 관리 — 인시던트 대응의 복선
~/.ssh/ 아래에 키가 무계획적으로 쌓이면 인시던트 대응에서 발목을 잡힌다. "지금 이 서버에 어떤 키가 등록되어 있고, 마지막 회전이 언제였나?"라는 질문에 즉시 답하지 못하면 키 유출 의심 상황에서 대응 속도가 치명적으로 느려진다.
우리는 {서비스명}_{환경}_{분기} 형태를 쓴다. hedvion_prod_2026q2, hedvion_sftp_2026q2 같은 식이다. 기존 키는 ~/.ssh/archive/2026q2/에 보관하며 폴더를 삭제하지 않는다. 키 파일 자체는 이미 무효화됐지만, 파일 타임스탬프와 코멘트로 "2026년 1분기부터 2분기까지 이 키가 유효했다"는 이력이 남는다. 보안 감사나 이상 접근 역추적에서 이 이력의 유무는 실제로 차이가 크다.
팀원 퇴사와 즉시 폐기 — 예외 없는 원칙
분기 회전과 달리 팀원 퇴사는 절차를 기다리지 않는다. 퇴사 처리 당일, HR 프로세스와 병렬로 해당 팀원의 공개키를 전체 서버에서 제거한다. 소규모 팀일수록 이 절차가 감정적으로 불편할 수 있지만, 불편함과 정책은 분리해야 한다. 7대 서버 기준으로 약 15분이면 끝난다. 담당자와 완료 여부를 슬랙 스레드에 기록하는 것까지가 절차다.
자동화 계정에 퇴사 팀원의 키가 혼재되지 않았는지도 반드시 함께 확인한다. 사람 키는 authorized_keys에서 눈에 보이지만, 배치 계정에 공유 키 형태로 들어가 있는 경우는 놓치기 쉽다. 퇴사 체크리스트에 이 항목을 명시적으로 포함시켜야 한다.
지금 바로 쓸 수 있는 회전 체크리스트
아래는 우리 팀이 실제로 쓰는 체크리스트다. 서버 수와 팀 규모에 맞게 변형해서 쓰면 된다.
사전 준비 (회전 1주 전)
- 자동화 키 레지스트리 확인 — 어떤 배치·크론이 어떤 키를 쓰는가
- 공유 서버가 있는 경우 슬랙에 회전 일정 공지
- 담당 서버 목록 재확인
회전 당일
-
ssh-keygen -t ed25519 -C "이름@hedvion-YYYYQQ"로 신규 키 생성 - 신규 공개키를
authorized_keys에 추가 (기존 키 유지) - 신규 키로 접속 검증 — 이 순서 절대 생략 금지
- 자동화 스크립트
IdentityFile경로 업데이트 및 테스트 실행 - 기존 공개키
authorized_keys에서 제거 - 기존 키 파일을
~/.ssh/archive/YYYYQQ/로 이동 - 완료 슬랙 스레드에 기록
퇴사 발생 시 (당일 즉시)
- 해당 팀원 공개키 전 서버 제거 — 당일 완료 필수
- 자동화 계정에 해당 팀원 키 혼재 여부 확인
- 슬랙 스레드에 완료 기록
분기 회전이 완벽한 보안 솔루션은 아니다. 키 유출은 주기 사이에도 일어날 수 있고, SSH 이외의 공격 경로는 여전히 열려 있다. 하지만 정책이 존재하고, 절차가 구체적이며, 실제로 지켜질 때 보안은 비로소 작동한다. 세 명짜리 팀에서 지킬 수 있는 정책이 최선의 정책이다.
* 위 링크는 인프런 affiliate 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
* 위 추천 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.